mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-29 00:10:02 -05:00
Compare commits
659 Commits
python_scr
...
releases/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77c1ee3e7a | ||
|
|
4be2c33985 | ||
|
|
3034d79373 | ||
|
|
e7daa586ba | ||
|
|
3f4bdfdf61 | ||
|
|
ab5860dc9a | ||
|
|
53b2347358 | ||
|
|
a195179101 | ||
|
|
fdccc55805 | ||
|
|
55dce338b2 | ||
|
|
03c217addb | ||
|
|
a3a3f52b48 | ||
|
|
477b284041 | ||
|
|
b52495bc33 | ||
|
|
46ed451712 | ||
|
|
963afdce96 | ||
|
|
3f18a9a536 | ||
|
|
64b226e12d | ||
|
|
b74dc3d8b9 | ||
|
|
9668a885e8 | ||
|
|
b7afbf4a74 | ||
|
|
4784a82d51 | ||
|
|
a1ff1af754 | ||
|
|
5c6b20c0ec | ||
|
|
79af360822 | ||
|
|
fb23708220 | ||
|
|
93f6ab25e6 | ||
|
|
6faefed4f4 | ||
|
|
6a159be861 | ||
|
|
d7b43b54f9 | ||
|
|
1a92425995 | ||
|
|
347bdd9508 | ||
|
|
b80e8b63c9 | ||
|
|
621d529682 | ||
|
|
6005af1595 | ||
|
|
9a4329807a | ||
|
|
8e01da4c12 | ||
|
|
eb8ea520c7 | ||
|
|
512fcd361b | ||
|
|
aad6f6bcbe | ||
|
|
0af21505d7 | ||
|
|
2ae69e8e72 | ||
|
|
9274fac8e1 | ||
|
|
e2f82c60e6 | ||
|
|
bfddf24204 | ||
|
|
382599dcf6 | ||
|
|
5f2c07f2d8 | ||
|
|
914024c0b5 | ||
|
|
c5d3387962 | ||
|
|
7cc99c6fc9 | ||
|
|
a29b502a33 | ||
|
|
20cb74364f | ||
|
|
1c5a50c8d8 | ||
|
|
470523cc86 | ||
|
|
f6bc3d4650 | ||
|
|
41b1228d31 | ||
|
|
2cb4462274 | ||
|
|
810cd40ccd | ||
|
|
f931beb49a | ||
|
|
1c3dfc9b2f | ||
|
|
a1d4545e29 | ||
|
|
8865db2007 | ||
|
|
d2056d9409 | ||
|
|
74e74ddc38 | ||
|
|
5fcb737559 | ||
|
|
9303025427 | ||
|
|
680985fc13 | ||
|
|
5a360eb614 | ||
|
|
4a74bd78fd | ||
|
|
0f53656952 | ||
|
|
9ca40d3651 | ||
|
|
ab12503f62 | ||
|
|
b446d7fd4a | ||
|
|
fd46d85762 | ||
|
|
fa421afb00 | ||
|
|
a79d3e28ca | ||
|
|
fbb4f65735 | ||
|
|
00c62c90f6 | ||
|
|
384aa6e6a9 | ||
|
|
1c755249ec | ||
|
|
2c303b5bf2 | ||
|
|
415e3b4a93 | ||
|
|
8d9b056c8c | ||
|
|
a527a7f0b0 | ||
|
|
d78d955d11 | ||
|
|
9375a60cd9 | ||
|
|
bb99b9a0ef | ||
|
|
313e59d7f9 | ||
|
|
e34e0e62f2 | ||
|
|
212f75f1cb | ||
|
|
a07c79efcb | ||
|
|
89090b25e3 | ||
|
|
721164e562 | ||
|
|
b8ba980a20 | ||
|
|
79ded38434 | ||
|
|
f52db884a9 | ||
|
|
ee4bb33b0a | ||
|
|
caf8fa8e25 | ||
|
|
c46dea4c9e | ||
|
|
002b7b4f87 | ||
|
|
0a6a8c671f | ||
|
|
36014b706d | ||
|
|
df5e01d4eb | ||
|
|
c6f1525f55 | ||
|
|
5511259f2d | ||
|
|
f2ea7ca5d1 | ||
|
|
6184bbeae2 | ||
|
|
21506578f5 | ||
|
|
f39f395393 | ||
|
|
ed0a94659e | ||
|
|
7f75706584 | ||
|
|
3f316e42f2 | ||
|
|
4a331c0331 | ||
|
|
6a28de100c | ||
|
|
992f18b94b | ||
|
|
040a606b39 | ||
|
|
13e079d1b8 | ||
|
|
d9a7f40eb4 | ||
|
|
8d123da847 | ||
|
|
093310a9e5 | ||
|
|
21b315b97e | ||
|
|
c70cc3a6f1 | ||
|
|
1e71d8afc0 | ||
|
|
cb6b74b269 | ||
|
|
a1e399aa1a | ||
|
|
e1dfdd9400 | ||
|
|
6ab2e81f1c | ||
|
|
cf09029847 | ||
|
|
d02e170dac | ||
|
|
2b715bb0de | ||
|
|
2dcaf2c77b | ||
|
|
1b9f4f33de | ||
|
|
3c73f88a52 | ||
|
|
8acdc19be4 | ||
|
|
22252d9044 | ||
|
|
5948a74ad1 | ||
|
|
e46d9d7650 | ||
|
|
813276c907 | ||
|
|
7032473ecf | ||
|
|
807f1fb561 | ||
|
|
296f80ffe5 | ||
|
|
d45e0d1cac | ||
|
|
4b8f9984d5 | ||
|
|
7623610704 | ||
|
|
a7fe384a31 | ||
|
|
485ce887ea | ||
|
|
2a0bb79513 | ||
|
|
21ae88702f | ||
|
|
0ff1bb392c | ||
|
|
01af2f364c | ||
|
|
a639dddd19 | ||
|
|
71ec6c5061 | ||
|
|
8c4c4f5e8b | ||
|
|
2c2d3b2de3 | ||
|
|
caae5c9711 | ||
|
|
72822d03aa | ||
|
|
9de3dd89c5 | ||
|
|
bcb69b9855 | ||
|
|
6d2761f141 | ||
|
|
05c25b6aff | ||
|
|
9be9eb90f6 | ||
|
|
71f2f3a5fc | ||
|
|
862b1d407c | ||
|
|
5da0da48c8 | ||
|
|
3f1a51e350 | ||
|
|
d167e43252 | ||
|
|
fe9eecd031 | ||
|
|
ded8cff415 | ||
|
|
3497716a00 | ||
|
|
c78b4a3343 | ||
|
|
17359be58a | ||
|
|
382a62343d | ||
|
|
7e0f60615b | ||
|
|
e1a49b38a7 | ||
|
|
4333b8c351 | ||
|
|
6464377a89 | ||
|
|
4fcf732814 | ||
|
|
0d4f3e5735 | ||
|
|
1f2e453e20 | ||
|
|
5236c7b468 | ||
|
|
1738e8883f | ||
|
|
cc4563afb0 | ||
|
|
4b3bf2f358 | ||
|
|
80084f5c5a | ||
|
|
6d14b3f6bd | ||
|
|
592f613a61 | ||
|
|
3739bcc40c | ||
|
|
101c7a36fb | ||
|
|
21be959cba | ||
|
|
b3a0ebe7b6 | ||
|
|
96a588bd86 | ||
|
|
866b956680 | ||
|
|
d88252c6fd | ||
|
|
414e7d36a0 | ||
|
|
e0b4931a54 | ||
|
|
a587c5ff74 | ||
|
|
0b2eca3066 | ||
|
|
fa28052958 | ||
|
|
54f5bd1d80 | ||
|
|
4b3bbb4a97 | ||
|
|
187d90e8f2 | ||
|
|
2f60f61c15 | ||
|
|
057543da15 | ||
|
|
3c060cc57a | ||
|
|
928b4c6c4c | ||
|
|
871a0d535c | ||
|
|
87db9def32 | ||
|
|
04763eaeea | ||
|
|
b6c08a1a11 | ||
|
|
811c995047 | ||
|
|
7011df2ced | ||
|
|
a24692b4be | ||
|
|
0e7a32470b | ||
|
|
212d2f9db4 | ||
|
|
0263d3538e | ||
|
|
63c6028522 | ||
|
|
075ece2da7 | ||
|
|
e9fb02285e | ||
|
|
5dfd8c89a3 | ||
|
|
e9f7908afb | ||
|
|
fafce72c01 | ||
|
|
c3d15157ad | ||
|
|
e0712f73c2 | ||
|
|
3dd5b2365a | ||
|
|
b523f55984 | ||
|
|
79b8b77b25 | ||
|
|
c6065808a7 | ||
|
|
d69ae39b6f | ||
|
|
35739d6d0d | ||
|
|
e726fce360 | ||
|
|
0a038fecff | ||
|
|
0184bf9a7d | ||
|
|
60663babc8 | ||
|
|
a7115d4300 | ||
|
|
29558c9910 | ||
|
|
7c1d643f97 | ||
|
|
b2fc80f970 | ||
|
|
efee128c1c | ||
|
|
c3ddd68866 | ||
|
|
3cde4472c8 | ||
|
|
4c38fe261d | ||
|
|
33f7191c0d | ||
|
|
cda9ad3b30 | ||
|
|
1a7bd49361 | ||
|
|
cf2e189049 | ||
|
|
d5f5ba941a | ||
|
|
9a973be7ba | ||
|
|
d8e1284946 | ||
|
|
ce26fe1db7 | ||
|
|
a8ad045248 | ||
|
|
d097f6ada0 | ||
|
|
1b26db40f7 | ||
|
|
602b946fc9 | ||
|
|
48fc1a7a1e | ||
|
|
416889f49d | ||
|
|
5ca3222e5b | ||
|
|
d49d82e982 | ||
|
|
a4d5679219 | ||
|
|
bead103f3d | ||
|
|
e50b6733c4 | ||
|
|
75e5dbaaa4 | ||
|
|
965113c2b4 | ||
|
|
3bddaf509d | ||
|
|
c1c51e0baf | ||
|
|
09b6c2ab5b | ||
|
|
13fd956039 | ||
|
|
b6f0ee90af | ||
|
|
90e11e1c5d | ||
|
|
fc40e8ba70 | ||
|
|
7652b4a5b8 | ||
|
|
fb249767f1 | ||
|
|
d7ed311bcf | ||
|
|
8422965d0b | ||
|
|
7975edade4 | ||
|
|
1e18935513 | ||
|
|
c311b5315f | ||
|
|
26a73e0fba | ||
|
|
07c259c9c1 | ||
|
|
9e1c2d5a2c | ||
|
|
d7fb1b737f | ||
|
|
84c9c69fa3 | ||
|
|
12ca4e29cf | ||
|
|
27b1a5dc98 | ||
|
|
de36cc8445 | ||
|
|
03d344c0a2 | ||
|
|
39f01538c7 | ||
|
|
28c57cf666 | ||
|
|
59d120537d | ||
|
|
66d18e9475 | ||
|
|
1f5e4ceb0c | ||
|
|
0cbc65a52f | ||
|
|
2b0367cca6 | ||
|
|
1f01f480e0 | ||
|
|
7a167962d6 | ||
|
|
dae028d25d | ||
|
|
88e2fa04e7 | ||
|
|
bb0a8047ea | ||
|
|
b652565b57 | ||
|
|
9aaf6f3105 | ||
|
|
c26eccfe28 | ||
|
|
9fd547112d | ||
|
|
14bfc8af72 | ||
|
|
20f3458e37 | ||
|
|
6326e2d141 | ||
|
|
23ca3c1d2d | ||
|
|
0656ab4b88 | ||
|
|
90bb5d187c | ||
|
|
75a62e2bde | ||
|
|
7cd36b80eb | ||
|
|
dd607621d7 | ||
|
|
2595febf14 | ||
|
|
dc058c4cf3 | ||
|
|
25824e1821 | ||
|
|
381c2d52ee | ||
|
|
4020ac9843 | ||
|
|
b3b7a19df4 | ||
|
|
313e3e748f | ||
|
|
09b9f26e6f | ||
|
|
01b9cc64d6 | ||
|
|
97bf1dc850 | ||
|
|
f94794fe3e | ||
|
|
68e528dd3a | ||
|
|
06ab1d34aa | ||
|
|
2f2717e9aa | ||
|
|
88d24c2a03 | ||
|
|
ec2a2a6fbb | ||
|
|
60b81e714b | ||
|
|
2cd8b13c1d | ||
|
|
4afedb5131 | ||
|
|
71880ad2ad | ||
|
|
a30cce4cbc | ||
|
|
08b4f60ead | ||
|
|
11498bd09b | ||
|
|
7384c88ad6 | ||
|
|
6f22d70d59 | ||
|
|
adc279d681 | ||
|
|
f90dc5d619 | ||
|
|
6fd594c1f4 | ||
|
|
b94a4288bf | ||
|
|
cbf415256b | ||
|
|
4b1884944d | ||
|
|
5ff752c9af | ||
|
|
0e331a7cd1 | ||
|
|
10970d170c | ||
|
|
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 |
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/
|
||||||
7
.github/workflows/analysis.yml
vendored
7
.github/workflows/analysis.yml
vendored
@@ -8,7 +8,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
codeql:
|
codeql:
|
||||||
name: 🐛 CodeQL
|
name: 🐛 CodeQL
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
set -x
|
set -x
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-12 CXX=g++-12 cmake \
|
CC=gcc-14 CXX=g++-14 cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -57,8 +57,9 @@ jobs:
|
|||||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
|
-G Ninja \
|
||||||
..
|
..
|
||||||
make -j 4 install
|
ninja install
|
||||||
|
|
||||||
- name: 🗯️ Perform CodeQL Analysis
|
- name: 🗯️ Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v2
|
||||||
216
.github/workflows/build.yml
vendored
216
.github/workflows/build.yml
vendored
@@ -5,6 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
- 'releases/**'
|
- 'releases/**'
|
||||||
|
- 'tests/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ jobs:
|
|||||||
cd build
|
cd build
|
||||||
|
|
||||||
cmake -G "Ninja" \
|
cmake -G "Ninja" \
|
||||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||||
-DIMHEX_GENERATE_PACKAGE=ON \
|
-DIMHEX_GENERATE_PACKAGE=ON \
|
||||||
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
|
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
|
||||||
@@ -81,7 +82,7 @@ jobs:
|
|||||||
cd build
|
cd build
|
||||||
ninja install
|
ninja install
|
||||||
cpack
|
cpack
|
||||||
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
|
mv ImHex-*.msi ../imhex-${{ env.IMHEX_VERSION }}-Windows-x86_64.msi
|
||||||
|
|
||||||
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
|
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
|
||||||
|
|
||||||
@@ -106,7 +107,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
|
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
|
7z e mesa.7z
|
||||||
mv opengl32.dll build/install
|
mv opengl32.dll build/install
|
||||||
|
|
||||||
@@ -118,9 +119,62 @@ jobs:
|
|||||||
path: |
|
path: |
|
||||||
build/install/*
|
build/install/*
|
||||||
|
|
||||||
|
win-plugin-template-test:
|
||||||
|
runs-on: windows-2022
|
||||||
|
name: 🧪 Plugin Template Test
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: msys2 {0}
|
||||||
|
needs: win
|
||||||
|
env:
|
||||||
|
IMHEX_SDK_PATH: "${{ github.workspace }}/out/sdk"
|
||||||
|
steps:
|
||||||
|
- name: 🧰 Checkout ImHex
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: imhex
|
||||||
|
|
||||||
|
- name: 🟦 Install msys2
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
msystem: mingw64
|
||||||
|
|
||||||
|
- name: ⬇️ Install dependencies
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
imhex/dist/get_deps_msys2.sh
|
||||||
|
|
||||||
|
- name: 🧰 Checkout ImHex-Plugin-Template
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: WerWolv/ImHex-Plugin-Template
|
||||||
|
submodules: recursive
|
||||||
|
path: template
|
||||||
|
|
||||||
|
- name: ⬇️ Download artifact
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Windows Portable x86_64
|
||||||
|
path: out
|
||||||
|
|
||||||
|
- name: 🛠️ Build
|
||||||
|
run: |
|
||||||
|
set -x
|
||||||
|
cd template
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
cmake -G "Ninja" \
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||||
|
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
|
||||||
|
-DUSE_SYSTEM_CAPSTONE=ON \
|
||||||
|
..
|
||||||
|
|
||||||
|
ninja
|
||||||
|
|
||||||
# MacOS build
|
# MacOS build
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-12
|
runs-on: macos-13
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -131,7 +185,7 @@ jobs:
|
|||||||
- suffix: ""
|
- suffix: ""
|
||||||
custom_glfw: false
|
custom_glfw: false
|
||||||
|
|
||||||
name: 🍎 macOS 12.0${{matrix.suffix}}
|
name: 🍎 macOS 13${{ matrix.suffix }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
@@ -152,15 +206,15 @@ jobs:
|
|||||||
|
|
||||||
- name: ⬇️ Install dependencies
|
- name: ⬇️ Install dependencies
|
||||||
run: |
|
run: |
|
||||||
set -x
|
brew reinstall python --quiet || true
|
||||||
brew reinstall python || brew link --overwrite python
|
brew link --overwrite --quiet python || true
|
||||||
brew bundle --no-lock --file dist/Brewfile
|
brew bundle --no-lock --quiet --file dist/Brewfile || true
|
||||||
rm -rf /usr/local/Cellar/capstone
|
rm -rf /usr/local/Cellar/capstone
|
||||||
|
|
||||||
- name: ⬇️ Install classic glfw
|
- name: ⬇️ Install classic glfw
|
||||||
if: ${{! matrix.custom_glfw}}
|
if: ${{! matrix.custom_glfw }}
|
||||||
run: |
|
run: |
|
||||||
brew install glfw
|
brew install --quiet glfw || true
|
||||||
|
|
||||||
- name: ⬇️ Install .NET
|
- name: ⬇️ Install .NET
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
@@ -168,7 +222,7 @@ jobs:
|
|||||||
dotnet-version: '8.0.100'
|
dotnet-version: '8.0.100'
|
||||||
|
|
||||||
- name: 🧰 Checkout glfw
|
- name: 🧰 Checkout glfw
|
||||||
if: ${{matrix.custom_glfw}}
|
if: ${{ matrix.custom_glfw }}
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: glfw/glfw
|
repository: glfw/glfw
|
||||||
@@ -176,7 +230,7 @@ jobs:
|
|||||||
|
|
||||||
# GLFW custom build (to allow software rendering)
|
# GLFW custom build (to allow software rendering)
|
||||||
- name: ⬇️ Patch and install custom glfw
|
- name: ⬇️ Patch and install custom glfw
|
||||||
if: ${{matrix.custom_glfw}}
|
if: ${{ matrix.custom_glfw }}
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
cd glfw
|
cd glfw
|
||||||
@@ -186,7 +240,7 @@ jobs:
|
|||||||
cd build
|
cd build
|
||||||
|
|
||||||
cmake -G "Ninja" \
|
cmake -G "Ninja" \
|
||||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||||
-DBUILD_SHARED_LIBS=ON \
|
-DBUILD_SHARED_LIBS=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -201,14 +255,15 @@ jobs:
|
|||||||
set -x
|
set -x
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
CC=$(brew --prefix llvm)/bin/clang \
|
||||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
CXX=$(brew --prefix llvm)/bin/clang++ \
|
||||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||||
cmake -G "Ninja" \
|
cmake -G "Ninja" \
|
||||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||||
-DIMHEX_GENERATE_PACKAGE=ON \
|
-DIMHEX_GENERATE_PACKAGE=ON \
|
||||||
|
-DIMHEX_SYSTEM_LIBRARY_PATH="$(brew --prefix llvm)/lib;$(brew --prefix llvm)/lib/unwind;$(brew --prefix llvm)/lib/c++;$(brew --prefix)/lib" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -236,6 +291,12 @@ jobs:
|
|||||||
cd build/install
|
cd build/install
|
||||||
chmod -R 755 ImHex.app/
|
chmod -R 755 ImHex.app/
|
||||||
|
|
||||||
|
- name: 🔫 Kill XProtect
|
||||||
|
run: |
|
||||||
|
# See https://github.com/actions/runner-images/issues/7522
|
||||||
|
echo Killing XProtect...; sudo pkill -9 XProtect >/dev/null || true;
|
||||||
|
echo Waiting for XProtect process...; while pgrep XProtect; do sleep 3; done;
|
||||||
|
|
||||||
- name: 📦 Create DMG
|
- name: 📦 Create DMG
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
@@ -244,18 +305,24 @@ jobs:
|
|||||||
cd bundle
|
cd bundle
|
||||||
ln -s /Applications Applications
|
ln -s /Applications Applications
|
||||||
cd ..
|
cd ..
|
||||||
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64.dmg
|
for i in $(seq 1 10); do
|
||||||
|
if hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{ env.IMHEX_VERSION }}-macOS${{ matrix.suffix }}-x86_64.dmg; then
|
||||||
|
echo "Created dmg after ${i} attempts"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
- name: ⬆️ Upload DMG
|
- name: ⬆️ Upload DMG
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
name: macOS DMG${{matrix.suffix}} x86_64
|
name: macOS DMG${{ matrix.suffix }} x86_64
|
||||||
path: ./*.dmg
|
path: ./*.dmg
|
||||||
|
|
||||||
macos-arm64-build:
|
macos-arm64-build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
name: 🍎 macOS 12.1 arm64
|
name: 🍎 macOS 13 arm64
|
||||||
outputs:
|
outputs:
|
||||||
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
|
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
|
||||||
steps:
|
steps:
|
||||||
@@ -298,8 +365,8 @@ jobs:
|
|||||||
gh actions-cache delete "build-macos-arm64-cache" --confirm || true
|
gh actions-cache delete "build-macos-arm64-cache" --confirm || true
|
||||||
|
|
||||||
macos-arm64-package:
|
macos-arm64-package:
|
||||||
runs-on: macos-12
|
runs-on: macos-13
|
||||||
name: 🍎 macOS 12.1 arm64 Packaging
|
name: 🍎 macOS 13 arm64 Packaging
|
||||||
needs: macos-arm64-build
|
needs: macos-arm64-build
|
||||||
env:
|
env:
|
||||||
IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }}
|
IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }}
|
||||||
@@ -329,6 +396,12 @@ jobs:
|
|||||||
cd out
|
cd out
|
||||||
chmod -R 755 ImHex.app/
|
chmod -R 755 ImHex.app/
|
||||||
|
|
||||||
|
- name: 🔫 Kill XProtect
|
||||||
|
run: |
|
||||||
|
# See https://github.com/actions/runner-images/issues/7522
|
||||||
|
echo Killing XProtect...; sudo pkill -9 XProtect >/dev/null || true;
|
||||||
|
echo Waiting for XProtect process...; while pgrep XProtect; do sleep 3; done;
|
||||||
|
|
||||||
- name: 📦 Create DMG
|
- name: 📦 Create DMG
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
@@ -337,7 +410,13 @@ jobs:
|
|||||||
cd bundle
|
cd bundle
|
||||||
ln -s /Applications Applications
|
ln -s /Applications Applications
|
||||||
cd ..
|
cd ..
|
||||||
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS-arm64.dmg
|
for i in $(seq 1 10); do
|
||||||
|
if hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{ env.IMHEX_VERSION }}-macOS-arm64.dmg; then
|
||||||
|
echo "Created dmg after ${i} attempts"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
- name: ⬆️ Upload DMG
|
- name: ⬆️ Upload DMG
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -352,13 +431,11 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- name: Ubuntu
|
- release_num: "24.04"
|
||||||
release_num: 22.04
|
- release_num: "24.10"
|
||||||
- name: Ubuntu
|
|
||||||
release_num: 23.04
|
|
||||||
|
|
||||||
name: 🐧 Ubuntu ${{ matrix.release_num }}
|
name: 🐧 Ubuntu ${{ matrix.release_num }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: "ubuntu:${{ matrix.release_num }}"
|
image: "ubuntu:${{ matrix.release_num }}"
|
||||||
@@ -376,8 +453,8 @@ jobs:
|
|||||||
- name: 📜 Setup ccache
|
- name: 📜 Setup ccache
|
||||||
uses: hendrikmuhs/ccache-action@v1
|
uses: hendrikmuhs/ccache-action@v1
|
||||||
with:
|
with:
|
||||||
key: Ubuntu-${{matrix.release_num}}-ccache-${{ github.run_id }}
|
key: Ubuntu-${{ matrix.release_num }}-ccache-${{ github.run_id }}
|
||||||
restore-keys: Ubuntu-${{matrix.release_num}}-ccache
|
restore-keys: Ubuntu-${{ matrix.release_num }}-ccache
|
||||||
max-size: 1G
|
max-size: 1G
|
||||||
|
|
||||||
- name: ⬇️ Install dependencies
|
- name: ⬇️ Install dependencies
|
||||||
@@ -398,8 +475,8 @@ jobs:
|
|||||||
git config --global --add safe.directory '*'
|
git config --global --add safe.directory '*'
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
|
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
|
||||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -422,7 +499,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp -r build/DEBIAN build/DebDir
|
cp -r build/DEBIAN build/DebDir
|
||||||
dpkg-deb -Zgzip --build build/DebDir
|
dpkg-deb -Zgzip --build build/DebDir
|
||||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
|
mv build/DebDir.deb imhex-${{ env.IMHEX_VERSION }}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
|
||||||
|
|
||||||
- name: ⬆️ Upload DEB
|
- name: ⬆️ Upload DEB
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -433,7 +510,7 @@ jobs:
|
|||||||
|
|
||||||
# AppImage build
|
# AppImage build
|
||||||
appimage:
|
appimage:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
name: ⬇️ AppImage
|
name: ⬇️ AppImage
|
||||||
steps:
|
steps:
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
@@ -477,7 +554,7 @@ jobs:
|
|||||||
# ArchLinux build
|
# ArchLinux build
|
||||||
archlinux-build:
|
archlinux-build:
|
||||||
name: 🐧 ArchLinux
|
name: 🐧 ArchLinux
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: archlinux:base-devel
|
image: archlinux:base-devel
|
||||||
@@ -519,7 +596,7 @@ jobs:
|
|||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc CXX=g++ cmake -G "Ninja" \
|
CC=gcc CXX=g++ cmake -G "Ninja" \
|
||||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -544,7 +621,7 @@ jobs:
|
|||||||
- name: ✒️ Prepare PKGBUILD
|
- name: ✒️ Prepare PKGBUILD
|
||||||
run: |
|
run: |
|
||||||
cp dist/Arch/PKGBUILD build
|
cp dist/Arch/PKGBUILD build
|
||||||
sed -i 's/%version%/${{env.IMHEX_VERSION}}/g' build/PKGBUILD
|
sed -i 's/%version%/${{ env.IMHEX_VERSION }}/g' build/PKGBUILD
|
||||||
|
|
||||||
# makepkg doesn't want to run as root, so I had to chmod 777 all over
|
# makepkg doesn't want to run as root, so I had to chmod 777 all over
|
||||||
- name: 📦 Package ArchLinux .pkg.tar.zst
|
- name: 📦 Package ArchLinux .pkg.tar.zst
|
||||||
@@ -554,16 +631,16 @@ jobs:
|
|||||||
|
|
||||||
# the name is a small trick to make makepkg recognize it as the source
|
# the name is a small trick to make makepkg recognize it as the source
|
||||||
# else, it would try to download the file from the release
|
# else, it would try to download the file from the release
|
||||||
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
|
tar -cvf imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
|
||||||
|
|
||||||
chmod -R 777 .
|
chmod -R 777 .
|
||||||
|
|
||||||
sudo -u nobody makepkg
|
sudo -u nobody makepkg
|
||||||
|
|
||||||
# Replace the old file
|
# Replace the old file
|
||||||
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
rm imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst
|
||||||
rm *imhex-bin-debug* # rm debug package which is created for some reason
|
rm *imhex-bin-debug* # rm debug package which is created for some reason
|
||||||
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
mv *.pkg.tar.zst imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst
|
||||||
|
|
||||||
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
|
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -571,7 +648,7 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
name: ArchLinux .pkg.tar.zst x86_64
|
name: ArchLinux .pkg.tar.zst x86_64
|
||||||
path: |
|
path: |
|
||||||
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
build/imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst
|
||||||
|
|
||||||
# RPM distro builds
|
# RPM distro builds
|
||||||
rpm-build:
|
rpm-build:
|
||||||
@@ -584,28 +661,41 @@ jobs:
|
|||||||
release_num: rawhide
|
release_num: rawhide
|
||||||
mock_config: fedora-rawhide
|
mock_config: fedora-rawhide
|
||||||
- name: Fedora
|
- name: Fedora
|
||||||
mock_release: f39
|
mock_release: f41
|
||||||
release_num: 39
|
release_num: 41
|
||||||
mock_config: fedora-39
|
mock_config: fedora-41
|
||||||
- name: Fedora
|
- name: Fedora
|
||||||
mock_release: f38
|
mock_release: f40
|
||||||
release_num: 38
|
release_num: 40
|
||||||
mock_config: fedora-38
|
mock_config: fedora-40
|
||||||
- name: RHEL-AlmaLinux
|
- name: RHEL-AlmaLinux
|
||||||
mock_release: epel9
|
mock_release: epel9
|
||||||
release_num: 9
|
release_num: 9
|
||||||
mock_config: "alma+epel-9"
|
mock_config: "alma+epel-9"
|
||||||
|
|
||||||
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
|
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: "fedora:latest"
|
image: "almalinux:9"
|
||||||
options: --privileged
|
options: --privileged --pid=host --security-opt apparmor=unconfined
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: ⬇️ Install git-core
|
# This, together with the `--pid=host --security-opt apparmor=unconfined` docker options is required to allow
|
||||||
run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y
|
# fedpkg to work inside a Docker container running on Ubuntu again.
|
||||||
|
# GitHub seems to have enabled AppArmor on their Ubuntu CI runners which limits Docker in ways that cause
|
||||||
|
# programs inside it to fail.
|
||||||
|
# Without this, fedpkg will throw the unhelpful error message 'Insufficient Rights'
|
||||||
|
# This step uses nsenter to execute commands on the host that disable AppArmor entirely.
|
||||||
|
- name: 🛡️ Disable AppArmor on Host
|
||||||
|
run: |
|
||||||
|
nsenter -t 1 -m -u -n -i sudo systemctl disable --now apparmor.service
|
||||||
|
nsenter -t 1 -m -u -n -i sudo aa-teardown || true
|
||||||
|
nsenter -t 1 -m -u -n -i sudo sysctl --write kernel.apparmor_restrict_unprivileged_unconfined=0
|
||||||
|
nsenter -t 1 -m -u -n -i sudo sysctl --write kernel.apparmor_restrict_unprivileged_userns=0
|
||||||
|
|
||||||
|
- name: ⬇️ Install git-core and EPEL repo
|
||||||
|
run: dnf install git-core epel-release -y
|
||||||
|
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
@@ -624,8 +714,8 @@ jobs:
|
|||||||
- name: ⬇️ Update all packages and install dependencies
|
- name: ⬇️ Update all packages and install dependencies
|
||||||
run: |
|
run: |
|
||||||
set -x
|
set -x
|
||||||
dnf upgrade --disablerepo="*" --enablerepo="fedora,updates" -y
|
dnf upgrade -y
|
||||||
dnf install --disablerepo="*" --enablerepo="fedora,updates" -y \
|
dnf install -y \
|
||||||
fedpkg \
|
fedpkg \
|
||||||
ccache
|
ccache
|
||||||
|
|
||||||
@@ -651,7 +741,7 @@ jobs:
|
|||||||
- name: ✒️ Modify spec file
|
- name: ✒️ Modify spec file
|
||||||
run: |
|
run: |
|
||||||
sed -i \
|
sed -i \
|
||||||
-e 's/Version: VERSION$/Version: ${{env.IMHEX_VERSION}}/g' \
|
-e 's/Version: VERSION$/Version: ${{ env.IMHEX_VERSION }}/g' \
|
||||||
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/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 '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
|
||||||
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
|
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
|
||||||
@@ -660,7 +750,7 @@ jobs:
|
|||||||
|
|
||||||
- name: 📜 Fix ccache on EL9
|
- name: 📜 Fix ccache on EL9
|
||||||
if: matrix.mock_release == 'epel9'
|
if: matrix.mock_release == 'epel9'
|
||||||
run: sed -i '/\. \/opt\/rh\/gcc-toolset-12\/enable/a PATH=/usr/lib64/ccache:$PATH' $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
run: sed -i '/\. \/opt\/rh\/gcc-toolset-14\/enable/a PATH=/usr/lib64/ccache:$PATH' $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
||||||
|
|
||||||
- name: 🟩 Copy spec file to build root
|
- name: 🟩 Copy spec file to build root
|
||||||
run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec
|
run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec
|
||||||
@@ -675,14 +765,6 @@ jobs:
|
|||||||
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
|
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
|
||||||
EOT
|
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)
|
# Fedora cmake build (in imhex.spec)
|
||||||
- name: 📦 Build RPM
|
- name: 📦 Build RPM
|
||||||
run: |
|
run: |
|
||||||
@@ -690,8 +772,8 @@ jobs:
|
|||||||
|
|
||||||
- name: 🟩 Move and rename finished RPM
|
- name: 🟩 Move and rename finished RPM
|
||||||
run: |
|
run: |
|
||||||
mv $GITHUB_WORKSPACE/results_imhex/${{env.IMHEX_VERSION}}/*/imhex-${{env.IMHEX_VERSION}}-0.*.x86_64.rpm \
|
mv $GITHUB_WORKSPACE/results_imhex/${{ env.IMHEX_VERSION }}/*/imhex-${{ env.IMHEX_VERSION }}-0.*.x86_64.rpm \
|
||||||
$GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
$GITHUB_WORKSPACE/imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.rpm
|
||||||
|
|
||||||
- name: ⬆️ Upload RPM
|
- name: ⬆️ Upload RPM
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -699,4 +781,4 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
|
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
|
||||||
path: |
|
path: |
|
||||||
imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.rpm
|
||||||
|
|||||||
16
.github/workflows/build_web.yml
vendored
16
.github/workflows/build_web.yml
vendored
@@ -5,6 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
- 'releases/**'
|
- 'releases/**'
|
||||||
|
- 'tests/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
name: 🌍 WebAssembly
|
name: 🌍 WebAssembly
|
||||||
steps:
|
steps:
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
@@ -31,7 +32,7 @@ jobs:
|
|||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: cache
|
path: cache
|
||||||
key: web-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
key: web-cache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||||
|
|
||||||
- name: 🐳 Inject /cache into docker
|
- name: 🐳 Inject /cache into docker
|
||||||
uses: reproducible-containers/buildkit-cache-dance@v2
|
uses: reproducible-containers/buildkit-cache-dance@v2
|
||||||
@@ -48,7 +49,7 @@ jobs:
|
|||||||
chmod -c -R +rX "out/"
|
chmod -c -R +rX "out/"
|
||||||
|
|
||||||
- name: ⬆️ Upload artifacts
|
- name: ⬆️ Upload artifacts
|
||||||
uses: actions/upload-pages-artifact@v2
|
uses: actions/upload-pages-artifact@v3
|
||||||
with:
|
with:
|
||||||
path: out/
|
path: out/
|
||||||
|
|
||||||
@@ -58,9 +59,8 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
run: |
|
run: |
|
||||||
gh extension install actions/gh-actions-cache
|
gh extension install actions/gh-actions-cache || true
|
||||||
gh actions-cache delete "build-web-cache" --confirm
|
gh actions-cache delete "build-web-cache" --confirm || true
|
||||||
|
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
environment:
|
environment:
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
url: ${{ steps.deployment.outputs.page_url }}
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
|
||||||
name: 📃 Deploy to GitHub Pages
|
name: 📃 Deploy to GitHub Pages
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
if: ${{ github.ref == 'refs/heads/master' && github.event.repository.fork == false }}
|
if: ${{ github.ref == 'refs/heads/master' && github.event.repository.fork == false }}
|
||||||
needs: build
|
needs: build
|
||||||
@@ -76,4 +76,4 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: 🌍 Deploy
|
- name: 🌍 Deploy
|
||||||
id: deployment
|
id: deployment
|
||||||
uses: actions/deploy-pages@v2
|
uses: actions/deploy-pages@v4
|
||||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -10,7 +10,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-update-repos:
|
release-update-repos:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-24.04
|
||||||
name: Release Update Repos
|
name: Release Update Repos
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -90,7 +90,7 @@ jobs:
|
|||||||
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
|
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
|
||||||
|
|
||||||
- name: ⬇️ Download artifacts from latest workflow
|
- name: ⬇️ Download artifacts from latest workflow
|
||||||
uses: dawidd6/action-download-artifact@v3
|
uses: dawidd6/action-download-artifact@v6
|
||||||
with:
|
with:
|
||||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
@@ -147,7 +147,7 @@ jobs:
|
|||||||
commit_email: itrooz@protonmail.com
|
commit_email: itrooz@protonmail.com
|
||||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
commit_message: Bump to version ${{ env.IMHEX_VERSION }}
|
commit_message: Bump to version ${{ env.IMHEX_VERSION }}
|
||||||
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
ssh_keyscan_types: rsa,ecdsa,ed25519
|
||||||
|
|
||||||
release-update-winget:
|
release-update-winget:
|
||||||
name: Release update winget package
|
name: Release update winget package
|
||||||
|
|||||||
30
.github/workflows/stale_issues.yml
vendored
Normal file
30
.github/workflows/stale_issues.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: Close inactive issues
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "30 1 * * 0"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
close-issues:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v5
|
||||||
|
with:
|
||||||
|
operations-per-run: '200'
|
||||||
|
ascending: true
|
||||||
|
days-before-issue-stale: 334
|
||||||
|
days-before-issue-close: 30
|
||||||
|
stale-issue-label: "stale"
|
||||||
|
stale-issue-message: |
|
||||||
|
This issue is marked stale as it has been open for 11 months without activity.
|
||||||
|
Please try the latest ImHex version. (Avaiable here: https://imhex.download/ for release and https://imhex.download/#nightly for development version)
|
||||||
|
If the issue persists on the latest version, please make a comment on this issue again
|
||||||
|
|
||||||
|
Without response, this issue will be closed in one month.
|
||||||
|
close-issue-message: ""
|
||||||
|
days-before-pr-stale: -1
|
||||||
|
days-before-pr-close: -1
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
47
.github/workflows/tests.yml
vendored
47
.github/workflows/tests.yml
vendored
@@ -5,6 +5,7 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
- 'releases/**'
|
- 'releases/**'
|
||||||
|
- 'tests/**'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- 'master'
|
||||||
@@ -14,7 +15,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: 🧪 Unit Tests
|
name: 🧪 Unit Tests
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
@@ -33,14 +34,6 @@ jobs:
|
|||||||
restore-keys: ${{ runner.os }}-tests-build
|
restore-keys: ${{ runner.os }}-tests-build
|
||||||
max-size: 50M
|
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
|
- name: ⬇️ Install dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
@@ -51,22 +44,50 @@ jobs:
|
|||||||
set -x
|
set -x
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-12 CXX=g++-12 cmake \
|
CC=gcc-14 CXX=g++-14 cmake \
|
||||||
-DCMAKE_BUILD_TYPE=Debug \
|
-DCMAKE_BUILD_TYPE=Debug \
|
||||||
-DIMHEX_ENABLE_UNIT_TESTS=ON \
|
-DIMHEX_ENABLE_UNIT_TESTS=ON \
|
||||||
|
-DIMHEX_ENABLE_PLUGIN_TESTS=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
-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" \
|
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \
|
||||||
-DIMHEX_OFFLINE_BUILD=ON \
|
-DIMHEX_OFFLINE_BUILD=ON \
|
||||||
|
-G Ninja \
|
||||||
..
|
..
|
||||||
make -j4 unit_tests
|
ninja unit_tests
|
||||||
|
ninja imhex_all
|
||||||
|
|
||||||
|
- name: 🧪 Perform plcli Integration Tests
|
||||||
|
run: |
|
||||||
|
cd lib/external/pattern_language
|
||||||
|
python tests/integration/integration.py ../../../build/imhex --pl
|
||||||
|
|
||||||
- name: 🧪 Perform Unit Tests
|
- name: 🧪 Perform Unit Tests
|
||||||
run: |
|
run: |
|
||||||
cd build
|
cd build
|
||||||
ctest --output-on-failure
|
ctest --output-on-failure
|
||||||
|
|
||||||
|
# Generate report from all gcov .gcda files
|
||||||
|
#- name: 🧪 Generate coverage report
|
||||||
|
# run: |
|
||||||
|
# sudo apt install python3-pip python3-venv
|
||||||
|
# python3 -m venv venv
|
||||||
|
# . venv/bin/activate
|
||||||
|
# pip3 install gcovr
|
||||||
|
# cd build
|
||||||
|
# gcovr --gcov-executable /usr/bin/gcov-14 --exclude '.*/yara_rules/' --exclude '.*/third_party/' --exclude '.*/external/' --root .. --xml coverage_report.xml --verbose --gcov-ignore-errors all
|
||||||
|
#
|
||||||
|
#- name: Upload coverage reports to Codecov
|
||||||
|
# env:
|
||||||
|
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
# if: ${{ env.CODECOV_TOKEN }}
|
||||||
|
# uses: codecov/codecov-action@v4
|
||||||
|
# with:
|
||||||
|
# fail_ci_if_error: true
|
||||||
|
# token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
# file: build/coverage_report.xml
|
||||||
|
|
||||||
langs:
|
langs:
|
||||||
name: 🧪 Langs
|
name: 🧪 Langs
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,13 +1,16 @@
|
|||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
|
.kdev4/
|
||||||
|
|
||||||
cmake-build-*/
|
cmake-build-*/
|
||||||
build*/
|
build*/
|
||||||
local/
|
local/
|
||||||
venv/
|
venv/
|
||||||
|
.cache/
|
||||||
|
|
||||||
*.mgc
|
*.mgc
|
||||||
|
*.kdev4
|
||||||
imgui.ini
|
imgui.ini
|
||||||
.DS_Store
|
.DS_Store
|
||||||
./CMakeUserPresets.json
|
CMakeUserPresets.json
|
||||||
Brewfile.lock.json
|
Brewfile.lock.json
|
||||||
11
.gitmodules
vendored
11
.gitmodules
vendored
@@ -22,6 +22,14 @@
|
|||||||
path = lib/third_party/jthread/jthread
|
path = lib/third_party/jthread/jthread
|
||||||
url = https://github.com/josuttis/jthread
|
url = https://github.com/josuttis/jthread
|
||||||
ignore = dirty
|
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/WerWolv/lunasvg
|
||||||
|
ignore = dirty
|
||||||
|
|
||||||
[submodule "lib/external/libromfs"]
|
[submodule "lib/external/libromfs"]
|
||||||
path = lib/external/libromfs
|
path = lib/external/libromfs
|
||||||
@@ -36,6 +44,3 @@
|
|||||||
[submodule "lib/third_party/HashLibPlus"]
|
[submodule "lib/third_party/HashLibPlus"]
|
||||||
path = lib/third_party/HashLibPlus
|
path = lib/third_party/HashLibPlus
|
||||||
url = https://github.com/WerWolv/HashLibPlus
|
url = https://github.com/WerWolv/HashLibPlus
|
||||||
[submodule "lib/third_party/edlib"]
|
|
||||||
path = lib/third_party/edlib
|
|
||||||
url = https://github.com/Martinsos/edlib
|
|
||||||
|
|||||||
@@ -21,24 +21,32 @@ option(IMHEX_REPLACE_DWARF_WITH_PDB "Remove DWARF information from binaries
|
|||||||
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" 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_UNIT_TESTS "Enable building unit tests" OFF)
|
||||||
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" 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
|
# Basic compiler and cmake configurations
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
||||||
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
|
||||||
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||||
|
|
||||||
# Setup project
|
# Setup project
|
||||||
loadVersion(IMHEX_VERSION)
|
loadVersion(IMHEX_VERSION IMHEX_VERSION_PLAIN)
|
||||||
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
|
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
|
||||||
|
|
||||||
configureCMake()
|
configureCMake()
|
||||||
project(imhex
|
project(imhex
|
||||||
LANGUAGES C CXX
|
LANGUAGES C CXX
|
||||||
VERSION ${IMHEX_VERSION}
|
VERSION ${IMHEX_VERSION_PLAIN}
|
||||||
DESCRIPTION "The ImHex Hex Editor"
|
DESCRIPTION "The ImHex Hex Editor"
|
||||||
HOMEPAGE_URL "https://imhex.werwolv.net"
|
HOMEPAGE_URL "https://imhex.werwolv.net"
|
||||||
)
|
)
|
||||||
|
configureProject()
|
||||||
|
|
||||||
# Add ImHex sources
|
# Add ImHex sources
|
||||||
add_custom_target(imhex_all ALL)
|
add_custom_target(imhex_all ALL)
|
||||||
@@ -65,8 +73,11 @@ addPluginDirectories()
|
|||||||
|
|
||||||
# Add unit tests
|
# Add unit tests
|
||||||
if (IMHEX_ENABLE_UNIT_TESTS)
|
if (IMHEX_ENABLE_UNIT_TESTS)
|
||||||
|
if (NOT TARGET unit_tests)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
add_custom_target(unit_tests)
|
||||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||||
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Configure more resources that will be added to the install package
|
# Configure more resources that will be added to the install package
|
||||||
@@ -75,3 +86,6 @@ generateSDKDirectory()
|
|||||||
|
|
||||||
# Handle package generation
|
# Handle package generation
|
||||||
createPackage()
|
createPackage()
|
||||||
|
|
||||||
|
# Accommodate IDEs with FOLDER support
|
||||||
|
tweakTargetsForIDESupport()
|
||||||
|
|||||||
@@ -28,6 +28,23 @@
|
|||||||
"displayName": "x86_64 Build",
|
"displayName": "x86_64 Build",
|
||||||
"description": "x86_64 build",
|
"description": "x86_64 build",
|
||||||
"inherits": [ "base" ]
|
"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": [
|
"buildPresets": [
|
||||||
|
|||||||
53
README.md
53
README.md
@@ -1,14 +1,16 @@
|
|||||||
<a href="https://imhex.werwolv.net">
|
<a href="https://imhex.werwolv.net">
|
||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
<picture>
|
<picture>
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="./resources/projects/logo_text_light.svg">
|
<img height="300px" style="margin: 0; padding: 0" src="./resources/dist/common/logo/ImHexLogoSVGBG.svg">
|
||||||
<img height="100px" src="./resources/projects/logo_text_dark.svg">
|
|
||||||
</picture>
|
</picture>
|
||||||
</h1>
|
</h1>
|
||||||
</a>
|
</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">
|
<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="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master"></a>
|
||||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge"></a>
|
<a title="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>
|
<details>
|
||||||
<summary><strong>Data Inspector</strong></summary>
|
<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)
|
- Unsigned and signed integers (8, 16, 24, 32, 48, 64 bit)
|
||||||
- Floats (16, 32, 64 bit)
|
- Floats (16, 32, 64 bit)
|
||||||
- Signed and Unsigned LEB128
|
- 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
|
- Numeric Value search
|
||||||
- Search for signed/unsigned integers and floats
|
- Search for signed/unsigned integers and floats
|
||||||
- Search for ranges of values
|
- Search for ranges of values
|
||||||
- Option to specify size and endianess
|
- Option to specify size and endianness
|
||||||
- Option to ignore unaligned values
|
- Option to ignore unaligned values
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
@@ -312,22 +314,26 @@ To use ImHex, the following minimal system requirements need to be met.
|
|||||||
> ImHex requires a GPU with OpenGL 3.0 support in general.
|
> ImHex requires a GPU with OpenGL 3.0 support in general.
|
||||||
> There are releases available (with the `-NoGPU` suffix) that are software rendered and don't require a GPU, however these can be a lot slower than the GPU accelerated versions.
|
> There are releases available (with the `-NoGPU` suffix) that are software rendered and don't require a GPU, however these can be a lot slower than the GPU accelerated versions.
|
||||||
>
|
>
|
||||||
> If possible at all, make ImHex use the dedicated GPU on your system instead of the integrated one (especially Intel HD GPUs are known to cause issues).
|
> If possible at all, make ImHex use the dedicated GPU on your system instead of the integrated one.
|
||||||
|
> ImHex will usually run fine with integrated GPUs as well but certain Intel HD GPU drivers on Windows are known to cause graphical artifacts.
|
||||||
|
|
||||||
- **OS**:
|
- **OS**:
|
||||||
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
|
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
|
||||||
- **macOS**: macOS 11 (Big Sur) or higher,
|
- **macOS**: macOS 13 (Ventura) or higher,
|
||||||
|
- Lower versions should still work too, but you'll need to compile ImHex yourself. The release binaries will NOT work.
|
||||||
|
- The macOS build is not signed and will require you to manually allow them in the Security & Privacy settings.
|
||||||
- **Linux**: "Modern" Linux. The following distributions have official releases available. Other distros are supported through the AppImage and Flatpak releases.
|
- **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
|
- Ubuntu and Debian
|
||||||
- Fedora 36/37
|
- Fedora
|
||||||
- RHEL/AlmaLinux 9
|
- RHEL/AlmaLinux
|
||||||
- Arch Linux
|
- Arch Linux
|
||||||
|
- Basically any other distro will work as well when compiling ImHex from sources.
|
||||||
- **CPU**: x86_64 (64 Bit)
|
- **CPU**: x86_64 (64 Bit)
|
||||||
- **GPU**: OpenGL 3.0 or higher
|
- **GPU**: OpenGL 3.0 or higher
|
||||||
- Intel HD drivers are really buggy and often cause graphic artifacts
|
- Integrated Intel HD iGPUs are supported, however certain drivers are known to cause various graphical artifacts, especially on Windows. Use at your own risk.
|
||||||
- In case you don't have a GPU available, there are software rendered releases available for Windows and macOS
|
- In case you don't have a GPU available, there are software rendered releases available for Windows and macOS
|
||||||
- **RAM**: 256MB, more may be required for more complicated analysis
|
- **RAM**: 256MB, more may be required for more complicated analysis
|
||||||
- **Storage**: 100MB
|
- **Storage**: 150MB
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
@@ -358,24 +364,29 @@ To develop plugins for ImHex, use the following template project to get started.
|
|||||||
|
|
||||||
### Contributors
|
### 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
|
- [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
|
- [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
|
- [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 :)
|
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
|
||||||
|
|
||||||
### Dependencies
|
### 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 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 epezent for [ImPlot](https://github.com/epezent/implot) used to plot data in various places
|
||||||
- Thanks to BalazsJako for their incredible [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
|
- Thanks to Nelarius for [ImNodes](https://github.com/Nelarius/imnodes) used as base for the data processor
|
||||||
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for project files
|
- Thanks to BalazsJako for [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
|
||||||
- Thanks to aquynh for [capstone](https://github.com/aquynh/capstone) which is the base of the disassembly window
|
- 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 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 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 VirusTotal for [Yara](https://github.com/VirusTotal/yara) used by the Yara plugin
|
||||||
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp)
|
- 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
|
- Thanks to all other groups and organizations whose libraries are used in ImHex
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ macro(detectOS)
|
|||||||
set(CMAKE_INSTALL_LIBDIR ".")
|
set(CMAKE_INSTALL_LIBDIR ".")
|
||||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||||
add_compile_definitions(WIN32_LEAN_AND_MEAN)
|
add_compile_definitions(WIN32_LEAN_AND_MEAN)
|
||||||
|
add_compile_definitions(UNICODE)
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
add_compile_definitions(OS_MACOS)
|
add_compile_definitions(OS_MACOS)
|
||||||
set(CMAKE_INSTALL_BINDIR ".")
|
set(CMAKE_INSTALL_BINDIR ".")
|
||||||
@@ -152,14 +153,12 @@ macro(addPluginDirectories)
|
|||||||
foreach (plugin IN LISTS PLUGINS)
|
foreach (plugin IN LISTS PLUGINS)
|
||||||
add_subdirectory("plugins/${plugin}")
|
add_subdirectory("plugins/${plugin}")
|
||||||
if (TARGET ${plugin})
|
if (TARGET ${plugin})
|
||||||
set_target_properties(${plugin} PROPERTIES RUNTIME_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 ${CMAKE_BINARY_DIR}/plugins)
|
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
if (IMHEX_GENERATE_PACKAGE)
|
if (IMHEX_GENERATE_PACKAGE)
|
||||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_INSTALL_LOCATION})
|
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 ()
|
endif ()
|
||||||
else ()
|
else ()
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
@@ -226,6 +225,7 @@ macro(createPackage)
|
|||||||
|
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
|
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}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||||
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.mime.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mime/packages RENAME imhex.xml)
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
||||||
downloadImHexPatternsFiles("./share/imhex")
|
downloadImHexPatternsFiles("./share/imhex")
|
||||||
|
|
||||||
@@ -240,6 +240,7 @@ macro(createPackage)
|
|||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
if (IMHEX_GENERATE_PACKAGE)
|
if (IMHEX_GENERATE_PACKAGE)
|
||||||
|
set(EXTRA_BUNDLE_LIBRARY_PATHS ${EXTRA_BUNDLE_LIBRARY_PATHS} "${IMHEX_SYSTEM_LIBRARY_PATH}")
|
||||||
include(PostprocessBundle)
|
include(PostprocessBundle)
|
||||||
|
|
||||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||||
@@ -270,11 +271,13 @@ macro(createPackage)
|
|||||||
find_program(CODESIGN_PATH codesign)
|
find_program(CODESIGN_PATH codesign)
|
||||||
if (CODESIGN_PATH)
|
if (CODESIGN_PATH)
|
||||||
install(CODE "message(STATUS \"Signing bundle '${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}'...\")")
|
install(CODE "message(STATUS \"Signing bundle '${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}'...\")")
|
||||||
install(CODE "execute_process(COMMAND ${CODESIGN_PATH} --force --deep --sign - ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME} COMMAND_ERROR_IS_FATAL ANY)")
|
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()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(CODE [[ message(STATUS "MacOS Bundle finalized. DO NOT TOUCH IT ANYMORE! ANY MODIFICATIONS WILL BREAK IT FROM NOW ON!") ]])
|
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()
|
endif()
|
||||||
else()
|
else()
|
||||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
@@ -306,9 +309,6 @@ endfunction()
|
|||||||
macro(configureCMake)
|
macro(configureCMake)
|
||||||
message(STATUS "Configuring ImHex v${IMHEX_VERSION}")
|
message(STATUS "Configuring ImHex v${IMHEX_VERSION}")
|
||||||
|
|
||||||
# Enable C and C++ languages
|
|
||||||
enable_language(C CXX)
|
|
||||||
|
|
||||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "Enable position independent code for all targets" FORCE)
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "Enable position independent code for all targets" FORCE)
|
||||||
|
|
||||||
# Configure use of recommended build tools
|
# Configure use of recommended build tools
|
||||||
@@ -342,8 +342,11 @@ macro(configureCMake)
|
|||||||
|
|
||||||
if (LD_LLD_PATH)
|
if (LD_LLD_PATH)
|
||||||
set(CMAKE_LINKER ${LD_LLD_PATH})
|
set(CMAKE_LINKER ${LD_LLD_PATH})
|
||||||
|
|
||||||
|
if (NOT XCODE)
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
|
||||||
|
endif()
|
||||||
else ()
|
else ()
|
||||||
message(WARNING "lld not found, using default linker!")
|
message(WARNING "lld not found, using default linker!")
|
||||||
endif ()
|
endif ()
|
||||||
@@ -378,6 +381,18 @@ macro(configureCMake)
|
|||||||
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
|
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
function(configureProject)
|
||||||
|
# Enable C and C++ languages
|
||||||
|
enable_language(C CXX)
|
||||||
|
|
||||||
|
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)
|
macro(setDefaultBuiltTypeIfUnset)
|
||||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
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)
|
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Using RelWithDebInfo build type as it was left unset" FORCE)
|
||||||
@@ -385,12 +400,14 @@ macro(setDefaultBuiltTypeIfUnset)
|
|||||||
endif()
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
function(loadVersion version)
|
function(loadVersion version plain_version)
|
||||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||||
file(READ "${VERSION_FILE}" read_version)
|
file(READ "${VERSION_FILE}" read_version)
|
||||||
string(STRIP ${read_version} read_version)
|
string(STRIP ${read_version} read_version)
|
||||||
|
string(REPLACE ".WIP" "" read_version_plain ${read_version})
|
||||||
set(${version} ${read_version} PARENT_SCOPE)
|
set(${version} ${read_version} PARENT_SCOPE)
|
||||||
|
set(${plain_version} ${read_version_plain} PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(detectBadClone)
|
function(detectBadClone)
|
||||||
@@ -480,20 +497,71 @@ function(downloadImHexPatternsFiles dest)
|
|||||||
message(STATUS "Finished downloading ImHex-Patterns")
|
message(STATUS "Finished downloading ImHex-Patterns")
|
||||||
|
|
||||||
else ()
|
else ()
|
||||||
|
set(imhex_patterns_SOURCE_DIR "")
|
||||||
|
|
||||||
# Maybe patterns are cloned to a subdirectory
|
# Maybe patterns are cloned to a subdirectory
|
||||||
|
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
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 ()
|
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)
|
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic nodes)
|
||||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
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 ()
|
endforeach ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
endfunction()
|
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)
|
macro(setupCompilerFlags target)
|
||||||
|
# IMHEX_COMMON_FLAGS: flags common for C, C++, Objective C, etc.. compilers
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||||
# Define strict compilation flags
|
# Define strict compilation flags
|
||||||
if (IMHEX_STRICT_WARNINGS)
|
if (IMHEX_STRICT_WARNINGS)
|
||||||
@@ -507,7 +575,7 @@ macro(setupCompilerFlags target)
|
|||||||
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
|
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
|
||||||
|
|
||||||
# Disable some warnings
|
# Disable some warnings
|
||||||
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations -Wno-unknown-pragmas")
|
set(IMHEX_C_CXX_FLAGS "-Wno-array-bounds -Wno-deprecated-declarations -Wno-unknown-pragmas")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
@@ -516,6 +584,13 @@ macro(setupCompilerFlags target)
|
|||||||
endif ()
|
endif ()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND APPLE)
|
||||||
|
execute_process(COMMAND brew --prefix llvm OUTPUT_VARIABLE LLVM_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
|
||||||
|
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Disable some warnings for gcc
|
# Disable some warnings for gcc
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-dangling-reference")
|
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-dangling-reference")
|
||||||
@@ -526,11 +601,24 @@ macro(setupCompilerFlags target)
|
|||||||
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -pthread -Wno-dollar-in-identifier-extension -Wno-pthreads-mem-growth")
|
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -pthread -Wno-dollar-in-identifier-extension -Wno-pthreads-mem-growth")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
if (IMHEX_COMPRESS_DEBUG_INFO)
|
||||||
|
setupDebugCompressionFlag()
|
||||||
|
endif()
|
||||||
|
|
||||||
# Set actual CMake flags
|
# Set actual CMake flags
|
||||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_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_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_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}")
|
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()
|
endmacro()
|
||||||
|
|
||||||
# uninstall target
|
# uninstall target
|
||||||
@@ -596,6 +684,14 @@ macro(addBundledLibraries)
|
|||||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
||||||
endif()
|
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)
|
if (NOT USE_SYSTEM_LLVM)
|
||||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
|
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
|
||||||
else()
|
else()
|
||||||
@@ -614,6 +710,14 @@ macro(addBundledLibraries)
|
|||||||
set(JTHREAD_LIBRARIES jthread)
|
set(JTHREAD_LIBRARIES jthread)
|
||||||
endif()
|
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_BUILD_CLI_AS_EXECUTABLE OFF CACHE BOOL "" FORCE)
|
||||||
set(LIBPL_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE)
|
set(LIBPL_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
@@ -753,6 +857,9 @@ function(generateSDKDirectory)
|
|||||||
if (NOT USE_SYSTEM_NLOHMANN_JSON)
|
if (NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
|
||||||
endif()
|
endif()
|
||||||
|
if (NOT USE_SYSTEM_BOOST)
|
||||||
|
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(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/modules DESTINATION "${SDK_PATH}/cmake")
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")
|
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")
|
||||||
|
|||||||
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")
|
set(CORECLR_SUBARCH "arm64")
|
||||||
endif()
|
endif()
|
||||||
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)
|
if (NOT DOTNET_EXECUTABLE)
|
||||||
set(DOTNET_EXECUTABLE dotnet)
|
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_LIBRARIES "${CoreClrEmbed_LIBRARY}" CACHE STRING "CoreClrEmbed libraries" FORCE)
|
||||||
set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}" CACHE STRING "CoreClrEmbed shared 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_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}" CACHE STRING "CoreClrEmbed include directories" FORCE)
|
||||||
|
set(CoreClrEmbed_VERSION "${CORECLR_RUNTIME_VERSION_FULL}" CACHE STRING "CoreClrEmbed version" FORCE)
|
||||||
endif()
|
endif()
|
||||||
60
cmake/modules/FindLZ4.cmake
Normal file
60
cmake/modules/FindLZ4.cmake
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
find_path(LZ4_INCLUDE_DIR
|
||||||
|
NAMES lz4.h
|
||||||
|
HINTS "${LZ4_INCLUDEDIR}" "${LZ4_HINTS}/include"
|
||||||
|
PATHS
|
||||||
|
/usr/local/include
|
||||||
|
/usr/include
|
||||||
|
)
|
||||||
|
|
||||||
|
find_library(LZ4_LIBRARY
|
||||||
|
NAMES lz4 liblz4
|
||||||
|
HINTS "${LZ4_LIBDIR}" "${LZ4_HINTS}/lib"
|
||||||
|
PATHS
|
||||||
|
/usr/local/lib
|
||||||
|
/usr/lib
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args( LZ4 DEFAULT_MSG LZ4_LIBRARY LZ4_INCLUDE_DIR )
|
||||||
|
|
||||||
|
if( LZ4_FOUND )
|
||||||
|
include( CheckIncludeFile )
|
||||||
|
include( CMakePushCheckState )
|
||||||
|
|
||||||
|
set( LZ4_INCLUDE_DIRS ${LZ4_INCLUDE_DIR} )
|
||||||
|
set( LZ4_LIBRARIES ${LZ4_LIBRARY} )
|
||||||
|
|
||||||
|
cmake_push_check_state()
|
||||||
|
set( CMAKE_REQUIRED_INCLUDES ${LZ4_INCLUDE_DIRS} )
|
||||||
|
check_include_file( lz4frame.h HAVE_LZ4FRAME_H )
|
||||||
|
cmake_pop_check_state()
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
set ( LZ4_DLL_DIR "${LZ4_HINTS}/bin"
|
||||||
|
CACHE PATH "Path to LZ4 DLL"
|
||||||
|
)
|
||||||
|
file( GLOB _lz4_dll RELATIVE "${LZ4_DLL_DIR}"
|
||||||
|
"${LZ4_DLL_DIR}/lz4*.dll"
|
||||||
|
)
|
||||||
|
set ( LZ4_DLL ${_lz4_dll}
|
||||||
|
# We're storing filenames only. Should we use STRING instead?
|
||||||
|
CACHE FILEPATH "LZ4 DLL file name"
|
||||||
|
)
|
||||||
|
file( GLOB _lz4_pdb RELATIVE "${LZ4_DLL_DIR}"
|
||||||
|
"${LZ4_DLL_DIR}/lz4*.pdb"
|
||||||
|
)
|
||||||
|
set ( LZ4_PDB ${_lz4_pdb}
|
||||||
|
CACHE FILEPATH "LZ4 PDB file name"
|
||||||
|
)
|
||||||
|
mark_as_advanced( LZ4_DLL_DIR LZ4_DLL LZ4_PDB )
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set( LZ4_INCLUDE_DIRS )
|
||||||
|
set( LZ4_LIBRARIES )
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced( LZ4_LIBRARIES LZ4_INCLUDE_DIRS )
|
||||||
|
|
||||||
|
add_library( LZ4::lz4 INTERFACE IMPORTED )
|
||||||
|
set_property( TARGET LZ4::lz4 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LZ4_INCLUDE_DIRS} )
|
||||||
|
set_property( TARGET LZ4::lz4 PROPERTY INTERFACE_LINK_LIBRARIES ${LZ4_LIBRARIES} )
|
||||||
@@ -39,3 +39,7 @@ if (ZSTD_FOUND)
|
|||||||
endif()
|
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})
|
||||||
@@ -55,9 +55,9 @@ IF(MBEDTLS_FOUND)
|
|||||||
MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}")
|
MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}")
|
||||||
ENDIF(NOT MBEDTLS_FIND_QUIETLY)
|
ENDIF(NOT MBEDTLS_FIND_QUIETLY)
|
||||||
ELSE(MBEDTLS_FOUND)
|
ELSE(MBEDTLS_FOUND)
|
||||||
IF(MBEDTLS_FIND_REQUIRED)
|
IF(mbedTLS_FIND_REQUIRED)
|
||||||
MESSAGE(FATAL_ERROR "Could not find mbedTLS")
|
MESSAGE(FATAL_ERROR "Could not find mbedTLS")
|
||||||
ENDIF(MBEDTLS_FIND_REQUIRED)
|
ENDIF(mbedTLS_FIND_REQUIRED)
|
||||||
ENDIF(MBEDTLS_FOUND)
|
ENDIF(MBEDTLS_FOUND)
|
||||||
|
|
||||||
MARK_AS_ADVANCED(
|
MARK_AS_ADVANCED(
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ macro(add_imhex_plugin)
|
|||||||
# Configure build properties
|
# Configure build properties
|
||||||
set_target_properties(${IMHEX_PLUGIN_NAME}
|
set_target_properties(${IMHEX_PLUGIN_NAME}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
|
RUNTIME_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins"
|
||||||
CXX_STANDARD 23
|
CXX_STANDARD 23
|
||||||
PREFIX ""
|
PREFIX ""
|
||||||
SUFFIX ${IMHEX_PLUGIN_SUFFIX}
|
SUFFIX ${IMHEX_PLUGIN_SUFFIX}
|
||||||
@@ -72,10 +72,23 @@ macro(add_imhex_plugin)
|
|||||||
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
|
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
|
||||||
|
|
||||||
foreach(feature ${IMHEX_PLUGIN_FEATURES})
|
set(FEATURE_DEFINE_CONTENT)
|
||||||
string(TOUPPER ${feature} feature)
|
|
||||||
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
|
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()
|
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
|
# Add the new plugin to the main dependency list so it gets built by default
|
||||||
if (TARGET imhex_all)
|
if (TARGET imhex_all)
|
||||||
@@ -88,12 +101,28 @@ macro(add_imhex_plugin)
|
|||||||
|
|
||||||
# Fix rpath
|
# Fix rpath
|
||||||
if (APPLE)
|
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)
|
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()
|
endif()
|
||||||
|
|
||||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt AND IMHEX_ENABLE_UNIT_TESTS)
|
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)
|
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_NAME}_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")
|
target_compile_definitions(${IMHEX_PLUGIN_NAME}_tests PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}-tests")
|
||||||
@@ -101,6 +130,10 @@ macro(add_imhex_plugin)
|
|||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
macro(add_romfs_resource input output)
|
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)
|
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
|
||||||
|
|
||||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
|
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
|
||||||
|
|||||||
@@ -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 PARENT_SCOPE)
|
||||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
|
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)
|
add_subdirectory(lib/external/libwolv EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
|
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
|
||||||
|
|||||||
21
dist/AppImageBuilder.yml
vendored
21
dist/AppImageBuilder.yml
vendored
@@ -14,22 +14,23 @@ AppDir:
|
|||||||
- amd64
|
- amd64
|
||||||
allow_unauthenticated: true
|
allow_unauthenticated: true
|
||||||
sources:
|
sources:
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular main restricted
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates main restricted
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy universe
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular universe
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates universe
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates universe
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular multiverse
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates multiverse
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-backports main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security main restricted
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
|
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security universe
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security multiverse
|
||||||
include:
|
include:
|
||||||
- librsvg2-common
|
- librsvg2-common
|
||||||
- libbz2-1.0:amd64
|
- libbz2-1.0:amd64
|
||||||
- libcap2:amd64
|
- libcap2:amd64
|
||||||
- libdbus-1-3:amd64
|
- libdbus-1-3:amd64
|
||||||
|
- libfontconfig1:amd64
|
||||||
- libgpg-error0:amd64
|
- libgpg-error0:amd64
|
||||||
- liblzma5:amd64
|
- liblzma5:amd64
|
||||||
- libnss-mdns:amd64
|
- libnss-mdns:amd64
|
||||||
|
|||||||
1
dist/Arch/Dockerfile
vendored
1
dist/Arch/Dockerfile
vendored
@@ -13,6 +13,7 @@ RUN pacman -S --needed --noconfirm \
|
|||||||
glfw-x11 \
|
glfw-x11 \
|
||||||
file \
|
file \
|
||||||
mbedtls \
|
mbedtls \
|
||||||
|
fontconfig \
|
||||||
freetype2 \
|
freetype2 \
|
||||||
curl \
|
curl \
|
||||||
dbus \
|
dbus \
|
||||||
|
|||||||
4
dist/Arch/PKGBUILD
vendored
4
dist/Arch/PKGBUILD
vendored
@@ -8,7 +8,7 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
|
|||||||
arch=("x86_64")
|
arch=("x86_64")
|
||||||
url="https://github.com/WerWolv/ImHex"
|
url="https://github.com/WerWolv/ImHex"
|
||||||
license=('GPL2')
|
license=('GPL2')
|
||||||
depends=(glfw mbedtls freetype2 libglvnd dbus gtk3 curl fmt yara nlohmann-json zlib bzip2 xz zstd)
|
depends=(glfw mbedtls fontconfig freetype2 libglvnd dbus gtk3 curl fmt yara nlohmann-json zlib bzip2 xz zstd)
|
||||||
makedepends=(git)
|
makedepends=(git)
|
||||||
provides=(imhex)
|
provides=(imhex)
|
||||||
conflicts=(imhex)
|
conflicts=(imhex)
|
||||||
@@ -26,5 +26,5 @@ package() {
|
|||||||
|
|
||||||
install -d "$pkgdir/usr/share/imhex"
|
install -d "$pkgdir/usr/share/imhex"
|
||||||
cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex"
|
cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex"
|
||||||
cp -r "$srcdir/usr/share/"{applications,licenses,pixmaps} "$pkgdir/usr/share"
|
cp -r "$srcdir/usr/share/"{applications,licenses,pixmaps,mime} "$pkgdir/usr/share"
|
||||||
}
|
}
|
||||||
|
|||||||
1
dist/Brewfile
vendored
1
dist/Brewfile
vendored
@@ -6,7 +6,6 @@ brew "freetype2"
|
|||||||
brew "libmagic"
|
brew "libmagic"
|
||||||
brew "pkg-config"
|
brew "pkg-config"
|
||||||
brew "curl"
|
brew "curl"
|
||||||
brew "gcc@12"
|
|
||||||
brew "llvm"
|
brew "llvm"
|
||||||
brew "glfw"
|
brew "glfw"
|
||||||
brew "ninja"
|
brew "ninja"
|
||||||
|
|||||||
2
dist/DEBIAN/control.in
vendored
2
dist/DEBIAN/control.in
vendored
@@ -4,7 +4,7 @@ Section: editors
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
License: GNU GPL-2
|
License: GNU GPL-2
|
||||||
Depends: libglfw3 | libglfw3-wayland, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
Depends: libfontconfig1, libglfw3 | libglfw3-wayland, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
||||||
Maintainer: WerWolv <hey@werwolv.net>
|
Maintainer: WerWolv <hey@werwolv.net>
|
||||||
Description: ImHex Hex Editor
|
Description: ImHex Hex Editor
|
||||||
A Hex Editor for Reverse Engineers, Programmers and
|
A Hex Editor for Reverse Engineers, Programmers and
|
||||||
|
|||||||
7
dist/ImHex-9999.ebuild
vendored
7
dist/ImHex-9999.ebuild
vendored
@@ -20,13 +20,14 @@ DEPEND=""
|
|||||||
RDEPEND="${DEPEND}
|
RDEPEND="${DEPEND}
|
||||||
media-libs/glfw
|
media-libs/glfw
|
||||||
sys-apps/file
|
sys-apps/file
|
||||||
dev-libs/mbedtls
|
net-libs/mbedtls
|
||||||
dev-cpp/nlohmann_json
|
dev-cpp/nlohmann_json
|
||||||
dbus
|
sys-apps/dbus
|
||||||
xdg-desktop-portal
|
sys-apps/xdg-desktop-portal
|
||||||
sys-libs/zlib
|
sys-libs/zlib
|
||||||
app-arch/bzip2
|
app-arch/bzip2
|
||||||
app-arch/lzma
|
app-arch/lzma
|
||||||
app-arch/zstd
|
app-arch/zstd
|
||||||
|
app-arch/lz4
|
||||||
"
|
"
|
||||||
BDEPEND="${DEPEND}"
|
BDEPEND="${DEPEND}"
|
||||||
|
|||||||
28
dist/appimage/Dockerfile
vendored
28
dist/appimage/Dockerfile
vendored
@@ -1,4 +1,4 @@
|
|||||||
FROM ubuntu:22.04 as build
|
FROM ubuntu:24.10 as build
|
||||||
|
|
||||||
# Used to invalidate layer cache but not mount cache
|
# Used to invalidate layer cache but not mount cache
|
||||||
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
|
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
|
||||||
@@ -14,24 +14,13 @@ apt update
|
|||||||
# general deps
|
# general deps
|
||||||
apt install -y ccache git wget
|
apt install -y ccache git wget
|
||||||
# appimage tools deps
|
# appimage tools deps
|
||||||
apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse ninja-build
|
apt install -y python3-pip python3-venv python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse ninja-build
|
||||||
apt install -y squashfs-tools zsync
|
apt install -y squashfs-tools zsync
|
||||||
|
|
||||||
# imhex deps
|
# imhex deps
|
||||||
/tmp/get_deps_debian.sh
|
/tmp/get_deps_debian.sh
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
RUN --mount=type=cache,target=/cache <<EOF
|
|
||||||
# Download appimage-builder
|
|
||||||
set -xe
|
|
||||||
|
|
||||||
mkdir -p /cache/bin
|
|
||||||
wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /cache/bin/appimagetool || true
|
|
||||||
chmod +x /cache/bin/appimagetool
|
|
||||||
|
|
||||||
pip3 install git+https://github.com/AppImageCrafters/appimage-builder@f38699e
|
|
||||||
EOF
|
|
||||||
|
|
||||||
ENV PATH="/cache/bin/:${PATH}"
|
ENV PATH="/cache/bin/:${PATH}"
|
||||||
|
|
||||||
# Copy Imhex source
|
# Copy Imhex source
|
||||||
@@ -47,7 +36,7 @@ RUN <<EOF
|
|||||||
# Prepare ImHex build
|
# Prepare ImHex build
|
||||||
set -xe
|
set -xe
|
||||||
|
|
||||||
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
|
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
|
||||||
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -71,9 +60,18 @@ ccache -s
|
|||||||
EOF
|
EOF
|
||||||
|
|
||||||
RUN <<EOF
|
RUN <<EOF
|
||||||
# Package ImHex as AppImage
|
# Download appimage-builder
|
||||||
set -xe
|
set -xe
|
||||||
|
|
||||||
|
mkdir -p /cache/bin
|
||||||
|
wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /cache/bin/appimagetool || true
|
||||||
|
chmod +x /cache/bin/appimagetool
|
||||||
|
|
||||||
|
python3 -m venv venv
|
||||||
|
. venv/bin/activate
|
||||||
|
pip3 install git+https://github.com/AppImageCrafters/appimage-builder@f38699e
|
||||||
|
|
||||||
|
# Package ImHex as AppImage
|
||||||
export VERSION=$(cat /imhex/VERSION)
|
export VERSION=$(cat /imhex/VERSION)
|
||||||
appimage-builder --recipe /imhex/dist/AppImageBuilder.yml
|
appimage-builder --recipe /imhex/dist/AppImageBuilder.yml
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
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))
|
||||||
4
dist/get_deps_archlinux.sh
vendored
4
dist/get_deps_archlinux.sh
vendored
@@ -5,6 +5,7 @@ pacman -S $@ --needed \
|
|||||||
gcc \
|
gcc \
|
||||||
lld \
|
lld \
|
||||||
glfw \
|
glfw \
|
||||||
|
fontconfig \
|
||||||
file \
|
file \
|
||||||
mbedtls \
|
mbedtls \
|
||||||
freetype2 \
|
freetype2 \
|
||||||
@@ -18,4 +19,5 @@ pacman -S $@ --needed \
|
|||||||
zlib \
|
zlib \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
xz \
|
xz \
|
||||||
zstd
|
zstd \
|
||||||
|
lz4
|
||||||
|
|||||||
8
dist/get_deps_debian.sh
vendored
8
dist/get_deps_debian.sh
vendored
@@ -8,8 +8,8 @@ fi
|
|||||||
|
|
||||||
apt install -y \
|
apt install -y \
|
||||||
build-essential \
|
build-essential \
|
||||||
gcc-12 \
|
gcc-14 \
|
||||||
g++-12 \
|
g++-14 \
|
||||||
lld \
|
lld \
|
||||||
${PKGCONF:-} \
|
${PKGCONF:-} \
|
||||||
cmake \
|
cmake \
|
||||||
@@ -18,6 +18,7 @@ apt install -y \
|
|||||||
libglm-dev \
|
libglm-dev \
|
||||||
libmagic-dev \
|
libmagic-dev \
|
||||||
libmbedtls-dev \
|
libmbedtls-dev \
|
||||||
|
libfontconfig-dev \
|
||||||
libfreetype-dev \
|
libfreetype-dev \
|
||||||
libdbus-1-dev \
|
libdbus-1-dev \
|
||||||
libcurl4-gnutls-dev \
|
libcurl4-gnutls-dev \
|
||||||
@@ -26,4 +27,5 @@ apt install -y \
|
|||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
libbz2-dev \
|
libbz2-dev \
|
||||||
liblzma-dev \
|
liblzma-dev \
|
||||||
libzstd-dev
|
libzstd-dev \
|
||||||
|
liblz4-dev
|
||||||
|
|||||||
4
dist/get_deps_fedora.sh
vendored
4
dist/get_deps_fedora.sh
vendored
@@ -4,6 +4,7 @@ dnf install -y \
|
|||||||
cmake \
|
cmake \
|
||||||
dbus-devel \
|
dbus-devel \
|
||||||
file-devel \
|
file-devel \
|
||||||
|
fontconfig-devel \
|
||||||
freetype-devel \
|
freetype-devel \
|
||||||
libcurl-devel \
|
libcurl-devel \
|
||||||
gcc-c++ \
|
gcc-c++ \
|
||||||
@@ -16,4 +17,5 @@ dnf install -y \
|
|||||||
libzstd-devel \
|
libzstd-devel \
|
||||||
zlib-devel \
|
zlib-devel \
|
||||||
bzip2-devel \
|
bzip2-devel \
|
||||||
xz-devel
|
xz-devel \
|
||||||
|
lz4-devel
|
||||||
3
dist/get_deps_msys2.sh
vendored
3
dist/get_deps_msys2.sh
vendored
@@ -17,4 +17,5 @@ pacboy -S --needed --noconfirm \
|
|||||||
zlib:p \
|
zlib:p \
|
||||||
bzip2:p \
|
bzip2:p \
|
||||||
xz:p \
|
xz:p \
|
||||||
zstd:p
|
zstd:p \
|
||||||
|
lz4:p
|
||||||
|
|||||||
21
dist/get_deps_tumbleweed.sh
vendored
Executable file
21
dist/get_deps_tumbleweed.sh
vendored
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
zypper install \
|
||||||
|
cmake \
|
||||||
|
ninja \
|
||||||
|
gcc14 \
|
||||||
|
gcc14-c++ \
|
||||||
|
fontconfig-devel \
|
||||||
|
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 \
|
||||||
|
lz4-dev
|
||||||
2
dist/imhex.desktop
vendored
2
dist/imhex.desktop
vendored
@@ -8,3 +8,5 @@ Type=Application
|
|||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
Categories=Development;IDE;
|
Categories=Development;IDE;
|
||||||
StartupWMClass=imhex
|
StartupWMClass=imhex
|
||||||
|
Keywords=static-analysis;reverse-engineering;disassembler;disassembly;hacking;forensics;hex-editor;cybersecurity;security;binary-analysis;
|
||||||
|
MimeType=application/vnd.imhex.proj;
|
||||||
|
|||||||
8
dist/imhex.mime.xml
vendored
Normal file
8
dist/imhex.mime.xml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||||
|
<mime-type type="application/vnd.imhex.proj">
|
||||||
|
<comment>ImHex Project</comment>
|
||||||
|
<glob pattern="*.hexproj"/>
|
||||||
|
</mime-type>
|
||||||
|
</mime-info>
|
||||||
240
dist/langtool.py
vendored
Normal file → Executable file
240
dist/langtool.py
vendored
Normal file → Executable file
@@ -1,104 +1,214 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sys
|
import argparse
|
||||||
import json
|
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 = "en_US"
|
||||||
|
DEFAULT_LANG_PATH = "plugins/*/romfs/lang/"
|
||||||
INVALID_TRANSLATION = ""
|
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():
|
def main():
|
||||||
if len(sys.argv) < 3:
|
parser = argparse.ArgumentParser(
|
||||||
print(f"Usage: {Path(sys.argv[0]).name} <check|translate|update|create> <lang folder path> <language>")
|
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
|
return 1
|
||||||
|
|
||||||
command = sys.argv[1]
|
for lang_folder in lang_folders:
|
||||||
if command not in ["check", "translate", "update", "create"]:
|
if not lang_folder.is_dir():
|
||||||
print(f"Unknown command: {command}")
|
print(f"Error: {lang_folder} is not a folder")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
print(f"Using langtool in {command} mode")
|
default_lang_data = {}
|
||||||
|
default_lang_path = lang_folder / Path(DEFAULT_LANG + ".json")
|
||||||
lang_folder_path = Path(sys.argv[2])
|
if not default_lang_path.exists():
|
||||||
if not lang_folder_path.exists():
|
print(
|
||||||
print(f"Error: {lang_folder_path} does not exist")
|
f"Error: Default language file {default_lang_path} does not exist in {lang_folder}"
|
||||||
|
)
|
||||||
return 1
|
return 1
|
||||||
|
with default_lang_path.open("r", encoding="utf-8") as file:
|
||||||
|
default_lang_data = json.load(file)
|
||||||
|
|
||||||
if not lang_folder_path.is_dir():
|
reference_lang_data = None
|
||||||
print(f"Error: {lang_folder_path} is not a folder")
|
reference_lang_path = lang_folder / Path(args.reflang + ".json")
|
||||||
return 1
|
if reference_lang_path.exists():
|
||||||
|
with reference_lang_path.open("r", encoding="utf-8") as file:
|
||||||
lang = sys.argv[3] if len(sys.argv) > 3 else ""
|
reference_lang_data = json.load(file)
|
||||||
|
|
||||||
print(f"Processing language files in {lang_folder_path}...")
|
|
||||||
|
|
||||||
default_lang_file_path = lang_folder_path / Path(DEFAULT_LANG + ".json")
|
|
||||||
if not default_lang_file_path.exists():
|
|
||||||
print(f"Error: Default language file {default_lang_file_path} does not exist")
|
|
||||||
return 1
|
|
||||||
|
|
||||||
print(f"Using file '{default_lang_file_path.name}' as template language file")
|
|
||||||
|
|
||||||
with default_lang_file_path.open("r", encoding="utf-8") as default_lang_file:
|
|
||||||
default_lang_data = json.load(default_lang_file)
|
|
||||||
|
|
||||||
if command == "create" and lang != "":
|
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():
|
if lang_file_path.exists():
|
||||||
print(f"Error: Language file {lang_file_path} already exists")
|
continue
|
||||||
return 1
|
|
||||||
|
|
||||||
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:
|
with lang_file_path.open("w", encoding="utf-8") as new_lang_file:
|
||||||
new_lang_data = {
|
new_lang_data = {
|
||||||
"code": lang,
|
"code": lang,
|
||||||
"language": input("Enter language: "),
|
"language": (
|
||||||
"country": input("Enter country: "),
|
exist_lang_data["language"]
|
||||||
"translations": {}
|
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)
|
json.dump(new_lang_data, new_lang_file, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
for additional_lang_file_path in lang_folder_path.glob("*.json"):
|
lang_files = set(lang_folder.glob(lang_files_glob))
|
||||||
if not lang == "" and not additional_lang_file_path.stem == lang:
|
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
|
continue
|
||||||
|
|
||||||
if additional_lang_file_path.name.startswith(DEFAULT_LANG):
|
print(f"\nProcessing '{lang_file_path}'")
|
||||||
continue
|
if not (command == "update" or command == "create"):
|
||||||
|
print("\n----------------------------\n")
|
||||||
|
|
||||||
print(f"\nProcessing file '{additional_lang_file_path.name}'\n----------------------------\n")
|
with lang_file_path.open("r+", encoding="utf-8") as target_lang_file:
|
||||||
|
lang_data = json.load(target_lang_file)
|
||||||
with additional_lang_file_path.open("r+", encoding="utf-8") as additional_lang_file:
|
|
||||||
additional_lang_data = json.load(additional_lang_file)
|
|
||||||
|
|
||||||
for key, value in default_lang_data["translations"].items():
|
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:
|
has_translation = (
|
||||||
handle_missing_key(command, additional_lang_data, key, value)
|
key in lang_data["translations"]
|
||||||
|
and lang_data["translations"][key] != INVALID_TRANSLATION
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
has_translation
|
||||||
|
and not (
|
||||||
|
(command == "retranslate" or command == "untranslate")
|
||||||
|
and re.compile(args.keys).fullmatch(key)
|
||||||
|
)
|
||||||
|
and not command == "fmtzh"
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
if command == "check":
|
||||||
|
print(
|
||||||
|
f"Error: Translation {lang_data['code']} is missing translation for key '{key}'"
|
||||||
|
)
|
||||||
|
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
|
||||||
|
and key in reference_lang_data["translations"]
|
||||||
|
)
|
||||||
|
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 = []
|
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"]:
|
if key not in default_lang_data["translations"]:
|
||||||
keys_to_remove.append(key)
|
keys_to_remove.append(key)
|
||||||
|
|
||||||
for key in keys_to_remove:
|
for key in keys_to_remove:
|
||||||
additional_lang_data["translations"].pop(key)
|
lang_data["translations"].pop(key)
|
||||||
print(f"Removed unused key '{key}' from translation '{additional_lang_data['code']}'")
|
print(
|
||||||
|
f"Removed unused key '{key}' from translation '{lang_data['code']}'"
|
||||||
|
)
|
||||||
|
|
||||||
additional_lang_file.seek(0)
|
target_lang_file.seek(0)
|
||||||
additional_lang_file.truncate()
|
target_lang_file.truncate()
|
||||||
json.dump(additional_lang_data, additional_lang_file, indent=4, sort_keys=True, ensure_ascii=False)
|
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())
|
exit(main())
|
||||||
|
|||||||
12
dist/macOS/arm64.Dockerfile
vendored
12
dist/macOS/arm64.Dockerfile
vendored
@@ -1,7 +1,7 @@
|
|||||||
# This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile
|
# This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile
|
||||||
FROM ghcr.io/itrooz/macos-crosscompile:clang17-nosdk as build
|
FROM ghcr.io/itrooz/macos-crosscompile:clang17-nosdk as build
|
||||||
|
|
||||||
ENV MACOSX_DEPLOYMENT_TARGET 12.1
|
ENV MACOSX_DEPLOYMENT_TARGET 13.0
|
||||||
|
|
||||||
# -- DOWNLOADING STUFF
|
# -- DOWNLOADING STUFF
|
||||||
|
|
||||||
@@ -35,9 +35,9 @@ EOF
|
|||||||
|
|
||||||
## Download libmagic
|
## Download libmagic
|
||||||
### Clone 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
|
### 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
|
# -- DOWNLOADING + BUILDING STUFF
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ if [ "$CUSTOM_GLFW" ]; then
|
|||||||
cd /mnt/glfw
|
cd /mnt/glfw
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
CC=o64-gcc CXX=o64-g++ cmake -G "Ninja" \
|
CC=o64-clang CXX=o64-clang++ cmake -G "Ninja" \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DBUILD_SHARED_LIBS=ON \
|
-DBUILD_SHARED_LIBS=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -126,7 +126,7 @@ if [ "$CUSTOM_GLFW" ]; then
|
|||||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \
|
-DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \
|
||||||
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 \
|
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \
|
||||||
..
|
..
|
||||||
ninja -j $JOBS install
|
ninja -j $JOBS install
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/
|
|||||||
`# ccache flags` \
|
`# ccache flags` \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||||
`# MacOS cross-compiling flags` \
|
`# MacOS cross-compiling flags` \
|
||||||
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 \
|
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \
|
||||||
`# Override compilers for code generators` \
|
`# Override compilers for code generators` \
|
||||||
-DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \
|
-DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \
|
||||||
`# Normal ImHex flags` \
|
`# Normal ImHex flags` \
|
||||||
|
|||||||
13
dist/macOS/arm64.crosscompile.Dockerfile
vendored
13
dist/macOS/arm64.crosscompile.Dockerfile
vendored
@@ -68,19 +68,6 @@ RUN --mount=type=cache,target=/cache <<EOF
|
|||||||
|
|
||||||
ccache -s
|
ccache -s
|
||||||
EOF
|
EOF
|
||||||
# Not needed, because we don't use gcc for cross-compiling anymore
|
|
||||||
# ## Install dependencies for gcc-13
|
|
||||||
# RUN apt install -y gcc g++ zlib1g-dev libmpc-dev libmpfr-dev libgmp-dev
|
|
||||||
# ## Build cross-compiler gcc-13
|
|
||||||
# RUN --mount=type=cache,target=/cache <<EOF
|
|
||||||
# set -xe
|
|
||||||
# ccache -zs
|
|
||||||
|
|
||||||
# cd /osxcross
|
|
||||||
# UNATTENDED=1 CC=/usr/lib/ccache/gcc CXX=/usr/lib/ccache/g++ GCC_VERSION=13.2.0 ./build_gcc.sh
|
|
||||||
|
|
||||||
# ccache -s
|
|
||||||
# EOF
|
|
||||||
|
|
||||||
ARG DELETE_SDK=1
|
ARG DELETE_SDK=1
|
||||||
RUN <<EOF
|
RUN <<EOF
|
||||||
|
|||||||
17
dist/rpm/imhex.spec
vendored
17
dist/rpm/imhex.spec
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
%define source_date_epoch_from_changelog 0
|
||||||
|
|
||||||
Name: imhex
|
Name: imhex
|
||||||
Version: VERSION
|
Version: VERSION
|
||||||
Release: 0%{?dist}
|
Release: 0%{?dist}
|
||||||
@@ -14,6 +16,7 @@ BuildRequires: cmake
|
|||||||
BuildRequires: desktop-file-utils
|
BuildRequires: desktop-file-utils
|
||||||
BuildRequires: dbus-devel
|
BuildRequires: dbus-devel
|
||||||
BuildRequires: file-devel
|
BuildRequires: file-devel
|
||||||
|
BuildRequires: fontconfig-devel
|
||||||
BuildRequires: freetype-devel
|
BuildRequires: freetype-devel
|
||||||
BuildRequires: fmt-devel
|
BuildRequires: fmt-devel
|
||||||
BuildRequires: gcc-c++
|
BuildRequires: gcc-c++
|
||||||
@@ -32,7 +35,7 @@ BuildRequires: zlib-devel
|
|||||||
BuildRequires: bzip2-devel
|
BuildRequires: bzip2-devel
|
||||||
BuildRequires: xz-devel
|
BuildRequires: xz-devel
|
||||||
%if 0%{?rhel}
|
%if 0%{?rhel}
|
||||||
BuildRequires: gcc-toolset-12
|
BuildRequires: gcc-toolset-14
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
Provides: bundled(gnulib)
|
Provides: bundled(gnulib)
|
||||||
@@ -68,9 +71,9 @@ rm -rf lib/third_party/{fmt,nlohmann_json,yara}
|
|||||||
|
|
||||||
%build
|
%build
|
||||||
%if 0%{?rhel}
|
%if 0%{?rhel}
|
||||||
. /opt/rh/gcc-toolset-12/enable
|
. /opt/rh/gcc-toolset-14/enable
|
||||||
%set_build_flags
|
%set_build_flags
|
||||||
CXXFLAGS+=" -std=gnu++2b"
|
CXXFLAGS+=" -std=gnu++23"
|
||||||
%endif
|
%endif
|
||||||
%cmake \
|
%cmake \
|
||||||
-D CMAKE_BUILD_TYPE=Release \
|
-D CMAKE_BUILD_TYPE=Release \
|
||||||
@@ -91,9 +94,9 @@ CXXFLAGS+=" -std=gnu++2b"
|
|||||||
|
|
||||||
%check
|
%check
|
||||||
%if 0%{?rhel}
|
%if 0%{?rhel}
|
||||||
. /opt/rh/gcc-toolset-12/enable
|
. /opt/rh/gcc-toolset-14/enable
|
||||||
%set_build_flags
|
%set_build_flags
|
||||||
CXXFLAGS+=" -std=gnu++2b"
|
CXXFLAGS+=" -std=gnu++23"
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
|
||||||
@@ -122,9 +125,7 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
|
|||||||
%{_bindir}/imhex-updater
|
%{_bindir}/imhex-updater
|
||||||
%{_datadir}/pixmaps/%{name}.png
|
%{_datadir}/pixmaps/%{name}.png
|
||||||
%{_datadir}/applications/%{name}.desktop
|
%{_datadir}/applications/%{name}.desktop
|
||||||
|
%{_datadir}/mime/packages/%{name}.xml
|
||||||
%{_libdir}/libimhex.so*
|
%{_libdir}/libimhex.so*
|
||||||
%{_libdir}/%{name}/
|
%{_libdir}/%{name}/
|
||||||
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||||
|
|
||||||
|
|
||||||
%changelog
|
|
||||||
|
|||||||
6
dist/web/Dockerfile
vendored
6
dist/web/Dockerfile
vendored
@@ -5,7 +5,7 @@ FROM emscripten/emsdk:3.1.51 as build
|
|||||||
ARG UNIQUEKEY 1
|
ARG UNIQUEKEY 1
|
||||||
|
|
||||||
RUN apt update
|
RUN apt update
|
||||||
RUN apt install -y git ccache autoconf automake libtool cmake pkg-config
|
RUN apt install -y git ccache autoconf automake libtool cmake pkg-config ninja-build
|
||||||
|
|
||||||
RUN <<EOF
|
RUN <<EOF
|
||||||
# Install vcpkg
|
# Install vcpkg
|
||||||
@@ -56,9 +56,11 @@ set -xe
|
|||||||
ccache -zs
|
ccache -zs
|
||||||
|
|
||||||
cmake /imhex \
|
cmake /imhex \
|
||||||
|
-G "Ninja" \
|
||||||
-DIMHEX_OFFLINE_BUILD=ON \
|
-DIMHEX_OFFLINE_BUILD=ON \
|
||||||
-DIMHEX_STATIC_LINK_PLUGINS=ON \
|
-DIMHEX_STATIC_LINK_PLUGINS=ON \
|
||||||
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
|
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
|
||||||
|
-DIMHEX_COMPRESS_DEBUG_INFO=OFF \
|
||||||
-DNATIVE_CMAKE_C_COMPILER=gcc \
|
-DNATIVE_CMAKE_C_COMPILER=gcc \
|
||||||
-DNATIVE_CMAKE_CXX_COMPILER=g++ \
|
-DNATIVE_CMAKE_CXX_COMPILER=g++ \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
@@ -67,7 +69,7 @@ cmake /imhex
|
|||||||
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
|
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
|
||||||
make -j $JOBS
|
ninja -j $JOBS
|
||||||
|
|
||||||
cp /imhex/dist/web/source/* /build
|
cp /imhex/dist/web/source/* /build
|
||||||
ccache -s
|
ccache -s
|
||||||
|
|||||||
2
dist/web/source/index.html
vendored
2
dist/web/source/index.html
vendored
@@ -62,7 +62,7 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="loading" class="centered">
|
<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>
|
<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>
|
<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>
|
<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 {
|
:root {
|
||||||
--progress: 25%;
|
--progress: 0%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress-bar-container {
|
.progress-bar-container {
|
||||||
@@ -175,3 +175,14 @@ a:hover {
|
|||||||
width: var(--progress);
|
width: var(--progress);
|
||||||
background-color: #3864cb;
|
background-color: #3864cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#logo {
|
||||||
|
height: 25%;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.canvas-fixed {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
142
dist/web/source/wasm-config.js
vendored
142
dist/web/source/wasm-config.js
vendored
@@ -100,7 +100,77 @@ var notWorkingTimer = setTimeout(() => {
|
|||||||
|
|
||||||
var Module = {
|
var Module = {
|
||||||
preRun: [],
|
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() {
|
onRuntimeInitialized: function() {
|
||||||
// Triggered when the wasm module is loaded and ready to use.
|
// Triggered when the wasm module is loaded and ready to use.
|
||||||
document.getElementById("loading").style.display = "none"
|
document.getElementById("loading").style.display = "none"
|
||||||
@@ -111,13 +181,55 @@ var Module = {
|
|||||||
print: (function() { })(),
|
print: (function() { })(),
|
||||||
printErr: function(text) { },
|
printErr: function(text) { },
|
||||||
canvas: (function() {
|
canvas: (function() {
|
||||||
let canvas = document.getElementById('canvas');
|
const canvas = document.getElementById('canvas');
|
||||||
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
|
canvas.addEventListener("webglcontextlost", function(e) {
|
||||||
// application robust, you may want to override this behavior before shipping!
|
alert('WebGL context lost, please reload the page');
|
||||||
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
|
e.preventDefault();
|
||||||
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
|
}, false);
|
||||||
|
|
||||||
|
// 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;
|
return canvas;
|
||||||
|
} else {
|
||||||
|
alert('WebGL 2 not supported by this browser');
|
||||||
|
}
|
||||||
})(),
|
})(),
|
||||||
setStatus: function(text) { },
|
setStatus: function(text) { },
|
||||||
totalDependencies: 0,
|
totalDependencies: 0,
|
||||||
@@ -144,14 +256,16 @@ if (urlParams.has("lang")) {
|
|||||||
window.addEventListener('resize', js_resizeCanvas, false);
|
window.addEventListener('resize', js_resizeCanvas, false);
|
||||||
function js_resizeCanvas() {
|
function js_resizeCanvas() {
|
||||||
let canvas = document.getElementById('canvas');
|
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.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);
|
||||||
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent some default browser shortcuts from preventing ImHex ones to work
|
||||||
|
document.addEventListener('keydown', e => {
|
||||||
|
if (e.ctrlKey) {
|
||||||
|
if (e.which == 83) e.preventDefault();
|
||||||
|
}
|
||||||
|
})
|
||||||
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: 6b4a9c7ddd...b9d7f4abaf
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: 7aa467c8be...f45156a55c
@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.16)
|
|||||||
project(libimhex)
|
project(libimhex)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
|
||||||
|
|
||||||
set(LIBIMHEX_SOURCES
|
set(LIBIMHEX_SOURCES
|
||||||
source/api/imhex_api.cpp
|
source/api/imhex_api.cpp
|
||||||
@@ -37,6 +36,9 @@ set(LIBIMHEX_SOURCES
|
|||||||
source/helpers/logger.cpp
|
source/helpers/logger.cpp
|
||||||
source/helpers/tar.cpp
|
source/helpers/tar.cpp
|
||||||
source/helpers/debugging.cpp
|
source/helpers/debugging.cpp
|
||||||
|
source/helpers/default_paths.cpp
|
||||||
|
source/helpers/imgui_hooks.cpp
|
||||||
|
source/helpers/semantic_version.cpp
|
||||||
|
|
||||||
source/test/tests.cpp
|
source/test/tests.cpp
|
||||||
|
|
||||||
@@ -124,7 +126,7 @@ target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR}
|
|||||||
|
|
||||||
if (NOT EMSCRIPTEN)
|
if (NOT EMSCRIPTEN)
|
||||||
# curl is only used in non-emscripten builds
|
# curl is only used in non-emscripten builds
|
||||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${CURL_LIBRARIES})
|
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} CURL::libcurl)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
@@ -143,7 +145,7 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
|
|||||||
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES})
|
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)
|
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
|
||||||
|
|
||||||
@@ -151,3 +153,4 @@ add_dependencies(imhex_all libimhex)
|
|||||||
|
|
||||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
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 RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
set_target_properties(libimhex PROPERTIES PREFIX "")
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <hex/helpers/types.hpp>
|
#include <hex/helpers/types.hpp>
|
||||||
#include <hex/helpers/intrinsics.hpp>
|
|
||||||
@@ -151,7 +151,7 @@ namespace hex {
|
|||||||
if (m_icon.isValid())
|
if (m_icon.isValid())
|
||||||
return m_icon;
|
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;
|
return m_icon;
|
||||||
}
|
}
|
||||||
@@ -295,6 +295,7 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class AchievementManager {
|
class AchievementManager {
|
||||||
|
static bool s_initialized;
|
||||||
public:
|
public:
|
||||||
AchievementManager() = delete;
|
AchievementManager() = delete;
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
#include <hex/api/localization_manager.hpp>
|
#include <hex/api/localization_manager.hpp>
|
||||||
|
#include <hex/api/shortcut_manager.hpp>
|
||||||
#include <hex/helpers/concepts.hpp>
|
#include <hex/helpers/concepts.hpp>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <mutex>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -23,7 +24,6 @@ enum ImGuiCustomCol : int;
|
|||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
class View;
|
class View;
|
||||||
class Shortcut;
|
|
||||||
class Task;
|
class Task;
|
||||||
|
|
||||||
namespace dp {
|
namespace dp {
|
||||||
@@ -98,7 +98,7 @@ namespace hex {
|
|||||||
bool m_requiresRestart = false;
|
bool m_requiresRestart = false;
|
||||||
std::function<bool()> m_enabledCallback;
|
std::function<bool()> m_enabledCallback;
|
||||||
std::function<void(Widget&)> m_changedCallback;
|
std::function<void(Widget&)> m_changedCallback;
|
||||||
std::optional<std::string> m_tooltip;
|
std::optional<UnlocalizedString> m_tooltip;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -112,7 +112,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const std::optional<std::string>& getTooltip() const {
|
const std::optional<UnlocalizedString>& getTooltip() const {
|
||||||
return m_interface.m_tooltip;
|
return m_interface.m_tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +175,21 @@ namespace hex {
|
|||||||
float m_min, m_max;
|
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 {
|
class ColorPicker : public Widget {
|
||||||
public:
|
public:
|
||||||
explicit ColorPicker(ImColor defaultColor);
|
explicit ColorPicker(ImColor defaultColor);
|
||||||
@@ -340,6 +355,8 @@ namespace hex {
|
|||||||
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &value) {
|
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &value) {
|
||||||
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
||||||
impl::runOnChangeHandlers(unlocalizedCategory, unlocalizedName, value);
|
impl::runOnChangeHandlers(unlocalizedCategory, unlocalizedName, value);
|
||||||
|
|
||||||
|
impl::store();
|
||||||
}
|
}
|
||||||
|
|
||||||
using OnChangeCallback = std::function<void(const SettingsValue &)>;
|
using OnChangeCallback = std::function<void(const SettingsValue &)>;
|
||||||
@@ -363,7 +380,7 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
using DisplayCallback = std::function<std::string(std::string)>;
|
using DisplayCallback = std::function<std::string(std::string)>;
|
||||||
using ExecuteCallback = std::function<void(std::string)>;
|
using ExecuteCallback = std::function<std::optional<std::string>(std::string)>;
|
||||||
using QueryCallback = std::function<std::vector<QueryResult>(std::string)>;
|
using QueryCallback = std::function<std::vector<QueryResult>(std::string)>;
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@@ -399,7 +416,7 @@ namespace hex {
|
|||||||
const std::string &command,
|
const std::string &command,
|
||||||
const UnlocalizedString &unlocalizedDescription,
|
const UnlocalizedString &unlocalizedDescription,
|
||||||
const impl::DisplayCallback &displayCallback,
|
const impl::DisplayCallback &displayCallback,
|
||||||
const impl::ExecuteCallback &executeCallback = [](auto) {});
|
const impl::ExecuteCallback &executeCallback = [](auto) { return std::nullopt; });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new command handler to the command palette
|
* @brief Adds a new command handler to the command palette
|
||||||
@@ -420,7 +437,7 @@ namespace hex {
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::IIterable&, bool, std::span<const pl::core::Token::Literal>)>;
|
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, bool, std::span<const pl::core::Token::Literal>)>;
|
||||||
|
|
||||||
struct FunctionDefinition {
|
struct FunctionDefinition {
|
||||||
pl::api::Namespace ns;
|
pl::api::Namespace ns;
|
||||||
@@ -432,6 +449,14 @@ namespace hex {
|
|||||||
bool dangerous;
|
bool dangerous;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TypeDefinition {
|
||||||
|
pl::api::Namespace ns;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
pl::api::FunctionParameterCount parameterCount;
|
||||||
|
pl::api::TypeCallback callback;
|
||||||
|
};
|
||||||
|
|
||||||
struct Visualizer {
|
struct Visualizer {
|
||||||
pl::api::FunctionParameterCount parameterCount;
|
pl::api::FunctionParameterCount parameterCount;
|
||||||
VisualizerFunctionCallback callback;
|
VisualizerFunctionCallback callback;
|
||||||
@@ -441,6 +466,7 @@ namespace hex {
|
|||||||
const std::map<std::string, Visualizer>& getInlineVisualizers();
|
const std::map<std::string, Visualizer>& getInlineVisualizers();
|
||||||
const std::map<std::string, pl::api::PragmaHandler>& getPragmas();
|
const std::map<std::string, pl::api::PragmaHandler>& getPragmas();
|
||||||
const std::vector<FunctionDefinition>& getFunctions();
|
const std::vector<FunctionDefinition>& getFunctions();
|
||||||
|
const std::vector<TypeDefinition>& getTypes();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,6 +525,20 @@ namespace hex {
|
|||||||
const pl::api::FunctionCallback &func
|
const pl::api::FunctionCallback &func
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new type to the pattern language
|
||||||
|
* @param ns The namespace of the type
|
||||||
|
* @param name The name of the type
|
||||||
|
* @param parameterCount The amount of non-type template parameters the type takes
|
||||||
|
* @param func The type callback
|
||||||
|
*/
|
||||||
|
void addType(
|
||||||
|
const pl::api::Namespace &ns,
|
||||||
|
const std::string &name,
|
||||||
|
pl::api::FunctionParameterCount parameterCount,
|
||||||
|
const pl::api::TypeCallback &func
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a new visualizer to the pattern language
|
* @brief Adds a new visualizer to the pattern language
|
||||||
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
|
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
|
||||||
@@ -730,7 +770,7 @@ namespace hex {
|
|||||||
struct MenuItem {
|
struct MenuItem {
|
||||||
std::vector<UnlocalizedString> unlocalizedNames;
|
std::vector<UnlocalizedString> unlocalizedNames;
|
||||||
Icon icon;
|
Icon icon;
|
||||||
std::unique_ptr<Shortcut> shortcut;
|
Shortcut shortcut;
|
||||||
View *view;
|
View *view;
|
||||||
MenuCallback callback;
|
MenuCallback callback;
|
||||||
EnabledCallback enabledCallback;
|
EnabledCallback enabledCallback;
|
||||||
@@ -756,6 +796,7 @@ namespace hex {
|
|||||||
const std::multimap<u32, MainMenuItem>& getMainMenuItems();
|
const std::multimap<u32, MainMenuItem>& getMainMenuItems();
|
||||||
|
|
||||||
const std::multimap<u32, MenuItem>& getMenuItems();
|
const std::multimap<u32, MenuItem>& getMenuItems();
|
||||||
|
const std::vector<MenuItem*>& getToolbarMenuItems();
|
||||||
std::multimap<u32, MenuItem>& getMenuItemsMutable();
|
std::multimap<u32, MenuItem>& getMenuItemsMutable();
|
||||||
|
|
||||||
const std::vector<DrawCallback>& getWelcomeScreenEntries();
|
const std::vector<DrawCallback>& getWelcomeScreenEntries();
|
||||||
@@ -898,6 +939,11 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
void addMenuItemToToolbar(const UnlocalizedString &unlocalizedName, ImGuiCustomCol color);
|
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
|
* @brief Adds a new sidebar item
|
||||||
* @param icon The icon to use for the item
|
* @param icon The icon to use for the item
|
||||||
@@ -963,12 +1009,34 @@ namespace hex {
|
|||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
|
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
|
||||||
struct Entry {
|
struct ExportMenuEntry {
|
||||||
UnlocalizedString unlocalizedName;
|
UnlocalizedString unlocalizedName;
|
||||||
Callback callback;
|
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 +1046,14 @@ namespace hex {
|
|||||||
* @param unlocalizedName The unlocalized name of the formatter
|
* @param unlocalizedName The unlocalized name of the formatter
|
||||||
* @param callback The function to call to format the data
|
* @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 +1114,7 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MiniMapVisualizer {
|
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;
|
UnlocalizedString unlocalizedName;
|
||||||
Callback callback;
|
Callback callback;
|
||||||
@@ -1220,7 +1295,7 @@ namespace hex {
|
|||||||
void stopServices();
|
void stopServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
|
void registerService(const UnlocalizedString &unlocalizedString, const impl::Callback &callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */
|
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */
|
||||||
|
|||||||
@@ -2,14 +2,16 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
#include <hex/helpers/patches.hpp>
|
||||||
|
|
||||||
#include <wolv/types/type_name.hpp>
|
#include <wolv/types/type_name.hpp>
|
||||||
|
|
||||||
@@ -19,12 +21,12 @@
|
|||||||
constexpr static auto ShouldLog = (should_log); \
|
constexpr static auto ShouldLog = (should_log); \
|
||||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
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 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, 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(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \
|
||||||
static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(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)...); } \
|
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(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__)
|
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
|
||||||
@@ -57,6 +59,10 @@ namespace hex {
|
|||||||
return m_hash == other.m_hash;
|
return m_hash == other.m_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr auto operator<=>(const EventId &other) const {
|
||||||
|
return m_hash <=> other.m_hash;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 m_hash;
|
u32 m_hash;
|
||||||
};
|
};
|
||||||
@@ -72,11 +78,12 @@ namespace hex {
|
|||||||
|
|
||||||
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
||||||
|
|
||||||
void operator()(std::string_view eventName, Params... params) const {
|
template<typename E>
|
||||||
|
void call(Params... params) const {
|
||||||
try {
|
try {
|
||||||
m_func(params...);
|
m_func(params...);
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
log::error("An exception occurred while handling event {}: {}", eventName, e.what());
|
log::error("An exception occurred while handling event {}: {}", wolv::type::getTypeName<E>(), e.what());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +104,7 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
class EventManager {
|
class EventManager {
|
||||||
public:
|
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
|
* @brief Subscribes to an event
|
||||||
@@ -110,7 +117,7 @@ namespace hex {
|
|||||||
std::scoped_lock lock(getEventMutex());
|
std::scoped_lock lock(getEventMutex());
|
||||||
|
|
||||||
auto &events = getEvents();
|
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) });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,16 +130,10 @@ namespace hex {
|
|||||||
static void subscribe(void *token, typename E::Callback function) {
|
static void subscribe(void *token, typename E::Callback function) {
|
||||||
std::scoped_lock lock(getEventMutex());
|
std::scoped_lock lock(getEventMutex());
|
||||||
|
|
||||||
if (getTokenStore().contains(token)) {
|
if (isAlreadyRegistered(token, E::Id)) {
|
||||||
auto&& [begin, end] = getTokenStore().equal_range(token);
|
|
||||||
const auto eventRegistered = std::any_of(begin, end, [&](auto &item) {
|
|
||||||
return item.second->first == E::Id;
|
|
||||||
});
|
|
||||||
if (eventRegistered) {
|
|
||||||
log::fatal("The token '{}' has already registered the same event ('{}')", token, wolv::type::getTypeName<E>());
|
log::fatal("The token '{}' has already registered the same event ('{}')", token, wolv::type::getTypeName<E>());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
getTokenStore().insert({ token, subscribe<E>(function) });
|
getTokenStore().insert({ token, subscribe<E>(function) });
|
||||||
}
|
}
|
||||||
@@ -156,16 +157,7 @@ namespace hex {
|
|||||||
static void unsubscribe(void *token) noexcept {
|
static void unsubscribe(void *token) noexcept {
|
||||||
std::scoped_lock lock(getEventMutex());
|
std::scoped_lock lock(getEventMutex());
|
||||||
|
|
||||||
auto &tokenStore = getTokenStore();
|
unsubscribe(token, E::Id);
|
||||||
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
|
|
||||||
return item.first == token && item.second->first == E::Id;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (iter != tokenStore.end()) {
|
|
||||||
getEvents().remove(*iter->second);
|
|
||||||
tokenStore.erase(iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,14 +169,14 @@ namespace hex {
|
|||||||
static void post(auto && ...args) {
|
static void post(auto && ...args) {
|
||||||
std::scoped_lock lock(getEventMutex());
|
std::scoped_lock lock(getEventMutex());
|
||||||
|
|
||||||
for (const auto &[id, event] : getEvents()) {
|
auto [begin, end] = getEvents().equal_range(E::Id);
|
||||||
if (id == E::Id) {
|
for (auto it = begin; it != end; ++it) {
|
||||||
(*static_cast<E *const>(event.get()))(wolv::type::getTypeName<E>(), std::forward<decltype(args)>(args)...);
|
const auto &[id, event] = *it;
|
||||||
}
|
(*static_cast<E *const>(event.get())).template call<E>(std::forward<decltype(args)>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined (DEBUG)
|
#if defined (DEBUG)
|
||||||
if (E::ShouldLog)
|
if constexpr (E::ShouldLog)
|
||||||
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
|
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -203,6 +195,9 @@ namespace hex {
|
|||||||
static std::multimap<void *, EventList::iterator>& getTokenStore();
|
static std::multimap<void *, EventList::iterator>& getTokenStore();
|
||||||
static EventList& getEvents();
|
static EventList& getEvents();
|
||||||
static std::recursive_mutex& getEventMutex();
|
static std::recursive_mutex& getEventMutex();
|
||||||
|
|
||||||
|
static bool isAlreadyRegistered(void *token, impl::EventId id);
|
||||||
|
static void unsubscribe(void *token, impl::EventId id);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default Events */
|
/* Default Events */
|
||||||
@@ -220,7 +215,9 @@ namespace hex {
|
|||||||
EVENT_DEF(EventAbnormalTermination, int);
|
EVENT_DEF(EventAbnormalTermination, int);
|
||||||
EVENT_DEF(EventThemeChanged);
|
EVENT_DEF(EventThemeChanged);
|
||||||
EVENT_DEF(EventOSThemeChanged);
|
EVENT_DEF(EventOSThemeChanged);
|
||||||
|
EVENT_DEF(EventDPIChanged, float, float);
|
||||||
EVENT_DEF(EventWindowFocused, bool);
|
EVENT_DEF(EventWindowFocused, bool);
|
||||||
|
EVENT_DEF(EventImHexUpdated, SemanticVersion, SemanticVersion);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when the provider is created.
|
* @brief Called when the provider is created.
|
||||||
@@ -246,7 +243,12 @@ namespace hex {
|
|||||||
EVENT_DEF(EventWindowInitialized);
|
EVENT_DEF(EventWindowInitialized);
|
||||||
EVENT_DEF(EventWindowDeinitializing, GLFWwindow *);
|
EVENT_DEF(EventWindowDeinitializing, GLFWwindow *);
|
||||||
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
|
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
|
||||||
EVENT_DEF(EventPatchCreated, u64, u8, u8);
|
|
||||||
|
/**
|
||||||
|
* @brief Called upon creation of an IPS patch.
|
||||||
|
* As for now, the event only serves a purpose for the achievement unlock.
|
||||||
|
*/
|
||||||
|
EVENT_DEF(EventPatchCreated, const u8*, u64, const PatchKind);
|
||||||
EVENT_DEF(EventPatternEvaluating);
|
EVENT_DEF(EventPatternEvaluating);
|
||||||
EVENT_DEF(EventPatternExecuted, const std::string&);
|
EVENT_DEF(EventPatternExecuted, const std::string&);
|
||||||
EVENT_DEF(EventPatternEditorChanged, const std::string&);
|
EVENT_DEF(EventPatternEditorChanged, const std::string&);
|
||||||
@@ -264,6 +266,7 @@ namespace hex {
|
|||||||
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
||||||
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
||||||
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
||||||
|
EVENT_DEF(EventProviderDirtied, prv::Provider *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Called when a project has been loaded
|
* @brief Called when a project has been loaded
|
||||||
@@ -273,6 +276,7 @@ namespace hex {
|
|||||||
EVENT_DEF_NO_LOG(EventFrameBegin);
|
EVENT_DEF_NO_LOG(EventFrameBegin);
|
||||||
EVENT_DEF_NO_LOG(EventFrameEnd);
|
EVENT_DEF_NO_LOG(EventFrameEnd);
|
||||||
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
|
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(RequestAddInitTask, std::string, bool, std::function<bool()>);
|
||||||
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
|
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
|
||||||
|
|||||||
@@ -2,12 +2,15 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
#include <hex/api/localization_manager.hpp>
|
#include <hex/api/localization_manager.hpp>
|
||||||
|
#include <hex/helpers/semantic_version.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <wolv/io/fs.hpp>
|
#include <wolv/io/fs.hpp>
|
||||||
|
|
||||||
@@ -73,7 +76,7 @@ namespace hex {
|
|||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
|
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, Highlighting>& getBackgroundHighlights();
|
||||||
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions();
|
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions();
|
||||||
@@ -291,7 +294,7 @@ namespace hex {
|
|||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
void resetClosingProvider();
|
void resetClosingProvider();
|
||||||
const std::vector<prv::Provider*>& getClosingProviders();
|
std::set<prv::Provider*> getClosingProviders();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,6 +435,7 @@ namespace hex {
|
|||||||
void setInitialWindowProperties(InitialWindowProperties properties);
|
void setInitialWindowProperties(InitialWindowProperties properties);
|
||||||
|
|
||||||
void setGPUVendor(const std::string &vendor);
|
void setGPUVendor(const std::string &vendor);
|
||||||
|
void setGLRenderer(const std::string &renderer);
|
||||||
|
|
||||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||||
|
|
||||||
@@ -571,6 +575,12 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
const std::string& getGPUVendor();
|
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
|
* @brief Checks if ImHex is running in portable mode
|
||||||
* @return Whether ImHex is running in portable mode
|
* @return Whether ImHex is running in portable mode
|
||||||
@@ -595,11 +605,21 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
std::string getArchitecture();
|
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
|
* @brief Gets the current ImHex version
|
||||||
* @return ImHex version
|
* @return ImHex version
|
||||||
*/
|
*/
|
||||||
std::string getImHexVersion(bool withBuildType = true);
|
SemanticVersion getImHexVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the current git commit hash
|
* @brief Gets the current git commit hash
|
||||||
@@ -620,6 +640,12 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
bool isDebugBuild();
|
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 {
|
enum class UpdateType {
|
||||||
Stable,
|
Stable,
|
||||||
Nightly
|
Nightly
|
||||||
@@ -670,6 +696,13 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
void* getLibImHexModuleHandle();
|
void* getLibImHexModuleHandle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new migration routine that will be executed when upgrading from a lower version than specified in migrationVersion
|
||||||
|
* @param migrationVersion Upgrade point version
|
||||||
|
* @param function Function to run
|
||||||
|
*/
|
||||||
|
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex.hpp>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/core.h>
|
||||||
|
#include <wolv/types/static_string.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
@@ -22,8 +25,10 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
void setFallbackLanguage(const std::string &language);
|
void setFallbackLanguage(const std::string &language);
|
||||||
void resetLanguageStrings();
|
void resetLanguageStrings();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadLanguage(const std::string &language);
|
void loadLanguage(const std::string &language);
|
||||||
@@ -32,14 +37,18 @@ namespace hex {
|
|||||||
[[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages();
|
[[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages();
|
||||||
[[nodiscard]] const std::string &getFallbackLanguage();
|
[[nodiscard]] const std::string &getFallbackLanguage();
|
||||||
[[nodiscard]] const std::string &getSelectedLanguage();
|
[[nodiscard]] const std::string &getSelectedLanguage();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct UnlocalizedString;
|
struct UnlocalizedString;
|
||||||
|
|
||||||
|
class LangConst;
|
||||||
|
|
||||||
class Lang {
|
class Lang {
|
||||||
public:
|
public:
|
||||||
explicit Lang(const char *unlocalizedString);
|
explicit Lang(const char *unlocalizedString);
|
||||||
explicit Lang(const std::string &unlocalizedString);
|
explicit Lang(const std::string &unlocalizedString);
|
||||||
|
explicit(false) Lang(const LangConst &localizedString);
|
||||||
explicit Lang(const UnlocalizedString &unlocalizedString);
|
explicit Lang(const UnlocalizedString &unlocalizedString);
|
||||||
explicit Lang(std::string_view unlocalizedString);
|
explicit Lang(std::string_view unlocalizedString);
|
||||||
|
|
||||||
@@ -47,30 +56,54 @@ namespace hex {
|
|||||||
[[nodiscard]] operator std::string_view() const;
|
[[nodiscard]] operator std::string_view() const;
|
||||||
[[nodiscard]] operator const char *() const;
|
[[nodiscard]] operator const char *() const;
|
||||||
|
|
||||||
[[nodiscard]] const std::string &get() const;
|
const char* get() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::size_t m_entryHash;
|
||||||
std::string m_unlocalizedString;
|
std::string m_unlocalizedString;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] std::string operator+(const std::string &&left, const Lang &&right);
|
class LangConst {
|
||||||
[[nodiscard]] std::string operator+(const Lang &&left, const std::string &&right);
|
public:
|
||||||
[[nodiscard]] std::string operator+(const std::string_view &&left, const Lang &&right);
|
[[nodiscard]] operator std::string() const;
|
||||||
[[nodiscard]] std::string operator+(const Lang &&left, const std::string_view &&right);
|
[[nodiscard]] operator std::string_view() const;
|
||||||
[[nodiscard]] std::string operator+(const char *left, const Lang &&right);
|
[[nodiscard]] operator const char *() const;
|
||||||
[[nodiscard]] std::string operator+(const Lang &&left, const char *right);
|
|
||||||
[[nodiscard]] std::string operator+(const Lang &&left, const Lang &&right);
|
|
||||||
|
|
||||||
[[nodiscard]] inline Lang operator""_lang(const char *string, size_t) {
|
const char* get() const;
|
||||||
return Lang(string);
|
|
||||||
|
constexpr static size_t hash(std::string_view string) {
|
||||||
|
constexpr u64 p = 131;
|
||||||
|
constexpr u64 m = std::numeric_limits<std::uint32_t>::max() - 4;
|
||||||
|
u64 total = 0;
|
||||||
|
u64 currentMultiplier = 1;
|
||||||
|
|
||||||
|
for (char c : string) {
|
||||||
|
total = (total + currentMultiplier * c) % m;
|
||||||
|
currentMultiplier = (currentMultiplier * p) % m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr explicit LangConst(std::size_t hash, const char *unlocalizedString) : m_entryHash(hash), m_unlocalizedString(unlocalizedString) {}
|
||||||
|
|
||||||
|
template<wolv::type::StaticString>
|
||||||
|
friend consteval LangConst operator""_lang();
|
||||||
|
friend class Lang;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::size_t m_entryHash;
|
||||||
|
const char *m_unlocalizedString = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
struct UnlocalizedString {
|
struct UnlocalizedString {
|
||||||
public:
|
public:
|
||||||
UnlocalizedString() = default;
|
UnlocalizedString() = default;
|
||||||
UnlocalizedString(auto && arg) : m_unlocalizedString(std::forward<decltype(arg)>(arg)) {
|
|
||||||
static_assert(!std::same_as<std::remove_cvref_t<decltype(arg)>, Lang>, "Expected a unlocalized name, got a localized one!");
|
template<typename T>
|
||||||
|
UnlocalizedString(T &&arg) : m_unlocalizedString(std::forward<T>(arg)) {
|
||||||
|
static_assert(!std::same_as<std::remove_cvref_t<T>, Lang>, "Expected a unlocalized name, got a localized one!");
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] operator std::string() const {
|
[[nodiscard]] operator std::string() const {
|
||||||
@@ -102,12 +135,17 @@ namespace hex {
|
|||||||
std::string m_unlocalizedString;
|
std::string m_unlocalizedString;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
template<wolv::type::StaticString String>
|
||||||
|
[[nodiscard]] consteval LangConst operator""_lang() {
|
||||||
template<>
|
return LangConst(LangConst::hash(String.value.data()), String.value.data());
|
||||||
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 and hex::LangConst
|
||||||
|
inline auto format_as(const hex::Lang &entry) {
|
||||||
|
return entry.get();
|
||||||
|
}
|
||||||
|
inline auto format_as(const hex::LangConst &entry) {
|
||||||
|
return entry.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace hex {
|
|||||||
|
|
||||||
class View;
|
class View;
|
||||||
|
|
||||||
enum class Keys {
|
enum class Keys : u32 {
|
||||||
Space = GLFW_KEY_SPACE,
|
Space = GLFW_KEY_SPACE,
|
||||||
Apostrophe = GLFW_KEY_APOSTROPHE,
|
Apostrophe = GLFW_KEY_APOSTROPHE,
|
||||||
Comma = GLFW_KEY_COMMA,
|
Comma = GLFW_KEY_COMMA,
|
||||||
@@ -138,6 +138,7 @@ namespace hex {
|
|||||||
constexpr Key() = default;
|
constexpr Key() = default;
|
||||||
constexpr Key(Keys key) : m_key(static_cast<u32>(key)) { }
|
constexpr Key(Keys key) : m_key(static_cast<u32>(key)) { }
|
||||||
|
|
||||||
|
bool operator==(const Key &) const = default;
|
||||||
auto operator<=>(const Key &) const = default;
|
auto operator<=>(const Key &) const = default;
|
||||||
|
|
||||||
[[nodiscard]] constexpr u32 getKeyCode() const { return m_key; }
|
[[nodiscard]] constexpr u32 getKeyCode() const { return m_key; }
|
||||||
@@ -152,224 +153,31 @@ namespace hex {
|
|||||||
constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000));
|
constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000));
|
||||||
constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000));
|
constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000));
|
||||||
constexpr static auto AllowWhileTyping = Key(static_cast<Keys>(0x2000'0000));
|
constexpr static auto AllowWhileTyping = Key(static_cast<Keys>(0x2000'0000));
|
||||||
|
constexpr static auto CTRLCMD = Key(static_cast<Keys>(0x4000'0000));
|
||||||
#if defined (OS_MACOS)
|
|
||||||
constexpr static auto CTRLCMD = SUPER;
|
|
||||||
#else
|
|
||||||
constexpr static auto CTRLCMD = CTRL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class Shortcut {
|
class Shortcut {
|
||||||
public:
|
public:
|
||||||
Shortcut() = default;
|
Shortcut() = default;
|
||||||
Shortcut(Keys key) : m_keys({ key }) { }
|
Shortcut(Keys key);
|
||||||
explicit Shortcut(std::set<Key> keys) : m_keys(std::move(keys)) { }
|
explicit Shortcut(std::set<Key> keys);
|
||||||
Shortcut(const Shortcut &other) = default;
|
Shortcut(const Shortcut &other) = default;
|
||||||
Shortcut(Shortcut &&) noexcept = default;
|
Shortcut(Shortcut &&) noexcept = default;
|
||||||
|
|
||||||
Shortcut& operator=(const Shortcut &other) = default;
|
constexpr static auto None = Keys(0);
|
||||||
|
|
||||||
|
Shortcut& operator=(const Shortcut &other) = default;
|
||||||
Shortcut& operator=(Shortcut &&) noexcept = default;
|
Shortcut& operator=(Shortcut &&) noexcept = default;
|
||||||
|
|
||||||
constexpr static inline auto None = Keys(0);
|
Shortcut operator+(const Key &other) const;
|
||||||
|
Shortcut &operator+=(const Key &other);
|
||||||
|
bool operator<(const Shortcut &other) const;
|
||||||
|
bool operator==(const Shortcut &other) const;
|
||||||
|
|
||||||
Shortcut operator+(const Key &other) const {
|
bool isLocal() const;
|
||||||
Shortcut result = *this;
|
std::string toString() const;
|
||||||
result.m_keys.insert(other);
|
const std::set<Key>& getKeys() const;
|
||||||
|
bool has(Key key) const;
|
||||||
return result;
|
bool matches(const Shortcut &other) const;
|
||||||
}
|
|
||||||
|
|
||||||
Shortcut &operator+=(const Key &other) {
|
|
||||||
m_keys.insert(other);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const Shortcut &other) const {
|
|
||||||
return m_keys < other.m_keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Shortcut &other) const {
|
|
||||||
auto thisKeys = m_keys;
|
|
||||||
auto otherKeys = other.m_keys;
|
|
||||||
|
|
||||||
thisKeys.erase(CurrentView);
|
|
||||||
thisKeys.erase(AllowWhileTyping);
|
|
||||||
otherKeys.erase(CurrentView);
|
|
||||||
otherKeys.erase(AllowWhileTyping);
|
|
||||||
|
|
||||||
return thisKeys == otherKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLocal() const {
|
|
||||||
return m_keys.contains(CurrentView);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string toString() const {
|
|
||||||
std::string result;
|
|
||||||
|
|
||||||
#if defined(OS_MACOS)
|
|
||||||
constexpr static auto CTRL_NAME = "CTRL";
|
|
||||||
constexpr static auto ALT_NAME = "OPT";
|
|
||||||
constexpr static auto SHIFT_NAME = "SHIFT";
|
|
||||||
constexpr static auto SUPER_NAME = "CMD";
|
|
||||||
#else
|
|
||||||
constexpr static auto CTRL_NAME = "CTRL";
|
|
||||||
constexpr static auto ALT_NAME = "ALT";
|
|
||||||
constexpr static auto SHIFT_NAME = "SHIFT";
|
|
||||||
constexpr static auto SUPER_NAME = "SUPER";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
constexpr static auto Concatination = " + ";
|
|
||||||
|
|
||||||
auto keys = m_keys;
|
|
||||||
if (keys.erase(CTRL) > 0) {
|
|
||||||
result += CTRL_NAME;
|
|
||||||
result += Concatination;
|
|
||||||
}
|
|
||||||
if (keys.erase(ALT) > 0) {
|
|
||||||
result += ALT_NAME;
|
|
||||||
result += Concatination;
|
|
||||||
}
|
|
||||||
if (keys.erase(SHIFT) > 0) {
|
|
||||||
result += SHIFT_NAME;
|
|
||||||
result += Concatination;
|
|
||||||
}
|
|
||||||
if (keys.erase(SUPER) > 0) {
|
|
||||||
result += SUPER_NAME;
|
|
||||||
result += Concatination;
|
|
||||||
}
|
|
||||||
keys.erase(CurrentView);
|
|
||||||
|
|
||||||
for (const auto &key : keys) {
|
|
||||||
switch (Keys(key.getKeyCode())) {
|
|
||||||
case Keys::Space: result += "SPACE"; break;
|
|
||||||
case Keys::Apostrophe: result += "'"; break;
|
|
||||||
case Keys::Comma: result += ","; break;
|
|
||||||
case Keys::Minus: result += "-"; break;
|
|
||||||
case Keys::Period: result += "."; break;
|
|
||||||
case Keys::Slash: result += "/"; break;
|
|
||||||
case Keys::Num0: result += "0"; break;
|
|
||||||
case Keys::Num1: result += "1"; break;
|
|
||||||
case Keys::Num2: result += "2"; break;
|
|
||||||
case Keys::Num3: result += "3"; break;
|
|
||||||
case Keys::Num4: result += "4"; break;
|
|
||||||
case Keys::Num5: result += "5"; break;
|
|
||||||
case Keys::Num6: result += "6"; break;
|
|
||||||
case Keys::Num7: result += "7"; break;
|
|
||||||
case Keys::Num8: result += "8"; break;
|
|
||||||
case Keys::Num9: result += "9"; break;
|
|
||||||
case Keys::Semicolon: result += ";"; break;
|
|
||||||
case Keys::Equals: result += "="; break;
|
|
||||||
case Keys::A: result += "A"; break;
|
|
||||||
case Keys::B: result += "B"; break;
|
|
||||||
case Keys::C: result += "C"; break;
|
|
||||||
case Keys::D: result += "D"; break;
|
|
||||||
case Keys::E: result += "E"; break;
|
|
||||||
case Keys::F: result += "F"; break;
|
|
||||||
case Keys::G: result += "G"; break;
|
|
||||||
case Keys::H: result += "H"; break;
|
|
||||||
case Keys::I: result += "I"; break;
|
|
||||||
case Keys::J: result += "J"; break;
|
|
||||||
case Keys::K: result += "K"; break;
|
|
||||||
case Keys::L: result += "L"; break;
|
|
||||||
case Keys::M: result += "M"; break;
|
|
||||||
case Keys::N: result += "N"; break;
|
|
||||||
case Keys::O: result += "O"; break;
|
|
||||||
case Keys::P: result += "P"; break;
|
|
||||||
case Keys::Q: result += "Q"; break;
|
|
||||||
case Keys::R: result += "R"; break;
|
|
||||||
case Keys::S: result += "S"; break;
|
|
||||||
case Keys::T: result += "T"; break;
|
|
||||||
case Keys::U: result += "U"; break;
|
|
||||||
case Keys::V: result += "V"; break;
|
|
||||||
case Keys::W: result += "W"; break;
|
|
||||||
case Keys::X: result += "X"; break;
|
|
||||||
case Keys::Y: result += "Y"; break;
|
|
||||||
case Keys::Z: result += "Z"; break;
|
|
||||||
case Keys::LeftBracket: result += "["; break;
|
|
||||||
case Keys::Backslash: result += "\\"; break;
|
|
||||||
case Keys::RightBracket: result += "]"; break;
|
|
||||||
case Keys::GraveAccent: result += "`"; break;
|
|
||||||
case Keys::World1: result += "WORLD1"; break;
|
|
||||||
case Keys::World2: result += "WORLD2"; break;
|
|
||||||
case Keys::Escape: result += "ESC"; break;
|
|
||||||
case Keys::Enter: result += "ENTER"; break;
|
|
||||||
case Keys::Tab: result += "TAB"; break;
|
|
||||||
case Keys::Backspace: result += "BACKSPACE"; break;
|
|
||||||
case Keys::Insert: result += "INSERT"; break;
|
|
||||||
case Keys::Delete: result += "DELETE"; break;
|
|
||||||
case Keys::Right: result += "RIGHT"; break;
|
|
||||||
case Keys::Left: result += "LEFT"; break;
|
|
||||||
case Keys::Down: result += "DOWN"; break;
|
|
||||||
case Keys::Up: result += "UP"; break;
|
|
||||||
case Keys::PageUp: result += "PAGEUP"; break;
|
|
||||||
case Keys::PageDown: result += "PAGEDOWN"; break;
|
|
||||||
case Keys::Home: result += "HOME"; break;
|
|
||||||
case Keys::End: result += "END"; break;
|
|
||||||
case Keys::CapsLock: result += "CAPSLOCK"; break;
|
|
||||||
case Keys::ScrollLock: result += "SCROLLLOCK"; break;
|
|
||||||
case Keys::NumLock: result += "NUMLOCK"; break;
|
|
||||||
case Keys::PrintScreen: result += "PRINTSCREEN"; break;
|
|
||||||
case Keys::Pause: result += "PAUSE"; break;
|
|
||||||
case Keys::F1: result += "F1"; break;
|
|
||||||
case Keys::F2: result += "F2"; break;
|
|
||||||
case Keys::F3: result += "F3"; break;
|
|
||||||
case Keys::F4: result += "F4"; break;
|
|
||||||
case Keys::F5: result += "F5"; break;
|
|
||||||
case Keys::F6: result += "F6"; break;
|
|
||||||
case Keys::F7: result += "F7"; break;
|
|
||||||
case Keys::F8: result += "F8"; break;
|
|
||||||
case Keys::F9: result += "F9"; break;
|
|
||||||
case Keys::F10: result += "F10"; break;
|
|
||||||
case Keys::F11: result += "F11"; break;
|
|
||||||
case Keys::F12: result += "F12"; break;
|
|
||||||
case Keys::F13: result += "F13"; break;
|
|
||||||
case Keys::F14: result += "F14"; break;
|
|
||||||
case Keys::F15: result += "F15"; break;
|
|
||||||
case Keys::F16: result += "F16"; break;
|
|
||||||
case Keys::F17: result += "F17"; break;
|
|
||||||
case Keys::F18: result += "F18"; break;
|
|
||||||
case Keys::F19: result += "F19"; break;
|
|
||||||
case Keys::F20: result += "F20"; break;
|
|
||||||
case Keys::F21: result += "F21"; break;
|
|
||||||
case Keys::F22: result += "F22"; break;
|
|
||||||
case Keys::F23: result += "F23"; break;
|
|
||||||
case Keys::F24: result += "F24"; break;
|
|
||||||
case Keys::F25: result += "F25"; break;
|
|
||||||
case Keys::KeyPad0: result += "KP0"; break;
|
|
||||||
case Keys::KeyPad1: result += "KP1"; break;
|
|
||||||
case Keys::KeyPad2: result += "KP2"; break;
|
|
||||||
case Keys::KeyPad3: result += "KP3"; break;
|
|
||||||
case Keys::KeyPad4: result += "KP4"; break;
|
|
||||||
case Keys::KeyPad5: result += "KP5"; break;
|
|
||||||
case Keys::KeyPad6: result += "KP6"; break;
|
|
||||||
case Keys::KeyPad7: result += "KP7"; break;
|
|
||||||
case Keys::KeyPad8: result += "KP8"; break;
|
|
||||||
case Keys::KeyPad9: result += "KP9"; break;
|
|
||||||
case Keys::KeyPadDecimal: result += "KPDECIMAL"; break;
|
|
||||||
case Keys::KeyPadDivide: result += "KPDIVIDE"; break;
|
|
||||||
case Keys::KeyPadMultiply: result += "KPMULTIPLY"; break;
|
|
||||||
case Keys::KeyPadSubtract: result += "KPSUBTRACT"; break;
|
|
||||||
case Keys::KeyPadAdd: result += "KPADD"; break;
|
|
||||||
case Keys::KeyPadEnter: result += "KPENTER"; break;
|
|
||||||
case Keys::KeyPadEqual: result += "KPEQUAL"; break;
|
|
||||||
case Keys::Menu: result += "MENU"; break;
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result += " + ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.ends_with(" + "))
|
|
||||||
result = result.substr(0, result.size() - 3);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::set<Key>& getKeys() const { return m_keys; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
||||||
@@ -377,12 +185,7 @@ namespace hex {
|
|||||||
std::set<Key> m_keys;
|
std::set<Key> m_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Shortcut operator+(const Key &lhs, const Key &rhs) {
|
Shortcut operator+(const Key &lhs, const Key &rhs);
|
||||||
Shortcut result;
|
|
||||||
result.m_keys = { lhs, rhs };
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The ShortcutManager handles global and view-specific shortcuts.
|
* @brief The ShortcutManager handles global and view-specific shortcuts.
|
||||||
@@ -393,7 +196,7 @@ namespace hex {
|
|||||||
using Callback = std::function<void()>;
|
using Callback = std::function<void()>;
|
||||||
struct ShortcutEntry {
|
struct ShortcutEntry {
|
||||||
Shortcut shortcut;
|
Shortcut shortcut;
|
||||||
UnlocalizedString unlocalizedName;
|
std::vector<UnlocalizedString> unlocalizedName;
|
||||||
Callback callback;
|
Callback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -403,6 +206,7 @@ namespace hex {
|
|||||||
* @param unlocalizedName The unlocalized name of the shortcut
|
* @param unlocalizedName The unlocalized name of the shortcut
|
||||||
* @param callback The callback to call when the shortcut is triggered.
|
* @param callback The callback to call when the shortcut is triggered.
|
||||||
*/
|
*/
|
||||||
|
static void addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
|
||||||
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
|
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,6 +216,7 @@ namespace hex {
|
|||||||
* @param unlocalizedName The unlocalized name of the shortcut
|
* @param unlocalizedName The unlocalized name of the shortcut
|
||||||
* @param callback The callback to call when the shortcut is triggered.
|
* @param callback The callback to call when the shortcut is triggered.
|
||||||
*/
|
*/
|
||||||
|
static void addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
|
||||||
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
|
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
|
||||||
|
|
||||||
|
|
||||||
@@ -445,12 +250,14 @@ namespace hex {
|
|||||||
static void resumeShortcuts();
|
static void resumeShortcuts();
|
||||||
static void pauseShortcuts();
|
static void pauseShortcuts();
|
||||||
|
|
||||||
|
static void enableMacOSMode();
|
||||||
|
|
||||||
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
|
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
|
||||||
|
|
||||||
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
|
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
|
||||||
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(const View *view);
|
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(const View *view);
|
||||||
|
|
||||||
[[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view = nullptr);
|
[[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, Shortcut newShortcut, View *view = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ namespace hex {
|
|||||||
class Task {
|
class Task {
|
||||||
public:
|
public:
|
||||||
Task() = default;
|
Task() = default;
|
||||||
Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||||
|
|
||||||
Task(const Task&) = delete;
|
Task(const Task&) = delete;
|
||||||
Task(Task &&other) noexcept;
|
Task(Task &&other) noexcept;
|
||||||
@@ -130,20 +130,37 @@ namespace hex {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
|
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
|
||||||
* @param name Name of the task
|
* @param unlocalizedName Name of the task
|
||||||
* @param maxValue Maximum value of the task
|
* @param maxValue Maximum value of the task
|
||||||
* @param function Function to be executed
|
* @param function Function to be executed
|
||||||
* @return A TaskHolder holding a weak reference to the task
|
* @return A TaskHolder holding a weak reference to the task
|
||||||
*/
|
*/
|
||||||
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager
|
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
|
||||||
* @param name Name of the task
|
* @param unlocalizedName Name of the task
|
||||||
|
* @param maxValue Maximum value of the task
|
||||||
* @param function Function to be executed
|
* @param function Function to be executed
|
||||||
* @return A TaskHolder holding a weak reference to the task
|
* @return A TaskHolder holding a weak reference to the task
|
||||||
*/
|
*/
|
||||||
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager
|
||||||
|
* @param unlocalizedName Name of the task
|
||||||
|
* @param function Function to be executed
|
||||||
|
* @return A TaskHolder holding a weak reference to the task
|
||||||
|
*/
|
||||||
|
static TaskHolder createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void(Task &)> function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager
|
||||||
|
* @param unlocalizedName Name of the task
|
||||||
|
* @param function Function to be executed
|
||||||
|
* @return A TaskHolder holding a weak reference to the task
|
||||||
|
*/
|
||||||
|
static TaskHolder createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void()> function);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
|
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
|
||||||
@@ -190,7 +207,7 @@ namespace hex {
|
|||||||
static void runDeferredCalls();
|
static void runDeferredCalls();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static TaskHolder createTask(std::string name, u64 maxValue, bool background, std::function<void(Task &)> function);
|
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,7 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
static void addStyleHandler(const std::string &name, const StyleMap &styleMap);
|
static void addStyleHandler(const std::string &name, const StyleMap &styleMap);
|
||||||
|
|
||||||
|
static void reapplyCurrentTheme();
|
||||||
|
|
||||||
static std::vector<std::string> getThemeNames();
|
static std::vector<std::string> getThemeNames();
|
||||||
static const std::string &getImageTheme();
|
static const std::string &getImageTheme();
|
||||||
|
|||||||
@@ -119,6 +119,8 @@ namespace hex {
|
|||||||
decltype(m_steps)::iterator m_currentStep, m_latestStep;
|
decltype(m_steps)::iterator m_currentStep, m_latestStep;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void init();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets a list of all tutorials
|
* @brief Gets a list of all tutorials
|
||||||
* @return List of all tutorials
|
* @return List of all tutorials
|
||||||
@@ -145,6 +147,10 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
static void startTutorial(const UnlocalizedString &unlocalizedName);
|
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
|
* @brief Draws the tutorial
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
#include <hex/api/localization_manager.hpp>
|
#include <hex/api/localization_manager.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/intrinsics.hpp>
|
|
||||||
#include <hex/data_processor/attribute.hpp>
|
#include <hex/data_processor/attribute.hpp>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
@@ -12,6 +11,7 @@
|
|||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
#include <hex/providers/provider_data.hpp>
|
||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
class Provider;
|
class Provider;
|
||||||
@@ -42,11 +42,12 @@ namespace hex::dp {
|
|||||||
m_overlay = overlay;
|
m_overlay = overlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void drawNode() { }
|
void draw();
|
||||||
virtual void process() = 0;
|
virtual void process() = 0;
|
||||||
|
virtual void reset() { }
|
||||||
|
|
||||||
virtual void store(nlohmann::json &j) const { hex::unused(j); }
|
virtual void store(nlohmann::json &j) const { std::ignore = j; }
|
||||||
virtual void load(const nlohmann::json &j) { hex::unused(j); }
|
virtual void load(const nlohmann::json &j) { std::ignore = j; }
|
||||||
|
|
||||||
struct NodeError {
|
struct NodeError {
|
||||||
Node *node;
|
Node *node;
|
||||||
@@ -80,6 +81,11 @@ namespace hex::dp {
|
|||||||
void setIntegerOnOutput(u32 index, i128 integer);
|
void setIntegerOnOutput(u32 index, i128 integer);
|
||||||
void setFloatOnOutput(u32 index, double floatingPoint);
|
void setFloatOnOutput(u32 index, double floatingPoint);
|
||||||
|
|
||||||
|
static void interrupt();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void drawNode() { }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_id;
|
int m_id;
|
||||||
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName;
|
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName;
|
||||||
@@ -90,45 +96,16 @@ namespace hex::dp {
|
|||||||
|
|
||||||
static int s_idCounter;
|
static int s_idCounter;
|
||||||
|
|
||||||
Attribute& getAttribute(u32 index) {
|
Attribute& getAttribute(u32 index);
|
||||||
if (index >= this->getAttributes().size())
|
Attribute *getConnectedInputAttribute(u32 index);
|
||||||
throw std::runtime_error("Attribute index out of bounds!");
|
void markInputProcessed(u32 index);
|
||||||
|
void unmarkInputProcessed(u32 index);
|
||||||
return this->getAttributes()[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
Attribute *getConnectedInputAttribute(u32 index) {
|
|
||||||
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
|
|
||||||
|
|
||||||
if (connectedAttribute.empty())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return connectedAttribute.begin()->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
void markInputProcessed(u32 index) {
|
|
||||||
const auto &[iter, inserted] = m_processedInputs.insert(index);
|
|
||||||
if (!inserted)
|
|
||||||
throwNodeError("Recursion detected!");
|
|
||||||
}
|
|
||||||
|
|
||||||
void unmarkInputProcessed(u32 index) {
|
|
||||||
m_processedInputs.erase(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
[[noreturn]] void throwNodeError(const std::string &message) {
|
[[noreturn]] void throwNodeError(const std::string &message);
|
||||||
throw NodeError { this, message };
|
|
||||||
}
|
|
||||||
|
|
||||||
void setOverlayData(u64 address, const std::vector<u8> &data);
|
void setOverlayData(u64 address, const std::vector<u8> &data);
|
||||||
|
void setAttributes(std::vector<Attribute> attributes);
|
||||||
void setAttributes(std::vector<Attribute> attributes) {
|
|
||||||
m_attributes = std::move(attributes);
|
|
||||||
|
|
||||||
for (auto &attr : m_attributes)
|
|
||||||
attr.setParentNode(this);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -50,14 +50,23 @@ namespace hex {
|
|||||||
|
|
||||||
T& operator=(const T &value) {
|
T& operator=(const T &value) {
|
||||||
m_value = value;
|
m_value = value;
|
||||||
|
m_valid = true;
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
T& operator=(T &&value) noexcept {
|
T& operator=(T &&value) noexcept {
|
||||||
m_value = std::move(value);
|
m_value = std::move(value);
|
||||||
|
m_valid = true;
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValid() const {
|
||||||
|
return m_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend void ImHexApi::System::impl::cleanup();
|
||||||
|
|
||||||
void reset() override {
|
void reset() override {
|
||||||
if constexpr (requires { m_value.reset(); }) {
|
if constexpr (requires { m_value.reset(); }) {
|
||||||
m_value.reset();
|
m_value.reset();
|
||||||
@@ -68,9 +77,12 @@ namespace hex {
|
|||||||
} else {
|
} else {
|
||||||
m_value = { };
|
m_value = { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_valid = true;
|
||||||
T m_value;
|
T m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,15 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
|
|
||||||
|
#include <wolv/utils/expected.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#define CRYPTO_ERROR_INVALID_KEY_LENGTH (-1)
|
||||||
|
#define CRYPTO_ERROR_INVALID_MODE (-2)
|
||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
class Provider;
|
class Provider;
|
||||||
}
|
}
|
||||||
@@ -60,5 +65,5 @@ namespace hex::crypt {
|
|||||||
Key256Bits = 2
|
Key256Bits = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<u8> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input);
|
wolv::util::Expected<std::vector<u8>, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input);
|
||||||
}
|
}
|
||||||
|
|||||||
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <fmt/format.h>
|
#include <fmt/core.h>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <hex.hpp>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@@ -31,36 +29,7 @@ namespace hex::fs {
|
|||||||
void openFolderExternal(const std::fs::path &dirPath);
|
void openFolderExternal(const std::fs::path &dirPath);
|
||||||
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath);
|
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);
|
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);
|
|
||||||
}
|
}
|
||||||
@@ -25,13 +25,16 @@
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
|
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
|
||||||
hex::unused(path, mimeName);
|
std::ignore = path;
|
||||||
|
std::ignore = mimeName;
|
||||||
throw std::logic_error("Not implemented");
|
throw std::logic_error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
|
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);
|
std::ignore = data;
|
||||||
|
std::ignore = mimeName;
|
||||||
|
std::ignore = fileName;
|
||||||
throw std::logic_error("Not implemented");
|
throw std::logic_error("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
void unused(auto && ... x) {
|
|
||||||
((void)x, ...);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,13 +2,11 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
#include <fmt/color.h>
|
#include <fmt/color.h>
|
||||||
|
|
||||||
#include <wolv/io/file.hpp>
|
#include <wolv/io/file.hpp>
|
||||||
#include <hex/helpers/fmt.hpp>
|
#include <wolv/utils/guards.hpp>
|
||||||
|
|
||||||
namespace hex::log {
|
namespace hex::log {
|
||||||
|
|
||||||
@@ -20,10 +18,12 @@ namespace hex::log {
|
|||||||
[[maybe_unused]] void redirectToFile();
|
[[maybe_unused]] void redirectToFile();
|
||||||
[[maybe_unused]] void enableColorPrinting();
|
[[maybe_unused]] void enableColorPrinting();
|
||||||
|
|
||||||
[[nodiscard]] std::recursive_mutex& getLoggerMutex();
|
|
||||||
[[nodiscard]] bool isLoggingSuspended();
|
[[nodiscard]] bool isLoggingSuspended();
|
||||||
[[nodiscard]] bool isDebugLoggingEnabled();
|
[[nodiscard]] bool isDebugLoggingEnabled();
|
||||||
|
|
||||||
|
void lockLoggerMutex();
|
||||||
|
void unlockLoggerMutex();
|
||||||
|
|
||||||
struct LogEntry {
|
struct LogEntry {
|
||||||
std::string project;
|
std::string project;
|
||||||
std::string level;
|
std::string level;
|
||||||
@@ -39,7 +39,8 @@ namespace hex::log {
|
|||||||
if (isLoggingSuspended()) [[unlikely]]
|
if (isLoggingSuspended()) [[unlikely]]
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::scoped_lock lock(getLoggerMutex());
|
lockLoggerMutex();
|
||||||
|
ON_SCOPE_EXIT { unlockLoggerMutex(); };
|
||||||
|
|
||||||
auto dest = getDestination();
|
auto dest = getDestination();
|
||||||
try {
|
try {
|
||||||
@@ -94,7 +95,8 @@ namespace hex::log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
|
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
|
||||||
std::scoped_lock lock(impl::getLoggerMutex());
|
impl::lockLoggerMutex();
|
||||||
|
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto dest = impl::getDestination();
|
auto dest = impl::getDestination();
|
||||||
@@ -105,7 +107,8 @@ namespace hex::log {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
|
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
|
||||||
std::scoped_lock lock(impl::getLoggerMutex());
|
impl::lockLoggerMutex();
|
||||||
|
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto dest = impl::getDestination();
|
auto dest = impl::getDestination();
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ namespace hex {
|
|||||||
MissingEOF
|
MissingEOF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PatchKind {
|
||||||
|
IPS,
|
||||||
|
IPS32
|
||||||
|
};
|
||||||
|
|
||||||
class Patches {
|
class Patches {
|
||||||
public:
|
public:
|
||||||
Patches() = default;
|
Patches() = default;
|
||||||
|
|||||||
36
lib/libimhex/include/hex/helpers/semantic_version.hpp
Normal file
36
lib/libimhex/include/hex/helpers/semantic_version.hpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex.hpp>
|
||||||
|
|
||||||
|
#include <compare>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
class SemanticVersion {
|
||||||
|
public:
|
||||||
|
SemanticVersion() = default;
|
||||||
|
SemanticVersion(std::string version);
|
||||||
|
SemanticVersion(std::string_view version);
|
||||||
|
SemanticVersion(const char *version);
|
||||||
|
|
||||||
|
std::strong_ordering operator<=>(const SemanticVersion &) const;
|
||||||
|
bool operator==(const SemanticVersion &other) const;
|
||||||
|
|
||||||
|
u32 major() const;
|
||||||
|
u32 minor() const;
|
||||||
|
u32 patch() const;
|
||||||
|
bool nightly() const;
|
||||||
|
const std::string& buildType() const;
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
|
||||||
|
std::string get(bool withBuildType = true) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> m_parts;
|
||||||
|
std::string m_buildType;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -29,7 +29,7 @@ namespace hex {
|
|||||||
void close();
|
void close();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get the error string explaining the error that occured when opening the file.
|
* @brief get the error string explaining the error that occurred when opening the file.
|
||||||
* This error is a combination of the tar error and the native file open error
|
* This error is a combination of the tar error and the native file open error
|
||||||
*/
|
*/
|
||||||
std::string getOpenErrorString() const;
|
std::string getOpenErrorString() const;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
using u8 = std::uint8_t;
|
using u8 = std::uint8_t;
|
||||||
using u16 = std::uint16_t;
|
using u16 = std::uint16_t;
|
||||||
@@ -61,6 +62,10 @@ namespace hex {
|
|||||||
constexpr static Region Invalid() {
|
constexpr static Region Invalid() {
|
||||||
return { 0, 0 };
|
return { 0, 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr bool operator<(const Region &other) const {
|
||||||
|
return this->address < other.address;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,29 @@ namespace hex {
|
|||||||
class Provider;
|
class Provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
[[nodiscard]] std::vector<std::vector<T>> sampleChannels(const std::vector<T> &data, size_t count, size_t channels) {
|
||||||
|
if (channels == 0) return {};
|
||||||
|
size_t signalLength = std::max(1.0, double(data.size()) / channels);
|
||||||
|
|
||||||
|
size_t stride = std::max(1.0, double(signalLength) / count);
|
||||||
|
|
||||||
|
std::vector<std::vector<T>> result;
|
||||||
|
result.resize(channels);
|
||||||
|
for (size_t i = 0; i < channels; i++) {
|
||||||
|
result[i].reserve(count);
|
||||||
|
}
|
||||||
|
result.reserve(count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data.size(); i += stride) {
|
||||||
|
for (size_t j = 0; j < channels; j++) {
|
||||||
|
result[j].push_back(data[i + j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] std::vector<T> sampleData(const std::vector<T> &data, size_t count) {
|
[[nodiscard]] std::vector<T> sampleData(const std::vector<T> &data, size_t count) {
|
||||||
size_t stride = std::max(1.0, double(data.size()) / count);
|
size_t stride = std::max(1.0, double(data.size()) / count);
|
||||||
@@ -152,7 +175,7 @@ namespace hex {
|
|||||||
using SizeType = typename SizeTypeImpl<Size>::Type;
|
using SizeType = typename SizeTypeImpl<Size>::Type;
|
||||||
|
|
||||||
template<typename T>
|
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)
|
if (endian == std::endian::native)
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
@@ -172,8 +195,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
[[nodiscard]] constexpr T changeEndianess(const T &value, std::endian endian) {
|
[[nodiscard]] constexpr T changeEndianness(const T &value, std::endian endian) {
|
||||||
return changeEndianess(value, sizeof(value), endian);
|
return changeEndianness(value, sizeof(value), endian);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr u128 bitmask(u8 bits) {
|
[[nodiscard]] constexpr u128 bitmask(u8 bits) {
|
||||||
@@ -262,13 +285,13 @@ namespace hex {
|
|||||||
|
|
||||||
[[nodiscard]] float float16ToFloat32(u16 float16);
|
[[nodiscard]] float float16ToFloat32(u16 float16);
|
||||||
|
|
||||||
[[nodiscard]] inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
|
[[nodiscard]] inline bool equalsIgnoreCase(std::string_view left, std::string_view right) {
|
||||||
return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) {
|
return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) {
|
||||||
return tolower(a) == tolower(b);
|
return tolower(a) == tolower(b);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline bool containsIgnoreCase(const std::string &a, const std::string &b) {
|
[[nodiscard]] inline bool containsIgnoreCase(std::string_view a, std::string_view b) {
|
||||||
auto iter = std::search(a.begin(), a.end(), b.begin(), b.end(), [](char ch1, char ch2) {
|
auto iter = std::search(a.begin(), a.end(), b.begin(), b.end(), [](char ch1, char ch2) {
|
||||||
return std::toupper(ch1) == std::toupper(ch2);
|
return std::toupper(ch1) == std::toupper(ch2);
|
||||||
});
|
});
|
||||||
@@ -298,31 +321,7 @@ namespace hex {
|
|||||||
|
|
||||||
[[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
[[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||||
|
|
||||||
[[nodiscard]] inline std::string limitStringLength(const std::string &string, size_t maxLength) {
|
[[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;
|
|
||||||
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::optional<std::fs::path> getInitialFilePath();
|
[[nodiscard]] std::optional<std::fs::path> getInitialFilePath();
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode);
|
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode);
|
||||||
|
|
||||||
void enumerateFontsMacos();
|
void enumerateFontsMacos();
|
||||||
|
|
||||||
|
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window);
|
||||||
|
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
|
||||||
|
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -37,21 +37,40 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static auto& getFeaturesImpl() {
|
||||||
|
static std::vector<hex::Feature> features;
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined (IMHEX_STATIC_LINK_PLUGINS)
|
#if defined (IMHEX_STATIC_LINK_PLUGINS)
|
||||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static
|
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static
|
||||||
#else
|
#else
|
||||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
|
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
|
||||||
#endif
|
#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.
|
* 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_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
||||||
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
|
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
|
||||||
|
|
||||||
#define IMHEX_LIBRARY_SETUP_IMPL(name) \
|
#define IMHEX_LIBRARY_SETUP_IMPL(name) \
|
||||||
namespace { static struct EXIT_HANDLER { ~EXIT_HANDLER() { hex::log::debug("Unloaded library '{}'", name); } } HANDLER; } \
|
namespace { static struct EXIT_HANDLER { ~EXIT_HANDLER() { hex::log::info("Unloaded library '{}'", name); } } HANDLER; } \
|
||||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME)(); \
|
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME)(); \
|
||||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *WOLV_TOKEN_CONCAT(getLibraryName_, IMHEX_PLUGIN_NAME)() { return name; } \
|
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *WOLV_TOKEN_CONCAT(getLibraryName_, IMHEX_PLUGIN_NAME)() { return name; } \
|
||||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(setImGuiContext_, IMHEX_PLUGIN_NAME)(ImGuiContext *ctx) { \
|
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(setImGuiContext_, IMHEX_PLUGIN_NAME)(ImGuiContext *ctx) { \
|
||||||
@@ -85,6 +104,7 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
|||||||
ImGui::SetCurrentContext(ctx); \
|
ImGui::SetCurrentContext(ctx); \
|
||||||
GImGui = ctx; \
|
GImGui = ctx; \
|
||||||
} \
|
} \
|
||||||
|
IMHEX_DEFINE_PLUGIN_FEATURES(); \
|
||||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
|
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
|
||||||
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
|
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
|
||||||
} \
|
} \
|
||||||
@@ -129,16 +149,3 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
|||||||
return &g_subCommands; \
|
return &g_subCommands; \
|
||||||
} \
|
} \
|
||||||
std::vector<hex::SubCommand> 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
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ namespace hex::prv {
|
|||||||
* @brief Gets the type name of this provider
|
* @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
|
* @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
|
* 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
|
* @return The provider's type name
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual std::string getTypeName() const = 0;
|
[[nodiscard]] virtual std::string getTypeName() const = 0;
|
||||||
@@ -165,7 +165,7 @@ namespace hex::prv {
|
|||||||
void insert(u64 offset, u64 size);
|
void insert(u64 offset, u64 size);
|
||||||
void remove(u64 offset, u64 size);
|
void remove(u64 offset, u64 size);
|
||||||
|
|
||||||
virtual void resizeRaw(u64 newSize) { hex::unused(newSize); }
|
virtual void resizeRaw(u64 newSize) { std::ignore = newSize; }
|
||||||
virtual void insertRaw(u64 offset, u64 size);
|
virtual void insertRaw(u64 offset, u64 size);
|
||||||
virtual void removeRaw(u64 offset, u64 size);
|
virtual void removeRaw(u64 offset, u64 size);
|
||||||
|
|
||||||
@@ -258,7 +258,7 @@ namespace hex::prv {
|
|||||||
*/
|
*/
|
||||||
bool m_skipLoadInterface = false;
|
bool m_skipLoadInterface = false;
|
||||||
|
|
||||||
std::string m_errorMessage;
|
std::string m_errorMessage = "Unspecified error";
|
||||||
|
|
||||||
u64 m_pageSize = MaxPageSize;
|
u64 m_pageSize = MaxPageSize;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -78,6 +78,10 @@ namespace hex {
|
|||||||
m_onCreateCallback = std::move(callback);
|
m_onCreateCallback = std::move(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setOnDestroyCallback(std::function<void(prv::Provider *, T&)> callback) {
|
||||||
|
m_onDestroyCallback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onCreate() {
|
void onCreate() {
|
||||||
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) {
|
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) {
|
||||||
@@ -88,7 +92,12 @@ namespace hex {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EventProviderDeleted::subscribe(this, [this](prv::Provider *provider){
|
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] {
|
EventImHexClosing::subscribe(this, [this] {
|
||||||
@@ -113,6 +122,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onDestroy() {
|
void onDestroy() {
|
||||||
|
|
||||||
EventProviderOpened::unsubscribe(this);
|
EventProviderOpened::unsubscribe(this);
|
||||||
EventProviderDeleted::unsubscribe(this);
|
EventProviderDeleted::unsubscribe(this);
|
||||||
EventImHexClosing::unsubscribe(this);
|
EventImHexClosing::unsubscribe(this);
|
||||||
@@ -121,7 +131,7 @@ namespace hex {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<const prv::Provider *, T> m_data;
|
std::map<const prv::Provider *, T> m_data;
|
||||||
std::function<void(prv::Provider *, T&)> m_onCreateCallback;
|
std::function<void(prv::Provider *, T&)> m_onCreateCallback, m_onDestroyCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -76,46 +76,51 @@ namespace ImGuiExt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Texture() = default;
|
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(const Texture&) = delete;
|
||||||
Texture(Texture&& other) noexcept;
|
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();
|
||||||
|
|
||||||
Texture& operator=(const Texture&) = delete;
|
Texture& operator=(const Texture&) = delete;
|
||||||
Texture& operator=(Texture&& other) noexcept;
|
Texture& operator=(Texture&& other) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||||
return m_textureId != nullptr;
|
return m_textureId != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] operator ImTextureID() const noexcept {
|
[[nodiscard]] operator ImTextureID() const noexcept {
|
||||||
return m_textureId;
|
return m_textureId;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] operator intptr_t() const noexcept {
|
[[nodiscard]] ImVec2 getSize() const noexcept {
|
||||||
return reinterpret_cast<intptr_t>(m_textureId);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto getSize() const noexcept {
|
|
||||||
return ImVec2(m_width, m_height);
|
return ImVec2(m_width, m_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr auto getAspectRatio() const noexcept {
|
[[nodiscard]] constexpr float getAspectRatio() const noexcept {
|
||||||
if (m_height == 0) return 1.0F;
|
if (m_height == 0) return 1.0F;
|
||||||
|
|
||||||
return float(m_width) / float(m_height);
|
return float(m_width) / float(m_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ImTextureID m_textureId = nullptr;
|
ImTextureID m_textureId = 0;
|
||||||
int m_width = 0, m_height = 0;
|
int m_width = 0, m_height = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float GetTextWrapPos();
|
||||||
|
|
||||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
|
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
|
||||||
|
|
||||||
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||||
@@ -124,10 +129,12 @@ namespace ImGuiExt {
|
|||||||
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||||
bool DescriptionButtonProgress(const char *label, const char *description, float fraction, 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));
|
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
||||||
|
|
||||||
|
void UnderwavedText(const char *label, ImColor textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text), ImColor lineColor = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
||||||
|
|
||||||
void TextSpinner(const char *label);
|
void TextSpinner(const char *label);
|
||||||
|
|
||||||
void Header(const char *label, bool firstEntry = false);
|
void Header(const char *label, bool firstEntry = false);
|
||||||
@@ -143,6 +150,8 @@ namespace ImGuiExt {
|
|||||||
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||||
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
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() {
|
inline bool HasSecondPassed() {
|
||||||
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
|
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
|
||||||
}
|
}
|
||||||
@@ -154,6 +163,7 @@ namespace ImGuiExt {
|
|||||||
|
|
||||||
struct Styles {
|
struct Styles {
|
||||||
float WindowBlur = 0.0F;
|
float WindowBlur = 0.0F;
|
||||||
|
float PopupWindowAlpha = 0.0F; // Alpha used by Popup tool windows when the user is not hovering over them
|
||||||
} styles;
|
} styles;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -175,11 +185,16 @@ namespace ImGuiExt {
|
|||||||
|
|
||||||
void SmallProgressBar(float fraction, float yOffset = 0.0F);
|
void SmallProgressBar(float fraction, float yOffset = 0.0F);
|
||||||
|
|
||||||
inline void TextFormatted(const std::string &fmt, auto &&...args) {
|
inline void TextFormatted(std::string_view fmt, auto &&...args) {
|
||||||
ImGui::TextUnformatted(hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
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)...);
|
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||||
|
|
||||||
ImGui::PushID(text.c_str());
|
ImGui::PushID(text.c_str());
|
||||||
@@ -187,8 +202,8 @@ namespace ImGuiExt {
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
||||||
|
|
||||||
ImGui::PushItemWidth(-FLT_MIN);
|
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);
|
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll);
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
@@ -197,19 +212,28 @@ namespace ImGuiExt {
|
|||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void TextFormattedColored(ImColor color, const std::string &fmt, auto &&...args) {
|
inline void TextFormattedColored(ImColor color, std::string_view fmt, auto &&...args) {
|
||||||
ImGui::TextColored(color, "%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
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) {
|
inline void TextFormattedDisabled(std::string_view fmt, auto &&...args) {
|
||||||
ImGui::TextDisabled("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
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) {
|
inline void TextFormattedWrapped(std::string_view fmt, auto &&...args) {
|
||||||
ImGui::TextWrapped("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
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.
|
// 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(
|
auto text = wolv::util::wrapMonospacedString(
|
||||||
hex::format(fmt, std::forward<decltype(args)>(args)...),
|
hex::format(fmt, std::forward<decltype(args)>(args)...),
|
||||||
@@ -222,7 +246,7 @@ namespace ImGuiExt {
|
|||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
||||||
|
|
||||||
ImGui::PushItemWidth(-FLT_MIN);
|
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
|
||||||
ImGui::InputTextMultiline(
|
ImGui::InputTextMultiline(
|
||||||
"##",
|
"##",
|
||||||
const_cast<char *>(text.c_str()),
|
const_cast<char *>(text.c_str()),
|
||||||
@@ -239,13 +263,13 @@ namespace ImGuiExt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextUnformattedCentered(const char *text);
|
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)...);
|
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||||
TextUnformattedCentered(text.c_str());
|
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 text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||||
auto availableSpace = ImGui::GetContentRegionAvail();
|
auto availableSpace = ImGui::GetContentRegionAvail();
|
||||||
auto textSize = ImGui::CalcTextSize(text.c_str(), nullptr, false, availableSpace.x * 0.75F);
|
auto textSize = ImGui::CalcTextSize(text.c_str(), nullptr, false, availableSpace.x * 0.75F);
|
||||||
@@ -258,6 +282,7 @@ namespace ImGuiExt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||||
|
bool InputTextIconHint(const char* label, const char *icon, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||||
|
|
||||||
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
|
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
|
||||||
|
|
||||||
@@ -271,12 +296,12 @@ namespace ImGuiExt {
|
|||||||
bool DimmedIconToggle(const char *icon, bool *v);
|
bool DimmedIconToggle(const char *icon, bool *v);
|
||||||
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v);
|
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v);
|
||||||
|
|
||||||
void TextOverlay(const char *text, ImVec2 pos);
|
void TextOverlay(const char *text, ImVec2 pos, float maxWidth = -1);
|
||||||
|
|
||||||
bool BeginBox();
|
bool BeginBox();
|
||||||
void EndBox();
|
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 EndSubWindow();
|
||||||
|
|
||||||
void ConfirmButtons(const char *textLeft, const char *textRight, const auto &leftButtonCallback, const auto &rightButtonCallback) {
|
void ConfirmButtons(const char *textLeft, const char *textRight, const auto &leftButtonCallback, const auto &rightButtonCallback) {
|
||||||
@@ -297,6 +322,9 @@ namespace ImGuiExt {
|
|||||||
bool ToggleSwitch(const char *label, bool *v);
|
bool ToggleSwitch(const char *label, bool *v);
|
||||||
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>
|
template<typename T>
|
||||||
constexpr ImGuiDataType getImGuiDataType() {
|
constexpr ImGuiDataType getImGuiDataType() {
|
||||||
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;
|
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ namespace hex {
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
|
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual bool shouldStoreWindowState() const { return true; }
|
||||||
|
|
||||||
[[nodiscard]] const char *getIcon() const { return m_icon; }
|
[[nodiscard]] const char *getIcon() const { return m_icon; }
|
||||||
|
|
||||||
[[nodiscard]] bool &getWindowOpenState();
|
[[nodiscard]] bool &getWindowOpenState();
|
||||||
@@ -156,6 +158,7 @@ namespace hex {
|
|||||||
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {}
|
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {}
|
||||||
|
|
||||||
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
|
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
|
||||||
|
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,12 +181,13 @@ namespace hex {
|
|||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
|
||||||
this->getWindowOpenState() = false;
|
this->getWindowOpenState() = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool hasCloseButton() const { return true; }
|
[[nodiscard]] virtual bool hasCloseButton() const { return true; }
|
||||||
|
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,14 @@
|
|||||||
#include <hex/api/event_manager.hpp>
|
#include <hex/api/event_manager.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/auto_reset.hpp>
|
#include <hex/helpers/auto_reset.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#if defined(OS_WEB)
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
static AutoReset<std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>> s_achievements;
|
static AutoReset<std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>> s_achievements;
|
||||||
@@ -195,9 +200,12 @@ namespace hex {
|
|||||||
|
|
||||||
|
|
||||||
constexpr static auto AchievementsFile = "achievements.json";
|
constexpr static auto AchievementsFile = "achievements.json";
|
||||||
|
bool AchievementManager::s_initialized = false;
|
||||||
|
|
||||||
void AchievementManager::loadProgress() {
|
void AchievementManager::loadProgress() {
|
||||||
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
if (s_initialized)
|
||||||
|
return;
|
||||||
|
for (const auto &directory : paths::Config.read()) {
|
||||||
auto path = directory / AchievementsFile;
|
auto path = directory / AchievementsFile;
|
||||||
|
|
||||||
if (!wolv::io::fs::exists(path)) {
|
if (!wolv::io::fs::exists(path)) {
|
||||||
@@ -211,7 +219,16 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto json = nlohmann::json::parse(file.readString());
|
#if defined(OS_WEB)
|
||||||
|
auto data = (char *) MAIN_THREAD_EM_ASM_INT({
|
||||||
|
let data = localStorage.getItem("achievements");
|
||||||
|
return data ? stringToNewUTF8(data) : null;
|
||||||
|
});
|
||||||
|
#else
|
||||||
|
auto data = file.readString();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto json = nlohmann::json::parse(data);
|
||||||
|
|
||||||
for (const auto &[categoryName, achievements] : getAchievements()) {
|
for (const auto &[categoryName, achievements] : getAchievements()) {
|
||||||
for (const auto &[achievementName, achievement] : achievements) {
|
for (const auto &[achievementName, achievement] : achievements) {
|
||||||
@@ -226,6 +243,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_initialized = true;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
log::error("Failed to load achievements: {}", e.what());
|
log::error("Failed to load achievements: {}", e.what());
|
||||||
}
|
}
|
||||||
@@ -234,6 +253,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AchievementManager::storeProgress() {
|
void AchievementManager::storeProgress() {
|
||||||
|
if (!s_initialized)
|
||||||
|
loadProgress();
|
||||||
nlohmann::json json;
|
nlohmann::json json;
|
||||||
for (const auto &[categoryName, achievements] : getAchievements()) {
|
for (const auto &[categoryName, achievements] : getAchievements()) {
|
||||||
json[categoryName] = nlohmann::json::object();
|
json[categoryName] = nlohmann::json::object();
|
||||||
@@ -246,7 +267,13 @@ namespace hex {
|
|||||||
if (json.empty())
|
if (json.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
#if defined(OS_WEB)
|
||||||
|
auto data = json.dump();
|
||||||
|
MAIN_THREAD_EM_ASM({
|
||||||
|
localStorage.setItem("achievements", UTF8ToString($0));
|
||||||
|
}, data.c_str());
|
||||||
|
#else
|
||||||
|
for (const auto &directory : paths::Config.write()) {
|
||||||
auto path = directory / AchievementsFile;
|
auto path = directory / AchievementsFile;
|
||||||
|
|
||||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||||
@@ -256,6 +283,7 @@ namespace hex {
|
|||||||
file.writeString(json.dump(4));
|
file.writeString(json.dump(4));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/helpers/auto_reset.hpp>
|
#include <hex/helpers/auto_reset.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
|
||||||
#include <hex/ui/view.hpp>
|
#include <hex/ui/view.hpp>
|
||||||
#include <hex/data_processor/node.hpp>
|
#include <hex/data_processor/node.hpp>
|
||||||
@@ -51,10 +52,14 @@ namespace hex {
|
|||||||
if (!settings[unlocalizedCategory].contains(unlocalizedName))
|
if (!settings[unlocalizedCategory].contains(unlocalizedName))
|
||||||
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||||
|
|
||||||
|
if (settings[unlocalizedCategory][unlocalizedName].is_null())
|
||||||
|
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||||
|
|
||||||
return settings[unlocalizedCategory][unlocalizedName];
|
return settings[unlocalizedCategory][unlocalizedName];
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_WEB)
|
#if defined(OS_WEB)
|
||||||
|
|
||||||
void load() {
|
void load() {
|
||||||
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
|
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
|
||||||
let data = localStorage.getItem("config");
|
let data = localStorage.getItem("config");
|
||||||
@@ -70,7 +75,11 @@ namespace hex {
|
|||||||
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
||||||
for (const auto &[name, callbacks] : rest) {
|
for (const auto &[name, callbacks] : rest) {
|
||||||
for (const auto &[id, callback] : callbacks) {
|
for (const auto &[id, callback] : callbacks) {
|
||||||
|
try {
|
||||||
callback(getSetting(category, name, {}));
|
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() {
|
void load() {
|
||||||
bool loaded = false;
|
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);
|
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
|
||||||
|
|
||||||
if (file.isValid()) {
|
if (file.isValid()) {
|
||||||
@@ -109,14 +118,21 @@ namespace hex {
|
|||||||
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
||||||
for (const auto &[name, callbacks] : rest) {
|
for (const auto &[name, callbacks] : rest) {
|
||||||
for (const auto &[id, callback] : callbacks) {
|
for (const auto &[id, callback] : callbacks) {
|
||||||
|
try {
|
||||||
callback(getSetting(category, name, {}));
|
callback(getSetting(category, name, {}));
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void store() {
|
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.
|
// During a crash settings can be empty, causing them to be overwritten.
|
||||||
if (settingsData.empty()) {
|
if (settingsData.empty()) {
|
||||||
@@ -127,7 +143,7 @@ namespace hex {
|
|||||||
if (result.empty()) {
|
if (result.empty()) {
|
||||||
return;
|
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);
|
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
|
||||||
|
|
||||||
if (file.isValid()) {
|
if (file.isValid()) {
|
||||||
@@ -138,7 +154,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
for (const auto &dir : paths::Config.write()) {
|
||||||
wolv::io::fs::remove(dir / SettingsFile);
|
wolv::io::fs::remove(dir / SettingsFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,6 +191,17 @@ namespace hex {
|
|||||||
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
|
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
|
||||||
|
|
||||||
entry->widget = std::move(widget);
|
entry->widget = std::move(widget);
|
||||||
|
if (entry->widget != nullptr) {
|
||||||
|
onChange(unlocalizedCategory, unlocalizedName, [widget = entry->widget.get(), unlocalizedCategory, unlocalizedName](const SettingsValue &) {
|
||||||
|
try {
|
||||||
|
auto defaultValue = widget->store();
|
||||||
|
widget->load(ContentRegistry::Settings::impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue));
|
||||||
|
widget->onChanged();
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return entry->widget.get();
|
return entry->widget.get();
|
||||||
}
|
}
|
||||||
@@ -297,6 +324,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) {
|
ColorPicker::ColorPicker(ImColor defaultColor) {
|
||||||
m_value = {
|
m_value = {
|
||||||
defaultColor.Value.x,
|
defaultColor.Value.x,
|
||||||
@@ -519,6 +563,11 @@ namespace hex {
|
|||||||
return *s_functions;
|
return *s_functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AutoReset<std::vector<TypeDefinition>> s_types;
|
||||||
|
const std::vector<TypeDefinition>& getTypes() {
|
||||||
|
return *s_types;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) {
|
static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) {
|
||||||
@@ -563,7 +612,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()) {
|
for (const auto &[ns, name, paramCount, callback, dangerous] : impl::getFunctions()) {
|
||||||
if (dangerous)
|
if (dangerous)
|
||||||
@@ -572,12 +621,16 @@ namespace hex {
|
|||||||
runtime.addFunction(ns, name, paramCount, callback);
|
runtime.addFunction(ns, name, paramCount, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &[ns, name, paramCount, callback] : impl::getTypes()) {
|
||||||
|
runtime.addType(ns, name, paramCount, callback);
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &[name, callback] : impl::getPragmas()) {
|
for (const auto &[name, callback] : impl::getPragmas()) {
|
||||||
runtime.addPragma(name, callback);
|
runtime.addPragma(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.addDefine("__IMHEX__");
|
runtime.addDefine("__IMHEX__");
|
||||||
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion());
|
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
||||||
@@ -606,6 +659,15 @@ namespace hex {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addType(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::TypeCallback &func) {
|
||||||
|
log::debug("Registered new pattern language type: {}", getFunctionName(ns, name));
|
||||||
|
|
||||||
|
impl::s_types->push_back({
|
||||||
|
ns, name,
|
||||||
|
parameterCount, func
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
|
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
|
||||||
log::debug("Registered new pattern visualizer function: {}", name);
|
log::debug("Registered new pattern visualizer function: {}", name);
|
||||||
@@ -788,6 +850,12 @@ namespace hex {
|
|||||||
return *s_menuItems;
|
return *s_menuItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static AutoReset<std::vector<MenuItem*>> s_toolbarMenuItems;
|
||||||
|
const std::vector<MenuItem*>& getToolbarMenuItems() {
|
||||||
|
return s_toolbarMenuItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::multimap<u32, MenuItem>& getMenuItemsMutable() {
|
std::multimap<u32, MenuItem>& getMenuItemsMutable() {
|
||||||
return *s_menuItems;
|
return *s_menuItems;
|
||||||
}
|
}
|
||||||
@@ -845,14 +913,21 @@ namespace hex {
|
|||||||
coloredIcon.color = ImGuiCustomCol_ToolbarGray;
|
coloredIcon.color = ImGuiCustomCol_ToolbarGray;
|
||||||
|
|
||||||
impl::s_menuItems->insert({
|
impl::s_menuItems->insert({
|
||||||
priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, std::make_unique<Shortcut>(shortcut), view, function, enabledCallback, selectedCallback, -1 }
|
priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, shortcut, view, function, enabledCallback, selectedCallback, -1 }
|
||||||
});
|
});
|
||||||
|
|
||||||
if (shortcut != Shortcut::None) {
|
if (shortcut != Shortcut::None) {
|
||||||
|
auto callbackIfEnabled = [enabledCallback, function]{ if (enabledCallback()) { function(); } };
|
||||||
|
|
||||||
|
const auto unlocalizedShortcutName =
|
||||||
|
unlocalizedMainMenuNames.size() == 1 ?
|
||||||
|
std::vector { unlocalizedMainMenuNames.back() } :
|
||||||
|
std::vector(unlocalizedMainMenuNames.begin() + 1, unlocalizedMainMenuNames.end());
|
||||||
|
|
||||||
if (shortcut.isLocal() && view != nullptr)
|
if (shortcut.isLocal() && view != nullptr)
|
||||||
ShortcutManager::addShortcut(view, shortcut, unlocalizedMainMenuNames.back(), function);
|
ShortcutManager::addShortcut(view, shortcut, unlocalizedShortcutName, callbackIfEnabled);
|
||||||
else
|
else
|
||||||
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedMainMenuNames.back(), function);
|
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedShortcutName, callbackIfEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,14 +940,14 @@ namespace hex {
|
|||||||
|
|
||||||
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
||||||
impl::s_menuItems->insert({
|
impl::s_menuItems->insert({
|
||||||
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, std::make_unique<Shortcut>(), nullptr, function, enabledCallback, []{ return false; }, -1 }
|
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, Shortcut::None, nullptr, function, enabledCallback, []{ return false; }, -1 }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority) {
|
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority) {
|
||||||
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
||||||
impl::s_menuItems->insert({
|
impl::s_menuItems->insert({
|
||||||
priority, impl::MenuItem { unlocalizedMainMenuNames, "", std::make_unique<Shortcut>(), nullptr, []{}, []{ return true; }, []{ return false; }, -1 }
|
priority, impl::MenuItem { unlocalizedMainMenuNames, "", Shortcut::None, nullptr, []{}, []{ return true; }, []{ return false; }, -1 }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -897,11 +972,35 @@ namespace hex {
|
|||||||
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
|
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
|
||||||
menuItem.toolbarIndex = maxIndex + 1;
|
menuItem.toolbarIndex = maxIndex + 1;
|
||||||
menuItem.icon.color = color;
|
menuItem.icon.color = color;
|
||||||
|
updateToolbarItems();
|
||||||
|
|
||||||
break;
|
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) {
|
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) {
|
||||||
impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
|
impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
|
||||||
@@ -950,17 +1049,28 @@ namespace hex {
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
static AutoReset<std::vector<Entry>> s_entries;
|
static AutoReset<std::vector<ExportMenuEntry>> s_exportMenuEntries;
|
||||||
const std::vector<Entry>& getEntries() {
|
const std::vector<ExportMenuEntry>& getExportMenuEntries() {
|
||||||
return *s_entries;
|
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());
|
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 });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1125,7 +1235,7 @@ namespace hex {
|
|||||||
|
|
||||||
class Service {
|
class Service {
|
||||||
public:
|
public:
|
||||||
Service(std::string name, std::jthread thread) : m_name(std::move(name)), m_thread(std::move(thread)) { }
|
Service(const UnlocalizedString &unlocalizedName, std::jthread thread) : m_unlocalizedName(std::move(unlocalizedName)), m_thread(std::move(thread)) { }
|
||||||
Service(const Service&) = delete;
|
Service(const Service&) = delete;
|
||||||
Service(Service &&) = default;
|
Service(Service &&) = default;
|
||||||
~Service() {
|
~Service() {
|
||||||
@@ -1137,8 +1247,8 @@ namespace hex {
|
|||||||
Service& operator=(const Service&) = delete;
|
Service& operator=(const Service&) = delete;
|
||||||
Service& operator=(Service &&) = default;
|
Service& operator=(Service &&) = default;
|
||||||
|
|
||||||
[[nodiscard]] const std::string& getName() const {
|
[[nodiscard]] const UnlocalizedString& getUnlocalizedName() const {
|
||||||
return m_name;
|
return m_unlocalizedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::jthread& getThread() const {
|
[[nodiscard]] const std::jthread& getThread() const {
|
||||||
@@ -1146,7 +1256,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_name;
|
UnlocalizedString m_unlocalizedName;
|
||||||
std::jthread m_thread;
|
std::jthread m_thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -21,4 +21,30 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool EventManager::isAlreadyRegistered(void *token, impl::EventId id) {
|
||||||
|
if (getTokenStore().contains(token)) {
|
||||||
|
auto&& [begin, end] = getTokenStore().equal_range(token);
|
||||||
|
|
||||||
|
return std::any_of(begin, end, [&](auto &item) {
|
||||||
|
return item.second->first == id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventManager::unsubscribe(void *token, impl::EventId id) {
|
||||||
|
auto &tokenStore = getTokenStore();
|
||||||
|
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
|
||||||
|
return item.first == token && item.second->first == id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (iter != tokenStore.end()) {
|
||||||
|
getEvents().erase(iter->second);
|
||||||
|
tokenStore.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
|
#include <set>
|
||||||
|
#include <algorithm>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
@@ -182,24 +184,24 @@ namespace hex {
|
|||||||
impl::s_hoveringFunctions->erase(id);
|
impl::s_hoveringFunctions->erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 tooltipId = 0;
|
static u32 s_tooltipId = 0;
|
||||||
u32 addTooltip(Region region, std::string value, color_t color) {
|
u32 addTooltip(Region region, std::string value, color_t color) {
|
||||||
tooltipId++;
|
s_tooltipId++;
|
||||||
impl::s_tooltips->insert({ tooltipId, { region, std::move(value), color } });
|
impl::s_tooltips->insert({ s_tooltipId, { region, std::move(value), color } });
|
||||||
|
|
||||||
return tooltipId;
|
return s_tooltipId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeTooltip(u32 id) {
|
void removeTooltip(u32 id) {
|
||||||
impl::s_tooltips->erase(id);
|
impl::s_tooltips->erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 tooltipFunctionId;
|
static u32 s_tooltipFunctionId;
|
||||||
u32 addTooltipProvider(TooltipFunction function) {
|
u32 addTooltipProvider(TooltipFunction function) {
|
||||||
tooltipFunctionId++;
|
s_tooltipFunctionId++;
|
||||||
impl::s_tooltipFunctions->insert({ tooltipFunctionId, std::move(function) });
|
impl::s_tooltipFunctions->insert({ s_tooltipFunctionId, std::move(function) });
|
||||||
|
|
||||||
return tooltipFunctionId;
|
return s_tooltipFunctionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeTooltipProvider(u32 id) {
|
void removeTooltipProvider(u32 id) {
|
||||||
@@ -216,7 +218,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clearSelection() {
|
void clearSelection() {
|
||||||
impl::s_currentSelection.reset();
|
impl::s_currentSelection->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSelection(const Region ®ion, prv::Provider *provider) {
|
void setSelection(const Region ®ion, prv::Provider *provider) {
|
||||||
@@ -266,18 +268,20 @@ namespace hex {
|
|||||||
|
|
||||||
static i64 s_currentProvider = -1;
|
static i64 s_currentProvider = -1;
|
||||||
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers;
|
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers;
|
||||||
|
static AutoReset<std::map<prv::Provider*, std::unique_ptr<prv::Provider>>> s_providersToRemove;
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
static std::vector<prv::Provider*> s_closingProviders;
|
static std::set<prv::Provider*> s_closingProviders;
|
||||||
void resetClosingProvider() {
|
void resetClosingProvider() {
|
||||||
s_closingProviders.clear();
|
s_closingProviders.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<prv::Provider*>& getClosingProviders() {
|
std::set<prv::Provider*> getClosingProviders() {
|
||||||
return s_closingProviders;
|
return s_closingProviders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::recursive_mutex s_providerMutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
prv::Provider *get() {
|
prv::Provider *get() {
|
||||||
@@ -297,6 +301,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setCurrentProvider(i64 index) {
|
void setCurrentProvider(i64 index) {
|
||||||
|
std::scoped_lock lock(impl::s_providerMutex);
|
||||||
|
|
||||||
if (TaskManager::getRunningTaskCount() > 0)
|
if (TaskManager::getRunningTaskCount() > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -310,6 +316,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setCurrentProvider(NonNull<prv::Provider*> provider) {
|
void setCurrentProvider(NonNull<prv::Provider*> provider) {
|
||||||
|
std::scoped_lock lock(impl::s_providerMutex);
|
||||||
|
|
||||||
if (TaskManager::getRunningTaskCount() > 0)
|
if (TaskManager::getRunningTaskCount() > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -329,7 +337,11 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void markDirty() {
|
void markDirty() {
|
||||||
get()->markDirty();
|
const auto provider = get();
|
||||||
|
if (!provider->isDirty()) {
|
||||||
|
provider->markDirty();
|
||||||
|
EventProviderDirtied::post(provider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetDirty() {
|
void resetDirty() {
|
||||||
@@ -344,6 +356,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
|
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
|
||||||
|
std::scoped_lock lock(impl::s_providerMutex);
|
||||||
|
|
||||||
if (TaskManager::getRunningTaskCount() > 0)
|
if (TaskManager::getRunningTaskCount() > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -358,6 +372,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void remove(prv::Provider *provider, bool noQuestions) {
|
void remove(prv::Provider *provider, bool noQuestions) {
|
||||||
|
std::scoped_lock lock(impl::s_providerMutex);
|
||||||
|
|
||||||
if (provider == nullptr)
|
if (provider == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -365,7 +381,7 @@ namespace hex {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!noQuestions) {
|
if (!noQuestions) {
|
||||||
impl::s_closingProviders.push_back(provider);
|
impl::s_closingProviders.insert(provider);
|
||||||
|
|
||||||
bool shouldClose = true;
|
bool shouldClose = true;
|
||||||
EventProviderClosing::post(provider, &shouldClose);
|
EventProviderClosing::post(provider, &shouldClose);
|
||||||
@@ -413,20 +429,38 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider->close();
|
static std::mutex eraseMutex;
|
||||||
EventProviderClosed::post(provider);
|
|
||||||
RequestUpdateWindowTitle::post();
|
|
||||||
|
|
||||||
TaskManager::runWhenTasksFinished([it, provider] {
|
// Move provider over to a list of providers to delete
|
||||||
EventProviderDeleted::post(provider);
|
eraseMutex.lock();
|
||||||
std::erase(impl::s_closingProviders, provider);
|
auto providerToRemove = it->get();
|
||||||
|
(*s_providersToRemove)[providerToRemove] = std::move(*it);
|
||||||
|
eraseMutex.unlock();
|
||||||
|
|
||||||
|
// Remove left over references from the main provider list
|
||||||
s_providers->erase(it);
|
s_providers->erase(it);
|
||||||
if (s_currentProvider >= i64(s_providers->size()))
|
impl::s_closingProviders.erase(provider);
|
||||||
setCurrentProvider(0);
|
|
||||||
|
if (s_currentProvider >= i64(s_providers->size()) && !s_providers->empty())
|
||||||
|
setCurrentProvider(s_providers->size() - 1);
|
||||||
|
|
||||||
if (s_providers->empty())
|
if (s_providers->empty())
|
||||||
EventProviderChanged::post(provider, nullptr);
|
EventProviderChanged::post(provider, nullptr);
|
||||||
|
|
||||||
|
EventProviderClosed::post(it->get());
|
||||||
|
RequestUpdateWindowTitle::post();
|
||||||
|
|
||||||
|
// Do the destruction of the provider in the background once all tasks have finished
|
||||||
|
TaskManager::runWhenTasksFinished([providerToRemove] {
|
||||||
|
EventProviderDeleted::post(providerToRemove);
|
||||||
|
TaskManager::createBackgroundTask("Closing Provider", [providerToRemove](Task &) {
|
||||||
|
eraseMutex.lock();
|
||||||
|
auto provider = std::move((*s_providersToRemove)[providerToRemove]);
|
||||||
|
s_providersToRemove->erase(providerToRemove);
|
||||||
|
eraseMutex.unlock();
|
||||||
|
|
||||||
|
provider->close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -441,7 +475,6 @@ namespace hex {
|
|||||||
|
|
||||||
namespace ImHexApi::System {
|
namespace ImHexApi::System {
|
||||||
|
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
// Default to true means we forward to ourselves by default
|
// Default to true means we forward to ourselves by default
|
||||||
@@ -503,6 +536,11 @@ namespace hex {
|
|||||||
s_gpuVendor = vendor;
|
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;
|
static AutoReset<std::map<std::string, std::string>> s_initArguments;
|
||||||
void addInitArgument(const std::string &key, const std::string &value) {
|
void addInitArgument(const std::string &key, const std::string &value) {
|
||||||
static std::mutex initArgumentsMutex;
|
static std::mutex initArgumentsMutex;
|
||||||
@@ -604,7 +642,15 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* getLibImHexModuleHandle() {
|
void* getLibImHexModuleHandle() {
|
||||||
return hex::getContainingModule((void*)&getLibImHexModuleHandle);
|
return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function) {
|
||||||
|
EventImHexUpdated::subscribe([migrationVersion, function](const SemanticVersion &oldVersion, const SemanticVersion &newVersion) {
|
||||||
|
if (oldVersion < migrationVersion && newVersion >= migrationVersion) {
|
||||||
|
function();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -647,6 +693,10 @@ namespace hex {
|
|||||||
return impl::s_gpuVendor;
|
return impl::s_gpuVendor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &getGLRenderer() {
|
||||||
|
return impl::s_glRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
bool isPortableVersion() {
|
bool isPortableVersion() {
|
||||||
static std::optional<bool> portable;
|
static std::optional<bool> portable;
|
||||||
if (portable.has_value())
|
if (portable.has_value())
|
||||||
@@ -733,16 +783,30 @@ namespace hex {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getImHexVersion(bool withBuildType) {
|
std::optional<LinuxDistro> getLinuxDistro() {
|
||||||
#if defined IMHEX_VERSION
|
wolv::io::File file("/etc/os-release", wolv::io::File::Mode::Read);
|
||||||
if (withBuildType) {
|
std::string name;
|
||||||
return IMHEX_VERSION;
|
std::string version;
|
||||||
} else {
|
|
||||||
auto version = std::string(IMHEX_VERSION);
|
auto fileContent = file.readString();
|
||||||
return version.substr(0, version.find('-'));
|
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 } };
|
||||||
|
}
|
||||||
|
|
||||||
|
SemanticVersion getImHexVersion() {
|
||||||
|
#if defined IMHEX_VERSION
|
||||||
|
return SemanticVersion(IMHEX_VERSION);
|
||||||
#else
|
#else
|
||||||
return "Unknown";
|
return {};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -754,7 +818,7 @@ namespace hex {
|
|||||||
return std::string(GIT_COMMIT_HASH_LONG).substr(0, 7);
|
return std::string(GIT_COMMIT_HASH_LONG).substr(0, 7);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
hex::unused(longHash);
|
std::ignore = longHash;
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -775,6 +839,10 @@ namespace hex {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isNightlyBuild() {
|
||||||
|
return getImHexVersion().nightly();
|
||||||
|
}
|
||||||
|
|
||||||
bool updateImHex(UpdateType updateType) {
|
bool updateImHex(UpdateType updateType) {
|
||||||
// Get the path of the updater executable
|
// Get the path of the updater executable
|
||||||
std::fs::path executablePath;
|
std::fs::path executablePath;
|
||||||
@@ -801,7 +869,7 @@ namespace hex {
|
|||||||
|
|
||||||
EventImHexClosing::subscribe([executablePath, updateTypeString] {
|
EventImHexClosing::subscribe([executablePath, updateTypeString] {
|
||||||
hex::executeCommand(
|
hex::executeCommand(
|
||||||
hex::format("{} {}",
|
hex::format("\"{}\" \"{}\"",
|
||||||
wolv::util::toUTF8String(executablePath),
|
wolv::util::toUTF8String(executablePath),
|
||||||
updateTypeString
|
updateTypeString
|
||||||
)
|
)
|
||||||
@@ -880,9 +948,9 @@ namespace hex {
|
|||||||
s_fontSize = size;
|
s_fontSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AutoReset<std::unique_ptr<ImFontAtlas>> s_fontAtlas;
|
static AutoReset<ImFontAtlas*> s_fontAtlas;
|
||||||
void setFontAtlas(ImFontAtlas* fontAtlas) {
|
void setFontAtlas(ImFontAtlas* fontAtlas) {
|
||||||
s_fontAtlas = std::unique_ptr<ImFontAtlas>(fontAtlas);
|
s_fontAtlas = fontAtlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ImFont *s_boldFont = nullptr;
|
static ImFont *s_boldFont = nullptr;
|
||||||
@@ -965,7 +1033,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImFontAtlas* getFontAtlas() {
|
ImFontAtlas* getFontAtlas() {
|
||||||
return impl::s_fontAtlas->get();
|
return impl::s_fontAtlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImFont* Bold() {
|
ImFont* Bold() {
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#include <hex/api/layout_manager.hpp>
|
#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/fs.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/helpers/auto_reset.hpp>
|
#include <hex/helpers/auto_reset.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
|
||||||
#include <wolv/utils/string.hpp>
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <hex/api/content_registry.hpp>
|
|
||||||
#include <hex/ui/view.hpp>
|
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
@@ -40,10 +42,7 @@ namespace hex {
|
|||||||
fileName += ".hexlyt";
|
fileName += ".hexlyt";
|
||||||
|
|
||||||
std::fs::path layoutPath;
|
std::fs::path layoutPath;
|
||||||
for (const auto &path : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
|
for (const auto &path : paths::Layouts.write()) {
|
||||||
if (!hex::fs::isPathWritable(layoutPath))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
layoutPath = path / fileName;
|
layoutPath = path / fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,15 +70,15 @@ namespace hex {
|
|||||||
void LayoutManager::removeLayout(const std::string& name) {
|
void LayoutManager::removeLayout(const std::string& name) {
|
||||||
for (const auto &layout : *s_layouts) {
|
for (const auto &layout : *s_layouts) {
|
||||||
if (layout.name == name) {
|
if (layout.name == name) {
|
||||||
if (wolv::io::File(layout.path, wolv::io::File::Mode::Write).remove()) {
|
if (wolv::io::fs::remove(layout.path)) {
|
||||||
log::info("Removed layout '{}'", name);
|
log::info("Removed layout '{}'", name);
|
||||||
LayoutManager::reload();
|
|
||||||
} else {
|
} else {
|
||||||
log::error("Failed to remove layout '{}'", name);
|
log::error("Failed to remove layout '{}'", name);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LayoutManager::reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -90,28 +89,26 @@ namespace hex {
|
|||||||
|
|
||||||
void LayoutManager::process() {
|
void LayoutManager::process() {
|
||||||
if (s_layoutPathToLoad->has_value()) {
|
if (s_layoutPathToLoad->has_value()) {
|
||||||
const auto pathString = wolv::util::toUTF8String(**s_layoutPathToLoad);
|
|
||||||
|
|
||||||
LayoutManager::closeAllViews();
|
LayoutManager::closeAllViews();
|
||||||
ImGui::LoadIniSettingsFromDisk(pathString.c_str());
|
|
||||||
|
|
||||||
s_layoutPathToLoad = std::nullopt;
|
wolv::io::File file(**s_layoutPathToLoad, wolv::io::File::Mode::Read);
|
||||||
log::info("Loaded layout from {}", pathString);
|
s_layoutStringToLoad = file.readString();
|
||||||
|
s_layoutPathToLoad->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s_layoutStringToLoad->has_value()) {
|
if (s_layoutStringToLoad->has_value()) {
|
||||||
LayoutManager::closeAllViews();
|
LayoutManager::closeAllViews();
|
||||||
ImGui::LoadIniSettingsFromMemory((*s_layoutStringToLoad)->c_str());
|
ImGui::LoadIniSettingsFromMemory((*s_layoutStringToLoad)->c_str());
|
||||||
|
|
||||||
s_layoutStringToLoad = std::nullopt;
|
s_layoutStringToLoad->reset();
|
||||||
log::info("Loaded layout from string");
|
log::info("Loaded new Layout");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayoutManager::reload() {
|
void LayoutManager::reload() {
|
||||||
s_layouts->clear();
|
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)) {
|
for (const auto &entry : std::fs::directory_iterator(directory)) {
|
||||||
const auto &path = entry.path();
|
const auto &path = entry.path();
|
||||||
|
|
||||||
@@ -134,8 +131,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LayoutManager::reset() {
|
void LayoutManager::reset() {
|
||||||
s_layoutPathToLoad.reset();
|
s_layoutPathToLoad->reset();
|
||||||
s_layoutStringToLoad.reset();
|
s_layoutStringToLoad->reset();
|
||||||
s_layouts->clear();
|
s_layouts->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace hex {
|
|||||||
|
|
||||||
AutoReset<std::string> s_fallbackLanguage;
|
AutoReset<std::string> s_fallbackLanguage;
|
||||||
AutoReset<std::string> s_selectedLanguage;
|
AutoReset<std::string> s_selectedLanguage;
|
||||||
AutoReset<std::map<std::string, std::string>> s_currStrings;
|
AutoReset<std::map<size_t, std::string>> s_currStrings;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +41,21 @@ namespace hex {
|
|||||||
return m_entries;
|
return m_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void loadLanguageDefinitions(const std::vector<LanguageDefinition> &definitions) {
|
||||||
|
for (const auto &definition : definitions) {
|
||||||
|
const auto &entries = definition.getEntries();
|
||||||
|
if (entries.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const auto &[key, value] : entries) {
|
||||||
|
if (value.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s_currStrings->emplace(LangConst::hash(key), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void loadLanguage(const std::string &language) {
|
void loadLanguage(const std::string &language) {
|
||||||
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
|
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
|
||||||
|
|
||||||
@@ -49,14 +64,10 @@ namespace hex {
|
|||||||
|
|
||||||
s_currStrings->clear();
|
s_currStrings->clear();
|
||||||
|
|
||||||
for (const auto &definition : definitions.at(language))
|
loadLanguageDefinitions(definitions.at(language));
|
||||||
s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end());
|
|
||||||
|
|
||||||
const auto& fallbackLanguage = getFallbackLanguage();
|
const auto& fallbackLanguage = getFallbackLanguage();
|
||||||
if (language != fallbackLanguage && definitions.contains(fallbackLanguage)) {
|
loadLanguageDefinitions(definitions.at(fallbackLanguage));
|
||||||
for (const auto &definition : definitions.at(fallbackLanguage))
|
|
||||||
s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end());
|
|
||||||
}
|
|
||||||
|
|
||||||
s_selectedLanguage = language;
|
s_selectedLanguage = language;
|
||||||
}
|
}
|
||||||
@@ -98,11 +109,11 @@ namespace hex {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Lang::Lang(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
Lang::Lang(const char *unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
|
||||||
Lang::Lang(const std::string &unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
Lang::Lang(const std::string &unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
|
||||||
Lang::Lang(const UnlocalizedString &unlocalizedString) : m_unlocalizedString(unlocalizedString.get()) { }
|
Lang::Lang(const LangConst &localizedString) : m_entryHash(localizedString.m_entryHash), m_unlocalizedString(localizedString.m_unlocalizedString) { }
|
||||||
Lang::Lang(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
Lang::Lang(const UnlocalizedString &unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString.get())), m_unlocalizedString(unlocalizedString.get()) { }
|
||||||
|
Lang::Lang(std::string_view unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
|
||||||
|
|
||||||
Lang::operator std::string() const {
|
Lang::operator std::string() const {
|
||||||
return get();
|
return get();
|
||||||
@@ -113,43 +124,41 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Lang::operator const char *() const {
|
Lang::operator const char *() const {
|
||||||
return get().c_str();
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator+(const std::string &&left, const Lang &&right) {
|
const char *Lang::get() const {
|
||||||
return left + static_cast<std::string>(right);
|
const auto &lang = *LocalizationManager::s_currStrings;
|
||||||
|
|
||||||
|
const auto it = lang.find(m_entryHash);
|
||||||
|
if (it == lang.end()) {
|
||||||
|
return m_unlocalizedString.c_str();
|
||||||
|
} else {
|
||||||
|
return it->second.c_str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator+(const Lang &&left, const std::string &&right) {
|
LangConst::operator std::string() const {
|
||||||
return static_cast<std::string>(left) + right;
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator+(const Lang &&left, const Lang &&right) {
|
LangConst::operator std::string_view() const {
|
||||||
return static_cast<std::string>(left) + static_cast<std::string>(right);
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator+(const std::string_view &&left, const Lang &&right) {
|
LangConst::operator const char *() const {
|
||||||
return std::string(left) + static_cast<std::string>(right);
|
return get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string operator+(const Lang &&left, const std::string_view &&right) {
|
const char *LangConst::get() const {
|
||||||
return static_cast<std::string>(left) + std::string(right);
|
const auto &lang = *LocalizationManager::s_currStrings;
|
||||||
}
|
|
||||||
|
|
||||||
std::string operator+(const char *left, const Lang &&right) {
|
const auto it = lang.find(m_entryHash);
|
||||||
return left + static_cast<std::string>(right);
|
if (it == lang.end()) {
|
||||||
}
|
|
||||||
|
|
||||||
std::string operator+(const Lang &&left, const char *right) {
|
|
||||||
return static_cast<std::string>(left) + right;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string &Lang::get() const {
|
|
||||||
auto &lang = LocalizationManager::s_currStrings;
|
|
||||||
if (lang->contains(m_unlocalizedString))
|
|
||||||
return lang->at(m_unlocalizedString);
|
|
||||||
else
|
|
||||||
return m_unlocalizedString;
|
return m_unlocalizedString;
|
||||||
|
} else {
|
||||||
|
return it->second.c_str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <hex/helpers/fmt.hpp>
|
#include <hex/helpers/fmt.hpp>
|
||||||
#include <hex/helpers/auto_reset.hpp>
|
#include <hex/helpers/auto_reset.hpp>
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
|
||||||
#include <wolv/utils/string.hpp>
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
@@ -111,10 +112,6 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Plugin::~Plugin() {
|
Plugin::~Plugin() {
|
||||||
if (isLoaded()) {
|
|
||||||
log::info("Trying to unload plugin '{}'", getPluginName());
|
|
||||||
}
|
|
||||||
|
|
||||||
unloadLibrary(m_handle, m_path);
|
unloadLibrary(m_handle, m_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +129,7 @@ namespace hex {
|
|||||||
|
|
||||||
|
|
||||||
const auto requestedVersion = getCompatibleVersion();
|
const auto requestedVersion = getCompatibleVersion();
|
||||||
const auto imhexVersion = ImHexApi::System::getImHexVersion();
|
const auto imhexVersion = ImHexApi::System::getImHexVersion().get();
|
||||||
if (!imhexVersion.starts_with(requestedVersion)) {
|
if (!imhexVersion.starts_with(requestedVersion)) {
|
||||||
if (requestedVersion.empty()) {
|
if (requestedVersion.empty()) {
|
||||||
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename()));
|
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename()));
|
||||||
@@ -306,7 +303,7 @@ namespace hex {
|
|||||||
|
|
||||||
bool PluginManager::loadLibraries() {
|
bool PluginManager::loadLibraries() {
|
||||||
bool success = true;
|
bool success = true;
|
||||||
for (const auto &loadPath : fs::getDefaultPaths(fs::ImHexPath::Libraries))
|
for (const auto &loadPath : paths::Libraries.read())
|
||||||
success = PluginManager::loadLibraries(loadPath) && success;
|
success = PluginManager::loadLibraries(loadPath) && success;
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@@ -334,7 +331,7 @@ namespace hex {
|
|||||||
void PluginManager::initializeNewPlugins() {
|
void PluginManager::initializeNewPlugins() {
|
||||||
for (const auto &plugin : getPlugins()) {
|
for (const auto &plugin : getPlugins()) {
|
||||||
if (!plugin.isLoaded())
|
if (!plugin.isLoaded())
|
||||||
hex::unused(plugin.initializePlugin());
|
std::ignore = plugin.initializePlugin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,31 +12,265 @@ namespace hex {
|
|||||||
AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts;
|
AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts;
|
||||||
std::atomic<bool> s_paused;
|
std::atomic<bool> s_paused;
|
||||||
std::optional<Shortcut> s_prevShortcut;
|
std::optional<Shortcut> s_prevShortcut;
|
||||||
|
bool s_macOSMode = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shortcut operator+(const Key &lhs, const Key &rhs) {
|
||||||
|
Shortcut result;
|
||||||
|
result.m_keys = { lhs, rhs };
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shortcut::Shortcut(Keys key) : m_keys({ key }) {
|
||||||
|
|
||||||
|
}
|
||||||
|
Shortcut::Shortcut(std::set<Key> keys) : m_keys(std::move(keys)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Shortcut Shortcut::operator+(const Key &other) const {
|
||||||
|
Shortcut result = *this;
|
||||||
|
result.m_keys.insert(other);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shortcut& Shortcut::operator+=(const Key &other) {
|
||||||
|
m_keys.insert(other);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shortcut::operator<(const Shortcut &other) const {
|
||||||
|
return m_keys < other.m_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shortcut::operator==(const Shortcut &other) const {
|
||||||
|
return m_keys == other.m_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shortcut::isLocal() const {
|
||||||
|
return m_keys.contains(CurrentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::set<Key>& Shortcut::getKeys() const {
|
||||||
|
return m_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shortcut::has(Key key) const {
|
||||||
|
return m_keys.contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shortcut::matches(const Shortcut& other) const {
|
||||||
|
auto left = this->m_keys;
|
||||||
|
auto right = other.m_keys;
|
||||||
|
|
||||||
|
left.erase(CurrentView);
|
||||||
|
left.erase(AllowWhileTyping);
|
||||||
|
right.erase(CurrentView);
|
||||||
|
right.erase(AllowWhileTyping);
|
||||||
|
|
||||||
|
return left == right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string Shortcut::toString() const {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
const auto CTRL_NAME = s_macOSMode ? "⌃" : "CTRL";
|
||||||
|
const auto ALT_NAME = s_macOSMode ? "⌥" : "ALT";
|
||||||
|
const auto SHIFT_NAME = s_macOSMode ? "⇧" : "SHIFT";
|
||||||
|
const auto SUPER_NAME = s_macOSMode ? "⌘" : "SUPER";
|
||||||
|
const auto Concatination = s_macOSMode ? " " : " + ";
|
||||||
|
|
||||||
|
auto keys = m_keys;
|
||||||
|
if (keys.erase(CTRL) > 0 || (!s_macOSMode && keys.erase(CTRLCMD) > 0)) {
|
||||||
|
result += CTRL_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
if (keys.erase(ALT) > 0) {
|
||||||
|
result += ALT_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
if (keys.erase(SHIFT) > 0) {
|
||||||
|
result += SHIFT_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
if (keys.erase(SUPER) > 0 || (s_macOSMode && keys.erase(CTRLCMD) > 0)) {
|
||||||
|
result += SUPER_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
keys.erase(CurrentView);
|
||||||
|
|
||||||
|
for (const auto &key : keys) {
|
||||||
|
switch (Keys(key.getKeyCode())) {
|
||||||
|
case Keys::Space: result += "⎵"; break;
|
||||||
|
case Keys::Apostrophe: result += "'"; break;
|
||||||
|
case Keys::Comma: result += ","; break;
|
||||||
|
case Keys::Minus: result += "-"; break;
|
||||||
|
case Keys::Period: result += "."; break;
|
||||||
|
case Keys::Slash: result += "/"; break;
|
||||||
|
case Keys::Num0: result += "0"; break;
|
||||||
|
case Keys::Num1: result += "1"; break;
|
||||||
|
case Keys::Num2: result += "2"; break;
|
||||||
|
case Keys::Num3: result += "3"; break;
|
||||||
|
case Keys::Num4: result += "4"; break;
|
||||||
|
case Keys::Num5: result += "5"; break;
|
||||||
|
case Keys::Num6: result += "6"; break;
|
||||||
|
case Keys::Num7: result += "7"; break;
|
||||||
|
case Keys::Num8: result += "8"; break;
|
||||||
|
case Keys::Num9: result += "9"; break;
|
||||||
|
case Keys::Semicolon: result += ";"; break;
|
||||||
|
case Keys::Equals: result += "="; break;
|
||||||
|
case Keys::A: result += "A"; break;
|
||||||
|
case Keys::B: result += "B"; break;
|
||||||
|
case Keys::C: result += "C"; break;
|
||||||
|
case Keys::D: result += "D"; break;
|
||||||
|
case Keys::E: result += "E"; break;
|
||||||
|
case Keys::F: result += "F"; break;
|
||||||
|
case Keys::G: result += "G"; break;
|
||||||
|
case Keys::H: result += "H"; break;
|
||||||
|
case Keys::I: result += "I"; break;
|
||||||
|
case Keys::J: result += "J"; break;
|
||||||
|
case Keys::K: result += "K"; break;
|
||||||
|
case Keys::L: result += "L"; break;
|
||||||
|
case Keys::M: result += "M"; break;
|
||||||
|
case Keys::N: result += "N"; break;
|
||||||
|
case Keys::O: result += "O"; break;
|
||||||
|
case Keys::P: result += "P"; break;
|
||||||
|
case Keys::Q: result += "Q"; break;
|
||||||
|
case Keys::R: result += "R"; break;
|
||||||
|
case Keys::S: result += "S"; break;
|
||||||
|
case Keys::T: result += "T"; break;
|
||||||
|
case Keys::U: result += "U"; break;
|
||||||
|
case Keys::V: result += "V"; break;
|
||||||
|
case Keys::W: result += "W"; break;
|
||||||
|
case Keys::X: result += "X"; break;
|
||||||
|
case Keys::Y: result += "Y"; break;
|
||||||
|
case Keys::Z: result += "Z"; break;
|
||||||
|
case Keys::LeftBracket: result += "["; break;
|
||||||
|
case Keys::Backslash: result += "\\"; break;
|
||||||
|
case Keys::RightBracket: result += "]"; break;
|
||||||
|
case Keys::GraveAccent: result += "`"; break;
|
||||||
|
case Keys::World1: result += "WORLD1"; break;
|
||||||
|
case Keys::World2: result += "WORLD2"; break;
|
||||||
|
case Keys::Escape: result += "ESC"; break;
|
||||||
|
case Keys::Enter: result += "⏎"; break;
|
||||||
|
case Keys::Tab: result += "⇥"; break;
|
||||||
|
case Keys::Backspace: result += "⌫"; break;
|
||||||
|
case Keys::Insert: result += "INSERT"; break;
|
||||||
|
case Keys::Delete: result += "DELETE"; break;
|
||||||
|
case Keys::Right: result += "RIGHT"; break;
|
||||||
|
case Keys::Left: result += "LEFT"; break;
|
||||||
|
case Keys::Down: result += "DOWN"; break;
|
||||||
|
case Keys::Up: result += "UP"; break;
|
||||||
|
case Keys::PageUp: result += "PAGEUP"; break;
|
||||||
|
case Keys::PageDown: result += "PAGEDOWN"; break;
|
||||||
|
case Keys::Home: result += "HOME"; break;
|
||||||
|
case Keys::End: result += "END"; break;
|
||||||
|
case Keys::CapsLock: result += "⇪"; break;
|
||||||
|
case Keys::ScrollLock: result += "SCROLLLOCK"; break;
|
||||||
|
case Keys::NumLock: result += "NUMLOCK"; break;
|
||||||
|
case Keys::PrintScreen: result += "PRINTSCREEN"; break;
|
||||||
|
case Keys::Pause: result += "PAUSE"; break;
|
||||||
|
case Keys::F1: result += "F1"; break;
|
||||||
|
case Keys::F2: result += "F2"; break;
|
||||||
|
case Keys::F3: result += "F3"; break;
|
||||||
|
case Keys::F4: result += "F4"; break;
|
||||||
|
case Keys::F5: result += "F5"; break;
|
||||||
|
case Keys::F6: result += "F6"; break;
|
||||||
|
case Keys::F7: result += "F7"; break;
|
||||||
|
case Keys::F8: result += "F8"; break;
|
||||||
|
case Keys::F9: result += "F9"; break;
|
||||||
|
case Keys::F10: result += "F10"; break;
|
||||||
|
case Keys::F11: result += "F11"; break;
|
||||||
|
case Keys::F12: result += "F12"; break;
|
||||||
|
case Keys::F13: result += "F13"; break;
|
||||||
|
case Keys::F14: result += "F14"; break;
|
||||||
|
case Keys::F15: result += "F15"; break;
|
||||||
|
case Keys::F16: result += "F16"; break;
|
||||||
|
case Keys::F17: result += "F17"; break;
|
||||||
|
case Keys::F18: result += "F18"; break;
|
||||||
|
case Keys::F19: result += "F19"; break;
|
||||||
|
case Keys::F20: result += "F20"; break;
|
||||||
|
case Keys::F21: result += "F21"; break;
|
||||||
|
case Keys::F22: result += "F22"; break;
|
||||||
|
case Keys::F23: result += "F23"; break;
|
||||||
|
case Keys::F24: result += "F24"; break;
|
||||||
|
case Keys::F25: result += "F25"; break;
|
||||||
|
case Keys::KeyPad0: result += "KP0"; break;
|
||||||
|
case Keys::KeyPad1: result += "KP1"; break;
|
||||||
|
case Keys::KeyPad2: result += "KP2"; break;
|
||||||
|
case Keys::KeyPad3: result += "KP3"; break;
|
||||||
|
case Keys::KeyPad4: result += "KP4"; break;
|
||||||
|
case Keys::KeyPad5: result += "KP5"; break;
|
||||||
|
case Keys::KeyPad6: result += "KP6"; break;
|
||||||
|
case Keys::KeyPad7: result += "KP7"; break;
|
||||||
|
case Keys::KeyPad8: result += "KP8"; break;
|
||||||
|
case Keys::KeyPad9: result += "KP9"; break;
|
||||||
|
case Keys::KeyPadDecimal: result += "KPDECIMAL"; break;
|
||||||
|
case Keys::KeyPadDivide: result += "KPDIVIDE"; break;
|
||||||
|
case Keys::KeyPadMultiply: result += "KPMULTIPLY"; break;
|
||||||
|
case Keys::KeyPadSubtract: result += "KPSUBTRACT"; break;
|
||||||
|
case Keys::KeyPadAdd: result += "KPADD"; break;
|
||||||
|
case Keys::KeyPadEnter: result += "KPENTER"; break;
|
||||||
|
case Keys::KeyPadEqual: result += "KPEQUAL"; break;
|
||||||
|
case Keys::Menu: result += "MENU"; break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.ends_with(Concatination))
|
||||||
|
result = result.substr(0, result.size() - strlen(Concatination));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback) {
|
||||||
|
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
|
||||||
|
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback } });
|
||||||
|
if (!inserted) log::error("Failed to add shortcut!");
|
||||||
|
}
|
||||||
|
|
||||||
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
||||||
s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback } });
|
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.get());
|
||||||
|
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, { unlocalizedName }, callback } });
|
||||||
|
if (!inserted) log::error("Failed to add shortcut!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback) {
|
||||||
|
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
|
||||||
|
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback } });
|
||||||
|
if (!inserted) log::error("Failed to add shortcut!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
||||||
view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback } });
|
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.get());
|
||||||
|
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, { unlocalizedName }, callback } });
|
||||||
|
if (!inserted) log::error("Failed to add shortcut!");
|
||||||
}
|
}
|
||||||
|
|
||||||
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
||||||
Shortcut pressedShortcut;
|
Shortcut pressedShortcut;
|
||||||
|
|
||||||
if (ctrl)
|
if (ctrl)
|
||||||
pressedShortcut += CTRL;
|
pressedShortcut += s_macOSMode ? CTRL : CTRLCMD;
|
||||||
if (alt)
|
if (alt)
|
||||||
pressedShortcut += ALT;
|
pressedShortcut += ALT;
|
||||||
if (shift)
|
if (shift)
|
||||||
pressedShortcut += SHIFT;
|
pressedShortcut += SHIFT;
|
||||||
if (super)
|
if (super)
|
||||||
pressedShortcut += SUPER;
|
pressedShortcut += s_macOSMode ? CTRLCMD : SUPER;
|
||||||
if (focused)
|
if (focused)
|
||||||
pressedShortcut += CurrentView;
|
pressedShortcut += CurrentView;
|
||||||
|
if (ImGui::GetIO().WantTextInput)
|
||||||
|
pressedShortcut += AllowWhileTyping;
|
||||||
|
|
||||||
pressedShortcut += static_cast<Keys>(keyCode);
|
pressedShortcut += static_cast<Keys>(keyCode);
|
||||||
|
|
||||||
@@ -49,11 +283,9 @@ namespace hex {
|
|||||||
if (ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId))
|
if (ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (shortcuts.contains(shortcut + AllowWhileTyping)) {
|
if (auto it = shortcuts.find(shortcut); it != shortcuts.end()) {
|
||||||
shortcuts.at(shortcut + AllowWhileTyping).callback();
|
const auto &[foundShortcut, entry] = *it;
|
||||||
} else if (shortcuts.contains(shortcut)) {
|
entry.callback();
|
||||||
if (!ImGui::GetIO().WantTextInput)
|
|
||||||
shortcuts.at(shortcut).callback();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,10 +354,13 @@ namespace hex {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShortcutManager::updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view) {
|
bool ShortcutManager::updateShortcut(const Shortcut &oldShortcut, Shortcut newShortcut, View *view) {
|
||||||
if (oldShortcut == newShortcut)
|
if (oldShortcut.matches(newShortcut))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (oldShortcut.has(AllowWhileTyping))
|
||||||
|
newShortcut += AllowWhileTyping;
|
||||||
|
|
||||||
bool result;
|
bool result;
|
||||||
if (view != nullptr) {
|
if (view != nullptr) {
|
||||||
result = updateShortcutImpl(oldShortcut + CurrentView, newShortcut + CurrentView , view->m_shortcuts);
|
result = updateShortcutImpl(oldShortcut + CurrentView, newShortcut + CurrentView , view->m_shortcuts);
|
||||||
@@ -134,9 +369,9 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItemsMutable()) {
|
||||||
if (menuItem.view == view && *menuItem.shortcut == oldShortcut) {
|
if (menuItem.view == view && menuItem.shortcut == oldShortcut) {
|
||||||
*menuItem.shortcut = newShortcut;
|
menuItem.shortcut = newShortcut;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,4 +380,9 @@ namespace hex {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShortcutManager::enableMacOSMode() {
|
||||||
|
s_macOSMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Task::Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
|
Task::Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
|
||||||
: m_unlocalizedName(std::move(unlocalizedName)), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
|
: m_unlocalizedName(std::move(unlocalizedName)), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
|
||||||
|
|
||||||
Task::Task(hex::Task &&other) noexcept {
|
Task::Task(hex::Task &&other) noexcept {
|
||||||
@@ -327,11 +327,11 @@ namespace hex {
|
|||||||
s_tasksFinishedCallbacks.clear();
|
s_tasksFinishedCallbacks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, bool background, std::function<void(Task&)> function) {
|
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task&)> function) {
|
||||||
std::scoped_lock lock(s_queueMutex);
|
std::scoped_lock lock(s_queueMutex);
|
||||||
|
|
||||||
// Construct new task
|
// Construct new task
|
||||||
auto task = std::make_shared<Task>(std::move(name), maxValue, background, std::move(function));
|
auto task = std::make_shared<Task>(std::move(unlocalizedName), maxValue, background, std::move(function));
|
||||||
|
|
||||||
s_tasks.emplace_back(task);
|
s_tasks.emplace_back(task);
|
||||||
|
|
||||||
@@ -344,14 +344,32 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
|
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function) {
|
||||||
log::debug("Creating task {}", name);
|
log::debug("Creating task {}", unlocalizedName.get());
|
||||||
return createTask(std::move(name), maxValue, false, std::move(function));
|
return createTask(std::move(unlocalizedName), maxValue, false, std::move(function));
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
|
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function) {
|
||||||
log::debug("Creating background task {}", name);
|
log::debug("Creating task {}", unlocalizedName.get());
|
||||||
return createTask(std::move(name), 0, true, std::move(function));
|
return createTask(std::move(unlocalizedName), maxValue, false,
|
||||||
|
[function = std::move(function)](Task&) {
|
||||||
|
function();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void(Task &)> function) {
|
||||||
|
log::debug("Creating background task {}", unlocalizedName.get());
|
||||||
|
return createTask(std::move(unlocalizedName), 0, true, std::move(function));
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void()> function) {
|
||||||
|
log::debug("Creating background task {}", unlocalizedName.get());
|
||||||
|
return createTask(std::move(unlocalizedName), 0, true,
|
||||||
|
[function = std::move(function)](Task&) {
|
||||||
|
function();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::collectGarbage() {
|
void TaskManager::collectGarbage() {
|
||||||
@@ -426,6 +444,10 @@ namespace hex {
|
|||||||
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
|
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
|
||||||
std::scoped_lock lock(s_tasksFinishedMutex);
|
std::scoped_lock lock(s_tasksFinishedMutex);
|
||||||
|
|
||||||
|
for (const auto &task : s_tasks) {
|
||||||
|
task->interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
s_tasksFinishedCallbacks.push_back(function);
|
s_tasksFinishedCallbacks.push_back(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,7 +461,7 @@ namespace hex {
|
|||||||
static auto setThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>(
|
static auto setThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>(
|
||||||
reinterpret_cast<uintptr_t>(
|
reinterpret_cast<uintptr_t>(
|
||||||
::GetProcAddress(
|
::GetProcAddress(
|
||||||
::GetModuleHandle("Kernel32.dll"),
|
::GetModuleHandleW(L"Kernel32.dll"),
|
||||||
"SetThreadDescription"
|
"SetThreadDescription"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -468,7 +490,7 @@ namespace hex {
|
|||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
pthread_setname_np(pthread_self(), name.c_str());
|
pthread_setname_np(pthread_self(), name.c_str());
|
||||||
#elif defined(OS_WEB)
|
#elif defined(OS_WEB)
|
||||||
hex::unused(name);
|
std::ignore = name;
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
pthread_setname_np(name.c_str());
|
pthread_setname_np(name.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,18 +17,30 @@ namespace hex {
|
|||||||
AutoReset<std::string> s_imageTheme;
|
AutoReset<std::string> s_imageTheme;
|
||||||
AutoReset<std::string> s_currTheme;
|
AutoReset<std::string> s_currTheme;
|
||||||
|
|
||||||
|
std::recursive_mutex s_themeMutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ThemeManager::reapplyCurrentTheme() {
|
||||||
|
ThemeManager::changeTheme(s_currTheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
|
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 };
|
(*s_themeHandlers)[name] = { colorMap, getFunction, setFunction };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
|
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
|
||||||
|
std::unique_lock lock(s_themeMutex);
|
||||||
|
|
||||||
(*s_styleHandlers)[name] = { styleMap };
|
(*s_styleHandlers)[name] = { styleMap };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::addTheme(const std::string &content) {
|
void ThemeManager::addTheme(const std::string &content) {
|
||||||
|
std::unique_lock lock(s_themeMutex);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto theme = nlohmann::json::parse(content);
|
auto theme = nlohmann::json::parse(content);
|
||||||
|
|
||||||
@@ -66,7 +78,7 @@ namespace hex {
|
|||||||
if (color == 0x00000000)
|
if (color == 0x00000000)
|
||||||
return ImVec4(0, 0, 0, -1);
|
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) {
|
nlohmann::json ThemeManager::exportCurrentTheme(const std::string &name) {
|
||||||
@@ -83,7 +95,7 @@ namespace hex {
|
|||||||
|
|
||||||
for (const auto &[key, value] : handler.colorMap) {
|
for (const auto &[key, value] : handler.colorMap) {
|
||||||
auto color = handler.getFunction(value);
|
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 +118,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::changeTheme(std::string name) {
|
void ThemeManager::changeTheme(std::string name) {
|
||||||
|
std::unique_lock lock(s_themeMutex);
|
||||||
|
|
||||||
if (!s_themes->contains(name)) {
|
if (!s_themes->contains(name)) {
|
||||||
if (s_themes->empty()) {
|
if (s_themes->empty()) {
|
||||||
return;
|
return;
|
||||||
@@ -168,12 +182,12 @@ namespace hex {
|
|||||||
const float scale = style.needsScaling ? 1_scaled : 1.0F;
|
const float scale = style.needsScaling ? 1_scaled : 1.0F;
|
||||||
|
|
||||||
if (value.is_number_float()) {
|
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;
|
**newValue = value.get<float>() * scale;
|
||||||
else
|
else
|
||||||
log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name);
|
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()) {
|
} 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);
|
**newValue = ImVec2(value[0].get<float>() * scale, value[1].get<float>() * scale);
|
||||||
else
|
else
|
||||||
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
|
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
|
||||||
@@ -191,6 +205,8 @@ namespace hex {
|
|||||||
hex::log::error("Theme '{}' has invalid image theme!", name);
|
hex::log::error("Theme '{}' has invalid image theme!", name);
|
||||||
s_imageTheme = "dark";
|
s_imageTheme = "dark";
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
s_imageTheme = "dark";
|
||||||
}
|
}
|
||||||
|
|
||||||
s_currTheme = name;
|
s_currTheme = name;
|
||||||
@@ -211,6 +227,8 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::reset() {
|
void ThemeManager::reset() {
|
||||||
|
std::unique_lock lock(s_themeMutex);
|
||||||
|
|
||||||
s_themes->clear();
|
s_themes->clear();
|
||||||
s_styleHandlers->clear();
|
s_styleHandlers->clear();
|
||||||
s_themeHandlers->clear();
|
s_themeHandlers->clear();
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ namespace hex {
|
|||||||
AutoReset<std::map<ImGuiID, std::string>> s_highlights;
|
AutoReset<std::map<ImGuiID, std::string>> s_highlights;
|
||||||
AutoReset<std::vector<std::pair<ImRect, std::string>>> s_highlightDisplays;
|
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 {
|
class IDStack {
|
||||||
public:
|
public:
|
||||||
@@ -28,6 +33,13 @@ namespace hex {
|
|||||||
idStack.push_back(0);
|
idStack.push_back(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add(const char *string) {
|
||||||
|
const ImGuiID seed = idStack.back();
|
||||||
|
const ImGuiID id = ImHashStr(string, 0, seed);
|
||||||
|
|
||||||
|
idStack.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
void add(const std::string &string) {
|
void add(const std::string &string) {
|
||||||
const ImGuiID seed = idStack.back();
|
const ImGuiID seed = idStack.back();
|
||||||
const ImGuiID id = ImHashStr(string.c_str(), string.length(), seed);
|
const ImGuiID id = ImHashStr(string.c_str(), string.length(), seed);
|
||||||
@@ -56,8 +68,46 @@ namespace hex {
|
|||||||
ImVector<ImGuiID> idStack;
|
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);
|
||||||
|
|
||||||
|
const auto window = ImGui::GetCurrentWindow();
|
||||||
|
if (window != nullptr && window->DockNode != nullptr && window->DockNode->TabBar != nullptr)
|
||||||
|
window->DockNode->TabBar->NextSelectedTabId = window->TabId;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() {
|
||||||
return s_tutorials;
|
return s_tutorials;
|
||||||
@@ -72,6 +122,28 @@ namespace hex {
|
|||||||
return s_tutorials->try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second;
|
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) {
|
void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) {
|
||||||
s_currentTutorial = s_tutorials->find(unlocalizedName);
|
s_currentTutorial = s_tutorials->find(unlocalizedName);
|
||||||
if (s_currentTutorial == s_tutorials->end())
|
if (s_currentTutorial == s_tutorials->end())
|
||||||
@@ -81,6 +153,30 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TutorialManager::drawHighlights() {
|
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) {
|
for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) {
|
||||||
const auto drawList = ImGui::GetForegroundDrawList();
|
const auto drawList = ImGui::GetForegroundDrawList();
|
||||||
|
|
||||||
@@ -241,39 +337,13 @@ namespace hex {
|
|||||||
m_onAppear();
|
m_onAppear();
|
||||||
|
|
||||||
for (const auto &[text, ids] : m_highlights) {
|
for (const auto &[text, ids] : m_highlights) {
|
||||||
IDStack idStack;
|
s_highlights->emplace(calculateId(ids), text);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TutorialManager::Tutorial::Step::removeHighlights() const {
|
void TutorialManager::Tutorial::Step::removeHighlights() const {
|
||||||
for (const auto &[text, ids] : m_highlights) {
|
for (const auto &[text, ids] : m_highlights) {
|
||||||
IDStack idStack;
|
s_highlights->erase(calculateId(ids));
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,14 +439,3 @@ 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,6 +3,7 @@
|
|||||||
|
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/helpers/auto_reset.hpp>
|
#include <hex/helpers/auto_reset.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
|
||||||
#include <wolv/io/file.hpp>
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
@@ -25,7 +26,7 @@ namespace hex {
|
|||||||
.builtin = false
|
.builtin = false
|
||||||
}).first;
|
}).first;
|
||||||
|
|
||||||
for (const auto &workspaceFolder : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
|
for (const auto &workspaceFolder : paths::Workspaces.write()) {
|
||||||
const auto workspacePath = workspaceFolder / (name + ".hexws");
|
const auto workspacePath = workspaceFolder / (name + ".hexws");
|
||||||
if (exportToFile(workspacePath)) {
|
if (exportToFile(workspacePath)) {
|
||||||
s_currentWorkspace->second.path = workspacePath;
|
s_currentWorkspace->second.path = workspacePath;
|
||||||
@@ -43,8 +44,9 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorkspaceManager::importFromFile(const std::fs::path& path) {
|
void WorkspaceManager::importFromFile(const std::fs::path& path) {
|
||||||
if (std::ranges::any_of(*s_workspaces, [path](const auto &pair) { return pair.second.path == path; }))
|
if (std::ranges::any_of(*s_workspaces, [path](const auto &pair) { return pair.second.path == path; })) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||||
if (!file.isValid()) {
|
if (!file.isValid()) {
|
||||||
@@ -74,19 +76,23 @@ namespace hex {
|
|||||||
|
|
||||||
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName, bool builtin) {
|
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName, bool builtin) {
|
||||||
if (path.empty()) {
|
if (path.empty()) {
|
||||||
if (s_currentWorkspace == s_workspaces->end())
|
if (s_currentWorkspace == s_workspaces->end()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
path = s_currentWorkspace->second.path;
|
path = s_currentWorkspace->second.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workspaceName.empty())
|
if (workspaceName.empty()) {
|
||||||
workspaceName = s_currentWorkspace->first;
|
workspaceName = s_currentWorkspace->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||||
|
|
||||||
if (!file.isValid())
|
if (!file.isValid()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
nlohmann::json json;
|
nlohmann::json json;
|
||||||
json["name"] = workspaceName;
|
json["name"] = workspaceName;
|
||||||
@@ -99,28 +105,36 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorkspaceManager::removeWorkspace(const std::string& name) {
|
void WorkspaceManager::removeWorkspace(const std::string& name) {
|
||||||
|
bool deletedCurrentWorkspace = false;
|
||||||
for (const auto &[workspaceName, workspace] : *s_workspaces) {
|
for (const auto &[workspaceName, workspace] : *s_workspaces) {
|
||||||
if (workspaceName == name) {
|
if (workspaceName == name) {
|
||||||
log::info("{}", wolv::util::toUTF8String(workspace.path));
|
log::info("Removing workspace file '{}'", wolv::util::toUTF8String(workspace.path));
|
||||||
if (wolv::io::File(workspace.path, wolv::io::File::Mode::Write).remove()) {
|
if (wolv::io::fs::remove(workspace.path)) {
|
||||||
log::info("Removed workspace '{}'", name);
|
log::info("Removed workspace '{}'", name);
|
||||||
|
|
||||||
switchWorkspace(s_workspaces->begin()->first);
|
if (workspaceName == s_currentWorkspace->first) {
|
||||||
s_workspaces->erase(workspaceName);
|
deletedCurrentWorkspace = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log::error("Failed to remove workspace '{}'", name);
|
log::error("Failed to remove workspace '{}'", name);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WorkspaceManager::reload();
|
||||||
|
|
||||||
|
if (deletedCurrentWorkspace && !s_workspaces->empty()) {
|
||||||
|
s_currentWorkspace = s_workspaces->begin();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WorkspaceManager::process() {
|
void WorkspaceManager::process() {
|
||||||
if (s_previousWorkspace != s_currentWorkspace) {
|
if (s_previousWorkspace != s_currentWorkspace) {
|
||||||
log::info("Updating workspace");
|
log::info("Updating workspace");
|
||||||
if (s_previousWorkspace != s_workspaces->end())
|
if (s_previousWorkspace != s_workspaces->end()) {
|
||||||
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first, s_previousWorkspace->second.builtin);
|
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first, s_previousWorkspace->second.builtin);
|
||||||
|
}
|
||||||
|
|
||||||
LayoutManager::closeAllViews();
|
LayoutManager::closeAllViews();
|
||||||
ImGui::LoadIniSettingsFromMemory(s_currentWorkspace->second.layout.c_str());
|
ImGui::LoadIniSettingsFromMemory(s_currentWorkspace->second.layout.c_str());
|
||||||
@@ -144,14 +158,16 @@ namespace hex {
|
|||||||
void WorkspaceManager::reload() {
|
void WorkspaceManager::reload() {
|
||||||
WorkspaceManager::reset();
|
WorkspaceManager::reset();
|
||||||
|
|
||||||
for (const auto &defaultPath : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
|
for (const auto &defaultPath : paths::Workspaces.read()) {
|
||||||
for (const auto &entry : std::fs::directory_iterator(defaultPath)) {
|
for (const auto &entry : std::fs::directory_iterator(defaultPath)) {
|
||||||
if (!entry.is_regular_file())
|
if (!entry.is_regular_file()) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const auto &path = entry.path();
|
const auto &path = entry.path();
|
||||||
if (path.extension() != ".hexws")
|
if (path.extension() != ".hexws") {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
WorkspaceManager::importFromFile(path);
|
WorkspaceManager::importFromFile(path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,18 @@
|
|||||||
namespace hex::dp {
|
namespace hex::dp {
|
||||||
|
|
||||||
int Node::s_idCounter = 1;
|
int Node::s_idCounter = 1;
|
||||||
|
static std::atomic_bool s_interrupted;
|
||||||
|
|
||||||
Node::Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
|
Node::Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
|
||||||
for (auto &attr : m_attributes)
|
for (auto &attr : m_attributes)
|
||||||
attr.setParentNode(this);
|
attr.setParentNode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Node::draw() {
|
||||||
|
this->drawNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::vector<u8>& Node::getBufferOnInput(u32 index) {
|
const std::vector<u8>& Node::getBufferOnInput(u32 index) {
|
||||||
auto attribute = this->getConnectedInputAttribute(index);
|
auto attribute = this->getConnectedInputAttribute(index);
|
||||||
|
|
||||||
@@ -29,9 +35,6 @@ namespace hex::dp {
|
|||||||
|
|
||||||
auto &outputData = attribute->getOutputData();
|
auto &outputData = attribute->getOutputData();
|
||||||
|
|
||||||
if (outputData.empty())
|
|
||||||
throwNodeError("No data available at connected attribute");
|
|
||||||
|
|
||||||
return outputData;
|
return outputData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,9 +151,56 @@ namespace hex::dp {
|
|||||||
m_overlay->getData() = data;
|
m_overlay->getData() = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[noreturn]] void Node::throwNodeError(const std::string &message) {
|
||||||
|
throw NodeError { this, message };
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::setAttributes(std::vector<Attribute> attributes) {
|
||||||
|
m_attributes = std::move(attributes);
|
||||||
|
|
||||||
|
for (auto &attr : m_attributes)
|
||||||
|
attr.setParentNode(this);
|
||||||
|
}
|
||||||
|
|
||||||
void Node::setIdCounter(int id) {
|
void Node::setIdCounter(int id) {
|
||||||
if (id > s_idCounter)
|
if (id > s_idCounter)
|
||||||
s_idCounter = id;
|
s_idCounter = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Attribute& Node::getAttribute(u32 index) {
|
||||||
|
if (index >= this->getAttributes().size())
|
||||||
|
throw std::runtime_error("Attribute index out of bounds!");
|
||||||
|
|
||||||
|
return this->getAttributes()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Attribute *Node::getConnectedInputAttribute(u32 index) {
|
||||||
|
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
|
||||||
|
|
||||||
|
if (connectedAttribute.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return connectedAttribute.begin()->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::markInputProcessed(u32 index) {
|
||||||
|
const auto &[iter, inserted] = m_processedInputs.insert(index);
|
||||||
|
if (!inserted)
|
||||||
|
throwNodeError("Recursion detected!");
|
||||||
|
|
||||||
|
if (s_interrupted) {
|
||||||
|
s_interrupted = false;
|
||||||
|
throwNodeError("Execution interrupted!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::unmarkInputProcessed(u32 index) {
|
||||||
|
m_processedInputs.erase(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::interrupt() {
|
||||||
|
s_interrupted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
|
#include <algorithm>
|
||||||
#include <hex/helpers/crypto.hpp>
|
#include <hex/helpers/crypto.hpp>
|
||||||
|
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
|
|
||||||
#include <wolv/utils/guards.hpp>
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/utils/expected.hpp>
|
||||||
|
|
||||||
#include <mbedtls/version.h>
|
#include <mbedtls/version.h>
|
||||||
#include <mbedtls/base64.h>
|
#include <mbedtls/base64.h>
|
||||||
@@ -496,8 +498,8 @@ namespace hex::crypt {
|
|||||||
return encodeLeb128<i128>(value);
|
return encodeLeb128<i128>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<u8> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
|
static wolv::util::Expected<std::vector<u8>, int> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key,
|
||||||
std::vector<u8> output;
|
std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::span<const u8> &input) {
|
||||||
|
|
||||||
if (input.empty())
|
if (input.empty())
|
||||||
return {};
|
return {};
|
||||||
@@ -507,38 +509,65 @@ namespace hex::crypt {
|
|||||||
mbedtls_cipher_context_t ctx;
|
mbedtls_cipher_context_t ctx;
|
||||||
auto cipherInfo = mbedtls_cipher_info_from_type(type);
|
auto cipherInfo = mbedtls_cipher_info_from_type(type);
|
||||||
|
|
||||||
|
if (cipherInfo == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
mbedtls_cipher_setup(&ctx, cipherInfo);
|
int setupResult = mbedtls_cipher_setup(&ctx, cipherInfo);
|
||||||
mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
|
if (setupResult != 0)
|
||||||
|
return wolv::util::Unexpected(setupResult);
|
||||||
|
|
||||||
|
int setKeyResult = mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
|
||||||
|
if (setKeyResult != 0)
|
||||||
|
return wolv::util::Unexpected(setKeyResult);
|
||||||
|
|
||||||
std::array<u8, 16> nonceCounter = { 0 };
|
std::array<u8, 16> nonceCounter = { 0 };
|
||||||
std::copy(nonce.begin(), nonce.end(), nonceCounter.begin());
|
|
||||||
std::copy(iv.begin(), iv.end(), nonceCounter.begin() + 8);
|
auto mode = mbedtls_cipher_get_cipher_mode(&ctx);
|
||||||
|
|
||||||
|
// if we are in ECB mode, we don't need to set the nonce
|
||||||
|
if (mode != MBEDTLS_MODE_ECB) {
|
||||||
|
std::ranges::copy(nonce, nonceCounter.begin());
|
||||||
|
std::ranges::copy(iv, nonceCounter.begin() + 8);
|
||||||
|
}
|
||||||
|
|
||||||
size_t outputSize = input.size() + mbedtls_cipher_get_block_size(&ctx);
|
size_t outputSize = input.size() + mbedtls_cipher_get_block_size(&ctx);
|
||||||
output.resize(outputSize, 0x00);
|
std::vector<u8> output(outputSize, 0x00);
|
||||||
mbedtls_cipher_crypt(&ctx, nonceCounter.data(), nonceCounter.size(), input.data(), input.size(), output.data(), &outputSize);
|
|
||||||
|
|
||||||
|
int cryptResult = 0;
|
||||||
|
if (mode == MBEDTLS_MODE_ECB) {
|
||||||
|
cryptResult = mbedtls_cipher_crypt(&ctx, nullptr, 0, input.data(), input.size(), output.data(), &outputSize);
|
||||||
|
} else {
|
||||||
|
cryptResult = mbedtls_cipher_crypt(&ctx, nonceCounter.data(), nonceCounter.size(), input.data(), input.size(), output.data(), &outputSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// free regardless of the result
|
||||||
mbedtls_cipher_free(&ctx);
|
mbedtls_cipher_free(&ctx);
|
||||||
|
|
||||||
|
if (cryptResult != 0) {
|
||||||
|
return wolv::util::Unexpected(cryptResult);
|
||||||
|
}
|
||||||
|
|
||||||
output.resize(input.size());
|
output.resize(input.size());
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
|
wolv::util::Expected<std::vector<u8>, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
|
||||||
switch (keyLength) {
|
switch (keyLength) {
|
||||||
case KeyLength::Key128Bits:
|
case KeyLength::Key128Bits:
|
||||||
if (key.size() != 128 / 8) return {};
|
if (key.size() != 128 / 8)
|
||||||
|
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||||
break;
|
break;
|
||||||
case KeyLength::Key192Bits:
|
case KeyLength::Key192Bits:
|
||||||
if (key.size() != 192 / 8) return {};
|
if (key.size() != 192 / 8)
|
||||||
|
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||||
break;
|
break;
|
||||||
case KeyLength::Key256Bits:
|
case KeyLength::Key256Bits:
|
||||||
if (key.size() != 256 / 8) return {};
|
if (key.size() != 256 / 8)
|
||||||
|
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return {};
|
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
mbedtls_cipher_type_t type;
|
mbedtls_cipher_type_t type;
|
||||||
@@ -568,7 +597,7 @@ namespace hex::crypt {
|
|||||||
type = MBEDTLS_CIPHER_AES_128_XTS;
|
type = MBEDTLS_CIPHER_AES_128_XTS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return {};
|
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
type = mbedtls_cipher_type_t(type + u8(keyLength));
|
type = mbedtls_cipher_type_t(type + u8(keyLength));
|
||||||
|
|||||||
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() / "imhex");
|
||||||
|
|
||||||
|
#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)
|
||||||
|
std::ignore = 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#if defined(OS_WEB)
|
#if defined(OS_WEB)
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#else
|
#else
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
#include <nfd.hpp>
|
#include <nfd.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -32,6 +33,9 @@
|
|||||||
#include <wolv/io/fs.hpp>
|
#include <wolv/io/fs.hpp>
|
||||||
#include <wolv/utils/string.hpp>
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fmt/xchar.h>
|
||||||
|
|
||||||
namespace hex::fs {
|
namespace hex::fs {
|
||||||
|
|
||||||
static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback;
|
static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback;
|
||||||
@@ -47,13 +51,11 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
hex::unused(
|
std::ignore = ShellExecuteW(nullptr, L"open", filePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
ShellExecute(nullptr, "open", wolv::util::toUTF8String(filePath).c_str(), nullptr, nullptr, SW_SHOWNORMAL)
|
|
||||||
);
|
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
hex::unused(system(
|
std::ignore = system(
|
||||||
hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str()
|
hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str()
|
||||||
));
|
);
|
||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
executeCmd({"xdg-open", wolv::util::toUTF8String(filePath)});
|
executeCmd({"xdg-open", wolv::util::toUTF8String(filePath)});
|
||||||
#endif
|
#endif
|
||||||
@@ -66,13 +68,12 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
hex::unused(system(
|
auto args = fmt::format(L"\"{}\"", dirPath.c_str());
|
||||||
hex::format("explorer.exe {}", wolv::util::toUTF8String(dirPath)).c_str()
|
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
|
||||||
));
|
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
hex::unused(system(
|
std::ignore = system(
|
||||||
hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str()
|
hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str()
|
||||||
));
|
);
|
||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
executeCmd({"xdg-open", wolv::util::toUTF8String(dirPath)});
|
executeCmd({"xdg-open", wolv::util::toUTF8String(dirPath)});
|
||||||
#endif
|
#endif
|
||||||
@@ -85,16 +86,15 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
hex::unused(system(
|
auto args = fmt::format(L"/select,\"{}\"", selectedFilePath.c_str());
|
||||||
hex::format(R"(explorer.exe /select,"{}")", wolv::util::toUTF8String(selectedFilePath)).c_str()
|
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
|
||||||
));
|
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
hex::unused(system(
|
std::ignore = system(
|
||||||
hex::format(
|
hex::format(
|
||||||
R"(osascript -e 'tell application "Finder" to reveal POSIX file "{}"')",
|
R"(osascript -e 'tell application "Finder" to reveal POSIX file "{}"')",
|
||||||
wolv::util::toUTF8String(selectedFilePath)
|
wolv::util::toUTF8String(selectedFilePath)
|
||||||
).c_str()
|
).c_str()
|
||||||
));
|
);
|
||||||
system(R"(osascript -e 'tell application "Finder" to activate')");
|
system(R"(osascript -e 'tell application "Finder" to activate')");
|
||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
// Fallback to only opening the folder for now
|
// Fallback to only opening the folder for now
|
||||||
@@ -123,7 +123,13 @@ namespace hex::fs {
|
|||||||
// Call callback that will write the file
|
// Call callback that will write the file
|
||||||
Module._fileBrowserCallback(stringToNewUTF8("/savedFiles/" + filename));
|
Module._fileBrowserCallback(stringToNewUTF8("/savedFiles/" + filename));
|
||||||
|
|
||||||
let data = FS.readFile("/savedFiles/" + filename);
|
let data;
|
||||||
|
try {
|
||||||
|
data = FS.readFile("/savedFiles/" + filename);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const reader = Object.assign(new FileReader(), {
|
const reader = Object.assign(new FileReader(), {
|
||||||
onload: () => {
|
onload: () => {
|
||||||
@@ -191,6 +197,7 @@ namespace hex::fs {
|
|||||||
else if (!validExtensions.empty())
|
else if (!validExtensions.empty())
|
||||||
path = "file." + validExtensions[0].spec;
|
path = "file." + validExtensions[0].spec;
|
||||||
|
|
||||||
|
std::fs::create_directory("/savedFiles");
|
||||||
callJs_saveFile(path.filename().string().c_str());
|
callJs_saveFile(path.filename().string().c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -286,170 +293,6 @@ namespace hex::fs {
|
|||||||
|
|
||||||
#endif
|
#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) {
|
bool isPathWritable(const std::fs::path &path) {
|
||||||
constexpr static auto TestFileName = "__imhex__tmp__";
|
constexpr static auto TestFileName = "__imhex__tmp__";
|
||||||
|
|
||||||
|
|||||||
@@ -41,17 +41,21 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::setProxyUrl(std::string proxy) {
|
void HttpRequest::setProxyUrl(std::string proxy) {
|
||||||
hex::unused(proxy);
|
std::ignore = proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::setProxyState(bool state) {
|
void HttpRequest::setProxyState(bool state) {
|
||||||
hex::unused(state);
|
std::ignore = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpRequest::checkProxyErrors() { }
|
void HttpRequest::checkProxyErrors() { }
|
||||||
|
|
||||||
int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
|
int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
|
||||||
hex::unused(contents, dlTotal, dlNow, ulTotal, ulNow);
|
std::ignore = contents;
|
||||||
|
std::ignore = dlTotal;
|
||||||
|
std::ignore = dlNow;
|
||||||
|
std::ignore = ulTotal;
|
||||||
|
std::ignore = ulNow;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
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,14 +1,17 @@
|
|||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
|
#include <hex/api/task_manager.hpp>
|
||||||
#include <hex/api/event_manager.hpp>
|
#include <hex/api/event_manager.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
#include <hex/helpers/fmt.hpp>
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
|
||||||
#include <wolv/io/file.hpp>
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
#include <hex/api/task_manager.hpp>
|
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
@@ -40,10 +43,15 @@ namespace hex::log {
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
std::recursive_mutex& getLoggerMutex() {
|
void lockLoggerMutex() {
|
||||||
return s_loggerMutex;
|
s_loggerMutex.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unlockLoggerMutex() {
|
||||||
|
s_loggerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool isLoggingSuspended() {
|
bool isLoggingSuspended() {
|
||||||
return s_loggingSuspended;
|
return s_loggingSuspended;
|
||||||
}
|
}
|
||||||
@@ -74,7 +82,7 @@ namespace hex::log {
|
|||||||
void redirectToFile() {
|
void redirectToFile() {
|
||||||
if (s_loggerFile.isValid()) return;
|
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);
|
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 = 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();
|
s_loggerFile.disableBuffering();
|
||||||
@@ -136,15 +144,13 @@ namespace hex::log {
|
|||||||
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
|
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
|
void assertionHandler(const char* exprString, const char* file, int line) {
|
||||||
if (!expr) {
|
|
||||||
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
||||||
|
|
||||||
#if defined (DEBUG)
|
#if defined (DEBUG)
|
||||||
std::abort();
|
std::abort();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
namespace color {
|
namespace color {
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
#include <hex/helpers/default_paths.hpp>
|
||||||
|
|
||||||
#include <wolv/utils/guards.hpp>
|
#include <wolv/utils/guards.hpp>
|
||||||
#include <wolv/utils/string.hpp>
|
#include <wolv/utils/string.hpp>
|
||||||
@@ -29,7 +30,7 @@ namespace hex::magic {
|
|||||||
std::string magicFiles;
|
std::string magicFiles;
|
||||||
|
|
||||||
std::error_code error;
|
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)) {
|
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
||||||
auto path = std::fs::absolute(entry.path());
|
auto path = std::fs::absolute(entry.path());
|
||||||
|
|
||||||
@@ -64,12 +65,12 @@ namespace hex::magic {
|
|||||||
if (magicFiles->empty())
|
if (magicFiles->empty())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
std::array<char, 1024> cwd = { 0x00 };
|
std::array<char, 1024> cwd = { };
|
||||||
if (getcwd(cwd.data(), cwd.size()) == nullptr)
|
if (getcwd(cwd.data(), cwd.size()) == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::optional<std::fs::path> magicFolder;
|
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)) {
|
if (std::fs::exists(dir) && fs::isPathWritable(dir)) {
|
||||||
magicFolder = dir;
|
magicFolder = dir;
|
||||||
break;
|
break;
|
||||||
@@ -105,8 +106,13 @@ namespace hex::magic {
|
|||||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||||
|
|
||||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
if (auto description = magic_buffer(ctx, data.data(), data.size()); description != nullptr) {
|
||||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
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); };
|
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||||
|
|
||||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
if (auto mimeType = magic_buffer(ctx, data.data(), data.size()); mimeType != nullptr) {
|
||||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
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); };
|
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||||
|
|
||||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
if (auto extension = magic_buffer(ctx, data.data(), data.size()); extension != nullptr) {
|
||||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
auto result = wolv::util::replaceStrings(extension, "\\012-", "\n-");
|
||||||
|
if (result.ends_with("- ???"))
|
||||||
|
result = result.substr(0, result.size() - 5);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ namespace hex {
|
|||||||
void close() override { }
|
void close() override { }
|
||||||
|
|
||||||
void readRaw(u64 offset, void *buffer, size_t size) override {
|
void readRaw(u64 offset, void *buffer, size_t size) override {
|
||||||
hex::unused(offset, buffer, size);
|
std::ignore = offset;
|
||||||
|
std::ignore = buffer;
|
||||||
|
std::ignore = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeRaw(u64 offset, const void *buffer, size_t size) override {
|
void writeRaw(u64 offset, const void *buffer, size_t size) override {
|
||||||
@@ -44,7 +46,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void resizeRaw(u64 newSize) override {
|
void resizeRaw(u64 newSize) override {
|
||||||
hex::unused(newSize);
|
std::ignore = newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void insertRaw(u64 offset, u64 size) override {
|
void insertRaw(u64 offset, u64 size) override {
|
||||||
@@ -138,7 +140,7 @@ namespace hex {
|
|||||||
result.push_back(addressBytes[2]);
|
result.push_back(addressBytes[2]);
|
||||||
result.push_back(addressBytes[1]);
|
result.push_back(addressBytes[1]);
|
||||||
result.push_back(addressBytes[0]);
|
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)
|
for (auto byte : bytes)
|
||||||
result.push_back(byte);
|
result.push_back(byte);
|
||||||
@@ -189,7 +191,7 @@ namespace hex {
|
|||||||
result.push_back(addressBytes[2]);
|
result.push_back(addressBytes[2]);
|
||||||
result.push_back(addressBytes[1]);
|
result.push_back(addressBytes[1]);
|
||||||
result.push_back(addressBytes[0]);
|
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)
|
for (auto byte : bytes)
|
||||||
result.push_back(byte);
|
result.push_back(byte);
|
||||||
|
|||||||
118
lib/libimhex/source/helpers/semantic_version.cpp
Normal file
118
lib/libimhex/source/helpers/semantic_version.cpp
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
#include <hex/helpers/semantic_version.hpp>
|
||||||
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
SemanticVersion::SemanticVersion(const char *version) : SemanticVersion(std::string(version)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SemanticVersion::SemanticVersion(std::string_view version) : SemanticVersion(std::string(version.begin(), version.end())) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SemanticVersion::SemanticVersion(std::string version) {
|
||||||
|
if (version.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (version.starts_with("v"))
|
||||||
|
version = version.substr(1);
|
||||||
|
|
||||||
|
m_parts = wolv::util::splitString(version, ".");
|
||||||
|
|
||||||
|
if (m_parts.size() != 3 && m_parts.size() != 4) {
|
||||||
|
m_parts.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_parts.back().contains("-")) {
|
||||||
|
auto buildTypeParts = wolv::util::splitString(m_parts.back(), "-");
|
||||||
|
if (buildTypeParts.size() != 2) {
|
||||||
|
m_parts.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_parts.back() = buildTypeParts[0];
|
||||||
|
m_buildType = buildTypeParts[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 SemanticVersion::major() const {
|
||||||
|
if (!isValid()) return 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return std::stoul(m_parts[0]);
|
||||||
|
} catch (...) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 SemanticVersion::minor() const {
|
||||||
|
if (!isValid()) return 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return std::stoul(m_parts[1]);
|
||||||
|
} catch (...) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 SemanticVersion::patch() const {
|
||||||
|
if (!isValid()) return 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return std::stoul(m_parts[2]);
|
||||||
|
} catch (...) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemanticVersion::nightly() const {
|
||||||
|
if (!isValid()) return false;
|
||||||
|
|
||||||
|
return m_parts.size() == 4 && m_parts[3] == "WIP";
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& SemanticVersion::buildType() const {
|
||||||
|
return m_buildType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SemanticVersion::isValid() const {
|
||||||
|
return !m_parts.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SemanticVersion::operator==(const SemanticVersion& other) const {
|
||||||
|
return this->m_parts == other.m_parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::strong_ordering SemanticVersion::operator<=>(const SemanticVersion &other) const {
|
||||||
|
if (*this == other)
|
||||||
|
return std::strong_ordering::equivalent;
|
||||||
|
|
||||||
|
if (this->major() > other.major())
|
||||||
|
return std::strong_ordering::greater;
|
||||||
|
if (this->minor() > other.minor())
|
||||||
|
return std::strong_ordering::greater;
|
||||||
|
if (this->patch() > other.patch())
|
||||||
|
return std::strong_ordering::greater;
|
||||||
|
if (!this->nightly() && other.nightly())
|
||||||
|
return std::strong_ordering::greater;
|
||||||
|
|
||||||
|
return std::strong_ordering::less;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SemanticVersion::get(bool withBuildType) const {
|
||||||
|
if (!isValid()) return "";
|
||||||
|
|
||||||
|
auto result = wolv::util::combineStrings(m_parts, ".");
|
||||||
|
|
||||||
|
if (withBuildType && !m_buildType.empty())
|
||||||
|
result += hex::format("-{}", m_buildType);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -90,11 +90,7 @@ namespace hex {
|
|||||||
bool Tar::contains(const std::fs::path &path) const {
|
bool Tar::contains(const std::fs::path &path) const {
|
||||||
mtar_header_t header;
|
mtar_header_t header;
|
||||||
|
|
||||||
auto fixedPath = path.string();
|
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return mtar_find(m_ctx.get(), fixedPath.c_str(), &header) == MTAR_ESUCCESS;
|
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 {
|
std::vector<u8> Tar::readVector(const std::fs::path &path) const {
|
||||||
mtar_header_t header;
|
mtar_header_t header;
|
||||||
|
|
||||||
auto fixedPath = path.string();
|
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
|
||||||
#endif
|
|
||||||
int ret = mtar_find(m_ctx.get(), fixedPath.c_str(), &header);
|
int ret = mtar_find(m_ctx.get(), fixedPath.c_str(), &header);
|
||||||
if (ret != MTAR_ESUCCESS){
|
if (ret != MTAR_ESUCCESS){
|
||||||
log::debug("Failed to read vector from path {} in tarred file {}: {}",
|
log::debug("Failed to read vector from path {} in tarred file {}: {}",
|
||||||
@@ -143,18 +136,12 @@ namespace hex {
|
|||||||
for (const auto &part : path.parent_path()) {
|
for (const auto &part : path.parent_path()) {
|
||||||
pathPart /= part;
|
pathPart /= part;
|
||||||
|
|
||||||
auto fixedPath = pathPart.string();
|
auto fixedPath = wolv::io::fs::toNormalizedPathString(pathPart);
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
|
||||||
#endif
|
|
||||||
mtar_write_dir_header(m_ctx.get(), fixedPath.c_str());
|
mtar_write_dir_header(m_ctx.get(), fixedPath.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fixedPath = path.string();
|
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
|
||||||
#endif
|
|
||||||
mtar_write_file_header(m_ctx.get(), fixedPath.c_str(), data.size());
|
mtar_write_file_header(m_ctx.get(), fixedPath.c_str(), data.size());
|
||||||
mtar_write_data(m_ctx.get(), data.data(), data.size());
|
mtar_write_data(m_ctx.get(), data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user