Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4badc5fd4 | ||
|
|
49b4b19c21 | ||
|
|
068520f923 | ||
|
|
f723ee3dee | ||
|
|
ce1f9181cf | ||
|
|
a043f93e72 | ||
|
|
c0cb4a5123 | ||
|
|
db64c517a4 | ||
|
|
9602d98307 | ||
|
|
d85739b5aa | ||
|
|
1828006c2b | ||
|
|
aff259387b | ||
|
|
fe80cff908 | ||
|
|
ae183f2c43 | ||
|
|
9ae80e4d62 | ||
|
|
e920c6aba8 | ||
|
|
5875f989d8 | ||
|
|
d95daf392f | ||
|
|
6c4997ac29 | ||
|
|
a8d239febd | ||
|
|
6b52aa0be1 | ||
|
|
19c3c07b99 | ||
|
|
ef8aba25e8 | ||
|
|
c2f042643a | ||
|
|
baf1afaca0 | ||
|
|
de8f2b476e | ||
|
|
bc6c362bd5 | ||
|
|
bff22b12bd | ||
|
|
63f2bd57cd | ||
|
|
5518aaa29d | ||
|
|
73856c6c32 | ||
|
|
018c210777 | ||
|
|
59a47845f0 | ||
|
|
11b530a526 | ||
|
|
f6b792020a | ||
|
|
c50dc3313f | ||
|
|
0e5a49c331 | ||
|
|
74c12685a0 | ||
|
|
93af6edfe9 | ||
|
|
977578a91e | ||
|
|
e980b1cb48 | ||
|
|
b5edef36bc | ||
|
|
1208624c77 | ||
|
|
eff435fc29 | ||
|
|
af1f536b0f | ||
|
|
6affec227d | ||
|
|
e0a120ad08 | ||
|
|
3383cc1d92 | ||
|
|
7eade2df0c | ||
|
|
bd1105f45d | ||
|
|
a7532b4d80 | ||
|
|
11240a1a0f | ||
|
|
ddb7bdb428 | ||
|
|
b912778e62 | ||
|
|
dc1fde07f5 | ||
|
|
1e089d9c37 | ||
|
|
e0e9690fd5 | ||
|
|
bbbea0adcd | ||
|
|
f8ef719e31 | ||
|
|
e560d5f88c | ||
|
|
3f9e2f78f9 | ||
|
|
d29c291ff7 | ||
|
|
e62e0a9d70 | ||
|
|
0ccc495308 | ||
|
|
95ca7a071f | ||
|
|
4e100c4fc3 | ||
|
|
abf90e6eaa | ||
|
|
dd28d5b367 | ||
|
|
d7fabe89f2 | ||
|
|
069b64679c | ||
|
|
7a8701f030 | ||
|
|
dafb693b59 | ||
|
|
8df94a0b91 | ||
|
|
e9c99b6da4 | ||
|
|
144dcce52f | ||
|
|
f6c5cf0cb8 | ||
|
|
c3ecfea9bb | ||
|
|
5c7dbaca9c | ||
|
|
2982ce12f9 | ||
|
|
eaf3b1ae36 | ||
|
|
c2da3b5c88 | ||
|
|
815267962d | ||
|
|
60da11e8d9 | ||
|
|
244596bcb0 | ||
|
|
27be4123c3 | ||
|
|
158ba57ae5 | ||
|
|
bb0c8ab6d4 | ||
|
|
e35d443079 | ||
|
|
55a401b3dc | ||
|
|
0ecf546b80 | ||
|
|
4a14b8ddfb | ||
|
|
61f47fca35 | ||
|
|
ab9eb65ac3 | ||
|
|
04ca1b2f13 | ||
|
|
24e410c41a | ||
|
|
9c0cf0116c | ||
|
|
3ea7715576 | ||
|
|
455617e037 | ||
|
|
0ff5a468e5 | ||
|
|
fb1b22c35f | ||
|
|
f67b3a624b | ||
|
|
146b28d184 | ||
|
|
f90e9931bb | ||
|
|
36702df4d2 | ||
|
|
e5e991eef1 | ||
|
|
5a2cacbb22 | ||
|
|
9ec68f2426 | ||
|
|
37c69f1be1 | ||
|
|
4907be5edb | ||
|
|
a426633df6 | ||
|
|
585abd51ea | ||
|
|
bc98912424 | ||
|
|
8c54b1650e | ||
|
|
fba1753457 | ||
|
|
7633fc891c | ||
|
|
976b41ffd5 | ||
|
|
d647d4291f | ||
|
|
45e895d746 | ||
|
|
c5b3632379 | ||
|
|
9ebea99c80 | ||
|
|
bd90af5a2a | ||
|
|
f48325b11e | ||
|
|
7a982fb681 | ||
|
|
da160271ad | ||
|
|
db945fc9b1 | ||
|
|
59c69f21c9 | ||
|
|
0dc50a7306 | ||
|
|
33223ed594 | ||
|
|
ed44971875 | ||
|
|
391d1d385e | ||
|
|
acf34585a5 | ||
|
|
7920ad3be6 | ||
|
|
67c2ccdb89 | ||
|
|
2638a61b59 | ||
|
|
cfc83bc92f | ||
|
|
4528457e93 | ||
|
|
60671f810d | ||
|
|
8bd4789a00 | ||
|
|
1a4ae4b22b | ||
|
|
2d3ab3cd46 | ||
|
|
eb89ac2829 | ||
|
|
6b9f07e10b | ||
|
|
323b6a77f2 | ||
|
|
b75507bafd | ||
|
|
c0041e087b | ||
|
|
9f9defe7fe | ||
|
|
6f06f58c24 | ||
|
|
0a04cfaeee | ||
|
|
b2bd4b3ff6 | ||
|
|
3048aa9634 | ||
|
|
b69358b7a6 | ||
|
|
0b89fa479e | ||
|
|
b4fb07fee7 | ||
|
|
837f85f0b2 | ||
|
|
3c71473e14 | ||
|
|
2cc4e4eb66 | ||
|
|
79123dd623 | ||
|
|
72889bcd2d | ||
|
|
8a1316d2bc | ||
|
|
b6eee838dd | ||
|
|
6bdf44423d | ||
|
|
a3b9012ee1 | ||
|
|
d9e5c17fda | ||
|
|
659f72ae8c | ||
|
|
9393a5f8a4 | ||
|
|
82b7ff33f2 | ||
|
|
bb29169e5c | ||
|
|
d2c228892f | ||
|
|
b6f8b69f54 | ||
|
|
a8fa25b49e | ||
|
|
15acc10df5 | ||
|
|
0f3dbdbe96 | ||
|
|
90f598bbe5 | ||
|
|
92816c58b0 | ||
|
|
fdaa11ba07 | ||
|
|
65ef2a6f2c | ||
|
|
13c4522523 | ||
|
|
1f9e0c4ad0 | ||
|
|
e8f7965a36 | ||
|
|
f7deacbf8d | ||
|
|
1352d7f368 | ||
|
|
c0982c368a | ||
|
|
81c9e6efbb | ||
|
|
8bdea890ee | ||
|
|
fb3f35f28c | ||
|
|
9ddfcfa67a | ||
|
|
5a6965f47f | ||
|
|
2375092641 | ||
|
|
20b46190f7 | ||
|
|
9bf15002d2 | ||
|
|
19e442b02b | ||
|
|
1462ab8605 | ||
|
|
a448f2e439 | ||
|
|
8d6511b0bb | ||
|
|
09bcc04457 | ||
|
|
840c053b78 | ||
|
|
b15f643175 | ||
|
|
fedf119f3d | ||
|
|
a58c64e19d | ||
|
|
ca5aba0b88 | ||
|
|
a06ee3a53f | ||
|
|
71501a5f9e | ||
|
|
021e6e7dd5 | ||
|
|
f00bd996b8 | ||
|
|
4e4ed4bf4e | ||
|
|
219b8bd347 | ||
|
|
c4744cf05d | ||
|
|
9847074e66 | ||
|
|
74142d0960 | ||
|
|
637cc91e05 | ||
|
|
09c4042b0a | ||
|
|
cb865912a4 | ||
|
|
f066af54c6 | ||
|
|
5d96c27c49 | ||
|
|
9dba69e73e | ||
|
|
fbcc33a107 | ||
|
|
43ee34e96b | ||
|
|
3199881132 | ||
|
|
5579b69d57 | ||
|
|
ce3e581e60 | ||
|
|
b49bff7695 | ||
|
|
b6e20cc15e | ||
|
|
96eb17e0c8 | ||
|
|
0d7396d141 | ||
|
|
1a50c804ff | ||
|
|
dbafec2394 | ||
|
|
0e6a4173d6 | ||
|
|
29ca4e870e | ||
|
|
43fa969337 | ||
|
|
9125397762 | ||
|
|
253de4ffd3 | ||
|
|
bafa30848e | ||
|
|
904d4e98f4 | ||
|
|
92c0005e89 | ||
|
|
d72ae5faec | ||
|
|
5c61582364 | ||
|
|
cbb0c53abf | ||
|
|
6483c8b4a6 | ||
|
|
48b2f74b12 | ||
|
|
028dbab360 | ||
|
|
3348f0f3f8 | ||
|
|
a071b97c45 | ||
|
|
a0a7b54a95 | ||
|
|
1e6d80ed95 | ||
|
|
d8eec7cc1f | ||
|
|
e0aec1f7aa | ||
|
|
b6a210fc67 | ||
|
|
0d86970f84 | ||
|
|
836d32c8d9 | ||
|
|
217d001177 | ||
|
|
c1c9300a25 | ||
|
|
b4a75222fd | ||
|
|
0e113bb25e | ||
|
|
2ea419e00a | ||
|
|
9920147530 | ||
|
|
05877345db | ||
|
|
1480a14414 | ||
|
|
de683ce850 | ||
|
|
55130697c5 | ||
|
|
03fb805a89 | ||
|
|
c251b496b2 | ||
|
|
c574e93208 | ||
|
|
44d7b76eb1 | ||
|
|
a0d3dcabdd | ||
|
|
50465c2827 | ||
|
|
636a326591 | ||
|
|
258c9c50bb | ||
|
|
ba715d93a8 | ||
|
|
a2ca4364e6 | ||
|
|
060400b375 | ||
|
|
f2055bb413 | ||
|
|
8dd8bea745 | ||
|
|
e7ac2795cd | ||
|
|
aadb3e53a3 | ||
|
|
0619f6aa6e | ||
|
|
c1c885541d | ||
|
|
96d2099036 | ||
|
|
5a02c74900 | ||
|
|
e2f04b4cb0 | ||
|
|
318636ce8c | ||
|
|
c401fd77e9 | ||
|
|
d6c44e3393 | ||
|
|
45120ece4a | ||
|
|
e61e731656 | ||
|
|
f2cee8a338 | ||
|
|
e58a412918 | ||
|
|
94e3f77731 | ||
|
|
8e41ec7543 | ||
|
|
02f952cef3 | ||
|
|
c9c55b00db | ||
|
|
4d611f4024 | ||
|
|
3b4da08524 | ||
|
|
0e08185050 | ||
|
|
696584caa7 | ||
|
|
c0c9f1bbfe | ||
|
|
e684efc225 | ||
|
|
31ded012fb | ||
|
|
d253413d73 | ||
|
|
345523e2c6 | ||
|
|
b69946ad36 | ||
|
|
e649769d5c | ||
|
|
33e09b50ea | ||
|
|
c00b73bc35 | ||
|
|
ba5c3251f8 | ||
|
|
e6e9dddba2 | ||
|
|
d47b0cbeaf | ||
|
|
94a7c8863f | ||
|
|
dfdeaf1836 | ||
|
|
0a35580620 | ||
|
|
302bbff3a3 | ||
|
|
f66dacf430 | ||
|
|
c7d1f4be3d | ||
|
|
44848d44de | ||
|
|
ce18a5ed50 | ||
|
|
179391c4e0 | ||
|
|
7bb6e48ca7 | ||
|
|
5263d67cc3 | ||
|
|
df49d29e83 | ||
|
|
d585b0889a | ||
|
|
dc268a9f12 | ||
|
|
97f38c6ae5 | ||
|
|
0b73d86f69 | ||
|
|
47f71cb7e5 | ||
|
|
bb9f6743dc | ||
|
|
b071ea0124 | ||
|
|
7dfd907c1c | ||
|
|
ca916f9a16 | ||
|
|
b67d2d2320 | ||
|
|
5aa3181ffd | ||
|
|
4d48a1ff69 | ||
|
|
39a389405f | ||
|
|
8ee7fab4bd | ||
|
|
0f58b79a4a | ||
|
|
b415c514aa | ||
|
|
9869ab8744 | ||
|
|
c5811fbfbb | ||
|
|
8b79f526a7 | ||
|
|
a0ce5356a8 | ||
|
|
418b9be377 | ||
|
|
d6da908caf | ||
|
|
e5410cf323 | ||
|
|
ffcf9646e8 | ||
|
|
46d038f244 | ||
|
|
58369fb768 | ||
|
|
a66a8c9780 | ||
|
|
1f762503aa | ||
|
|
fbc4561220 | ||
|
|
5b1f63fa0d | ||
|
|
6687c73f0f | ||
|
|
4917f52db1 | ||
|
|
d88ba52ec5 | ||
|
|
743b515950 | ||
|
|
f6845f0c83 | ||
|
|
3dfebf68bc | ||
|
|
542a3f4de5 | ||
|
|
a48b74e9d3 | ||
|
|
4284126fb9 | ||
|
|
790878048e | ||
|
|
11449f4514 | ||
|
|
3fa08ede74 | ||
|
|
d2987d6f3b | ||
|
|
7aa0b9b2e3 | ||
|
|
3d49d12b2d | ||
|
|
14bd8e68cb | ||
|
|
ce618fb021 | ||
|
|
58d80f39e3 | ||
|
|
04c3675d38 | ||
|
|
760ab5f266 | ||
|
|
08b3be3c7e | ||
|
|
6448a18076 | ||
|
|
ce04d6500b | ||
|
|
8e84add23b | ||
|
|
db4351626e | ||
|
|
ff93981bd9 | ||
|
|
94d799d6a3 | ||
|
|
cb47b42a8e | ||
|
|
186f91a0a5 | ||
|
|
3ea208938c | ||
|
|
7eb816fdb0 | ||
|
|
e71c630153 | ||
|
|
cf5b1dbee7 | ||
|
|
1636f59f9d | ||
|
|
b7c1c507d6 | ||
|
|
1b5984c0ae | ||
|
|
5f44a3259b | ||
|
|
868a7e732f | ||
|
|
492552cbe6 | ||
|
|
5780bbd265 | ||
|
|
5068a0be61 | ||
|
|
83e7a8513b | ||
|
|
ce0334c695 | ||
|
|
3ea6674dfc | ||
|
|
f1f01e5d1a | ||
|
|
01d7ae86c3 | ||
|
|
1c49e49eff | ||
|
|
d3d4f54a7d | ||
|
|
9d0294be7f | ||
|
|
9faa9e9b9d | ||
|
|
c85334f956 | ||
|
|
ef7467ebf7 | ||
|
|
27cdc1793c | ||
|
|
920a5b8386 | ||
|
|
d0bea6ebaa | ||
|
|
9a2f8ae70b | ||
|
|
da62c9a38c | ||
|
|
4982ddefbb | ||
|
|
ab823af695 | ||
|
|
93e3e13d2f | ||
|
|
18a01fba1a | ||
|
|
2cf5412424 | ||
|
|
a7f087aa82 | ||
|
|
72e754cdc2 | ||
|
|
6833013df8 | ||
|
|
997ba77421 | ||
|
|
7a514f6510 | ||
|
|
e16301a1b1 | ||
|
|
a107b234d8 | ||
|
|
1326aaca78 | ||
|
|
ea8f224aa3 | ||
|
|
6ffbef59c5 | ||
|
|
c89a4afd9f | ||
|
|
d856ea5e91 | ||
|
|
6b4d9663be | ||
|
|
1e6e664137 | ||
|
|
e9512807e4 | ||
|
|
6b6caf3303 | ||
|
|
fa08199f43 | ||
|
|
f2cf3ed7ed | ||
|
|
51db05bb23 | ||
|
|
2a69d7ee3a | ||
|
|
64279006d2 | ||
|
|
f3fe8f1f08 | ||
|
|
1b5581a255 | ||
|
|
db360dd6d3 | ||
|
|
521aefc5e4 | ||
|
|
e97fc30c61 | ||
|
|
f89a6ffc02 | ||
|
|
8698122bc0 | ||
|
|
d39bb2c21d | ||
|
|
6bcadd4b72 | ||
|
|
f5913b36eb | ||
|
|
9eda7c7137 | ||
|
|
2967120d3f | ||
|
|
f5c574cf64 | ||
|
|
7be0680637 | ||
|
|
4688eab951 | ||
|
|
b2b08d7509 | ||
|
|
de1d39d8c7 | ||
|
|
7735ffaf5f | ||
|
|
e60eea24a6 | ||
|
|
ccaa70ac41 | ||
|
|
c7021f35d3 | ||
|
|
bf666cfbbb | ||
|
|
5221578aed | ||
|
|
743de1881a | ||
|
|
efc9f079f2 | ||
|
|
153e0f8fc4 | ||
|
|
88f0f480cd | ||
|
|
2284734b85 | ||
|
|
211784ae69 | ||
|
|
01c3263d9d | ||
|
|
e564cfa4fd | ||
|
|
27994a07b3 | ||
|
|
af5a48b80e | ||
|
|
7ebc3fed78 | ||
|
|
1419b3961f | ||
|
|
be2e7de8e3 | ||
|
|
5bc13a6272 | ||
|
|
305d2fe4cf | ||
|
|
1e64bc0c05 | ||
|
|
c0c7396fa2 | ||
|
|
11d4795f3b | ||
|
|
1f64a78c54 | ||
|
|
9f8c7a3dbf | ||
|
|
5b96cbf3ca | ||
|
|
5c6fe552b2 | ||
|
|
c05f417fcb | ||
|
|
7a730bce9a | ||
|
|
6453c3ef9f | ||
|
|
b5a895cc3b | ||
|
|
785023b9b3 | ||
|
|
2c081c18ca | ||
|
|
a090bed5b9 | ||
|
|
cc24f31bca | ||
|
|
185eba3290 | ||
|
|
59369651b3 | ||
|
|
d0e917dc0e | ||
|
|
f1b1278092 | ||
|
|
3b1ceb1c4d | ||
|
|
6c7c6218c6 | ||
|
|
88f08af1c9 | ||
|
|
854bd468b7 | ||
|
|
61ec84ac18 | ||
|
|
0c7f4db3d0 | ||
|
|
0a154acaa6 | ||
|
|
3670a4b5b2 | ||
|
|
dba7165058 | ||
|
|
b1c2770175 | ||
|
|
26759c1b41 | ||
|
|
94a57b0bfb | ||
|
|
9ec7a26112 | ||
|
|
6b52baf740 | ||
|
|
5aa9c50aed | ||
|
|
c1d833704a | ||
|
|
9efbc4670c | ||
|
|
5d73465949 | ||
|
|
1dc396a97d | ||
|
|
9ba4fafe85 | ||
|
|
fe5b45000c | ||
|
|
2b1aed2038 | ||
|
|
cf2abdb318 | ||
|
|
5e10777cf3 | ||
|
|
eddd40ba3c | ||
|
|
a410416b35 | ||
|
|
f5849b4113 | ||
|
|
4b81e9dcd7 | ||
|
|
2780f3cfd3 | ||
|
|
ff6034a8bf | ||
|
|
2770981072 | ||
|
|
347b101a64 | ||
|
|
8f385ab4e5 | ||
|
|
82490ef6e4 | ||
|
|
154ca0a4f7 | ||
|
|
76aea8e7e1 | ||
|
|
aa9053dd26 | ||
|
|
0fd0bf0747 | ||
|
|
6f5d62e7dd | ||
|
|
ad9f17e7ca | ||
|
|
74a48500bc | ||
|
|
01b5e89d86 | ||
|
|
1c5b19e674 | ||
|
|
5ba09b8586 | ||
|
|
434ec4f3ea | ||
|
|
ad77a4600f | ||
|
|
41f436aa6a | ||
|
|
fa58912e33 | ||
|
|
97dca359cc | ||
|
|
97bdad44dc | ||
|
|
1eafdabb17 | ||
|
|
8a22594745 | ||
|
|
ab6b51cde3 | ||
|
|
76952aa408 | ||
|
|
f09023c08c | ||
|
|
2f6460bfab | ||
|
|
0589bd7f96 | ||
|
|
f357f400b0 | ||
|
|
ccbbad4765 | ||
|
|
8d72dbce55 | ||
|
|
7e36b2b1b6 | ||
|
|
ad7b7fa57b | ||
|
|
ee91eb34d4 | ||
|
|
45098358a6 | ||
|
|
14d843c138 | ||
|
|
86af2a4cf2 | ||
|
|
195e4a4392 | ||
|
|
9f64d3f28e | ||
|
|
addeaa2309 | ||
|
|
422f4b07b4 | ||
|
|
c15a3e2a49 | ||
|
|
3d7e682b9b | ||
|
|
008e0e34e6 | ||
|
|
e8f4e135a4 | ||
|
|
33df6dcec3 | ||
|
|
9ebab409ac | ||
|
|
419b54e0c1 | ||
|
|
d7d07c47bc | ||
|
|
53b207ce68 | ||
|
|
bf5c780d34 | ||
|
|
3c5c9654f3 | ||
|
|
fd1e3a7016 | ||
|
|
31a1203122 | ||
|
|
e58a28f168 | ||
|
|
604d2b542a | ||
|
|
8ba6574b0c | ||
|
|
bfba4e838d | ||
|
|
79a2767fae | ||
|
|
768fbe237b | ||
|
|
6c8b195d00 | ||
|
|
49b54e5b5d | ||
|
|
0974d525ea | ||
|
|
465cf40df7 | ||
|
|
7c7bf0f04b | ||
|
|
2eb886f750 | ||
|
|
b9422fe192 | ||
|
|
00627e83c3 | ||
|
|
b9bbbb1229 | ||
|
|
ce22b5878c | ||
|
|
71a8db3fda | ||
|
|
af786dc874 | ||
|
|
441606e2f4 | ||
|
|
72c14ecd87 | ||
|
|
7d624ab6e4 | ||
|
|
a107bd7443 | ||
|
|
34c3419d3c | ||
|
|
915d27345b | ||
|
|
3dafd0ce78 | ||
|
|
1713b651f2 | ||
|
|
07f60a902f | ||
|
|
6f2e5dfc44 | ||
|
|
9a4d376681 | ||
|
|
41858793c8 | ||
|
|
a816bf6b1a | ||
|
|
b7143d87b4 | ||
|
|
5e2e33db4c | ||
|
|
6c2a85aac8 | ||
|
|
ced621bfda | ||
|
|
6cc996db47 | ||
|
|
5feb20ec83 | ||
|
|
7b69406cf0 | ||
|
|
5934226a69 | ||
|
|
36df8cf2e2 | ||
|
|
7351cc453d | ||
|
|
1832888bcf | ||
|
|
c3de15d278 | ||
|
|
296063e231 | ||
|
|
e1711582ec | ||
|
|
a140e1b386 | ||
|
|
5d67bc28ea | ||
|
|
629eeb4176 | ||
|
|
29563f3f03 | ||
|
|
a5e98926af | ||
|
|
a47c67d797 | ||
|
|
3d67eac402 | ||
|
|
a5eea419d8 | ||
|
|
1b62051543 | ||
|
|
774ba4dd86 | ||
|
|
aa1f0eb5c1 | ||
|
|
93d5f8eda6 | ||
|
|
b6ac112d10 | ||
|
|
da2f6e79d3 | ||
|
|
db9c0effba | ||
|
|
764cf05571 | ||
|
|
bed468679f | ||
|
|
6b6994cf1e | ||
|
|
8d940ce7e1 | ||
|
|
b5d8182780 | ||
|
|
64f2bfa15b | ||
|
|
5d6a014157 | ||
|
|
dc51d5fe16 | ||
|
|
b091a0902e | ||
|
|
e30f47f5de | ||
|
|
469f520b30 | ||
|
|
5ed77ef1bb | ||
|
|
37288d81a7 | ||
|
|
e6d52eed44 | ||
|
|
9b23f42a0a | ||
|
|
78bae22fb2 | ||
|
|
667aaff62d | ||
|
|
8a51ef8524 | ||
|
|
56bd22f4e3 | ||
|
|
2abcacb722 | ||
|
|
a727f93d0e | ||
|
|
272f0da513 | ||
|
|
64fecfbebb | ||
|
|
869998b58a | ||
|
|
f0cef8e4f5 | ||
|
|
2b47060190 | ||
|
|
eaba7bbdad | ||
|
|
beae7d7551 | ||
|
|
d7970177f3 | ||
|
|
cd7a2d08ca | ||
|
|
c3409ab251 | ||
|
|
18ac71a371 | ||
|
|
8ccd7d9dd5 | ||
|
|
c15b35c74f | ||
|
|
272a9da194 | ||
|
|
2cd5d0109c | ||
|
|
8b48ce96e1 | ||
|
|
108c605897 | ||
|
|
70be993cfd | ||
|
|
09d7d62632 | ||
|
|
534dfde000 | ||
|
|
75e4afe5ce | ||
|
|
c0eeba3cfc | ||
|
|
0976bf2aa8 | ||
|
|
b658b2bbc2 | ||
|
|
d934619abe | ||
|
|
d68207b59e | ||
|
|
672acd902b | ||
|
|
9735074c7c | ||
|
|
3b89622ba8 | ||
|
|
77be9b82c1 | ||
|
|
620ac0081f | ||
|
|
1a0a486c71 | ||
|
|
3feb7b2a93 | ||
|
|
d4ca777cbd | ||
|
|
9101519e26 | ||
|
|
1896d7ffec | ||
|
|
5871f6ea1c | ||
|
|
d7fe9272b8 | ||
|
|
40ee584fcf | ||
|
|
93a24b3ad0 | ||
|
|
661d273ab7 | ||
|
|
3aee0c3548 | ||
|
|
dd60c551cd | ||
|
|
1c984ae94b | ||
|
|
ddac25ee39 | ||
|
|
2fe18dead5 | ||
|
|
b16408049b | ||
|
|
110fa13b1d | ||
|
|
d911376774 | ||
|
|
3a246798b8 | ||
|
|
0de3f90b6c | ||
|
|
4c7e23e0a6 | ||
|
|
9b6bce7e58 | ||
|
|
9e3f9f6345 | ||
|
|
a1356fbdd9 | ||
|
|
d33a8dc7a2 | ||
|
|
e1b5e909c4 | ||
|
|
cbf7bc6a3d | ||
|
|
1ae192e48e | ||
|
|
0dc095ff71 | ||
|
|
e5277f39a1 | ||
|
|
e5444aa9e6 | ||
|
|
bbaa1abfe5 | ||
|
|
a101ba7167 | ||
|
|
33b32edb4a | ||
|
|
ecc7d05a05 | ||
|
|
3efbbc85ab | ||
|
|
7a3e617585 | ||
|
|
6767934906 | ||
|
|
85f757efb9 | ||
|
|
132ef13af6 | ||
|
|
4329e20359 | ||
|
|
6babbbdfe9 | ||
|
|
f7318c3033 | ||
|
|
80ff0a6f7b | ||
|
|
dfb48fcf0c | ||
|
|
3cd046fdd0 | ||
|
|
df65aa9aa6 | ||
|
|
5f9a0840cc |
No files matched your search
@@ -0,0 +1,120 @@
|
||||
# .clang-format for Qt Creator
|
||||
#
|
||||
# This is for clang-format >= 5.0.
|
||||
#
|
||||
# The configuration below follows the Qt Creator Coding Rules [1] as closely as
|
||||
# possible. For documentation of the options, see [2].
|
||||
#
|
||||
# Use ../../tests/manual/clang-format-for-qtc/test.cpp for documenting problems
|
||||
# or testing changes.
|
||||
#
|
||||
# In case you update this configuration please also update the qtcStyle() in src\plugins\clangformat\clangformatutils.cpp
|
||||
#
|
||||
# [1] https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html
|
||||
# [2] https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
#
|
||||
# yaml-language-server: $schema=https://json.schemastore.org/clang-format.json
|
||||
#
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- forever # avoids { wrapped to next line
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeCategories:
|
||||
- Regex: '^<Q.*'
|
||||
Priority: 200
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
# InsertBraces: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
# Do not add QT_BEGIN_NAMESPACE/QT_END_NAMESPACE as this will indent lines in between.
|
||||
MacroBlockBegin: ""
|
||||
MacroBlockEnd: ""
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 88
|
||||
PenaltyBreakBeforeFirstCallParameter: 300
|
||||
PenaltyBreakComment: 500
|
||||
PenaltyBreakFirstLessLess: 400
|
||||
PenaltyBreakString: 600
|
||||
PenaltyExcessCharacter: 50
|
||||
PenaltyReturnTypeOnItsOwnLine: 300
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: CaseSensitive
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: c++17
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -1,9 +1,18 @@
|
||||
name: iaito CI
|
||||
|
||||
env:
|
||||
R2V: 5.8.4
|
||||
R2V: 6.2.6
|
||||
R2GHIDRA_VERSION: 6.2.6
|
||||
QT_MAC_INSTALL_VERSION: 6.11.*
|
||||
QT_WIN_INSTALL_VERSION: 6.10.*
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: Existing version tag to build and publish
|
||||
required: true
|
||||
type: string
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
@@ -12,205 +21,533 @@ on:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
acr-linux-r2git:
|
||||
runs-on: ubuntu-20.04
|
||||
source:
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
sha: ${{ steps.source.outputs.sha }}
|
||||
r2: ${{ steps.source.outputs.R2V }}
|
||||
r2ghidra: ${{ steps.source.outputs.R2GHIDRA_VERSION }}
|
||||
qt_mac: ${{ steps.source.outputs.QT_MAC_INSTALL_VERSION }}
|
||||
qt_win: ${{ steps.source.outputs.QT_WIN_INSTALL_VERSION }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ inputs.release_tag && format('refs/tags/{0}', inputs.release_tag) || github.sha }}
|
||||
persist-credentials: false
|
||||
- name: Resolve build source and dependencies
|
||||
id: source
|
||||
env:
|
||||
RELEASE_TAG: ${{ inputs.release_tag }}
|
||||
shell: bash
|
||||
run: |
|
||||
if [ -n "$RELEASE_TAG" ]; then
|
||||
[[ "$RELEASE_TAG" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
||||
test "$(./configure -qV)" = "$RELEASE_TAG"
|
||||
fi
|
||||
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||
python3 - <<'PYTHON'
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
workflow = Path('.github/workflows/ci.yml').read_text()
|
||||
keys = ('R2V', 'R2GHIDRA_VERSION', 'QT_MAC_INSTALL_VERSION', 'QT_WIN_INSTALL_VERSION')
|
||||
with open(os.environ['GITHUB_OUTPUT'], 'a') as output:
|
||||
for key in keys:
|
||||
value = os.environ[key]
|
||||
if os.environ['RELEASE_TAG']:
|
||||
match = re.search(r'^ ' + key + r': ([0-9.*]+)$', workflow, re.M)
|
||||
if not match:
|
||||
raise SystemExit(f'Missing dependency version: {key}')
|
||||
value = match.group(1)
|
||||
print(f'{key}={value}', file=output)
|
||||
PYTHON
|
||||
|
||||
acr-linux-r2git:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: false # 'recursive' 'true' or 'false'
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: 3.8.x
|
||||
python-version: 3.12.x
|
||||
- name: apt dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt install -y libgraphviz-dev mesa-common-dev ninja-build meson
|
||||
sudo apt install -y libqt5svg5-dev qttools5-dev qttools5-dev-tools
|
||||
sudo apt install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
|
||||
sudo apt-get install -y libgraphviz-dev mesa-common-dev ninja-build meson libqt5svg5-dev qttools5-dev qttools5-dev-tools qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
|
||||
- name: install r2
|
||||
run: git clone --depth=1 https://github.com/radareorg/radare2 r2git && CFLAGS=-O0 r2git/sys/install.sh
|
||||
- name: build iaito
|
||||
run: |
|
||||
./configure --prefix=/usr
|
||||
make -j4
|
||||
- name: command-line checks
|
||||
run: python3 tests/commandline/test_commandline.py build/iaito
|
||||
- name: packaging
|
||||
run: |
|
||||
make -j -C dist/debian
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: iaito-amd64.deb
|
||||
path: dist/debian/*/*.deb
|
||||
acr-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
run: make -j -C dist/debian
|
||||
indent-check:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
runs-on: ubuntu-24.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: install clang-format
|
||||
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends clang-format-20
|
||||
- name: make indent
|
||||
run: make indent-host && git diff --exit-code
|
||||
acr-linux:
|
||||
needs: source
|
||||
env:
|
||||
R2V: ${{ needs.source.outputs.r2 }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.source.outputs.sha }}
|
||||
submodules: false # 'recursive' 'true' or 'false'
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v1
|
||||
- uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: 3.8.x
|
||||
python-version: 3.12.x
|
||||
- name: apt dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt install -y libgraphviz-dev mesa-common-dev ninja-build
|
||||
sudo apt install -y libqt5svg5-dev qttools5-dev qttools5-dev-tools
|
||||
sudo apt install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
|
||||
sudo apt-get install -y libgraphviz-dev mesa-common-dev ninja-build qt6-base-dev qt6-declarative-dev libqt6svg6-dev qt6-l10n-tools
|
||||
echo /usr/lib/qt6/bin >> $GITHUB_PATH
|
||||
- name: install r2
|
||||
run: |
|
||||
wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2_${{env.R2V}}_amd64.deb
|
||||
wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-dev_${{env.R2V}}_amd64.deb
|
||||
sudo dpkg -i *.deb
|
||||
- name: configure iaito
|
||||
run: ./configure --prefix=/usr --with-qmake6
|
||||
- name: build iaito
|
||||
run: |
|
||||
./configure --prefix=/usr
|
||||
make -j4
|
||||
run: make -j4
|
||||
- name: command-line checks
|
||||
if: ${{ hashFiles('tests/commandline/test_commandline.py') != '' }}
|
||||
run: python3 tests/commandline/test_commandline.py build/iaito
|
||||
- name: packaging
|
||||
run: |
|
||||
make -C dist/debian
|
||||
- uses: actions/upload-artifact@v3
|
||||
run: make -C dist/debian
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: iaito-amd64.deb
|
||||
path: dist/debian/*/*.deb
|
||||
acr-macos:
|
||||
runs-on: macos-latest
|
||||
acr-linux-nodebugger:
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: false # 'recursive' 'true' or 'false'
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v1
|
||||
- uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: 3.8.x
|
||||
- name: homebrew dependencies
|
||||
python-version: 3.12.x
|
||||
- name: apt dependencies
|
||||
run: |
|
||||
brew update
|
||||
brew install pkg-config qt@5
|
||||
brew unlink qt@5 || true
|
||||
brew link --force qt@5
|
||||
pip3 install meson
|
||||
pip3 install ninja
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgraphviz-dev mesa-common-dev ninja-build qt6-base-dev qt6-declarative-dev libqt6svg6-dev qt6-l10n-tools
|
||||
echo /usr/lib/qt6/bin >> $GITHUB_PATH
|
||||
- name: install r2
|
||||
run: |
|
||||
wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-x64-${{env.R2V}}.pkg
|
||||
sudo installer -pkg *.pkg -target /
|
||||
wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2_${{env.R2V}}_amd64.deb
|
||||
wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-dev_${{env.R2V}}_amd64.deb
|
||||
sudo dpkg -i *.deb
|
||||
- name: configure iaito
|
||||
run: ./configure --prefix=/usr --with-qmake6 --without-debugger
|
||||
- name: build iaito
|
||||
run: make -j4
|
||||
- name: command-line checks
|
||||
run: python3 tests/commandline/test_commandline.py build/iaito
|
||||
acr-macos:
|
||||
needs: source
|
||||
env:
|
||||
R2V: ${{ needs.source.outputs.r2 }}
|
||||
R2GHIDRA_VERSION: ${{ needs.source.outputs.r2ghidra }}
|
||||
QT_MAC_INSTALL_VERSION: ${{ needs.source.outputs.qt_mac }}
|
||||
QT_WIN_INSTALL_VERSION: ${{ needs.source.outputs.qt_win }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: arm64
|
||||
runs-on: macos-latest
|
||||
- arch: x64
|
||||
runs-on: macos-15-intel
|
||||
arch_alt: x86_64
|
||||
name: acr-macos-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.source.outputs.sha }}
|
||||
submodules: false # 'recursive' 'true' or 'false'
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: 3.12.x
|
||||
- name: uname
|
||||
run: uname -a
|
||||
- name: install dependencies
|
||||
run: pip3 install meson ninja
|
||||
- name: install Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: ${{env.QT_MAC_INSTALL_VERSION}}
|
||||
- name: download radare components
|
||||
working-directory: dist/macos
|
||||
env:
|
||||
GH_TOKEN: ${{github.token}}
|
||||
run: |
|
||||
validate_download() {
|
||||
case "$2" in
|
||||
tar.gz) tar -tzf "$1" >/dev/null 2>&1 ;;
|
||||
zip) unzip -tq "$1" >/dev/null 2>&1 ;;
|
||||
*) test -s "$1" ;;
|
||||
esac
|
||||
}
|
||||
download() {
|
||||
local output="$1"
|
||||
local url="$2"
|
||||
local type="$3"
|
||||
local attempt
|
||||
|
||||
for ((attempt = 1; attempt <= 3; attempt++)); do
|
||||
rm -f "${output}.tmp"
|
||||
if curl --fail --location --silent --show-error \
|
||||
--connect-timeout 30 --max-time 300 --output "${output}.tmp" "$url" \
|
||||
&& validate_download "${output}.tmp" "$type"; then
|
||||
mv "${output}.tmp" "$output"
|
||||
return 0
|
||||
fi
|
||||
if [ "$attempt" -lt 3 ]; then
|
||||
echo "Download of ${output} failed (attempt ${attempt}/3); retrying in 10s"
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
echo "::error::Unable to download a valid ${output} after 3 attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
r2ai_version="$(gh api /repos/radareorg/r2ai/releases/latest --jq .tag_name)"
|
||||
download radare2.pkg "https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-${{matrix.arch}}-${{env.R2V}}.pkg" pkg
|
||||
download r2ai.tar.gz "https://github.com/radareorg/r2ai/archive/refs/tags/${r2ai_version}.tar.gz" tar.gz
|
||||
download r2ghidra.zip "https://github.com/radareorg/r2ghidra/releases/download/${{env.R2GHIDRA_VERSION}}/r2ghidra-${{env.R2GHIDRA_VERSION}}-macos-${{matrix.arch_alt||matrix.arch}}.zip" zip
|
||||
download r2ghidra_sleigh.zip "https://github.com/radareorg/r2ghidra/releases/download/${{env.R2GHIDRA_VERSION}}/r2ghidra_sleigh-${{env.R2GHIDRA_VERSION}}.zip" zip
|
||||
make unpack-comps
|
||||
- name: install r2
|
||||
run: sudo installer -pkg dist/macos/radare2.pkg -target /
|
||||
- name: build iaito
|
||||
run: |
|
||||
export PATH="/usr/local/opt/qt@5/bin:$PATH"
|
||||
export PATH="/opt/homebrew/opt/qt@5/bin:$PATH" # doesnt seems to be necessary
|
||||
export LDFLAGS="-L/usr/local/opt/qt@5/lib"
|
||||
export CPPFLAGS="-I/usr/local/opt/qt@5/include"
|
||||
export PKG_CONFIG_PATH="/usr/local/opt/qt@5/lib/pkgconfig"
|
||||
./configure
|
||||
make -j4
|
||||
make -j4 -C dist/macos app
|
||||
- name: ad-hoc sign
|
||||
run: codesign --force --deep -s - dist/macos/disk/iaito.app
|
||||
- name: packaging
|
||||
run: |
|
||||
make -C dist/macos
|
||||
- uses: actions/upload-artifact@v3
|
||||
run: make -C dist/macos zip
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: iaito-mac-amd64.zip
|
||||
path: dist/macos/iaito*.zip
|
||||
name: iaito-macos-${{ matrix.arch }}
|
||||
path: dist/macos/iaito.zip
|
||||
meson:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
python-version: [3.8.x]
|
||||
system-deps: [true]
|
||||
cc-override: [default]
|
||||
cxx-override: [default]
|
||||
# Prevent one job from pausing the rest
|
||||
fail-fast: false
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: false # 'recursive' 'true' or 'false'
|
||||
persist-credentials: false
|
||||
- name: apt dependencies
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libgraphviz-dev mesa-common-dev
|
||||
sudo apt-get install ninja-build make git patch wget
|
||||
sudo apt install -y libqt5svg5-dev qttools5-dev qttools5-dev-tools
|
||||
sudo apt install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
|
||||
sudo apt-get install -y libgraphviz-dev mesa-common-dev ninja-build libqt5svg5-dev qttools5-dev qttools5-dev-tools qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools
|
||||
- name: install r2
|
||||
run: git clone --depth=1 https://github.com/radareorg/radare2 r2git && CFLAGS=-O0 r2git/sys/install.sh
|
||||
- uses: actions/setup-python@v1
|
||||
run: |
|
||||
wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2_${{env.R2V}}_amd64.deb
|
||||
wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-dev_${{env.R2V}}_amd64.deb
|
||||
sudo dpkg -i *.deb
|
||||
- uses: actions/setup-python@v7
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: homebrew dependencies
|
||||
if: contains(matrix.os, 'macos')
|
||||
run: |
|
||||
brew update --preinstall # temporary workaround for https://github.com/Homebrew/homebrew-bundle/issues/751
|
||||
brew install coreutils pkg-config
|
||||
brew install pkg-config qt@5
|
||||
brew unlink qt@5 || true
|
||||
brew link --force qt@5
|
||||
pip3 install meson
|
||||
pip3 install ninja
|
||||
- name: macos build
|
||||
if: contains(matrix.os, 'macos')
|
||||
run: |
|
||||
cd src && meson ../build
|
||||
cd ../build && ninja -j4
|
||||
python-version: 3.12.x
|
||||
- name: meson+ninja ubuntu
|
||||
if: contains(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
pip install meson
|
||||
cd src && meson ../build
|
||||
cd ../build && ninja -j4
|
||||
meson setup build src
|
||||
ninja -C build -j4
|
||||
w64-meson:
|
||||
needs: source
|
||||
env:
|
||||
R2V: ${{ needs.source.outputs.r2 }}
|
||||
QT_WIN_INSTALL_VERSION: ${{ needs.source.outputs.qt_win }}
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
submodules: false # 'recursive' 'true' or 'false'
|
||||
ref: ${{ needs.source.outputs.sha }}
|
||||
submodules: false
|
||||
persist-credentials: false
|
||||
- name: Preparing msvc toolchain
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
uses: TheMrMilchmann/setup-msvc-dev@v4
|
||||
with:
|
||||
arch: x64
|
||||
# - uses: actions/setup-python@v1
|
||||
# with:
|
||||
# python-version: 3.8.x
|
||||
# - name: Prepare Qt
|
||||
# working-directory: build
|
||||
# shell: cmd
|
||||
# run: |
|
||||
# curl -vLo qt-unified-windows-x86-online.exe http://download.qt.io/official_releases/online_installers/qt-unified-windows-x86-online.exe
|
||||
# qt-unified-windows-x86-online.exe --verbose --script ..\ci\qt.qs
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
- name: dependencies
|
||||
shell: cmd
|
||||
run: |
|
||||
pip install ninja meson wget
|
||||
choco install zip
|
||||
# - name: install r2
|
||||
# shell: bash
|
||||
# run: |
|
||||
# python -m wget https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-${{env.R2V}}-w64.zip -o r2.zip
|
||||
# unzip r2.zip
|
||||
# mv radare2-${{env.R2V}}-w64 radare2
|
||||
# pwd
|
||||
- name: w64-make
|
||||
shell: cmd
|
||||
run: |
|
||||
SET ARCH=x64
|
||||
set IAITO_DEPS=%CD%\iaito-deps
|
||||
set PATH=%CD%\iaito-deps\qt\bin;%CD%\r2_dist\bin;%PATH%
|
||||
pip install meson ninja wget
|
||||
call preconfigure.bat
|
||||
call configure.bat
|
||||
call make.bat
|
||||
dir /s
|
||||
- uses: actions/upload-artifact@v3
|
||||
- name: install Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
name: iaito.exe
|
||||
version: ${{env.QT_WIN_INSTALL_VERSION}}
|
||||
- name: install dependencies
|
||||
shell: cmd
|
||||
run: pip install ninja "meson==1.10.2"
|
||||
- name: install r2 (preconfigure)
|
||||
shell: bash
|
||||
run: |
|
||||
curl -L -o r2.zip https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-${{env.R2V}}-w64.zip
|
||||
7z x r2.zip
|
||||
mv radare2-${{env.R2V}}-w64 radare2
|
||||
# XXX workaround for r2-6.2.4 headers not being msvc c++ friendly (fixed in r2 master)
|
||||
sed -i 's/(RStrs) { NULL, NULL }/r_strs_new (NULL, NULL)/' radare2/include/libr/r_cmd.h
|
||||
echo "%CD%\radare2\bin" >> $GITHUB_PATH
|
||||
- name: configure
|
||||
shell: cmd
|
||||
run: configure.bat
|
||||
- name: make
|
||||
shell: cmd
|
||||
env:
|
||||
ARCH: x64
|
||||
run: make.bat -Dwith_qt6=true
|
||||
- name: dist
|
||||
shell: cmd
|
||||
run: 7z a iaito.zip iaito
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: iaito-w64.exe
|
||||
path: iaito\iaito.exe
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ env.PACKAGE_NAME }}
|
||||
path: build/${{ env.PACKAGE_NAME }}
|
||||
name: iaito-w64.zip
|
||||
path: iaito.zip
|
||||
|
||||
check_release:
|
||||
if: ${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/master') }}
|
||||
outputs:
|
||||
is_release: ${{ steps.release.outputs.is }}
|
||||
tag_name: ${{ steps.release.outputs.tag }}
|
||||
needs:
|
||||
- source
|
||||
- acr-linux
|
||||
- acr-macos
|
||||
- w64-meson
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.source.outputs.sha }}
|
||||
fetch-depth: 0 # Download all git history and tags
|
||||
- name: Check if is a release
|
||||
run: git describe --exact-match --tags HEAD | awk 'BEGIN{tag="-";r="no"}/^[0-9]+\.[0-9]+/{tag=$0;r="yes"};END{print "is="r;print "tag="tag}' >> ${GITHUB_OUTPUT}
|
||||
id: release
|
||||
|
||||
macos-sign:
|
||||
if: ${{ needs.check_release.outputs.is_release == 'yes' }}
|
||||
needs:
|
||||
- check_release
|
||||
runs-on: macos-latest
|
||||
environment: release
|
||||
# Environment secrets for signing:
|
||||
# APPLE_DEVELOPER_CERTIFICATE_P12_BASE64:
|
||||
# Base64 of the p12 export (cert+private key), the certificate must be named
|
||||
# "Developer ID Application: DEVELOPER_NAME (TEAM_ID)"
|
||||
# APPLE_DEVELOPER_CERTIFICATE_PASSWORD: Random password used to encrypt the exported P12
|
||||
# Environment secrets for notarization:
|
||||
# APPLE_DEVELOPER_ID: email of the developer
|
||||
# APPLE_TEAM_ID: Team ID (can be extracted from the certificate name too)
|
||||
# APPLE_APP_SPECIFIC_PASSWORD: https://support.apple.com/en-us/102654
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: refs/tags/${{ needs.check_release.outputs.tag_name }}
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: iaito-macos-*
|
||||
path: dist/artifacts
|
||||
|
||||
- name: Install Apple Certificate
|
||||
env:
|
||||
CERTIFICATE_BASE64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
|
||||
CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: "keychainpass-${{ github.run_id }}"
|
||||
run: |
|
||||
# Create keychain
|
||||
security create-keychain -p "${KEYCHAIN_PASSWORD}" release.keychain
|
||||
security default-keychain -s release.keychain
|
||||
security unlock-keychain -p "${KEYCHAIN_PASSWORD}" release.keychain
|
||||
security set-keychain-settings -t 3600 -u release.keychain
|
||||
|
||||
# Import certificate
|
||||
echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12
|
||||
security import certificate.p12 -k release.keychain -P "${CERTIFICATE_PASSWORD}" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k "${KEYCHAIN_PASSWORD}" release.keychain
|
||||
|
||||
# Check if the certificate was imported correctly and find its identity
|
||||
security find-identity -v -p codesigning release.keychain
|
||||
|
||||
# Clean up
|
||||
rm certificate.p12
|
||||
|
||||
- name: Sign and package the App Bundle
|
||||
run: |
|
||||
# Find the Developer ID Application certificate identity
|
||||
IDENTITY=$(security find-identity -v -p codesigning | awk '/Developer ID Application/{print $2;exit}')
|
||||
|
||||
if [ -z "$IDENTITY" ]; then
|
||||
echo "Error: No Developer ID Application certificate found in keychain"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Sign and package for all architectures
|
||||
for arch in arm64 x64; do
|
||||
echo "[${arch}] Extracting build..."
|
||||
mkdir -p dist/macos/disk
|
||||
ditto -x -k dist/artifacts/iaito-macos-${arch}/iaito.zip dist/macos/disk/
|
||||
|
||||
echo "[${arch}] Signing app bundle..."
|
||||
codesign --force --deep --options runtime --entitlements "dist/macos/iaito.entitlements" --sign "$IDENTITY" dist/macos/disk/iaito.app
|
||||
codesign --verify --verbose dist/macos/disk/iaito.app
|
||||
|
||||
echo "[${arch}] Packaging into DMG..."
|
||||
rm -v dist/macos/disk/READ*.txt # no workaround needed
|
||||
ln -fs /Applications dist/macos/disk/
|
||||
(cd dist/macos; hdiutil create -format UDZO -fs APFS -volname iaito -srcfolder disk iaito)
|
||||
mv -v dist/macos/iaito.dmg "iaito-${arch}.dmg"
|
||||
rm -fR dist/macos/disk
|
||||
|
||||
echo "[${arch}] Signing DMG..."
|
||||
codesign --force --sign "$IDENTITY" --timestamp "iaito-${arch}.dmg"
|
||||
done
|
||||
|
||||
- name: Notarize DMG
|
||||
env:
|
||||
APPLE_ID: ${{ secrets.APPLE_DEVELOPER_ID }}
|
||||
TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
||||
APP_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||
run: |
|
||||
for arch in arm64 x64; do
|
||||
echo "[${arch}] Notary DMG..."
|
||||
xcrun notarytool submit "iaito-${arch}.dmg" --apple-id "$APPLE_ID" --team-id "$TEAM_ID" --password "$APP_PASSWORD" --wait
|
||||
xcrun stapler staple "iaito-${arch}.dmg"
|
||||
done
|
||||
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: iaito-arm64.dmg
|
||||
path: iaito-arm64.dmg
|
||||
|
||||
- uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: iaito-x64.dmg
|
||||
path: iaito-x64.dmg
|
||||
|
||||
- name: Remove keychain
|
||||
if: always()
|
||||
run: security delete-keychain release.keychain
|
||||
|
||||
release:
|
||||
permissions:
|
||||
contents: write
|
||||
if: ${{ needs.check_release.outputs.is_release == 'yes' }}
|
||||
needs:
|
||||
- macos-sign
|
||||
- check_release
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
ref: refs/tags/${{ needs.check_release.outputs.tag_name }}
|
||||
fetch-depth: 0 # Download all git history and tags
|
||||
- name: Extract version
|
||||
run: echo "string=`./configure -qV`" >> $GITHUB_OUTPUT
|
||||
id: version
|
||||
- name: Prepare release notes
|
||||
env:
|
||||
RELEASE_TAG: ${{ needs.check_release.outputs.tag_name }}
|
||||
run: |
|
||||
previous=$(git describe --tags --abbrev=0 "${RELEASE_TAG}^")
|
||||
./scripts/release-notes.sh "$previous" "$RELEASE_TAG" | tee ./RELEASE_NOTES.md
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: dist/artifacts
|
||||
- name: Display structure of downloaded files
|
||||
run: find dist/artifacts
|
||||
- name: Create GitHub release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ needs.check_release.outputs.tag_name }}
|
||||
release_name: ${{ steps.version.outputs.string }}
|
||||
body_path: ./RELEASE_NOTES.md
|
||||
draft: true
|
||||
prerelease: false
|
||||
- name: Upload Linux asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: dist/artifacts/iaito-amd64.deb/iaito/iaito_${{ steps.version.outputs.string }}_amd64.deb
|
||||
asset_name: iaito_${{ steps.version.outputs.string }}_amd64.deb
|
||||
asset_content_type: application/vnd.debian.binary-package
|
||||
- name: Upload macOS x64 asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: dist/artifacts/iaito-x64.dmg/iaito-x64.dmg
|
||||
asset_name: iaito_${{ steps.version.outputs.string }}_x64.dmg
|
||||
asset_content_type: application/vnd.debian.binary-package
|
||||
- name: Upload macOS arm64 asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: dist/artifacts/iaito-arm64.dmg/iaito-arm64.dmg
|
||||
asset_name: iaito_${{ steps.version.outputs.string }}_arm64.dmg
|
||||
asset_content_type: application/vnd.debian.binary-package
|
||||
- name: Upload Windows QtDeploy asset
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: dist/artifacts/iaito-w64.zip/iaito.zip
|
||||
asset_name: iaito-${{ steps.version.outputs.string }}-w64.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload Windows executable
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: dist/artifacts/iaito-w64.exe/iaito.exe
|
||||
asset_name: iaito-${{ steps.version.outputs.string }}.exe
|
||||
asset_content_type: application/zip
|
||||
- name: Publish complete release
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
RELEASE_ID: ${{ steps.create_release.outputs.id }}
|
||||
run: |
|
||||
gh api --method PATCH "repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}" \
|
||||
-F draft=false -f make_latest=legacy --jq .html_url
|
||||
@@ -0,0 +1,23 @@
|
||||
on:
|
||||
pull_request: {}
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths:
|
||||
- .github/workflows/semgrep.yml
|
||||
schedule:
|
||||
# random HH:MM to avoid a load spike on GitHub Actions at 00:00
|
||||
- cron: 45 3 * * *
|
||||
name: Semgrep
|
||||
jobs:
|
||||
semgrep:
|
||||
name: Scan
|
||||
runs-on: ubuntu-24.04
|
||||
env:
|
||||
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
|
||||
container:
|
||||
image: returntocorp/semgrep
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- run: semgrep ci
|
||||
@@ -1,5 +1,10 @@
|
||||
# Binaries
|
||||
AStyle*
|
||||
./config.mk
|
||||
config.mk
|
||||
|
||||
# Generated configuration header (qmake / Meson)
|
||||
IaitoConfig.h
|
||||
|
||||
# OSX files
|
||||
*.DS_Store
|
||||
@@ -20,6 +25,7 @@ AStyle*
|
||||
# Qt files
|
||||
*.qmake.cache
|
||||
*.qmake.stash
|
||||
src/Makefile
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*.qbs.user
|
||||
@@ -91,4 +97,13 @@ src/out
|
||||
*.orig
|
||||
|
||||
# Translations
|
||||
src/translations
|
||||
src/translations
|
||||
|
||||
# macOS package
|
||||
/dist/macos/radare2.pkg
|
||||
/dist/macos/radare2-unpkg
|
||||
/dist/macos/disk
|
||||
/dist/macos/extra
|
||||
/dist/macos/*.dmg
|
||||
/dist/macos/*.zip
|
||||
/dist/macos/*.tar.gz
|
||||
@@ -0,0 +1,72 @@
|
||||
# Agentic Coding Guidelines for the iaito project
|
||||
|
||||
## Overview
|
||||
|
||||
iaito is the official Qt-based GUI for radare2. It uses qmake for building and requires radare2 and Qt5/6.
|
||||
|
||||
## Locations
|
||||
|
||||
- Source code is in `./src/` (widgets, dialogs, menus, common, core, plugins)
|
||||
- Qt project file: `./src/Iaito.pro`
|
||||
- Plugin interface: `./src/plugins/IaitoPlugin.h`
|
||||
- Sample plugins: `./src/plugins/sample-cpp/` and `./src/plugins/sample-python/`
|
||||
- UI forms: `./src/dialogs/*.ui` and `./src/widgets/*.ui`
|
||||
- Resources: `./src/resources.qrc`, `./src/themes/`
|
||||
|
||||
## Formatting Style
|
||||
|
||||
- Follow C++ / Qt Creator coding style (see `.clang-format`)
|
||||
- Indent with **4 spaces** (no tabs)
|
||||
- Column limit: 100 characters
|
||||
- Use `make fmt` to format the whole project source
|
||||
|
||||
## Coding Rules
|
||||
|
||||
- C++20 standard
|
||||
- Code must be portable across windows, macos and linux
|
||||
- Use Qt signals/slots for communication between components
|
||||
- Widgets inherit from `IaitoDockWidget` or `AddressableDockWidget`
|
||||
- Access radare2 via the `Core()` singleton (defined in `core/Iaito.h`)
|
||||
- Use `CutterCore::cmd()` and `CutterCore::cmdj()` for r2 commands
|
||||
|
||||
## Actions
|
||||
|
||||
- Configure: `./configure`
|
||||
- Build: `make -j8 > /dev/null`
|
||||
- Never run qmake or compilers directly
|
||||
- Limit to 8 jobs to avoid resource exhaustion
|
||||
- Redirect stdout to /dev/null to reduce noise
|
||||
- Run: `make run`
|
||||
- Clean: `make clean`
|
||||
- Install to home: `make user-install`
|
||||
- Build r2 plugin: `make plugin`
|
||||
|
||||
## Dependencies
|
||||
|
||||
Requires radare2 installed system-wide:
|
||||
```sh
|
||||
git clone https://github.com/radareorg/radare2 && radare2/sys/install.sh
|
||||
```
|
||||
|
||||
Qt5 packages (Debian/Ubuntu):
|
||||
```sh
|
||||
sudo apt install qttools5-dev qtbase5-dev libqt5svg5-dev
|
||||
```
|
||||
|
||||
## Adding Widgets
|
||||
|
||||
1. Create `.h`, `.cpp`, and `.ui` files in `src/widgets/`
|
||||
2. Add to `SOURCES`, `HEADERS`, `FORMS` in `src/Iaito.pro`
|
||||
3. Register in `core/MainWindow.cpp`
|
||||
|
||||
## Adding Plugins
|
||||
|
||||
- C++ plugins: see `src/plugins/sample-cpp/`
|
||||
- Python plugins: see `src/plugins/sample-python/`
|
||||
- Implement `IaitoPlugin` interface from `plugins/IaitoPlugin.h`
|
||||
|
||||
## Debugging
|
||||
|
||||
- Run with: `R2_DEBUG=1 make run`
|
||||
- Debug with gdb: `make gdb`
|
||||
- Debug with lldb: `make lldb`
|
||||
@@ -1,4 +1,4 @@
|
||||
include config.mk
|
||||
-include config.mk
|
||||
|
||||
ifeq ($(shell uname),Darwin)
|
||||
BIN=build/iaito.app/Contents/MacOS/iaito
|
||||
@@ -6,23 +6,57 @@ else
|
||||
BIN=build/iaito
|
||||
endif
|
||||
|
||||
#QMAKE_FLAGS+=IAITO_ENABLE_PYTHON=false
|
||||
QMAKE_FLAGS+=-config release
|
||||
|
||||
#install_name_tool -change /path/to/Qt/lib/QtCore.framework/Versions/4.0/QtCore
|
||||
# @executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
|
||||
# plugandpaint.app/Contents/plugins/libpnp_basictools.dylib
|
||||
|
||||
ifeq ($(WANT_PYTHON),1)
|
||||
QMAKE_FLAGS+=IAITO_ENABLE_PYTHON=true
|
||||
endif
|
||||
ifeq ($(WANT_PYTHON_BINDINGS),1)
|
||||
QMAKE_FLAGS+=IAITO_ENABLE_PYTHON_BINDINGS=true
|
||||
endif
|
||||
ifeq ($(WANT_DEBUGGER),0)
|
||||
QMAKE_FLAGS+=IAITO_ENABLE_DEBUGGER=false
|
||||
else
|
||||
QMAKE_FLAGS+=IAITO_ENABLE_DEBUGGER=true
|
||||
endif
|
||||
ifeq ($(WANT_CRASH_REPORTS),1)
|
||||
QMAKE_FLAGS+=IAITO_ENABLE_CRASH_REPORTS=true
|
||||
endif
|
||||
QMAKE_FLAGS+=PREFIX=$(PREFIX)
|
||||
INDENT_IMAGE_NAME ?= clang-format-image
|
||||
INDENT_IMAGE_TAG ?= llvm20
|
||||
INDENT_IMAGE := $(INDENT_IMAGE_NAME):$(INDENT_IMAGE_TAG)
|
||||
INDENT_FILES := $(shell find src \( -name '*.cpp' -o -name '*.h' \))
|
||||
CLANG_FORMAT ?= clang-format-20
|
||||
|
||||
all: iaito
|
||||
|
||||
CXX?=g++
|
||||
|
||||
reset:
|
||||
rm -rf ~/.config/radareorg/iaito.conf
|
||||
|
||||
QTLIBS=$(shell grep "^LIBS" build/Makefile | cut -d = -f 2-)
|
||||
R2LIBS=$(shell pkg-config --cflags --libs r_core)
|
||||
R2_LIBEXT=$(shell r2 -H R2_LIBEXT)
|
||||
R2_USER_PLUGINS=$(shell r2 -H R2_USER_PLUGINS)
|
||||
|
||||
plugin core_plugin: iaito
|
||||
SUBLIBS=true $(CXX) build/*.o src/CorePlugin.cpp -shared -fPIC $(QTLIBS) $(R2LIBS) -o build/CorePlugin.$(R2_LIBEXT)
|
||||
mkdir -p $(R2_USER_PLUGINS)
|
||||
rm -f $(R2_USER_PLUGINS)/IaitoPlugin.$(R2_LIBEXT)
|
||||
cp -f build/CorePlugin.$(R2_LIBEXT) $(R2_USER_PLUGINS)/IaitoPlugin.$(R2_LIBEXT)
|
||||
|
||||
asan:
|
||||
export CXXFLAGS=-fsanitize=address ; \
|
||||
export CFLAGS=-fsanitize=address ; \
|
||||
export LDFLAGS=-fsanitize=address ; \
|
||||
$(MAKE) build && $(MAKE) -C build -j4
|
||||
|
||||
clean:
|
||||
rm -f src/ui_*.h
|
||||
rm -f src/moc_*
|
||||
rm -rf build
|
||||
|
||||
dist:
|
||||
@@ -36,6 +70,8 @@ mrproper: clean
|
||||
git clean -xdf
|
||||
|
||||
.PHONY: install run user-install dist macos clean mrproper install-translations
|
||||
.PHONY: dockindent dockindent-image indent indent-host
|
||||
.PHONY: install-deeplink uninstall-deeplink
|
||||
|
||||
# force qt5 build when QtCreator is installed in user's home
|
||||
ifeq ($(shell test -x ~/Qt/5.*/clang_64/bin/qmake || echo err),)
|
||||
@@ -43,7 +79,7 @@ QMAKE=~/Qt/5.*/clang_64/bin/qmake
|
||||
endif
|
||||
|
||||
iaito: build
|
||||
$(MAKE) -C build -j4
|
||||
$(MAKE) -C build
|
||||
|
||||
build:
|
||||
mkdir -p build
|
||||
@@ -62,6 +98,8 @@ ifeq ($(shell uname),Darwin)
|
||||
ln -fs '/Applications/iaito.app/Contents/MacOS/iaito' $(DESTDIR)/$(PREFIX)'/bin/iaito'
|
||||
else
|
||||
$(MAKE) -C build install INSTALL_ROOT=$(DESTDIR)
|
||||
# Refresh the desktop DB so the .desktop MimeType registers iaito://
|
||||
-update-desktop-database "$(DESTDIR)$(PREFIX)/share/applications" 2>/dev/null
|
||||
endif
|
||||
$(MAKE) install-man
|
||||
|
||||
@@ -74,6 +112,7 @@ else
|
||||
rm -rf "$(DESTDIR)/$(PREFIX)/bin/iaito"
|
||||
endif
|
||||
rm -f "${DESTDIR}$(MANDIR)/man1/iaito.1"
|
||||
-$(MAKE) uninstall-deeplink
|
||||
|
||||
user-install: build
|
||||
ifeq ($(shell uname),Darwin)
|
||||
@@ -84,13 +123,42 @@ else
|
||||
$(MAKE) -C build install INSTALL_ROOT=/ PREFIX=${HOME}/.local
|
||||
endif
|
||||
$(MAKE) install-man DESTDIR=/ PREFIX=${HOME}/.local MANDIR=${HOME}/.local/share/man
|
||||
$(MAKE) install-deeplink
|
||||
|
||||
user-uninstall:
|
||||
$(MAKE) uninstall DESTDIR=/ PREFIX=${HOME}/.local MANDIR=${HOME}/.local/share/man
|
||||
|
||||
ifneq ($(shell uname),Darwin)
|
||||
run: install-desktop-user
|
||||
endif
|
||||
|
||||
run:
|
||||
rarun2 libpath=$(shell r2 -H R2_LIBDIR) program=$(BIN)
|
||||
|
||||
install-desktop-user:
|
||||
@mkdir -p $(HOME)/.local/share/applications
|
||||
@mkdir -p $(HOME)/.local/share/icons/hicolor/scalable/apps
|
||||
@cp -f src/org.radare.iaito.desktop $(HOME)/.local/share/applications/org.radare.iaito.desktop
|
||||
@cp -f src/img/org.radare.iaito.svg $(HOME)/.local/share/icons/hicolor/scalable/apps/org.radare.iaito.svg
|
||||
@$(MAKE) install-deeplink
|
||||
|
||||
# Register/unregister the iaito:// deep link URI scheme handler
|
||||
install-deeplink:
|
||||
ifeq ($(shell uname),Darwin)
|
||||
sh scripts/deeplink/register.sh "$(DESTDIR)/Applications/iaito.app"
|
||||
else
|
||||
sh scripts/deeplink/register.sh
|
||||
endif
|
||||
|
||||
uninstall-deeplink:
|
||||
sh scripts/deeplink/unregister.sh
|
||||
|
||||
gdb:
|
||||
gdb --args $(BIN)
|
||||
|
||||
lldb:
|
||||
lldb -- $(BIN)
|
||||
|
||||
src/translations/README.md:
|
||||
git clone https://github.com/radareorg/iaito-translations.git src/translations
|
||||
|
||||
@@ -99,3 +167,18 @@ install-translations: src/translations/README.md
|
||||
|
||||
user-install-translations: src/translations/README.md
|
||||
$(MAKE) -C src/translations user-install
|
||||
|
||||
dockindent:
|
||||
$(MAKE) dockindent-image
|
||||
docker run --rm -v "$$PWD:/project" $(INDENT_IMAGE) -i $(INDENT_FILES)
|
||||
|
||||
dockindent-image:
|
||||
docker image inspect $(INDENT_IMAGE) >/dev/null 2>&1 || \
|
||||
$(MAKE) -C scripts/indent IMAGE_NAME=$(INDENT_IMAGE_NAME) IMAGE_TAG=$(INDENT_IMAGE_TAG)
|
||||
|
||||
fmt format indent:
|
||||
$(MAKE) dockindent
|
||||
|
||||
indent-host:
|
||||
$(CLANG_FORMAT) --version | grep 'version 20.'
|
||||
$(CLANG_FORMAT) -i $(INDENT_FILES)
|
||||
@@ -1,31 +1,114 @@
|
||||
<img width="150" height="150" align="left" style="float: left; margin: 0 10px 0 0;" alt="Iaito logo" src="https://raw.githubusercontent.com/radareorg/iaito/master/src/img/iaito-circle.svg?sanitize=true">
|
||||
|
||||
# iaito
|
||||
# iaito: use radare2 with one hand!
|
||||
|
||||
iaito is the official graphical interface for radare2, a libre reverse engineering framework.
|
||||
|
||||
* Iaito was the original name of this GUI before being forked as Cutter.
|
||||
* It's written in Qt/C++ (qt5 for now). No Qt6 support yet (contribs are welcome)
|
||||
* Support latest versions, plugins and features of radare2
|
||||
* Use r2 plugins (f.ex: no need for r2ghidra-iaito plugin if r2ghidra is installed)
|
||||
* Focus on parity of commands, keybindings and r2-style workflows.
|
||||
* Translations are community [contributed](https://crowdin.com/project/iaito)!
|
||||
* Aims to support all the features from the core, not just disassembler-based ones
|
||||
* forensics, networking, bindiffing, solvers, ...
|
||||
<img width="150" height="150" align="left" style="float: left; margin: 0 30px 0 0;" alt="Iaito logo" src="https://raw.githubusercontent.com/radareorg/iaito/master/src/img/iaito.svg?sanitize=true">
|
||||
|
||||
* Based on radare2 and Qt-5/6
|
||||
* Iaito was the original name before being forked as Cutter.
|
||||
* Use all your favourite r2 plugins and scripts (nothing is specific to iaito)
|
||||
* Focus on simplicity, parity with commands, features, keybindings
|
||||
* Forensics, bindiffing, binary patching, .. not just a static disassembler
|
||||
|
||||
[](https://crowdin.com/project/iaito)
|
||||
[](https://github.com/radareorg/iaito/actions)
|
||||
[](https://repology.org/project/iaito/versions)
|
||||
|
||||

|
||||

|
||||
|
||||
## Help
|
||||
|
||||
Get help, updates, meet the community or discuss about development in these channels:
|
||||
|
||||
- **Discord:** [https://radare.org/discord](https://radare.org/discord)
|
||||
- **Telegram:** https://t.me/radare
|
||||
- **Mastodon:** [@radareorg](https://infosec.exchange/@radareorg)
|
||||
- **Translations:** [crowdin](https://crowdin.com/project/iaito)!
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
There are automated CI builds and [releases](https://github.com/radareorg/iaito/releases) of iaito for Linux, macOS and Windows.
|
||||
|
||||
On WSL or Linux you can use these steps to install it with Flatpak:
|
||||
|
||||
```sh
|
||||
sudo flatpak remote-add flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
sudo flatpak install flathub org.radare.iaito
|
||||
flatpak run org.radare.iaito
|
||||
```
|
||||
|
||||
On macOS, you may want to fix the signature
|
||||
|
||||
```sh
|
||||
sudo xattr -c /Applications/iaito.app
|
||||
sudo codesign --force --deep --sign - /Applications/iaito.app
|
||||
```
|
||||
|
||||
<a href='https://flathub.org/apps/details/org.radare.iaito'><img width='120' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a>
|
||||
|
||||
### Translations
|
||||
## Source Builds
|
||||
|
||||
### Dependencies
|
||||
|
||||
iaito requires [radare2](https://github.com/radareorg/radare2) and qt5 (or qt6):
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/radareorg/radare2 && radare2/sys/install.sh
|
||||
```
|
||||
|
||||
Install QT on macOS like this:
|
||||
|
||||
```sh
|
||||
brew install qt@5
|
||||
echo 'export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"' >> ~/.profile
|
||||
```
|
||||
|
||||
On Ubuntu/Debian
|
||||
|
||||
```sh
|
||||
sudo apt install qttools5-dev qttools5-dev-tools qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5svg5-dev make pkg-config build-essential
|
||||
```
|
||||
|
||||
For QT6:
|
||||
|
||||
```sh
|
||||
sudo apt install qt6-svg-dev
|
||||
```
|
||||
|
||||
### Compilation
|
||||
|
||||
```sh
|
||||
./configure
|
||||
make
|
||||
make run
|
||||
```
|
||||
|
||||
On macOS, `make run` launches the app from `build/iaito.app` without installing it.
|
||||
Registering the `iaito://` URI handler is optional; see [deep links](doc/deeplinks.md#macos).
|
||||
|
||||
To install the app in your home:
|
||||
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
|
||||
### Building iaito as an r2 plugin
|
||||
|
||||
It is also possible to launch iaito from the r2 shell reusing the Core instance:
|
||||
|
||||
```
|
||||
make plugin
|
||||
```
|
||||
|
||||
The previous command will build iaito, the iaito plugin and copy it it into your home plugin directory.
|
||||
|
||||
```
|
||||
$ r2 /bin/ls
|
||||
> iaito
|
||||
...
|
||||
```
|
||||
|
||||
### Translations (Optional)
|
||||
|
||||
Note: The flatpak/flathub version already ships the translations as an optional extension.
|
||||
|
||||
@@ -47,49 +130,14 @@ OR
|
||||
$ make install-translations # to install to system
|
||||
```
|
||||
|
||||
## Source Builds
|
||||
### Binaries
|
||||
|
||||
### Dependencies
|
||||
Most distros may Checkout the [Releases](https://github.com/radareorg/iaito/releases) page to download the build for Linux, macOS or Windows, and read the notes in case of problems!
|
||||
|
||||
iaito requires [radare2](https://github.com/radareorg/radare2) and qt5:
|
||||
As shown below, most distros are packaging iaito already, pick the build you like the most!
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/radareorg/radare2
|
||||
$ radare2/sys/install.sh
|
||||
```
|
||||
[](https://repology.org/project/iaito/versions)
|
||||
|
||||
Install QT on macOS like this:
|
||||
Snap:
|
||||
|
||||
```sh
|
||||
brew install qt@5
|
||||
echo 'export PATH="/opt/homebrew/opt/qt@5/bin:$PATH"' >> ~/.profile
|
||||
```
|
||||
|
||||
On Ubuntu/Debian
|
||||
|
||||
```sh
|
||||
sudo apt install qttools5-dev qttools5-dev-tools qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5svg5-dev make pkg-config build-essential
|
||||
|
||||
```
|
||||
|
||||
## Building from sources
|
||||
|
||||
```sh
|
||||
./configure
|
||||
make
|
||||
make run
|
||||
```
|
||||
|
||||
To install the app in your home:
|
||||
|
||||
```sh
|
||||
make install
|
||||
```
|
||||
|
||||
## Help
|
||||
|
||||
Get help, updates, meet the community or discuss about development in these channels:
|
||||
|
||||
- **Telegram:** https://t.me/radare
|
||||
- **IRC:** #radare on irc.freenode.net
|
||||
- **Twitter:** [@radareorg](https://twitter.com/radareorg)
|
||||
[](https://snapcraft.io/iaito)
|
||||
@@ -1,10 +1,8 @@
|
||||
PREFIX=@PREFIX@
|
||||
QMAKE=@QMAKE@
|
||||
LRELEASE=@LRELEASE@
|
||||
QMAKE=@QMAKE_BIN@
|
||||
|
||||
WANT_PYTHON=@WANT_PYTHON@
|
||||
WANT_PYTHON_BINDINGS=@WANT_PYTHON_BINDINGS@
|
||||
WANT_CRASH_REPORTS=@WANT_CRASH_REPORTS@
|
||||
WANT_DEBUGGER=@WANT_DEBUGGER@
|
||||
|
||||
DESTDIR?=
|
||||
MANDIR=@MANDIR@
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# This script was automatically generated by ACR v2.1.1
|
||||
# This script was automatically generated by ACR v2.2.8
|
||||
# @author: pancake <nopcode.org>
|
||||
# @url: http://www.nopcode.org
|
||||
# @repo: git clone https://github.com/radare/acr
|
||||
@@ -18,6 +18,9 @@ control_c() {
|
||||
exit 1
|
||||
}
|
||||
trap control_c 2
|
||||
WANT_QMAKE6=0
|
||||
WANT_CRASH_REPORTS=0
|
||||
WANT_DEBUGGER=1
|
||||
split_host() {
|
||||
S="$"
|
||||
while : ; do
|
||||
@@ -65,13 +68,27 @@ if [ -e "${VPATH}/config.guess" ]; then
|
||||
sh ${VPATH}/config.guess
|
||||
return
|
||||
fi
|
||||
CPU="`uname -m|sed -e 's, ,,g'|cut -d - -f 1`"
|
||||
CPU="`uname -m | tr 'A-Z' 'a-z' | sed -e 's, ,,g' | cut -d - -f 1`"
|
||||
OS="`uname -s|tr A-Z a-z`"
|
||||
uname -r | grep -qE "(Microsoft|WSL)" 2>/dev/null && OS="wsl"
|
||||
GNU="`uname --help 2>&1 | grep gnu`"
|
||||
[ "${GNU}" ] && OS="${OS}-gnu"
|
||||
[ "${CPU}" = ppc ] && CPU="powerpc"
|
||||
echo "${CPU}-unknown-${OS}"
|
||||
# normalize CPU
|
||||
case "${CPU}" in
|
||||
ppc*|powermac*|powermacintosh*|powerpc*)
|
||||
if echo "${CPU}" | grep -q '64'; then
|
||||
CPU=powerpc64
|
||||
else
|
||||
CPU=powerpc
|
||||
fi
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
VENDOR="unknown"
|
||||
if [ "${OS}" = "darwin" ]; then
|
||||
VENDOR=apple
|
||||
fi
|
||||
echo "${CPU}-${VENDOR}-${OS}"
|
||||
}
|
||||
|
||||
SEARCHPATH="/usr /usr/local /usr/pkg /sw"
|
||||
@@ -92,8 +109,8 @@ create_environ() {
|
||||
: ${SBINDIR:="${PREFIX}/sbin"}
|
||||
: ${ETCDIR:="${SPREFIX}/etc"}
|
||||
: ${LIBDIR:="${SPREFIX}/lib"}
|
||||
: ${PKGCFG_LIBDIR:="\${exec_prefix}/lib"}
|
||||
: ${PKGCFG_INCDIR:="\${prefix}/include"}
|
||||
: ${PKGCFG_LIBDIR:='${exec_prefix}/lib'}
|
||||
: ${PKGCFG_INCDIR:='${prefix}/include'}
|
||||
: ${LIBEXECDIR:="${SPREFIX}/libexec"}
|
||||
: ${INCLUDEDIR:="${SPREFIX}/include"}
|
||||
: ${DATADIR:="${SPREFIX}/share"}
|
||||
@@ -112,12 +129,12 @@ done
|
||||
: ${INSTALL_PROGRAM_STRIP:=${INSTALL} -m 755 -s}
|
||||
: ${INSTALL_MAN:=${INSTALL} -m 444}
|
||||
: ${INSTALL_LIB:=${INSTALL} -m 755 -c}
|
||||
PKGNAME='iaito' ; VERSION='5.8.4' ; VERSION_MAJOR=5; VERSION_MINOR=8; VERSION_PATCH=4; VERSION_NUMBER=50804; CONTACT_MAIL="[email protected]" ; CONTACT_NAME="pancake" ; CONTACT="pancake <[email protected]>" ;
|
||||
PKGNAME='iaito' ; VERSION='6.2.6' ; VERSION_MAJOR=6; VERSION_MINOR=2; VERSION_PATCH=6; VERSION_NUMBER=60206; CONTACT_MAIL="[email protected]" ; CONTACT_NAME="pancake" ; CONTACT="pancake <[email protected]>" ;
|
||||
}
|
||||
|
||||
show_usage() {
|
||||
cat <<EOF2
|
||||
'configure' configures iaito-5.8.4 to adapt to many kinds of systems.
|
||||
'configure' configures iaito-6.2.6 to adapt to many kinds of systems.
|
||||
|
||||
Usage: ./configure [OPTION]... [VAR=VALUE]...
|
||||
|
||||
@@ -159,6 +176,12 @@ System types:
|
||||
--target=TARGET configure for building compilers for TARGET [HOST]
|
||||
EOF2
|
||||
|
||||
printf "
|
||||
Optional Features:
|
||||
--with-qmake6 ignore qmake in path when qmake6 is found
|
||||
--with-crash-reports handle crashes nicely
|
||||
--without-debugger native support for debugging
|
||||
"
|
||||
printf "
|
||||
Some influential environment variables:
|
||||
CXX C++ compiler command
|
||||
@@ -189,10 +212,10 @@ ocho() {
|
||||
|
||||
show_version() {
|
||||
if [ "$QUIET" = 1 ]; then
|
||||
echo "5.8.4"
|
||||
echo "6.2.6"
|
||||
exit 0
|
||||
fi
|
||||
echo "iaito-5.8.4 configuration script done with acr v2.1.1.
|
||||
echo "iaito-6.2.6 configuration script done with acr v2.2.8.
|
||||
The 'Free Software Foundation' message is only for autodetection.
|
||||
Originally written by pancake <nopcode.org>."
|
||||
exit 0
|
||||
@@ -221,11 +244,12 @@ case $flag in
|
||||
show_version ; ;;
|
||||
-r|--r|--report)
|
||||
echo "PKGNAME: iaito"
|
||||
echo "VERSION: 5.8.4"
|
||||
echo "VERSION: 6.2.6"
|
||||
echo "AUTHOR: pancake"
|
||||
echo "EMAIL: [email protected]"
|
||||
echo "LANGS: c++"
|
||||
echo "PKGCONFIG: r_core"
|
||||
echo "FLAGS: --with-qmake6 --with-crash-reports --without-debugger"
|
||||
exit 0
|
||||
;;
|
||||
--cache-file)
|
||||
@@ -277,6 +301,9 @@ echo "PKGCONFIG: r_core"
|
||||
--mandir)
|
||||
MANDIR="$value"; ;;
|
||||
|
||||
"--with-qmake6") WANT_QMAKE6="1"; ;;
|
||||
"--with-crash-reports") WANT_CRASH_REPORTS="1"; ;;
|
||||
"--without-debugger") WANT_DEBUGGER="0"; ;;
|
||||
*) if [ "$value" ]; then eval "`echo $flag2=$value`" ;
|
||||
else echo ; echo "WARNING: Unknown flag '$flag'." >&2 ; echo ; fi ;;
|
||||
esac
|
||||
@@ -294,7 +321,7 @@ parse_options "$1"
|
||||
shift
|
||||
done
|
||||
|
||||
ENVWORDS="MANDIR DESCRIPTION INFODIR LIBDIR INCLUDEDIR LOCALSTATEDIR ETCDIR SYSCONFDIR DATADIR DOCDIR LIBEXECDIR SBINDIR BINDIR EPREFIX PREFIX SPREFIX TARGET HOST BUILD INSTALL INSTALL_LIB INSTALL_MAN INSTALL_PROGRAM INSTALL_PROGRAM_STRIP INSTALL_DIR INSTALL_SCRIPT INSTALL_DATA HOST_OS HOST_CPU BUILD_OS BUILD_CPU TARGET_OS TARGET_CPU VERSION VERSION_MAJOR VERSION_MINOR VERSION_PATCH VERSION_NUMBER PKGCFG_LIBDIR PKGCFG_INCDIR PKGNAME VPATH CONTACT CONTACT_NAME CONTACT_MAIL CXX CXXFLAGS LDFLAGS HAVE_LANG_CXX CPP PKGCONFIG HAVE_R2 R2 R2_CFLAGS R2_LDFLAGS HAVE_PKGCFG_R_CORE HAVE_QMAKE QMAKE HAVE_LRELEASE LRELEASE WANT_PYTHON WANT_PYTHON_BINDINGS WANT_CRASH_REPORTS"
|
||||
ENVWORDS="MANDIR DESCRIPTION INFODIR LIBDIR INCLUDEDIR LOCALSTATEDIR ETCDIR SYSCONFDIR DATADIR DOCDIR LIBEXECDIR SBINDIR BINDIR EPREFIX PREFIX SPREFIX TARGET HOST BUILD INSTALL INSTALL_LIB INSTALL_MAN INSTALL_PROGRAM INSTALL_PROGRAM_STRIP INSTALL_DIR INSTALL_SCRIPT INSTALL_DATA HOST_OS HOST_CPU BUILD_OS BUILD_CPU TARGET_OS TARGET_CPU VERSION VERSION_MAJOR VERSION_MINOR VERSION_PATCH VERSION_NUMBER PKGCFG_LIBDIR PKGCFG_INCDIR PKGNAME VPATH CONTACT CONTACT_NAME CONTACT_MAIL CXX CXXFLAGS LDFLAGS HAVE_LANG_CXX CPP PKGCONFIG HAVE_R2 R2 R2_CFLAGS R2_LDFLAGS HAVE_PKGCFG_R_CORE HAVE_QMAKE QMAKE HAVE_QMAKE6 QMAKE6 WANT_QMAKE6 QMAKE_BIN WANT_CRASH_REPORTS WANT_DEBUGGER"
|
||||
|
||||
create_environ
|
||||
|
||||
@@ -336,6 +363,7 @@ exit 1
|
||||
if [ 0 = 0 ]; then echo ${CPP}; else
|
||||
echo "ERROR: ${CPP} cannot parse sources"; fi
|
||||
ochof "checking for pkg-config... "
|
||||
ENVWORDS="${ENVWORDS} HAVE_PKGCONFIG"
|
||||
if [ -n "$PKGCONFIG" ]; then
|
||||
if [ -x "$PKGCONFIG" ]; then
|
||||
_HAVE_PKGCONFIG="${PKGCONFIG}"
|
||||
@@ -359,7 +387,9 @@ else
|
||||
fi
|
||||
if [ -n "${PKGCONFIG}" ]; then
|
||||
ocho ${PKGCONFIG}
|
||||
HAVE_PKGCONFIG=1
|
||||
else
|
||||
HAVE_PKGCONFIG=0
|
||||
echo "Cannot find pkg-config or pkgconf in PATH" >&2
|
||||
exit 1
|
||||
ocho no; fi
|
||||
@@ -431,18 +461,16 @@ if [ "" = 1 ]; then
|
||||
echo "Cannot find qmake" >&2
|
||||
else
|
||||
echo no
|
||||
fi
|
||||
echo "error: This program is required." >&2
|
||||
exit 1 ; fi
|
||||
ochof "checking for lrelease... "
|
||||
if [ -x "${LRELEASE}" ]; then
|
||||
FIND=${LRELEASE}
|
||||
fi ; fi
|
||||
ochof "checking for qmake6... "
|
||||
if [ -x "${QMAKE6}" ]; then
|
||||
FIND=${QMAKE6}
|
||||
else
|
||||
FIND=""
|
||||
IFS=:
|
||||
for A in ${PATH} ; do
|
||||
if [ -x "${A}/lrelease" ]; then
|
||||
FIND="${A}/lrelease"
|
||||
if [ -x "${A}/qmake6" ]; then
|
||||
FIND="${A}/qmake6"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
@@ -450,20 +478,26 @@ else
|
||||
fi
|
||||
if [ -n "${FIND}" ]; then
|
||||
ocho ${FIND};
|
||||
HAVE_LRELEASE=1
|
||||
LRELEASE=${FIND}
|
||||
HAVE_QMAKE6=1
|
||||
QMAKE6=${FIND}
|
||||
else
|
||||
HAVE_LRELEASE=0
|
||||
LRELEASE=lrelease
|
||||
HAVE_QMAKE6=0
|
||||
QMAKE6=qmake6
|
||||
if [ "" = 1 ]; then
|
||||
echo "Cannot find lrelease" >&2
|
||||
echo "Cannot find qmake6" >&2
|
||||
else
|
||||
echo no
|
||||
fi
|
||||
echo "error: This program is required." >&2
|
||||
exit 1 ; fi
|
||||
WANT_PYTHON="0"
|
||||
WANT_PYTHON_BINDINGS="0"
|
||||
fi ; fi
|
||||
if [ "$WANT_QMAKE6" = "1" ]; then
|
||||
if [ "$HAVE_QMAKE6" = "1" ]; then
|
||||
QMAKE_BIN="${QMAKE6}"
|
||||
else
|
||||
case "$undefined_variable" in 0|"") echo ; echo "ERROR: Missing qmake6" >&2 ; echo ; exit 1 ;; esac; fi
|
||||
else
|
||||
if [ "$HAVE_QMAKE" = "1" ]; then
|
||||
QMAKE_BIN="${QMAKE}"; fi; fi
|
||||
if [ "$QMAKE_BIN" = """" ]; then
|
||||
case "$undefined_variable" in 0|"") echo ; echo "ERROR: Missing qmake" >&2 ; echo ; exit 1 ;; esac; fi
|
||||
WANT_CRASH_REPORTS="0"
|
||||
SEDFLAGS=" -e '"
|
||||
COUNT=0
|
||||
@@ -471,7 +505,14 @@ for A in ${ENVWORDS} ; do
|
||||
[ "${A}" = VPATH ] && continue
|
||||
[ "${A}" = srcdir ] && continue
|
||||
eval "VAR=\$${A}"
|
||||
VAR="`echo ${VAR} | sed -e 's/\,/\\\,/g'`"
|
||||
case "" in
|
||||
mingw*|cygwin*|msys*)
|
||||
VAR="`echo ${VAR} | sed -e 's/\\/\\\\/g' -e 's/\,/\\\,/g'`"
|
||||
;;
|
||||
*)
|
||||
VAR="`echo ${VAR} | sed -e 's/\,/\\\,/g'`"
|
||||
;;
|
||||
esac
|
||||
[ $COUNT = 10 ] && COUNT=0 && SEDFLAGS="${SEDFLAGS}' -e '"
|
||||
COUNT=$(($COUNT+1))
|
||||
SEDFLAGS="${SEDFLAGS}s,@${A}@,${VAR},g;"
|
||||
@@ -509,3 +550,12 @@ done
|
||||
done
|
||||
|
||||
do_remove
|
||||
if [ "$QUIET" = 0 ]; then
|
||||
echo
|
||||
echo "Final report:"
|
||||
for A in R2 QMAKE_BIN ; do
|
||||
eval VAL="\$${A}"
|
||||
[ -z "${VAL}" ] && VAL="\"\""
|
||||
echo " - ${A} = ${VAL}"
|
||||
done
|
||||
fi
|
||||
@@ -1,5 +1,5 @@
|
||||
PKGNAME iaito
|
||||
VERSION 5.8.4
|
||||
VERSION 6.2.6
|
||||
CONTACT pancake ; [email protected]
|
||||
|
||||
LANG_CXX!
|
||||
@@ -7,16 +7,34 @@ LANG_CXX!
|
||||
USE_PKGCONFIG!
|
||||
CHKPRG! R2 r2
|
||||
PKGCFG! R2_CFLAGS R2_LDFLAGS r_core
|
||||
CHKPRG! QMAKE qmake
|
||||
CHKPRG! LRELEASE lrelease
|
||||
CHKPRG QMAKE qmake
|
||||
CHKPRG QMAKE6 qmake6
|
||||
(( CHKPRG! LRELEASE lrelease ))
|
||||
|
||||
ARG_WITH WANT_QMAKE6 qmake6 ignore qmake in path when qmake6 is found ;
|
||||
|
||||
IFEQ WANT_QMAKE6 1 ; {
|
||||
IFEQ HAVE_QMAKE6 1 ; {
|
||||
QMAKE_BIN = ${QMAKE6} ;
|
||||
}{
|
||||
DIENOW Missing qmake6 ;
|
||||
}
|
||||
}{
|
||||
IFEQ HAVE_QMAKE 1 ; {
|
||||
QMAKE_BIN = ${QMAKE} ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
IFEQ QMAKE_BIN "" ; {
|
||||
DIENOW Missing qmake ;
|
||||
}
|
||||
|
||||
WANT_PYTHON = 0 ;
|
||||
WANT_PYTHON_BINDINGS = 0 ;
|
||||
WANT_CRASH_REPORTS = 0 ;
|
||||
((
|
||||
ARG_WITH WANT_PYTHON python build with support for Python ;
|
||||
ARG_WITH WANT_PYTHON_BINDINGS python-bindings build with Python bindings ;
|
||||
|
||||
ARG_WITH WANT_CRASH_REPORTS crash-reports handle crashes nicely ;
|
||||
))
|
||||
ARG_WITHOUT WANT_DEBUGGER debugger native support for debugging ;
|
||||
|
||||
SUBDIRS config.mk ;
|
||||
|
||||
REPORT R2 QMAKE_BIN ;
|
||||
@@ -10,7 +10,7 @@ IF !ERRORLEVEL! NEQ 0 (
|
||||
EXIT /B 1
|
||||
)
|
||||
|
||||
SET "R2DIST=r2_dist"
|
||||
SET "R2DIR=radare2"
|
||||
SET "BUILDDIR=build_%PLATFORM%"
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@ IF NOT EXIST "src\translations\NUL" (
|
||||
FOR %%i in (src\translations\*.ts) DO lrelease %%i
|
||||
|
||||
ECHO Preparing directory
|
||||
rem MOVE radare2 %R2DIR%
|
||||
IF NOT EXIST %BUILDDIR% (
|
||||
MKDIR %BUILDDIR%
|
||||
)
|
||||
CD %BUILDDIR%
|
||||
|
||||
IF NOT DEFINED IAITO_ENABLE_CRASH_REPORTS (
|
||||
@@ -29,4 +33,5 @@ SET "IAITO_ENABLE_CRASH_REPORTS=false"
|
||||
|
||||
ECHO Building iaito
|
||||
qmake BREAKPAD_SOURCE_DIR=%BREAKPAD_SOURCE_DIR% IAITO_ENABLE_CRASH_REPORTS=%IAITO_ENABLE_CRASH_REPORTS% %* ..\src\iaito.pro -config release
|
||||
COPY iaito_resource.rc ..\src
|
||||
IF !ERRORLEVEL! NEQ 0 EXIT /B 1
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
set(EMBED_PYTHON_SH "@EMBED_PYTHON_SH@")
|
||||
set(PYTHON_FRAMEWORK_DIR "@PYTHON_FRAMEWORK_DIR@")
|
||||
set(PYSIDE_PREFIX "@PYSIDE_PREFIX@")
|
||||
|
||||
get_filename_component(BUNDLE_PATH "${CMAKE_INSTALL_PREFIX}/../.." ABSOLUTE)
|
||||
|
||||
set(ENV{PKG_CONFIG_PATH} "${PYSIDE_PREFIX}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
|
||||
|
||||
# TODO: instead of calling a shellscript, implement the whole thing in cmake
|
||||
execute_process(COMMAND
|
||||
"${EMBED_PYTHON_SH}"
|
||||
"${PYTHON_FRAMEWORK_DIR}"
|
||||
"${BUNDLE_PATH}"
|
||||
"${BUNDLE_PATH}/Contents/MacOS/Iaito"
|
||||
RESULT_VARIABLE SCRIPT_RESULT)
|
||||
if(SCRIPT_RESULT)
|
||||
message(FATAL_ERROR "Failed to bundle python")
|
||||
endif()
|
||||
|
||||
@@ -6,7 +6,6 @@ set(ADJUST_RIZIN_LIBS "@ADJUST_RIZIN_LIBS@")
|
||||
set(IAITO_ENABLE_CRASH_REPORTS "@IAITO_ENABLE_CRASH_REPORTS@")
|
||||
set(Breakpad_LINK_LIBRARIES "@Breakpad_LINK_LIBRARIES@")
|
||||
set(IAITO_PACKAGE_DEPENDENCIES "@IAITO_PACKAGE_DEPENDENCIES@")
|
||||
set(IAITO_ENABLE_PYTHON "@IAITO_ENABLE_PYTHON@")
|
||||
|
||||
macro(run_or_die)
|
||||
execute_process(${ARGV} RESULT_VARIABLE PROC_RESULT)
|
||||
@@ -65,13 +64,7 @@ run_or_die(COMMAND install_name_tool
|
||||
set(MACDEPLOYQT_COMMAND "${MACDEPLOYQT_PATH}" "${BUNDLE_PATH}" "-verbose=2" "-libpath=${CMAKE_INSTALL_PREFIX}/lib")
|
||||
message("Running macdeployqt \"${MACDEPLOYQT_COMMAND}\"")
|
||||
run_or_die(COMMAND ${MACDEPLOYQT_COMMAND}) # First run
|
||||
if (IAITO_PACKAGE_DEPENDENCIES AND IAITO_ENABLE_PYTHON)
|
||||
file(REAL_PATH "${FRAMEWORK_DIR}/Python.framework/Python" _python_lib_path)
|
||||
message("Python lib ${_python_lib_path}")
|
||||
list(APPEND MACDEPLOYQT_COMMAND "-executable=${_python_lib_path}")
|
||||
endif()
|
||||
# Qt plugins are not getting deployed on first macdeployqt run. Runing twice helps.
|
||||
# If python is added as additional executable in first run it also breaks plugin copying.
|
||||
# Qt plugins are not getting deployed on first macdeployqt run. Running twice helps.
|
||||
run_or_die(COMMAND ${MACDEPLOYQT_COMMAND}) # Second run
|
||||
|
||||
# Clean up the mess that macdeployqt made (duplicate rz libs, we only want the ones in the prefix)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
NAME=iaito
|
||||
SECTION=editors
|
||||
PRIORITY=optional
|
||||
DEPENDS=qt5-default libqt5svg5
|
||||
DEPENDS=$(shell ../getpkgversions.sh radare2), libqt6core6 (>= 6.2.4), libqt6gui6 (>= 6.2.4), libqt6widgets6 (>= 6.2.4), libqt6network6 (>= 6.2.4), libqt6svg6 (>= 6.2.4), libqt6svgwidgets6 (>= 6.2.4), qt6-qpa-plugins (>= 6.2.4)
|
||||
MAINTAINER=pancake <[email protected]>
|
||||
ARCH?=amd64
|
||||
VERSION=$(shell ../../../configure -qV)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
for pkg in "$@"
|
||||
do
|
||||
VERSION=$(apt show $pkg 2> /dev/null | grep -F "Version: " | sed -e 's/Version:\s\([[[:digit:]\.]\+\).*/\1/')
|
||||
if [ $pkg != $1 ]; then
|
||||
echo -n ", "
|
||||
fi
|
||||
echo -n "$pkg (>= $VERSION)"
|
||||
done
|
||||
@@ -1,6 +1,5 @@
|
||||
PACKAGE_DIR=$(shell pwd)
|
||||
include ./CONFIG
|
||||
DEPENDS=
|
||||
|
||||
SUDO=fakeroot
|
||||
SUDO=sudo
|
||||
|
||||
@@ -1,12 +1,87 @@
|
||||
all:
|
||||
rm -f ../../build/iaito.dmg
|
||||
cd ../../build && macdeployqt iaito.app -dmg && cp -f iaito.dmg ../dist/macos
|
||||
.PHONY: all app dmg zip unpack-comps clean mrproper
|
||||
|
||||
app:
|
||||
$(SHELL) make-macos-app.sh
|
||||
all: clean app dmg
|
||||
app: disk/iaito.app
|
||||
dmg: iaito.dmg
|
||||
zip: iaito.zip
|
||||
unpack-comps: radare2-unpkg extra/r2ai extra/r2ghidra extra/r2ghidra_sleigh
|
||||
|
||||
pkg:
|
||||
$(SHELL) make-macos-pkg.sh
|
||||
disk/iaito.app: ../../build/iaito.app unpack-comps
|
||||
mkdir disk
|
||||
# Copy base bundle app
|
||||
cp -a ../../build/iaito.app disk/
|
||||
# Copy r2 binary plugins
|
||||
mkdir -p disk/iaito.app/Contents/PlugIns/radare2
|
||||
install -p -m 0755 \
|
||||
extra/r2ghidra/core_ghidra.dylib \
|
||||
disk/iaito.app/Contents/PlugIns/radare2/
|
||||
# Copy r2 pkg files and update linking path for all binary files
|
||||
scripts/embed-radare2.sh radare2-unpkg disk/iaito.app
|
||||
# Copy r2 non-binary plugins
|
||||
install -p -m 0644 \
|
||||
extra/r2ai/decai/decai.r2.js \
|
||||
disk/iaito.app/Contents/Resources/radare2/lib/radare2/last/
|
||||
cp -a extra/r2ghidra_sleigh \
|
||||
disk/iaito.app/Contents/Resources/radare2/share/
|
||||
# Copy QT frameworks
|
||||
macdeployqt disk/iaito.app -verbose=2
|
||||
|
||||
iaito.dmg: disk/iaito.app
|
||||
cp doc/README.txt disk/READ_THIS_FIRST.txt
|
||||
ln -fs /Applications disk/
|
||||
hdiutil create -format UDZO -fs APFS -volname iaito -srcfolder disk iaito
|
||||
|
||||
iaito.zip:
|
||||
cp doc/README.txt disk/READ_THIS_FIRST.txt
|
||||
ditto -c -k --rsrc --extattr --sequesterRsrc disk iaito.zip
|
||||
|
||||
radare2-unpkg: radare2.pkg
|
||||
pkgutil --expand-full $< $@
|
||||
touch $@
|
||||
|
||||
radare2.pkg:
|
||||
echo "Download first radare2.pkg from https://github.com/radareorg/radare2/releases"
|
||||
@false
|
||||
|
||||
r2ai.tar.gz:
|
||||
echo "Download first r2ai.tar.gz (source) from https://github.com/radareorg/r2ai/releases"
|
||||
@false
|
||||
|
||||
extra/r2ai: r2ai.tar.gz
|
||||
mkdir -p extra
|
||||
rm -rf extra/r2ai extra/r2ai-* extra/radareorg-r2ai-*
|
||||
tar -f $< -xzC extra/
|
||||
cd extra && mv *r2ai-* r2ai
|
||||
touch $@
|
||||
|
||||
r2ghidra.zip:
|
||||
echo "Download first r2ghidra.zip (binary) from https://github.com/radareorg/r2ghidra/releases"
|
||||
@false
|
||||
|
||||
extra/r2ghidra: r2ghidra.zip
|
||||
mkdir -p extra
|
||||
rm -rf extra/r2ghidra extra/r2ghidra-*-macos-*
|
||||
unzip $< -d extra/
|
||||
cd extra && mv r2ghidra-*-macos-* r2ghidra
|
||||
touch $@
|
||||
|
||||
r2ghidra_sleigh.zip:
|
||||
echo "Download first r2ghidra_sleigh.zip from https://github.com/radareorg/r2ghidra/releases"
|
||||
@false
|
||||
|
||||
extra/r2ghidra_sleigh: r2ghidra_sleigh.zip
|
||||
mkdir -p extra
|
||||
rm -rf extra/r2ghidra_sleigh*
|
||||
unzip $< -d extra/
|
||||
cd extra && mv r2ghidra_sleigh-* r2ghidra_sleigh
|
||||
touch $@
|
||||
|
||||
../../build/iaito.app:
|
||||
echo "Building iaito..."
|
||||
$(MAKE) -C ../.. QMAKE_FLAGS=IAITO_BUNDLE_R2_APPBUNDLE=true
|
||||
|
||||
clean:
|
||||
rm -rf macos-pkg tmp
|
||||
rm -rf radare2-unpkg disk iaito.dmg
|
||||
|
||||
mrproper: clean
|
||||
rm -rf radare2.pkg r2ai.tar.gz r2ghidra*.zip extra
|
||||
@@ -1,26 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<installer-gui-script minSpecVersion="2">
|
||||
<title>Iaito</title>
|
||||
<license file="COPYING.LESSER" mime-type="text/plain"/>
|
||||
<pkg-ref id="org.radare.iaito">
|
||||
<bundle-version/>
|
||||
</pkg-ref>
|
||||
<options customize="never" require-scripts="false" hostArchitectures="x86_64,arm64"/>
|
||||
<volume-check>
|
||||
<allowed-os-versions>
|
||||
<os-version min="10.7"/>
|
||||
</allowed-os-versions>
|
||||
</volume-check>
|
||||
<choices-outline>
|
||||
<line choice="default">
|
||||
<line choice="org.radare.iaito"/>
|
||||
</line>
|
||||
</choices-outline>
|
||||
<choice id="default" customLocation="usr"/>
|
||||
<choice id="org.radare.iaito" visible="false">
|
||||
<pkg-ref id="org.radare.iaito"/>
|
||||
</choice>
|
||||
<pkg-ref id="org.radare.iaito" version="0" onConclusion="none" installKBytes="51182">#iaito.pkg</pkg-ref>
|
||||
<welcome file="welcome.rtf" mime-type="text/enriched"/>
|
||||
<background file="iaitologo.png" mime-type="image/png" alignment="bottomleft"/>
|
||||
</installer-gui-script>
|
||||
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
Before Width: | Height: | Size: 33 KiB |
@@ -1,13 +0,0 @@
|
||||
{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210
|
||||
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
|
||||
{\colortbl;\red255\green255\blue255;}
|
||||
\margl1440\margr1440\vieww10800\viewh6300\viewkind0
|
||||
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural
|
||||
|
||||
\f0\fs28 \cf0 \
|
||||
\
|
||||
You will be guided through the steps necessary to\
|
||||
install this software. This pkg requires radare2 to\
|
||||
be installed in your system. \
|
||||
\
|
||||
This will install Iaito in /usr/local}
|
||||
@@ -0,0 +1,7 @@
|
||||
IMPORTANT!
|
||||
|
||||
To install iaito you can drag and drop the application to /Applications.
|
||||
But then you are required to run this commands from Terminal before you can execute for the first time.
|
||||
|
||||
sudo xattr -c /Applications/iaito.app
|
||||
sudo codesign --force --deep --sign - /Applications/iaito.app
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
SKIPBUILD=0
|
||||
BUNDLE=1
|
||||
|
||||
SRC=/tmp/iaito-macos
|
||||
PREFIX=/usr/local
|
||||
DST="$(pwd)/tmp/iaito.unpkg"
|
||||
if [ -n "$1" ]; then
|
||||
VERSION="$1"
|
||||
else
|
||||
VERSION="`../../configure -qV`"
|
||||
[ -z "${VERSION}" ] && VERSION=5.3.l
|
||||
fi
|
||||
|
||||
[ -z "${MAKE}" ] && MAKE=make
|
||||
|
||||
while : ; do
|
||||
[ -x "$PWD/configure" ] && break
|
||||
[ "$PWD" = / ] && break
|
||||
cd ..
|
||||
done
|
||||
|
||||
[ ! -x "$PWD/configure" ] && exit 1
|
||||
|
||||
pwd
|
||||
if [ ! -d build/iaito.app ]; then
|
||||
rm -rf "${SRC}"
|
||||
${MAKE} mrproper 2>/dev/null
|
||||
# ${MAKE} -j4 || exit 1
|
||||
fi
|
||||
export CFLAGS=-O2
|
||||
if [ "$SKIPBUILD" = 0 ]; then
|
||||
./configure --prefix="${PREFIX}" || exit 1
|
||||
fi
|
||||
${MAKE} install install-translations PREFIX="${PREFIX}" DESTDIR=${SRC} || exit 1
|
||||
mkdir -p "${DST}"
|
||||
echo "DST=$DST"
|
||||
if [ -d "${SRC}" ]; then
|
||||
( # bundle
|
||||
LIBS=`rabin2 -ql ${SRC}/usr/local/bin/iaito | grep -v System`
|
||||
mkdir -p bundle
|
||||
for a in $LIBS ; do
|
||||
echo "LIB $a"
|
||||
D="`basename '$a'`"
|
||||
cp -f $a bundle
|
||||
LIBS2=`rabin2 -ql ${a} | grep -v System`
|
||||
for b in $LIBS2 ; do
|
||||
D2="`basename '$a'`"
|
||||
echo "$a $b"
|
||||
cp $b bundle
|
||||
done
|
||||
done
|
||||
# binary patch the binary
|
||||
echo cp -f ${SRC}/usr/local/bin/iaito bundle/
|
||||
cp -f ${SRC}/usr/local/bin/iaito bundle/
|
||||
for a in bundle/* ; do
|
||||
libs=`rabin2 -ql $a | grep -v System`
|
||||
for b in $libs ; do
|
||||
bn=`basename "$b"`
|
||||
if ls bundle | grep -q "$bn" ; then
|
||||
# its bundled
|
||||
from="$b"
|
||||
to="@executable_path/lib/$bn"
|
||||
echo install_name_tool "$from" "$to" "$a"
|
||||
install_name_tool -change "$from" "$to" "$a"
|
||||
fi
|
||||
done
|
||||
done
|
||||
rm -rf bundle/lib
|
||||
mkdir -p bundle/lib
|
||||
mv bundle/* bundle/lib
|
||||
mv bundle/lib/iaito bundle/
|
||||
# cp -f ${SRC}/usr/local/bin/iaito bundle/
|
||||
exit 1
|
||||
)
|
||||
( # massage
|
||||
cd ${SRC} && find .
|
||||
mv usr/local/share/iaito/translations Applications/iaito.app/Contents/Resources || exit 1
|
||||
cd Applications || exit 1
|
||||
rm -f /tmp/iaito-${VERSION}.zip
|
||||
zip -r /tmp/iaito-${VERSION}.zip iaito.app
|
||||
)
|
||||
mv /tmp/iaito-${VERSION}.zip dist/macos
|
||||
else
|
||||
echo "Failed install. DESTDIR is empty"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,57 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# based on
|
||||
# http://blog.coolaj86.com/articles/how-to-unpackage-and-repackage-pkg-macos.html
|
||||
|
||||
# to uninstall:
|
||||
# sudo pkgutil --forget org.radare.iaito
|
||||
SKIPBUILD=0
|
||||
|
||||
SRC=/tmp/iaito-macos
|
||||
PREFIX=/usr/local
|
||||
DST="$(pwd)/tmp/iaito.unpkg"
|
||||
if [ -n "$1" ]; then
|
||||
VERSION="$1"
|
||||
else
|
||||
VERSION="`../../configure -qV`"
|
||||
[ -z "${VERSION}" ] && VERSION=5.3.l
|
||||
fi
|
||||
|
||||
[ -z "${MAKE}" ] && MAKE=make
|
||||
|
||||
while : ; do
|
||||
[ -x "$PWD/configure" ] && break
|
||||
[ "$PWD" = / ] && break
|
||||
cd ..
|
||||
done
|
||||
|
||||
[ ! -x "$PWD/configure" ] && exit 1
|
||||
|
||||
pwd
|
||||
if [ ! -d build/iaito.app ]; then
|
||||
rm -rf "${SRC}"
|
||||
${MAKE} mrproper 2>/dev/null
|
||||
# ${MAKE} -j4 || exit 1
|
||||
fi
|
||||
export CFLAGS=-O2
|
||||
if [ "$SKIPBUILD" = 0 ]; then
|
||||
./configure --prefix="${PREFIX}" || exit 1
|
||||
fi
|
||||
${MAKE} install install-translations PREFIX="${PREFIX}" DESTDIR=${SRC} || exit 1
|
||||
mkdir -p "${DST}"
|
||||
echo "DST=$DST"
|
||||
if [ -d "${SRC}" ]; then
|
||||
(
|
||||
cd ${SRC} && \
|
||||
find . | cpio -o --format odc | gzip -c > "${DST}/Payload"
|
||||
)
|
||||
echo mkbom "${SRC}" "${DST}/Bom"
|
||||
mkbom "${SRC}" "${DST}/Bom"
|
||||
cp -rf dist/macos/Metadata/* "${DST}"
|
||||
pwd
|
||||
# Repackage
|
||||
pkgutil --flatten "${DST}" "${DST}/../../iaito-${VERSION}.pkg"
|
||||
else
|
||||
echo "Failed install. DESTDIR is empty"
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
CMD=$(basename "$0")
|
||||
APPDIR=$(cd "$(dirname "$0")/../../../.."; pwd)
|
||||
|
||||
R2_BINDIR="${APPDIR}/Contents/Helpers"
|
||||
R2_LIBDIR="${APPDIR}/Contents/Frameworks"
|
||||
R2_PREFIX="${APPDIR}/Contents/Resources/radare2"
|
||||
|
||||
XDG_CACHE_HOME="${HOME}/Library/Caches/radareorg/iaito"
|
||||
XDG_CONFIG_HOME="${HOME}/Library/Preferences/radareorg/iaito"
|
||||
XDG_DATA_HOME="${HOME}/Library/Application Support/radareorg/iaito"
|
||||
|
||||
export R2_BINDIR
|
||||
export R2_LIBDIR
|
||||
export R2_PREFIX
|
||||
export XDG_CACHE_HOME
|
||||
export XDG_CONFIG_HOME
|
||||
export XDG_DATA_HOME
|
||||
|
||||
exec "${R2_BINDIR}/${CMD}" "$@"
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
R2PKGDIR="$1"
|
||||
APPDIR="$2"
|
||||
|
||||
SCRIPTS="$(dirname "$0")"
|
||||
R2DIR="${R2PKGDIR}/Payload/usr/local"
|
||||
R2V=$(readlink "${R2DIR}/lib/radare2/last")
|
||||
|
||||
fix_binary() {
|
||||
FILE=$1
|
||||
PREFIX=$2
|
||||
shift 2
|
||||
echo "Change library paths for \"$FILE\"..."
|
||||
ARGS=$(otool -L "$FILE" | awk 'BEGIN{ORS=" "}/\/usr\/local\/lib\/libr_/{dst=$1; sub(/\/usr\/local\/lib/,"'"$PREFIX"'", dst); print "-change "$1" "dst}')
|
||||
if [ -n "$ARGS" -o -n "$1" ]; then
|
||||
echo " install_name_tool $@ $ARGS \"$FILE\""
|
||||
install_name_tool $@ $ARGS "$FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
mkdir -p \
|
||||
"${APPDIR}/Contents/Helpers" \
|
||||
"${APPDIR}/Contents/Frameworks" \
|
||||
"${APPDIR}/Contents/PlugIns/radare2" \
|
||||
"${APPDIR}/Contents/Resources/radare2/bin" \
|
||||
"${APPDIR}/Contents/Resources/radare2/lib/radare2/${R2V}/"
|
||||
|
||||
cp -a "${R2DIR}/bin/"* "${APPDIR}/Contents/Helpers/"
|
||||
cp -a "${R2DIR}/lib/radare2/${R2V}/"*.dylib "${APPDIR}/Contents/PlugIns/radare2/"
|
||||
cp -a "${R2DIR}/lib/"*.dylib "${APPDIR}/Contents/Frameworks/"
|
||||
cp -a "${R2DIR}/include" "${APPDIR}/Contents/Resources/radare2/"
|
||||
cp -a "${R2DIR}/share" "${APPDIR}/Contents/Resources/radare2/"
|
||||
#cp -a "${R2DIR}/lib/pkgconfig" "${APPDIR}/Contents/Resources/radare2/lib/"
|
||||
cp -p "${SCRIPTS}/command.sh" "${APPDIR}/Contents/Resources/radare2/bin/radare2"
|
||||
cp -a "${R2DIR}/lib/radare2/last" "${APPDIR}/Contents/Resources/radare2/lib/radare2/"
|
||||
#cp -a "${R2DIR}/lib/radare2/${R2V}/"*.js "${APPDIR}/Contents/Resources/radare2/lib/radare2/${R2V}/"
|
||||
|
||||
# Move all non-binary files outside Helpers folder
|
||||
mv "${APPDIR}/Contents/Helpers/clang-format-radare2" "${APPDIR}/Contents/Resources/radare2/bin/"
|
||||
|
||||
(
|
||||
cd "${APPDIR}/Contents/MacOS"
|
||||
fix_binary "iaito" "@rpath"
|
||||
)
|
||||
|
||||
(
|
||||
cd "${APPDIR}/Contents/Helpers"
|
||||
for c in *; do
|
||||
[ -L "$c" ] || fix_binary "$c" "@rpath" -add_rpath "@executable_path/../Frameworks"
|
||||
[ "$c" != "radare2" ] && ln -s radare2 "../Resources/radare2/bin/$c"
|
||||
done
|
||||
)
|
||||
|
||||
(
|
||||
LIBS=$(cd "${R2DIR}/lib"; ls *.dylib)
|
||||
cd "${APPDIR}/Contents/Frameworks"
|
||||
for c in $LIBS; do
|
||||
[ -L "$c" ] || fix_binary "$c" "@loader_path" -id "@rpath/$c"
|
||||
c2=$c # Resolve upto 2 link levels
|
||||
[ -L "$c2" ] && c2=$(readlink "$c2")
|
||||
[ -L "$c2" ] && c2=$(readlink "$c2")
|
||||
ln -s "../../../Frameworks/$c2" "../Resources/radare2/lib/$c"
|
||||
done
|
||||
)
|
||||
|
||||
(
|
||||
cd "${APPDIR}/Contents/PlugIns/radare2"
|
||||
for c in *.dylib; do
|
||||
[ -L "$c" ] || fix_binary "$c" "@rpath" -add_rpath "@loader_path/../../Frameworks" -id "$c"
|
||||
ln -s "../../../../../PlugIns/radare2/$c" "../../Resources/radare2/lib/radare2/${R2V}/$c"
|
||||
done
|
||||
# Required for plugins rpath when loaded from Resources
|
||||
ln -s "../../../Frameworks" "../../Resources/radare2/lib/Frameworks"
|
||||
)
|
||||
@@ -0,0 +1,50 @@
|
||||
# Data Analysis
|
||||
|
||||
Open **View → Data → Analysis**. The dock is hidden in the default layout and when
|
||||
first added to an older saved layout. Hidden docks do not sample data. **Zoom** is
|
||||
also available under **View → Data**.
|
||||
|
||||
- **Algorithms** enables multiple byte metrics. Hover over a named legend entry
|
||||
for its definition; click it to edit its color or visibility. Clicking the legend
|
||||
does not remove the series.
|
||||
- **Options → Resolution (buckets)** selects 32, 64, 128, 256, 512, 1024, 2048 or
|
||||
4096 buckets. Lower values give coarser graphs and less work. The default is 1024.
|
||||
- **Options** also controls lines, filled lines or vertical bars, separate tracks,
|
||||
greyscale/rainbow/theme colors, custom colors, and structural markers.
|
||||
- Click the graph to seek. Drag to select bytes. Wheel or `+`/`-` zooms;
|
||||
Shift+wheel or the arrow keys pans. `Home` fits all data, and `Esc` clears selection.
|
||||
- The bottom entropy overview shows the complete address span. Drag its window
|
||||
to pan, drag its edges to resize the range, or double-click to fit all data.
|
||||
- **Range** fits the current section, segment, map, block or selection.
|
||||
**Edit range** accepts radare2 expressions and inclusive endpoints.
|
||||
- **Follow** keeps the current seek address visible. Offset synchronization and
|
||||
the global address-selection synchronization setting control integration with
|
||||
disassembly and hexdump widgets.
|
||||
- **Find marker** searches sections, segments, maps, flags (including search hits)
|
||||
and comments. The graph context menu provides comments, flags and “Show in”.
|
||||
Hover details appear after the pointer rests for 650 ms.
|
||||
- Hexdump selections, sections and segments have direct analysis actions.
|
||||
Other addressable widgets can use **Show in → Data Analysis**.
|
||||
|
||||
The graph uses the current radare2 address space: virtual addresses with `io.va`
|
||||
enabled, otherwise physical offsets in the active descriptor. Gaps and failed reads
|
||||
do not contribute invented bytes. Each bucket reads at most 4096 bytes from centered
|
||||
windows in readable spans. Tooltips, the status line and exported CSV report how
|
||||
many bytes were actually read. Zoom in for complete coverage of a region. Entropy
|
||||
is measured per bucket, so very small buckets have a lower attainable entropy.
|
||||
|
||||
Multiple overlaid series use a normalized percentage scale. Entropy's native scale
|
||||
is 0–8 bits/byte, unique bytes 0–256, and mean byte 0–255. A single series or separate
|
||||
tracks uses its native scale. CSV exports normalized values plus exact bucket bounds
|
||||
and coverage. Display settings are saved with the layout.
|
||||
|
||||
Other widgets can call `MainWindow::showDataAnalysis(start, end)` or
|
||||
`DataAnalysisWidget::showRange(start, end)` with **inclusive** endpoints. Internally,
|
||||
`DataAnalysis::Range` and graph signals use half-open ranges.
|
||||
|
||||
Run the focused tests with:
|
||||
|
||||
```sh
|
||||
make -C tests/dataanalysis -j8 > /dev/null
|
||||
QT_QPA_PLATFORM=offscreen tests/dataanalysis/build/test_dataanalysis
|
||||
```
|
||||
@@ -0,0 +1,264 @@
|
||||
Iaito Deep Links
|
||||
================
|
||||
|
||||
Iaito registers the `iaito://` URI scheme so binaries, projects, samples and raw
|
||||
bytes can be referenced with stable, shareable links that open a specific
|
||||
location and view. Clicking such a link (from a browser, file manager, chat
|
||||
client, terminal, etc.) launches Iaito and navigates straight to the target.
|
||||
|
||||
The implementation lives in a single, self-contained pair of files,
|
||||
`src/common/DeepLink.{h,cpp}`, so it is easy to find, maintain and remove.
|
||||
|
||||
|
||||
URI format
|
||||
----------
|
||||
|
||||
```
|
||||
iaito://<handler>/<payload>?<query>
|
||||
```
|
||||
|
||||
There are exactly four top-level handlers:
|
||||
|
||||
| Handler | Payload | Opens |
|
||||
|----------------|------------------|------------------------------------------|
|
||||
| `file` | absolute path | a file from disk |
|
||||
| `project` | project name | a saved radare2/iaito project |
|
||||
| `sha256` | 64 hex chars | a locally registered sample by its hash |
|
||||
| `bytes` | hex byte string | an in-memory buffer built from raw bytes |
|
||||
|
||||
Only **absolute paths** are accepted for `file`.
|
||||
|
||||
As a convenience, if the host part of the URI is empty the absolute path is
|
||||
treated as a `file` reference:
|
||||
|
||||
```
|
||||
iaito:///bin/ls is the same as iaito://file/bin/ls
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
iaito://file/tmp/a.out
|
||||
iaito://project/r2
|
||||
iaito://sha256/0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
|
||||
iaito://bytes/554889e54883ec10
|
||||
```
|
||||
|
||||
|
||||
Query parameters
|
||||
----------------
|
||||
|
||||
Parameters are passed as standard URL query parameters (`?a=1&b=2`), not as
|
||||
`#fragments`. Unknown parameters are ignored, so the format can be extended in
|
||||
the future without breaking existing links.
|
||||
|
||||
### Navigation
|
||||
|
||||
| Param | Meaning |
|
||||
|---------|------------------------------------------------------------------------|
|
||||
| `addr` | Any expression radare2 can resolve via `s <expr>` |
|
||||
| `view` | The panel to raise after opening |
|
||||
| `size` | Region length / block size (integer, decimal or `0x` hex) |
|
||||
|
||||
`addr` accepts anything radare2 understands:
|
||||
|
||||
```
|
||||
addr=0x401000
|
||||
addr=sym.main
|
||||
addr=entry0
|
||||
addr=str.Hello
|
||||
```
|
||||
|
||||
`view` may be one of:
|
||||
|
||||
```
|
||||
disasm graph hex decompiler
|
||||
strings imports exports functions
|
||||
```
|
||||
|
||||
`disasm`, `graph`, `hex` and `decompiler` open/raise the corresponding memory
|
||||
widget; the other names raise the matching tool panel by name.
|
||||
|
||||
`size` sets the current block size (radare2 `b`), e.g. `size=64` or `size=0x100`.
|
||||
|
||||
### Analysis (mostly for `bytes` and raw/unknown binaries)
|
||||
|
||||
| Param | Examples |
|
||||
|----------|-----------------------------------------------------|
|
||||
| `arch` | `x86`, `arm`, `arm64`, `mips`, `riscv`, `ppc` |
|
||||
| `bits` | `16`, `32`, `64` |
|
||||
| `endian` | `little`, `big` |
|
||||
| `cpu` | `generic`, `cortex`, `avr`, `68000`, `v850` |
|
||||
| `os` | `linux`, `darwin`, `windows`, `ios`, `android` |
|
||||
| `base` | base/map address, e.g. `0`, `0x1000`, `0x401000` |
|
||||
|
||||
For `bytes` links Iaito builds an in-memory `malloc://` buffer, writes the
|
||||
provided bytes into it and configures the session accordingly:
|
||||
|
||||
| Query param | radare2 config |
|
||||
|-------------|----------------|
|
||||
| `arch` | `asm.arch` |
|
||||
| `bits` | `asm.bits` |
|
||||
| `endian` | `cfg.bigendian`|
|
||||
| `cpu` | `asm.cpu` |
|
||||
| `os` | `asm.os` |
|
||||
| `base` | `bin.baddr` |
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Open a file and jump to an address:
|
||||
|
||||
```
|
||||
iaito://file/tmp/a.out?addr=0x401000
|
||||
```
|
||||
|
||||
Open a project and show the graph view at `main`:
|
||||
|
||||
```
|
||||
iaito://project/r2?addr=sym.main&view=graph
|
||||
```
|
||||
|
||||
Open a sample by SHA256 and show the decompiler:
|
||||
|
||||
```
|
||||
iaito://sha256/<hash>?addr=sym.main&view=decompiler
|
||||
```
|
||||
|
||||
Open a sample by SHA256 and select a region in the hex view:
|
||||
|
||||
```
|
||||
iaito://sha256/<hash>?addr=0x401000&size=0x100&view=hex
|
||||
```
|
||||
|
||||
Disassemble raw x86-64 shellcode:
|
||||
|
||||
```
|
||||
iaito://bytes/554889e54883ec10?arch=x86&bits=64&view=disasm
|
||||
```
|
||||
|
||||
Disassemble little-endian ARM code:
|
||||
|
||||
```
|
||||
iaito://bytes/e92d4800e8bd8800?arch=arm&bits=32&endian=little
|
||||
```
|
||||
|
||||
Analyze a raw big-endian MIPS firmware blob mapped at a base address:
|
||||
|
||||
```
|
||||
iaito://bytes/<hex>?arch=mips&bits=32&endian=big&base=0x80000000
|
||||
```
|
||||
|
||||
Open bytes and jump to an offset in the hex view:
|
||||
|
||||
```
|
||||
iaito://bytes/<hex>?arch=x86&bits=64&addr=0x10&view=hex
|
||||
```
|
||||
|
||||
|
||||
SHA256 samples database
|
||||
------------------------
|
||||
|
||||
`sha256` links resolve a hash to a local file through Iaito's samples database,
|
||||
which maps the SHA256 of every binary it has seen to its path on disk. Files are
|
||||
registered automatically when opened and can be managed from the *Sha256* tab in
|
||||
the New File dialog. If the hash is unknown, Iaito shows a dialog explaining how
|
||||
to register it; downloading unknown samples is out of scope.
|
||||
|
||||
See [sha256.md](sha256.md) for the on-disk layout, hashing, how to populate the
|
||||
database, and the configurable online lookup URL.
|
||||
|
||||
|
||||
Registering the URI handler
|
||||
---------------------------
|
||||
|
||||
The `iaito://` scheme must be associated with the Iaito executable at the OS
|
||||
level. This happens automatically with the standard install targets, and can
|
||||
also be run on its own.
|
||||
|
||||
### Make targets
|
||||
|
||||
```
|
||||
make install-deeplink # register iaito:// for the current user
|
||||
make uninstall-deeplink # remove the association
|
||||
```
|
||||
|
||||
`make user-install` registers the handler as part of installation, and
|
||||
`make uninstall` / `make user-uninstall` removes it. A system-wide
|
||||
`make install` refreshes the desktop database so the `.desktop` MimeType
|
||||
association is picked up.
|
||||
|
||||
### Linux
|
||||
|
||||
Registration relies on the desktop entry `src/org.radare.iaito.desktop`, which
|
||||
declares:
|
||||
|
||||
```
|
||||
Exec=iaito %u
|
||||
MimeType=x-scheme-handler/iaito;
|
||||
```
|
||||
|
||||
`scripts/deeplink/register.sh` runs `xdg-mime default` and
|
||||
`update-desktop-database`; `scripts/deeplink/unregister.sh` removes the
|
||||
association from `~/.config/mimeapps.list`.
|
||||
|
||||
### macOS
|
||||
|
||||
The app bundle declares the scheme in `Info.plist` via `CFBundleURLTypes`
|
||||
(`CFBundleURLSchemes = iaito`). LaunchServices registers it automatically when
|
||||
the bundle is installed; `scripts/deeplink/register.sh` forces a refresh with
|
||||
`lsregister -f <iaito.app>`. The handler is dropped when the bundle is removed.
|
||||
|
||||
`make run` launches the build without registering the URI handler. To optionally
|
||||
register the local bundle without installing it, run:
|
||||
|
||||
```sh
|
||||
sh scripts/deeplink/register.sh "$PWD/build/iaito.app"
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
`scripts/deeplink/register.bat` writes the `HKCU\Software\Classes\iaito` keys
|
||||
(including `URL Protocol` and `shell\open\command`) and
|
||||
`scripts/deeplink/unregister.bat` deletes them. Pass the path to `iaito.exe` as
|
||||
the first argument:
|
||||
|
||||
```
|
||||
scripts\deeplink\register.bat "C:\Program Files\iaito\iaito.exe"
|
||||
scripts\deeplink\unregister.bat
|
||||
```
|
||||
|
||||
|
||||
Using deep links from the UI
|
||||
----------------------------
|
||||
|
||||
Every code view and listing exposes a **Copy deep link** action that builds a
|
||||
link to the current address:
|
||||
|
||||
- Disassembly, decompiler and graph context menus (under *Copy* -> *Deep link*),
|
||||
embedding the matching `view=` value (`disasm`, `decompiler`, `graph`).
|
||||
- Hexdump context menu (*Copy* -> *Deep link*, `view=hex`).
|
||||
- The listing widgets (functions, symbols, imports, exports, strings, relocs,
|
||||
sections, ...) via the *Copy deep link* entry in their context menu.
|
||||
|
||||
When triggered, a dialog asks how the open file should be referenced: by loaded
|
||||
project name, by `sha256`, or by absolute `file` path. The resulting URI is
|
||||
placed on the clipboard, ready to paste into a report or a comment.
|
||||
|
||||
Links pasted into comments are rendered as clickable text in the disassembly and
|
||||
decompiler views: hovering shows a pointing-hand cursor and a left click follows
|
||||
the link. A link that points back into the file already open navigates in place
|
||||
(seek + view switch) instead of reopening the binary.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
- `addr` is resolved through radare2's `s` command, so it accepts the full range
|
||||
of radare2 address expressions (flags, symbols, math, etc.).
|
||||
- `size` is always resolved to a number before use, so it cannot inject
|
||||
additional radare2 commands.
|
||||
- Query parameters are preferred over `#fragments`; future parameters can be
|
||||
added without changing the URI format.
|
||||
- The four handlers (`file`, `project`, `sha256`, `bytes`) are intentionally the
|
||||
only top-level entry points.
|
||||
@@ -0,0 +1,94 @@
|
||||
Iaito SHA256 Samples Database
|
||||
=============================
|
||||
|
||||
Iaito keeps a local database that maps the SHA256 of every binary it has seen to
|
||||
its path on disk. It powers `iaito://sha256/<hash>` deep links (see
|
||||
[deeplinks.md](deeplinks.md)) and the *Sha256* tab in the New File dialog, and it
|
||||
lets you look a sample up online (VirusTotal by default).
|
||||
|
||||
The implementation lives in `src/common/SamplesDB.{h,cpp}`.
|
||||
|
||||
|
||||
On-disk layout
|
||||
--------------
|
||||
|
||||
The database lives under Iaito's application data directory
|
||||
(`QStandardPaths::AppDataLocation`, e.g. `~/.local/share/radareorg/iaito/samples/`
|
||||
on Linux).
|
||||
|
||||
To scale to large collections without a single huge index file, entries are
|
||||
sharded git/rainbow-table style across two hash-prefix directory levels. The
|
||||
leaf is a plain text bucket file holding one `"<sha256> <absolute-path>"` entry
|
||||
per line:
|
||||
|
||||
```
|
||||
samples/<h0:2>/<h2:4>/<h0:4>
|
||||
|
||||
samples/53/a9/53a9 -> 53a9c0557a948069...172161625 /samples/a.out
|
||||
53a9ffeede... /samples/b.bin
|
||||
```
|
||||
|
||||
- The two directory levels are the first two and next two hex characters of the
|
||||
hash, giving up to 65536 buckets so no single directory grows unbounded.
|
||||
- The leaf bucket file is named after the 4-character prefix and contains all
|
||||
entries sharing it, hash and absolute path separated by a single space.
|
||||
- Lookups read just one bucket file; the whole database is only walked when the
|
||||
*Sha256* tab lists every entry.
|
||||
|
||||
When the same hash is registered again with a different path, the latest path
|
||||
wins (one path per hash).
|
||||
|
||||
|
||||
Hashing
|
||||
-------
|
||||
|
||||
`SamplesDB::sha256File()` computes the digest with radare2's `r_muta` SHA256
|
||||
session API, reading the file in fixed-size blocks. Memory stays bounded
|
||||
regardless of file size, so even multi-gigabyte files hash safely without being
|
||||
loaded into memory at once.
|
||||
|
||||
|
||||
Populating the database
|
||||
-----------------------
|
||||
|
||||
- **Automatically** — every file you open in Iaito is registered (sha256 -> path)
|
||||
once it finishes loading, from `MainWindow::finalizeOpen()`. Hashing runs on a
|
||||
background thread so the UI stays responsive on large files. Live debug
|
||||
sessions and non-file targets (`malloc://`, `dbg://`, ...) are skipped, as are
|
||||
paths that no longer exist.
|
||||
- **Manually** — the *Sha256* tab in the New File dialog lets you:
|
||||
- **Scan folder…** — recursively register every file under a chosen directory
|
||||
(runs in the background).
|
||||
- **Filter** — the input field filters the list by file name or hash as you
|
||||
type.
|
||||
- **On disk** — a column shows whether each registered file still exists.
|
||||
- **Open** — open the selected sample (also on double-click).
|
||||
- **Lookup** — open the configured lookup URL for the selected hash.
|
||||
- **Delete** — remove the selected entry from the database (the file is left
|
||||
untouched).
|
||||
- **Right-click** — *Copy path*, *Copy hash*, *Open containing folder*,
|
||||
*Open in lookup URL*, *Remove from database*.
|
||||
|
||||
|
||||
Online lookup URL
|
||||
-----------------
|
||||
|
||||
The *Lookup* button and the *Open in lookup URL* context action open a base URL
|
||||
with the selected file's SHA256 appended. The base URL defaults to VirusTotal:
|
||||
|
||||
```
|
||||
https://www.virustotal.com/gui/file/<sha256>
|
||||
```
|
||||
|
||||
It is configurable in *Settings -> Samples* (stored as `sha256.lookupBaseUrl`),
|
||||
where a *Reset* button restores the VirusTotal default. This lets you point the
|
||||
lookup at any service that resolves a file by its SHA256.
|
||||
|
||||
|
||||
Deep link resolution
|
||||
---------------------
|
||||
|
||||
`iaito://sha256/<hash>` looks the hash up in the database and opens the mapped
|
||||
file if it still exists, applying any `addr`/`view`/`size` parameters. If the
|
||||
hash is unknown, Iaito shows a dialog explaining how to register it. Downloading
|
||||
unknown samples is intentionally out of scope.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Structures in the hexdump
|
||||
|
||||
Open the hexdump sidebar's **Structures** tab, choose an r2 type, enter an address
|
||||
or expression, and press **Inspect**. **At cursor** uses the first selected byte
|
||||
or the current cursor. You can also right-click the hexdump and choose **Inspect
|
||||
structure here**; a type already linked to that address is selected automatically.
|
||||
|
||||
The tree shows each field's declared type, value, address, and size. Expand nested
|
||||
structures, unions, arrays, and pointers to explore them. Selecting a field selects
|
||||
its bytes in the hexdump. Field colors match the byte highlights. The inspected
|
||||
structure stays anchored while you navigate, and **Refresh** preserves expanded
|
||||
fields and the selected row while rereading memory and type definitions.
|
||||
|
||||
Types come from r2's type database, including imported C definitions and typedefs.
|
||||
The tree uses stored member offsets and the current `asm.bits` and `cfg.bigendian`
|
||||
settings. Large arrays are divided into expandable groups. Unmapped pointers and
|
||||
recursive references stop expansion; invalid or overflowing layouts are reported.
|
||||
Array expressions such as `uint16_t[16]` can be inspected directly.
|
||||
|
||||
**Pin type** creates an r2 type link (`tl`) at the inspected address. The pinned
|
||||
address list also includes existing type links and command annotations (`Cr`) from
|
||||
the current r2 session. Define a named typedef before pinning an array expression.
|
||||
|
||||
**Pin command…** stores a command at the address using the selected byte range or
|
||||
the chosen type's size. Double-click a pin to navigate to its address. Select a
|
||||
command pin and press **Run command** to display its output. **Unpin** removes only
|
||||
the selected type link or command annotation. Pins use r2's existing project data
|
||||
and are saved with the project. iaito also writes `iaito-memory-pins.json` inside the
|
||||
project directory to preserve types and pins omitted by some r2 binary project versions;
|
||||
keep that companion file when copying a project.
|
||||
@@ -1,24 +1,30 @@
|
||||
SET "R2DIST=r2_dist"
|
||||
SET "R2DIR=radare2"
|
||||
SET "BUILDDIR=build_%PLATFORM%"
|
||||
|
||||
ECHO Preparing directory
|
||||
RMDIR /S /Q %BUILDDIR%
|
||||
MKDIR %BUILDDIR%
|
||||
CD src
|
||||
meson ..\release
|
||||
CD ..\release
|
||||
ninja -v -j1
|
||||
REM IF !ERRORLEVEL! NEQ 0 EXIT /B 1
|
||||
meson --buildtype=release %* ..\%BUILDDIR%
|
||||
CD ..\%BUILDDIR%
|
||||
ninja -j4
|
||||
if %ERRORLEVEL% NEQ 0 (
|
||||
EXIT /B 1
|
||||
)
|
||||
CD ..
|
||||
|
||||
ECHO Deploying iaito
|
||||
MKDIR iaito
|
||||
COPY release\iaito.exe iaito\iaito.exe
|
||||
XCOPY /S /I ..\%R2DIST%\share iaito\share
|
||||
XCOPY /S /I ..\%R2DIST%\lib iaito\lib
|
||||
DEL iaito\lib\*.lib
|
||||
COPY ..\%R2DIST%\bin\*.dll iaito\
|
||||
windeployqt iaito\iaito.exe
|
||||
FOR %%i in (..\src\translations\*.qm) DO MOVE "%%~fi" iaito\translations
|
||||
IF NOT EXIST release (
|
||||
MKDIR release
|
||||
)
|
||||
COPY %BUILDDIR%\iaito.exe release\iaito.exe
|
||||
XCOPY /S /I %R2DIR%\share release\share
|
||||
XCOPY /S /I %R2DIR%\lib release\lib
|
||||
DEL release\lib\*.lib
|
||||
COPY %R2DIR%\bin\*.dll release\
|
||||
windeployqt release\iaito.exe
|
||||
FOR %%i in (..\src\translations\*.qm) DO MOVE "%%~fi" release\translations
|
||||
|
||||
IF DEFINED CI (
|
||||
RENAME release iaito
|
||||
)
|
||||
|
||||
ENDLOCAL
|
||||
@@ -1,6 +1,6 @@
|
||||
@ECHO OFF
|
||||
|
||||
SET "R2V=5.7.0"
|
||||
IF NOT DEFINED R2V SET "R2V=5.8.8"
|
||||
SET ARCH=x64
|
||||
|
||||
SETLOCAL ENABLEDELAYEDEXPANSION
|
||||
@@ -14,24 +14,22 @@ IF !ERRORLEVEL! NEQ 0 (
|
||||
)
|
||||
|
||||
SET "PATH=%CD%;%PATH%"
|
||||
SET "R2DIST=r2_dist"
|
||||
SET "R2DIR=radare2"
|
||||
|
||||
IF NOT DEFINED CI (
|
||||
ECHO Downloading radare2 (%PLATFORM%)
|
||||
rem powershell -command "Invoke-WebRequest 'https://github.com/radareorg/radare2/releases/download/5.1.0/radare2-5.1.0_windows.zip' -OutFile 'radare2-5.1.0_windows.zip'"
|
||||
pip install wget
|
||||
python -m wget -o r2.zip https://github.com/radareorg/radare2/releases/download/%R2V%/radare2-%R2V%-w64.zip
|
||||
curl -L -o r2.zip https://github.com/radareorg/radare2/releases/download/%R2V%/radare2-%R2V%-w64.zip
|
||||
unzip r2.zip
|
||||
RENAME radare2-%R2V%-w64 radare2
|
||||
RMDIR /S /Q %R2DIST%
|
||||
MOVE radare2-%R2V%-w64 %R2DIST%
|
||||
SET "PATH=%CD%\%R2DIST%\bin;%PATH%"
|
||||
RENAME radare2-%R2V%-w64 %R2DIR%
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %ARCH%
|
||||
)
|
||||
SET "PATH=%CD%\%R2DIR%\bin;%PATH%"
|
||||
|
||||
rem ECHO Building radare2 (%PLATFORM%)
|
||||
rem CD radare2
|
||||
rem git clean -xfd
|
||||
rem RMDIR /S /Q ..\%R2DIST%
|
||||
rem RMDIR /S /Q ..\%R2DIR%
|
||||
rem meson -C src r2_builddir
|
||||
rem meson.exe r2_builddir --buildtype=release --prefix=%CD%\..\%R2DIST% || EXIT /B 1
|
||||
rem meson.exe r2_builddir --buildtype=release --prefix=%CD%\..\%R2DIR% || EXIT /B 1
|
||||
rem ninja -C r2_builddir install || EXIT /B 1
|
||||
rem IF !ERRORLEVEL! NEQ 0 EXIT /B 1
|
||||
|
Before Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 674 KiB |
@@ -1,59 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
if ! [[ $# -eq 3 ]]; then
|
||||
echo "Usage: $0 [Python.framework] [AppBundle.app] [AppBundle.app/Contents/MacOS/Executable]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python_version=python3.6
|
||||
|
||||
py_framework=$1
|
||||
appbundle=$2
|
||||
executable=$3
|
||||
|
||||
echo "Embedding $py_framework into $appbundle | $executable"
|
||||
|
||||
mkdir -p "$appbundle/Contents/Frameworks"
|
||||
if [ ! -d "$appbundle/Contents/Frameworks/Python.framework" ]
|
||||
then
|
||||
cp -a -n "$py_framework" "$appbundle/Contents/Frameworks/"
|
||||
echo "Cleaning up embedded Python Framework"
|
||||
cd "$appbundle/Contents/Frameworks/Python.framework"
|
||||
find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
|
||||
rm -r Versions/Current/Resources/* "Versions/Current/lib/$python_version/test" "Versions/Current/lib/$python_version/idlelib" "Versions/Current/lib/$python_version/curses" "Versions/Current/lib/$python_version/lib2to3" || echo "Couldn't remove something"
|
||||
else
|
||||
echo "Python.framework already exists, skipping copying"
|
||||
cd "$appbundle/Contents/Frameworks/Python.framework"
|
||||
fi
|
||||
|
||||
echo "Making executable $executable point to embedded Framework"
|
||||
install_name_tool -change `otool -L "$executable" | sed -n "s/^[[:blank:]]*\([^[:blank:]]*Python\) (.*$/\1/p"` @executable_path/../Frameworks/Python.framework/Versions/Current/Python "$executable"
|
||||
|
||||
<<<<<<< HEAD:scripts/appbundle_embed_python.sh
|
||||
echo "Cleaning up embedded Python Framework"
|
||||
cd "$appbundle/Contents/Frameworks/Python.framework" || exit 1
|
||||
find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf || exit 1
|
||||
rm -r Versions/Current/Resources/* Versions/Current/lib/python3.6/test Versions/Current/lib/python3.6/idlelib Versions/Current/lib/python3.6/curses Versions/Current/lib/python3.6/lib2to3 || exit 1
|
||||
|
||||
=======
|
||||
>>>>>>> 29cbd06a... Run macos packaging in GHA. (#2529):dist/appbundle_embed_python.sh
|
||||
echo "Checking if PySide2 is available"
|
||||
|
||||
pyside_prefix=$(pkg-config --variable=prefix pyside2)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "PySide2 is not available, ignoring."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "PySide is at $pyside_prefix"
|
||||
|
||||
if [ ! -d "Versions/Current/lib/$python_version/site-packages/PySide2" ]
|
||||
then
|
||||
cp -va "$pyside_prefix/lib/$python_version/" "Versions/Current/lib/$python_version"
|
||||
cd .. # $appbundle/Contents/Frameworks
|
||||
cp -va "$pyside_prefix/lib/"*.dylib .
|
||||
else
|
||||
echo "site-packages/Pyside2 exists, skipping copying"
|
||||
fi
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if ! [[ $# -eq 1 ]]; then
|
||||
echo "Usage: $0 [AppBundle.app]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
appbundle=$1
|
||||
qtwebegineprocess="$1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess"
|
||||
|
||||
echo "Patching $appbundle to fix QtWebEngine"
|
||||
|
||||
if ! [[ -f "$qtwebegineprocess" ]]; then
|
||||
echo "$qtwebegineprocess does not exist. Did you forget to run macdeployqt?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
install_name_tool `otool -L "$qtwebegineprocess" | sed -n "s/^[[:blank:]]*\(\/usr\/local\/Cellar[^[:blank:]]*\(Qt[A-Za-z]*\.framework[^[:blank:]]*\)\) (.*$/-change \1 @executable_path\/..\/..\/..\/..\/..\/..\/..\/\2/p"` \
|
||||
$1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess \
|
||||
|| exit 1
|
||||
|
||||
mkdir -p $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks
|
||||
ln -s ../../../../../../../QtCore.framework $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks/
|
||||
ln -s ../../../../../../../QtQuick.framework $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks/
|
||||
ln -s ../../../../../../../QtGui.framework $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks/
|
||||
ln -s ../../../../../../../QtQml.framework $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks/
|
||||
ln -s ../../../../../../../QtNetwork.framework $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks/
|
||||
ln -s ../../../../../../../QtWebChannel.framework $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks/
|
||||
ln -s ../../../../../../../QtPositioning.framework $1/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Frameworks/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if ! [[ $# -eq 1 ]]; then
|
||||
echo "Usage: $0 [appdir]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python_version=python3.6
|
||||
|
||||
python_prefix=$(pkg-config --variable=prefix python3)
|
||||
appdir=$1
|
||||
|
||||
echo "Embedding Python from prefix $python_prefix in appdir $appdir"
|
||||
|
||||
mkdir -p "$appdir/usr"
|
||||
cd "$appdir/usr/" || exit 1
|
||||
|
||||
cp -RT "$python_prefix" "." || exit 1
|
||||
echo "Cleaning up embedded Python"
|
||||
find . | grep -E "(__pycache__|\.pyc|\.pyo$)" | xargs rm -rf
|
||||
rm -r lib/$python_version/test lib/$python_version/idlelib lib/$python_version/curses lib/$python_version/lib2to3
|
||||
|
||||
echo "Checking if PySide2 is available"
|
||||
|
||||
pyside_prefix=$(pkg-config --variable=prefix pyside2)
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "PySide2 is not available, ignoring."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "PySide is at $pyside_prefix"
|
||||
|
||||
if [ "$pyside_prefix" == "$python_prefix" ]; then
|
||||
echo "Prefixes are equal, not copying anything from lib"
|
||||
else
|
||||
cp -RT "$pyside_prefix/lib/$python_version" "lib/$python_version" || exit 1
|
||||
fi
|
||||
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
scripts/r2ghidra.sh \
|
||||
-DCMAKE_C_COMPILER=cl \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_PREFIX_PATH="$APPVEYOR_BUILD_FOLDER/r2_dist;$APPVEYOR_BUILD_FOLDER/r2_dist/include/libr;$APPVEYOR_BUILD_FOLDER/r2_dist/include/libr/sdb" \
|
||||
-DCMAKE_INSTALL_PREFIX="$APPVEYOR_BUILD_FOLDER/r2_dist" \
|
||||
-DRADARE2_INSTALL_PLUGDIR="$APPVEYOR_BUILD_FOLDER/r2_dist/lib/plugins" \
|
||||
-DBUILD_SLEIGH_PLUGIN=OFF
|
||||
@@ -1,8 +1,10 @@
|
||||
# This script is deprecated and it is not going to work
|
||||
# But it's kept for future work towards supporting it again
|
||||
$dist = $args[0]
|
||||
$python = Split-Path((Get-Command python.exe).Path)
|
||||
|
||||
if (-not (Test-Path -Path 'r2dec-js' -PathType Container)) {
|
||||
git clone https://github.com/radareorg/r2dec-js.git --branch master --depth 1
|
||||
git clone https://github.com/wargio/r2dec-js.git --branch master --depth 1
|
||||
}
|
||||
cd r2dec-js
|
||||
#git checkout b5a0d15c7bcc488f268ffb0931b7ced2919f6c9d
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
rem Register the iaito:// URI scheme handler for the current user.
|
||||
rem Usage: register.bat [path-to-iaito.exe]
|
||||
|
||||
setlocal
|
||||
set "IAITO=%~1"
|
||||
if "%IAITO%"=="" set "IAITO=%~dp0..\..\build\iaito.exe"
|
||||
|
||||
reg add "HKCU\Software\Classes\iaito" /ve /d "URL:iaito Protocol" /f
|
||||
reg add "HKCU\Software\Classes\iaito" /v "URL Protocol" /d "" /f
|
||||
reg add "HKCU\Software\Classes\iaito\DefaultIcon" /ve /d "\"%IAITO%\",0" /f
|
||||
reg add "HKCU\Software\Classes\iaito\shell\open\command" /ve /d "\"%IAITO%\" \"%%1\"" /f
|
||||
echo Registered iaito:// -^> %IAITO%
|
||||
endlocal
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
# Register the iaito:// URI scheme handler on Linux and macOS.
|
||||
# Usage: register.sh [path-to-iaito.app] (the argument is only used on macOS)
|
||||
|
||||
case "$(uname)" in
|
||||
Darwin)
|
||||
APP="$1"
|
||||
[ -d "$APP" ] || APP="/Applications/iaito.app"
|
||||
[ -d "$APP" ] || APP="$HOME/Applications/iaito.app"
|
||||
if [ ! -d "$APP" ]; then
|
||||
echo "Cannot find iaito.app, pass its path as first argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
LSREG="/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister"
|
||||
"$LSREG" -f "$APP"
|
||||
echo "Registered iaito:// for $APP"
|
||||
;;
|
||||
*)
|
||||
DESKTOP="org.radare.iaito.desktop"
|
||||
if command -v xdg-mime >/dev/null 2>&1; then
|
||||
xdg-mime default "$DESKTOP" x-scheme-handler/iaito
|
||||
fi
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
|
||||
fi
|
||||
echo "Registered iaito:// -> $DESKTOP"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
rem Unregister the iaito:// URI scheme handler for the current user.
|
||||
reg delete "HKCU\Software\Classes\iaito" /f
|
||||
echo Unregistered iaito://
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
# Unregister the iaito:// URI scheme handler on Linux and macOS.
|
||||
|
||||
case "$(uname)" in
|
||||
Darwin)
|
||||
echo "macOS drops the iaito:// handler when the iaito.app bundle is removed."
|
||||
;;
|
||||
*)
|
||||
MIMEAPPS="$HOME/.config/mimeapps.list"
|
||||
if [ -f "$MIMEAPPS" ]; then
|
||||
sed -i.bak '/x-scheme-handler\/iaito=/d' "$MIMEAPPS"
|
||||
rm -f "$MIMEAPPS.bak"
|
||||
fi
|
||||
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||
update-desktop-database "$HOME/.local/share/applications" 2>/dev/null || true
|
||||
fi
|
||||
echo "Unregistered iaito:// handler"
|
||||
;;
|
||||
esac
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
'includes': [
|
||||
'../../../build/common.gypi',
|
||||
],
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'dump_syms',
|
||||
'type': 'executable',
|
||||
'sources': [
|
||||
'dump_syms.cc',
|
||||
],
|
||||
'dependencies': [
|
||||
'../../../common/windows/common_windows.gyp:common_windows_lib',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! $# -eq 2 ]; then
|
||||
echo "usage: $0 [Iaito.app] [dst]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
appbundle="$1"
|
||||
dst="$2"
|
||||
files="$appbundle/Contents/MacOS/Iaito.bin $appbundle/Contents/Frameworks/Python.framework/Python $(find "$appbundle" -type f -name '*.dylib')"
|
||||
|
||||
mkdir -p "$dst" || exit 1
|
||||
|
||||
for file in $files; do
|
||||
echo "Dumping syms from $file"
|
||||
dump_syms "$file" > "$dst/tmp.sym" || echo "Failed to dump syms from $file"
|
||||
infoline=($(head -n1 "$dst/tmp.sym"))
|
||||
id=${infoline[3]}
|
||||
name=${infoline[4]}
|
||||
dir="$dst/$name/$id"
|
||||
mkdir -p "$dir"
|
||||
mv "$dst/tmp.sym" "$dir/$name.sym"
|
||||
done
|
||||
|
||||
echo "Done"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
FROM ubuntu:24.04
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends clang-format-20 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /project
|
||||
ENTRYPOINT ["clang-format-20"]
|
||||
@@ -0,0 +1,5 @@
|
||||
IMAGE_NAME ?= clang-format-image
|
||||
IMAGE_TAG ?= llvm20
|
||||
|
||||
all:
|
||||
docker build -t $(IMAGE_NAME):$(IMAGE_TAG) .
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
import re
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script parses the commit messages between the last 2 git tags
|
||||
# if the last commit contains the word "Release", otherwise it shows
|
||||
# all the changes between the last tag and HEAD.
|
||||
#
|
||||
# Commits are grouped in different sections specified in the commit
|
||||
# message with the middle-dot character '·'. The section names are
|
||||
# arbitrary and we may be careful to use them properly but having
|
||||
# in mind that this may change.
|
||||
#
|
||||
# Commits without any middle·dot in the message are discarted and
|
||||
# displayed in the "to review" section.
|
||||
#
|
||||
# The tool prints Markdown, no plans to support other formats.
|
||||
#
|
||||
# Usage: sys/release-notes.sh 4.5.1 # from HEAD to 4.5.1
|
||||
# $ sys/release-notes.sh 4.5.1 -v # same as above but include untagged commits
|
||||
# $ sys/release-notes.sh 4.5.0 4.5.1 # from 4.5.0 to 4.5.1
|
||||
#
|
||||
# --pancake
|
||||
|
||||
if [ -n "`git log -n 1 | grep Release`" ]; then
|
||||
VERS=`git tag --sort=committerdate | grep -v conti | tail -n 1`
|
||||
PREV=`git tag --sort=committerdate | grep -v conti | tail -n 2 | head -n1`
|
||||
else
|
||||
VERS=HEAD
|
||||
PREV=`git tag --sort=committerdate | grep -v conti | tail -n 1`
|
||||
fi
|
||||
|
||||
[ -n "$1" ] && PREV="$1"
|
||||
[ -n "$2" ] && VERS="$2"
|
||||
|
||||
git log ${PREV}..${VERS} > .l
|
||||
# When HEAD contains a tag do this magic
|
||||
if [ ! -s .l ]; then
|
||||
VERS=$PREV
|
||||
PREV=`git tag --sort=committerdate | grep -v conti | tail -n 2 | head -n1`
|
||||
git log ${PREV}..${VERS} > .l
|
||||
fi
|
||||
grep ^Author .l | cut -d : -f 2- | sed -e 's,radare,pancake,' | sort -u > .A
|
||||
|
||||
echo "## Release Notes"
|
||||
echo
|
||||
echo "Version: ${VERS} (previous: ${PREV})"
|
||||
N=`grep ^commit .l | wc -l`
|
||||
echo "Commits: $N from `wc -l .A | awk '{print $1}'` contributors"
|
||||
echo
|
||||
echo "Release builds (binary assets below) are considered work-in-progress, use flatpak or your distro packaging if anything is not working"
|
||||
echo
|
||||
echo "## Flatpak (WSL / Linux)"
|
||||
echo
|
||||
echo "\`\`\`sh"
|
||||
echo "sudo flatpak remote-add flathub https://dl.flathub.org/repo/flathub.flatpakrepo"
|
||||
echo "sudo flatpak install flathub org.radare.iaito"
|
||||
echo "flatpak run org.radare.iaito"
|
||||
echo "\`\`\`"
|
||||
echo
|
||||
echo "## Build from Source"
|
||||
echo
|
||||
echo "\`\`\`sh"
|
||||
echo "curl -sL https://github.com/radareorg/iaito/archive/refs/tags/${VERS}.tar.gz | tar xzv"
|
||||
echo "iaito-${VERS}/sys/install.sh"
|
||||
echo "\`\`\`"
|
||||
echo
|
||||
echo "## Highlights"
|
||||
|
||||
echo "<details><summary>More details</summary><p>"
|
||||
echo
|
||||
echo "## Authors"
|
||||
echo
|
||||
cat .A | perl -ne '/([^<]+)(.*)$/;$a=$1;$b=$2;$a=~s/^\s+|\s+$//g;$b=~s/[<>\s]//g;print "[$a](mailto:$b) "'
|
||||
echo
|
||||
echo
|
||||
|
||||
cat .x | grep -v '##' | sed -e 's,^ *,,g' | grep -v "^$" | \
|
||||
perl -ne 'if (/^\*/) { print "$_"; } else { print "* $_";}'
|
||||
|
||||
# echo "## Changes"
|
||||
# echo
|
||||
# cat .l | grep -v ^commit | grep -v ^Author | grep -v ^Date > .x
|
||||
# cat .x | grep '##' | perl -ne '/##([^ ]*)/; if ($1) {print "$1\n";}' | sort -u > .y
|
||||
# for a in `cat .y` ; do
|
||||
# echo "**$a**"
|
||||
# echo
|
||||
# cat .x | grep "##$a" | sed -e 's/##.*//g' | perl -ne '{ s/^\s+//; print "* $_"; }'
|
||||
# echo
|
||||
# done
|
||||
# rm -f .x .y .l .A
|
||||
|
||||
echo '</p></details>'
|
||||
@@ -1,64 +0,0 @@
|
||||
# Copyright 2019 Wason Technology, LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "No bat file specified"
|
||||
return
|
||||
fi
|
||||
|
||||
#echo `dirname "$(readlink -f "$_")"`
|
||||
___update_env_func___() {
|
||||
tmpbat=$(mktemp --suffix .bat)
|
||||
rc=$?; if [[ $rc != 0 ]]; then
|
||||
echo "Could not create temporary bat file"
|
||||
return $rc
|
||||
fi
|
||||
|
||||
echo "@echo off " >> $tmpbat
|
||||
echo "call \"$@\" 1>&2 " >> $tmpbat
|
||||
echo "if %errorlevel% neq 0 exit /b %errorlevel%" >> $tmpbat
|
||||
echo "printenv " >> $tmpbat
|
||||
echo "if %errorlevel% neq 0 exit /b %errorlevel%" >> $tmpbat
|
||||
rc=$?; if [[ $rc != 0 ]]; then
|
||||
echo "Could not write temporary bat file"
|
||||
return $rc
|
||||
fi
|
||||
|
||||
tmpbat_win=$(basename $tmpbat)
|
||||
env_data=$(cmd "/c call %TEMP%\\$tmpbat_win ")
|
||||
rc=$?; if [[ $rc != 0 ]]; then
|
||||
echo "Could not run temporary bat file"
|
||||
return $rc
|
||||
fi
|
||||
|
||||
echo
|
||||
echo
|
||||
echo
|
||||
|
||||
#Space at the end is lost for some reason,
|
||||
#save and restore PS1
|
||||
ps1_old=$PS1
|
||||
|
||||
while read -r line; do
|
||||
echo "export $line"
|
||||
export "$line"
|
||||
done <<< "$env_data"
|
||||
|
||||
export PS1="$ps1_old"
|
||||
}
|
||||
|
||||
___update_env_func___ $@
|
||||
unset -f ___update_env_func___
|
||||
cd `pwd`
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
a="$1"
|
||||
b="$2"
|
||||
if [ -z "$a" ]; then
|
||||
echo "Usage: sys/subst.sh [old] [new]"
|
||||
exit 1
|
||||
fi
|
||||
#[ -z "$a" ] && a="r_str_chop "
|
||||
#[ -z "$b" ] && b="r_str_trim "
|
||||
WHERE="src"
|
||||
git grep "$a" ${WHERE} | less -R
|
||||
if [ -n "$b" ]; then
|
||||
FILES=`git grep "$a" ${WHERE} | cut -d : -f 1 | uniq `
|
||||
for f in $FILES ; do
|
||||
echo "Sedded $a"
|
||||
sed -e "s/$a/$b/g" < $f > $f.sub
|
||||
mv $f.sub $f
|
||||
done
|
||||
else
|
||||
echo "Oops"
|
||||
fi
|
||||
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python
|
||||
import xml.etree.ElementTree as ET
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def remove_lines_with_dashes(input_string):
|
||||
lines = input_string.splitlines()
|
||||
filtered_lines = [line for line in lines if "----------" not in line]
|
||||
return "\n".join(filtered_lines).strip()
|
||||
|
||||
# Define the translation function
|
||||
def translate_text(input_text, existing_translation, language):
|
||||
"""
|
||||
Calls an external program to translate the input text, using existing translation if provided.
|
||||
|
||||
Args:
|
||||
input_text (str): The text to translate.
|
||||
existing_translation (str): The existing translation to provide context.
|
||||
|
||||
Returns:
|
||||
str: The translated text.
|
||||
"""
|
||||
inspiration = ""
|
||||
if existing_translation and existing_translation != "":
|
||||
inspiration = ". Take this original text as inspiration: '"+existing_translation+"'"
|
||||
try:
|
||||
# Replace 'translation_program' with the actual program/command
|
||||
process = subprocess.Popen(
|
||||
['/usr/local/bin/ai', '--', '"translate this sentence to '+language+', the output must be just the text, the context for this translation is the Iaito program, which is the graphical interface for radare2, a reverse engineering tool for analyzing and debugging programs'+inspiration+'"'],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
print('"translate this sentence to '+language+', the output must be just the text, the context for this translation is the Iaito program, which is the graphical interface for radare2, a reverse engineering tool for analyzing and debugging programs'+inspiration+'"')
|
||||
input_data = f"{input_text}"
|
||||
stdout, stderr = process.communicate(input=input_data)
|
||||
|
||||
if process.returncode != 0:
|
||||
raise RuntimeError(f"Translation program error: {stderr.strip()}")
|
||||
|
||||
print(stdout)
|
||||
return remove_lines_with_dashes(stdout)
|
||||
except Exception as e:
|
||||
print(f"Error during translation: {e}", file=sys.stderr)
|
||||
return input_text # Fallback to the original text if an error occurs
|
||||
|
||||
# Define the function to find existing translation
|
||||
def find_existing_translation(existing_tree, source_text):
|
||||
"""
|
||||
Finds the translation for a given source text in an existing .ts file.
|
||||
|
||||
Args:
|
||||
existing_tree (ElementTree): Parsed XML tree of the existing .ts file.
|
||||
source_text (str): The source text to look for.
|
||||
|
||||
Returns:
|
||||
str: The existing translation if found, else an empty string.
|
||||
"""
|
||||
for context in existing_tree.findall('context'):
|
||||
for message in context.findall('message'):
|
||||
source = message.find('source')
|
||||
translation = message.find('translation')
|
||||
if source is not None and source.text == source_text and translation is not None:
|
||||
return translation.text
|
||||
return ""
|
||||
|
||||
# Define the main function to parse and modify the XML file
|
||||
def process_ts_file(input_file, output_file, existing_file, language):
|
||||
"""
|
||||
Parses the .ts file, adds a <translation> node with translated content, and writes the output.
|
||||
|
||||
Args:
|
||||
input_file (str): Path to the input .ts file.
|
||||
output_file (str): Path to save the modified .ts file.
|
||||
existing_file (str): Path to an existing .ts file to find previous translations.
|
||||
"""
|
||||
tree = ET.parse(input_file)
|
||||
root = tree.getroot()
|
||||
|
||||
existing_tree = ET.parse(existing_file)
|
||||
|
||||
for context in root.findall('context'):
|
||||
for message in context.findall('message'):
|
||||
source = message.find('source')
|
||||
if source is not None and source.text:
|
||||
original_text = source.text
|
||||
existing_translation = find_existing_translation(existing_tree, original_text)
|
||||
translated_text = translate_text(original_text, existing_translation, language)
|
||||
# Check if <translation> node exists, if not create it
|
||||
translation = message.find('translation')
|
||||
if translation is None:
|
||||
translation = ET.SubElement(message, 'translation')
|
||||
translation.text = translated_text
|
||||
if 'type' in translation.attrib:
|
||||
del translation.attrib['type']
|
||||
|
||||
# Save the updated XML to the output file
|
||||
tree.write(output_file, encoding='utf-8', xml_declaration=True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) <= 4:
|
||||
print("Usage: python script.py input.ts output.ts existing.ts (Language)", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
input_ts = sys.argv[1]
|
||||
output_ts = sys.argv[2]
|
||||
existing_ts = sys.argv[3]
|
||||
if len(sys.argv) <= 5:
|
||||
language = sys.argv[4]
|
||||
|
||||
process_ts_file(input_ts, output_ts, existing_ts, language)
|
||||
print(f"Translated file saved to {output_ts}")
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "common/Radare2Compat.h"
|
||||
|
||||
extern int main_iaito();
|
||||
static int r_cmd_anal_call(void *user, const char *input)
|
||||
{
|
||||
RCore *core = (RCore *) user;
|
||||
if (r_str_startswith(input, "iaito")) {
|
||||
char *n = r_str_newf("%p", user);
|
||||
r_sys_setenv("R2COREPTR", n);
|
||||
free(n);
|
||||
main_iaito();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
extern "C" {
|
||||
// PLUGIN Definition Info
|
||||
RCorePlugin r_core_plugin_iaito = {
|
||||
.meta =
|
||||
{
|
||||
.name = (char *)"iaito",
|
||||
.desc = (char *)"Start iaito GUI from the radare2 shell",
|
||||
.license = (char *)"LGPL3",
|
||||
},
|
||||
.call = r_cmd_anal_call,
|
||||
};
|
||||
|
||||
#ifndef R2_PLUGIN_INCORE
|
||||
R_API RLibStruct radare_plugin
|
||||
= {.type = R_LIB_TYPE_CORE,
|
||||
.data = &r_core_plugin_iaito,
|
||||
.version = R2_VERSION,
|
||||
.abiver = R2_ABIVERSION};
|
||||
#endif
|
||||
}
|
||||
@@ -2,18 +2,34 @@ TEMPLATE = app
|
||||
|
||||
TARGET = iaito
|
||||
|
||||
IAITO_VERSION_MAJOR = 5
|
||||
IAITO_VERSION_MINOR = 8
|
||||
IAITO_VERSION_PATCH = 4
|
||||
IAITO_VERSION_MAJOR = 6
|
||||
IAITO_VERSION_MINOR = 2
|
||||
IAITO_VERSION_PATCH = 6
|
||||
|
||||
CONFIG+=app_bundle
|
||||
LIBS+= -dead_strip
|
||||
CONFIG += c++20
|
||||
QMAKE_CXXFLAGS += -std=c++20
|
||||
QMAKE_CXXFLAGS += -include $$absolute_path(common/CompilerWorkarounds.h, $$PWD)
|
||||
|
||||
CONFIG += app_bundle
|
||||
# LIBS+= -dead_strip
|
||||
|
||||
CONFIG += sdk_no_version_check
|
||||
|
||||
unix:QMAKE_RPATHDIR += /usr/local/lib
|
||||
unix:QMAKE_LFLAGS_RPATH=
|
||||
unix:QMAKE_LFLAGS += "-Wl,-rpath,/usr/local/lib"
|
||||
!defined(IAITO_BUNDLE_R2_APPBUNDLE, var) IAITO_BUNDLE_R2_APPBUNDLE=false
|
||||
equals(IAITO_BUNDLE_R2_APPBUNDLE, true) CONFIG += IAITO_BUNDLE_R2_APPBUNDLE
|
||||
|
||||
unix:!IAITO_BUNDLE_R2_APPBUNDLE {
|
||||
isEmpty(R2_LIBDIR) {
|
||||
R2_LIBDIR = $$system(r2 -H R2_LIBDIR)
|
||||
}
|
||||
QMAKE_RPATHDIR += $${R2_LIBDIR}
|
||||
QMAKE_LFLAGS_RPATH=
|
||||
QMAKE_LFLAGS += "-Wl,-rpath,$${R2_LIBDIR}"
|
||||
}
|
||||
|
||||
QMAKE_CXXFLAGS += $$(CXXFLAGS)
|
||||
QMAKE_CFLAGS += $$(CFLAGS)
|
||||
QMAKE_LFLAGS += $$(LDFLAGS)
|
||||
|
||||
# build with thread-sanitizer
|
||||
# unix:QMAKE_LFLAGS += "-fsanitize=thread"
|
||||
@@ -25,16 +41,15 @@ QMAKE_CXXFLAGS += -g -O0
|
||||
VERSION = $${IAITO_VERSION_MAJOR}.$${IAITO_VERSION_MINOR}.$${IAITO_VERSION_PATCH}
|
||||
|
||||
# Required QT version
|
||||
lessThan(QT_MAJOR_VERSION, 5): error("requires Qt 5")
|
||||
# Doesnt build for Qt6 yet... but will do soon
|
||||
lessThan(QT_MAJOR_VERSION, 5): error("requires at least Qt 5")
|
||||
|
||||
# Icon for OS X
|
||||
ICON = img/iaito-o.icns
|
||||
ICON = img/iaito.icns
|
||||
|
||||
# Icon/resources for Windows
|
||||
win32: RC_ICONS = img/iaito-o.ico
|
||||
win32: RC_ICONS = img/iaito.ico
|
||||
|
||||
QT += core gui widgets svg network
|
||||
QT += widgets svg network
|
||||
QT_CONFIG -= no-pkg-config
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 5): QT += svgwidgets
|
||||
@@ -42,19 +57,8 @@ greaterThan(QT_MAJOR_VERSION, 5): QT += svgwidgets
|
||||
!defined(IAITO_ENABLE_CRASH_REPORTS, var) IAITO_ENABLE_CRASH_REPORTS=false
|
||||
equals(IAITO_ENABLE_CRASH_REPORTS, true) CONFIG += IAITO_ENABLE_CRASH_REPORTS
|
||||
|
||||
!defined(IAITO_ENABLE_PYTHON, var) IAITO_ENABLE_PYTHON=false
|
||||
equals(IAITO_ENABLE_PYTHON, true) CONFIG += IAITO_ENABLE_PYTHON
|
||||
IAITO_ENABLE_PYTHON=false
|
||||
|
||||
!defined(IAITO_ENABLE_PYTHON_BINDINGS, var) IAITO_ENABLE_PYTHON_BINDINGS=false
|
||||
equals(IAITO_ENABLE_PYTHON, true) {
|
||||
equals(IAITO_ENABLE_PYTHON_BINDINGS, true) {
|
||||
CONFIG += IAITO_ENABLE_PYTHON_BINDINGS
|
||||
}
|
||||
}
|
||||
|
||||
!defined(IAITO_BUNDLE_R2_APPBUNDLE, var) IAITO_BUNDLE_R2_APPBUNDLE=false
|
||||
equals(IAITO_BUNDLE_R2_APPBUNDLE, true) CONFIG += IAITO_BUNDLE_R2_APPBUNDLE
|
||||
!defined(IAITO_ENABLE_DEBUGGER, var) IAITO_ENABLE_DEBUGGER=true
|
||||
equals(IAITO_ENABLE_DEBUGGER, true) CONFIG += IAITO_ENABLE_DEBUGGER
|
||||
|
||||
!defined(IAITO_APPVEYOR_R2DEC, var) IAITO_APPVEYOR_R2DEC=false
|
||||
equals(IAITO_APPVEYOR_R2DEC, true) CONFIG += IAITO_APPVEYOR_R2DEC
|
||||
@@ -64,9 +68,6 @@ equals(IAITO_R2GHIDRA_STATIC, true) CONFIG += IAITO_R2GHIDRA_STATIC
|
||||
|
||||
DEFINES += IAITO_SOURCE_BUILD
|
||||
|
||||
|
||||
# crash reports and python code has been removed and its unmaintained,
|
||||
# so let's just disable the messages that are printed out
|
||||
IAITO_ENABLE_CRASH_REPORTS {
|
||||
message("Crash report support enabled.")
|
||||
DEFINES += IAITO_ENABLE_CRASH_REPORTS
|
||||
@@ -74,54 +75,37 @@ IAITO_ENABLE_CRASH_REPORTS {
|
||||
# message("Crash report support disabled.")
|
||||
}
|
||||
|
||||
IAITO_ENABLE_PYTHON {
|
||||
message("Python enabled.")
|
||||
DEFINES += IAITO_ENABLE_PYTHON
|
||||
IAITO_ENABLE_DEBUGGER {
|
||||
message("Native debugger support enabled.")
|
||||
DEFINES += IAITO_ENABLE_DEBUGGER
|
||||
} else {
|
||||
# message("Python disabled.")
|
||||
}
|
||||
|
||||
IAITO_ENABLE_PYTHON_BINDINGS {
|
||||
message("Python Bindings enabled.")
|
||||
DEFINES += IAITO_ENABLE_PYTHON_BINDINGS
|
||||
} else {
|
||||
# message("Python Bindings disabled. (requires IAITO_ENABLE_PYTHON=true)")
|
||||
}
|
||||
|
||||
win32:defined(IAITO_DEPS_DIR, var) {
|
||||
!defined(SHIBOKEN_EXECUTABLE, var) SHIBOKEN_EXECUTABLE="$${IAITO_DEPS_DIR}/pyside/bin/shiboken2.exe"
|
||||
!defined(SHIBOKEN_INCLUDEDIR, var) SHIBOKEN_INCLUDEDIR="$${IAITO_DEPS_DIR}/pyside/include/shiboken2"
|
||||
!defined(SHIBOKEN_LIBRARY, var) SHIBOKEN_LIBRARY="$${IAITO_DEPS_DIR}/pyside/lib/shiboken2.abi3.lib"
|
||||
!defined(PYSIDE_INCLUDEDIR, var) PYSIDE_INCLUDEDIR="$${IAITO_DEPS_DIR}/pyside/include/PySide2"
|
||||
!defined(PYSIDE_LIBRARY, var) PYSIDE_LIBRARY="$${IAITO_DEPS_DIR}/pyside/lib/pyside2.abi3.lib"
|
||||
!defined(PYSIDE_TYPESYSTEMS, var) PYSIDE_TYPESYSTEMS="$${IAITO_DEPS_DIR}/pyside/share/PySide2/typesystems"
|
||||
message("Native debugger support disabled.")
|
||||
}
|
||||
|
||||
INCLUDEPATH *= . core widgets dialogs common plugins menus
|
||||
|
||||
win32 {
|
||||
# Generate debug symbols in release mode
|
||||
QMAKE_CXXFLAGS_RELEASE += -Zi # Compiler
|
||||
QMAKE_LFLAGS_RELEASE += /DEBUG # Linker
|
||||
# QMAKE_CXXFLAGS_RELEASE += -Zi # Compiler
|
||||
# QMAKE_LFLAGS_RELEASE += /DEBUG # Linker
|
||||
|
||||
# Multithreaded compilation
|
||||
QMAKE_CXXFLAGS += -MP
|
||||
}
|
||||
|
||||
macx {
|
||||
QMAKE_CXXFLAGS += -mmacosx-version-min=10.7 -std=c++17 -stdlib=libc++ -g
|
||||
QMAKE_CXXFLAGS += -mmacosx-version-min=10.7 -std=c++20 -stdlib=libc++ -g
|
||||
QMAKE_TARGET_BUNDLE_PREFIX = org.radare
|
||||
QMAKE_BUNDLE = iaito
|
||||
QMAKE_INFO_PLIST = macos/Info.plist
|
||||
}
|
||||
|
||||
unix:exists(/usr/local/include/libr)|bsd:exists(/usr/local/include/libr) {
|
||||
INCLUDEPATH += /usr/local/include/libr
|
||||
INCLUDEPATH += /usr/local/include/libr/sdb
|
||||
}
|
||||
unix:exists(/usr/include/libr) {
|
||||
INCLUDEPATH += /usr/include/libr
|
||||
INCLUDEPATH += /usr/include/libr/sdb
|
||||
unix {
|
||||
isEmpty(R2_INCDIR) {
|
||||
R2_INCDIR = $$system(r2 -H R2_INCDIR)
|
||||
}
|
||||
INCLUDEPATH += $${R2_INCDIR}
|
||||
INCLUDEPATH += $${R2_INCDIR}/sdb
|
||||
}
|
||||
unix {
|
||||
QMAKE_LFLAGS += -rdynamic # Export dynamic symbols for plugins
|
||||
@@ -134,132 +118,6 @@ include(lib_radare2.pri)
|
||||
CONFIG += link_pkgconfig
|
||||
}
|
||||
|
||||
IAITO_ENABLE_PYTHON {
|
||||
win32 {
|
||||
PYTHON_EXECUTABLE = $$system("where python", lines)
|
||||
PYTHON_EXECUTABLE = $$first(PYTHON_EXECUTABLE)
|
||||
pythonpath = $$clean_path($$dirname(PYTHON_EXECUTABLE))
|
||||
LIBS += -L$${pythonpath}/libs -lpython3
|
||||
INCLUDEPATH += $${pythonpath}/include
|
||||
}
|
||||
|
||||
unix|macx|bsd {
|
||||
defined(PYTHON_FRAMEWORK_DIR, var) {
|
||||
message("Using Python.framework at $$PYTHON_FRAMEWORK_DIR")
|
||||
INCLUDEPATH += $$PYTHON_FRAMEWORK_DIR/Python.framework/Headers
|
||||
LIBS += -F$$PYTHON_FRAMEWORK_DIR -framework Python
|
||||
DEFINES += MACOS_PYTHON_FRAMEWORK_BUNDLED
|
||||
} else {
|
||||
!packagesExist(python3) {
|
||||
error("ERROR: Python 3 could not be found. Make sure it is available to pkg-config.")
|
||||
}
|
||||
PKGCONFIG += python3
|
||||
}
|
||||
}
|
||||
|
||||
IAITO_ENABLE_PYTHON_BINDINGS {
|
||||
isEmpty(SHIBOKEN_EXECUTABLE):!packagesExist(shiboken2) {
|
||||
error("ERROR: Shiboken2, which is required to build the Python Bindings, could not be found. Make sure it is available to pkg-config.")
|
||||
}
|
||||
isEmpty(PYSIDE_LIBRARY):!packagesExist(pyside2) {
|
||||
error("ERROR: PySide2, which is required to build the Python Bindings, could not be found. Make sure it is available to pkg-config.")
|
||||
}
|
||||
win32 {
|
||||
BINDINGS_SRC_LIST_CMD = "\"$${PYTHON_EXECUTABLE}\" bindings/src_list.py"
|
||||
} else {
|
||||
BINDINGS_SRC_LIST_CMD = "python3 bindings/src_list.py"
|
||||
}
|
||||
BINDINGS_SRC_DIR = "$${PWD}/bindings"
|
||||
BINDINGS_BUILD_DIR = "$${OUT_PWD}/bindings"
|
||||
BINDINGS_SOURCE_DIR = "$${BINDINGS_BUILD_DIR}/IaitoBindings"
|
||||
BINDINGS_SOURCE = $$system("$${BINDINGS_SRC_LIST_CMD} qmake \"$${BINDINGS_BUILD_DIR}\"")
|
||||
BINDINGS_INCLUDE_DIRS = "$$[QT_INSTALL_HEADERS]" \
|
||||
"$$[QT_INSTALL_HEADERS]/QtCore" \
|
||||
"$$[QT_INSTALL_HEADERS]/QtWidgets" \
|
||||
"$$[QT_INSTALL_HEADERS]/QtGui"
|
||||
for (path, R2_INCLUDEPATH) {
|
||||
BINDINGS_INCLUDE_DIRS += "$$path"
|
||||
}
|
||||
for(path, INCLUDEPATH) {
|
||||
BINDINGS_INCLUDE_DIRS += $$absolute_path("$$path")
|
||||
}
|
||||
|
||||
win32 {
|
||||
PATH_SEP = ";"
|
||||
} else {
|
||||
PATH_SEP = ":"
|
||||
}
|
||||
BINDINGS_INCLUDE_DIRS = $$join(BINDINGS_INCLUDE_DIRS, $$PATH_SEP)
|
||||
|
||||
isEmpty(SHIBOKEN_EXECUTABLE) {
|
||||
SHIBOKEN_EXECUTABLE = $$system("pkg-config --variable=generator_location shiboken2")
|
||||
}
|
||||
|
||||
isEmpty(PYSIDE_TYPESYSTEMS) {
|
||||
PYSIDE_TYPESYSTEMS = $$system("pkg-config --variable=typesystemdir pyside2")
|
||||
}
|
||||
isEmpty(PYSIDE_INCLUDEDIR) {
|
||||
PYSIDE_INCLUDEDIR = $$system("pkg-config --variable=includedir pyside2")
|
||||
}
|
||||
|
||||
QMAKE_SUBSTITUTES += bindings/bindings.txt.in
|
||||
|
||||
SHIBOKEN_OPTIONS = --project-file="$${BINDINGS_BUILD_DIR}/bindings.txt"
|
||||
defined(SHIBOKEN_EXTRA_OPTIONS, var) SHIBOKEN_OPTIONS += $${SHIBOKEN_EXTRA_OPTIONS}
|
||||
|
||||
win32:SHIBOKEN_OPTIONS += --avoid-protected-hack
|
||||
bindings.target = bindings_target
|
||||
bindings.commands = $$quote($$system_path($${SHIBOKEN_EXECUTABLE})) $${SHIBOKEN_OPTIONS}
|
||||
QMAKE_EXTRA_TARGETS += bindings
|
||||
PRE_TARGETDEPS += bindings_target
|
||||
# GENERATED_SOURCES += $${BINDINGS_SOURCE} done by dummy targets bellow
|
||||
|
||||
INCLUDEPATH += "$${BINDINGS_SOURCE_DIR}"
|
||||
|
||||
win32:DEFINES += WIN32_LEAN_AND_MEAN
|
||||
|
||||
!isEmpty(PYSIDE_LIBRARY) {
|
||||
LIBS += "$$SHIBOKEN_LIBRARY" "$$PYSIDE_LIBRARY"
|
||||
INCLUDEPATH += "$$SHIBOKEN_INCLUDEDIR"
|
||||
} else:macx {
|
||||
# Hack needed because with regular PKGCONFIG qmake will mess up everything
|
||||
QMAKE_CXXFLAGS += $$system("pkg-config --cflags shiboken2 pyside2")
|
||||
LIBS += $$system("pkg-config --libs shiboken2 pyside2")
|
||||
} else {
|
||||
PKGCONFIG += shiboken2 pyside2
|
||||
}
|
||||
INCLUDEPATH += "$$PYSIDE_INCLUDEDIR" "$$PYSIDE_INCLUDEDIR/QtCore" "$$PYSIDE_INCLUDEDIR/QtWidgets" "$$PYSIDE_INCLUDEDIR/QtGui"
|
||||
|
||||
|
||||
BINDINGS_DUMMY_INPUT_LIST = bindings/src_list.py
|
||||
|
||||
# dummy rules to specify dependency between generated binding files and bindings_target
|
||||
bindings_h.input = BINDINGS_DUMMY_INPUT_LIST
|
||||
bindings_h.depends = bindings_target
|
||||
bindings_h.output = iaitobindings_python.h
|
||||
bindings_h.commands = "echo placeholder command ${QMAKE_FILE_OUT}"
|
||||
bindings_h.variable_out = HEADERS
|
||||
QMAKE_EXTRA_COMPILERS += bindings_h
|
||||
|
||||
for(path, BINDINGS_SOURCE) {
|
||||
dummy_input = $$replace(path, .cpp, .txt)
|
||||
BINDINGS_DUMMY_INPUTS += $$dummy_input
|
||||
win32 {
|
||||
_ = $$system("mkdir \"$$dirname(dummy_input)\"; echo a >\"$$dummy_input\"")
|
||||
} else {
|
||||
_ = $$system("mkdir -p \"$$dirname(dummy_input)\"; echo a >\"$$dummy_input\"")
|
||||
}
|
||||
}
|
||||
|
||||
bindings_cpp.input = BINDINGS_DUMMY_INPUTS
|
||||
bindings_cpp.depends = bindings_target
|
||||
bindings_cpp.output = "$${BINDINGS_SOURCE_DIR}/${QMAKE_FILE_IN_BASE}.cpp"
|
||||
bindings_cpp.commands = "echo placeholder command ${QMAKE_FILE_OUT}"
|
||||
bindings_cpp.variable_out = GENERATED_SOURCES
|
||||
QMAKE_EXTRA_COMPILERS += bindings_cpp
|
||||
}
|
||||
}
|
||||
|
||||
IAITO_ENABLE_CRASH_REPORTS {
|
||||
defined(BREAKPAD_FRAMEWORK_DIR, var)|defined(BREAKPAD_SOURCE_DIR, var) {
|
||||
defined(BREAKPAD_FRAMEWORK_DIR, var) {
|
||||
@@ -306,15 +164,20 @@ IAITO_R2GHIDRA_STATIC {
|
||||
QMAKE_SUBSTITUTES += IaitoConfig.h.in
|
||||
|
||||
SOURCES += \
|
||||
common/ExceptionInfo.cpp \
|
||||
widgets/ExceptionBar.cpp \
|
||||
Main.cpp \
|
||||
core/Iaito.cpp \
|
||||
dialogs/EditStringDialog.cpp \
|
||||
dialogs/DumpDialog.cpp \
|
||||
dialogs/WriteCommandsDialogs.cpp \
|
||||
widgets/DisassemblerGraphView.cpp \
|
||||
widgets/OverviewView.cpp \
|
||||
common/PreviewTooltip.cpp \
|
||||
common/RichTextPainter.cpp \
|
||||
dialogs/InitialOptionsDialog.cpp \
|
||||
dialogs/AboutDialog.cpp \
|
||||
dialogs/AddressSpaceManagerDialog.cpp \
|
||||
dialogs/CommentsDialog.cpp \
|
||||
dialogs/EditInstructionDialog.cpp \
|
||||
dialogs/FlagDialog.cpp \
|
||||
@@ -322,57 +185,81 @@ SOURCES += \
|
||||
dialogs/NativeDebugDialog.cpp \
|
||||
dialogs/XrefsDialog.cpp \
|
||||
core/MainWindow.cpp \
|
||||
core/DockManager.cpp \
|
||||
core/QtDockBackend.cpp \
|
||||
common/Helpers.cpp \
|
||||
common/TextEditDialog.cpp \
|
||||
common/Highlighter.cpp \
|
||||
common/MdHighlighter.cpp \
|
||||
common/Markdown.cpp \
|
||||
common/DirectionalComboBox.cpp \
|
||||
dialogs/preferences/AsmOptionsWidget.cpp \
|
||||
dialogs/NewFileDialog.cpp \
|
||||
common/TypeScriptHighlighter.cpp \
|
||||
common/AnalTask.cpp \
|
||||
dialogs/settings/AsmOptionsWidget.cpp \
|
||||
dialogs/FortuneDialog.cpp \
|
||||
dialogs/NewFileDialog.cpp \
|
||||
widgets/CommentsWidget.cpp \
|
||||
widgets/ConsoleWidget.cpp \
|
||||
widgets/CustomCommandWidget.cpp \
|
||||
widgets/Dashboard.cpp \
|
||||
widgets/EntrypointWidget.cpp \
|
||||
widgets/ExportsWidget.cpp \
|
||||
widgets/FlagsWidget.cpp \
|
||||
widgets/FunctionsWidget.cpp \
|
||||
widgets/GlobalVariablesWidget.cpp \
|
||||
widgets/ImportsWidget.cpp \
|
||||
widgets/CodeEditor.cpp \
|
||||
widgets/Omnibar.cpp \
|
||||
widgets/RelocsWidget.cpp \
|
||||
widgets/SectionsWidget.cpp \
|
||||
widgets/SegmentsWidget.cpp \
|
||||
widgets/StringsWidget.cpp \
|
||||
widgets/SymbolsWidget.cpp \
|
||||
widgets/XrefsWidget.cpp \
|
||||
widgets/RefsWidget.cpp \
|
||||
widgets/CodeInfoWidget.cpp \
|
||||
menus/DisassemblyContextMenu.cpp \
|
||||
menus/DecompilerContextMenu.cpp \
|
||||
menus/ColorPickerMenu.cpp \
|
||||
menus/PinPickerMenu.cpp \
|
||||
widgets/DisassemblyWidget.cpp \
|
||||
widgets/HexdumpWidget.cpp \
|
||||
common/Configuration.cpp \
|
||||
common/theme/Theme.cpp \
|
||||
common/theme/IaitoStyle.cpp \
|
||||
common/Colors.cpp \
|
||||
dialogs/SaveProjectDialog.cpp \
|
||||
common/TempConfig.cpp \
|
||||
common/SvgIconEngine.cpp \
|
||||
common/SyntaxHighlighter.cpp \
|
||||
widgets/DecompilerWidget.cpp \
|
||||
widgets/DecompilerTextEdit.cpp \
|
||||
widgets/VisualNavbar.cpp \
|
||||
widgets/GraphView.cpp \
|
||||
dialogs/preferences/PreferencesDialog.cpp \
|
||||
dialogs/preferences/AppearanceOptionsWidget.cpp \
|
||||
dialogs/preferences/GraphOptionsWidget.cpp \
|
||||
dialogs/preferences/PreferenceCategory.cpp \
|
||||
dialogs/preferences/InitializationFileEditor.cpp \
|
||||
dialogs/settings/SettingsDialog.cpp \
|
||||
dialogs/settings/AppearanceOptionsWidget.cpp \
|
||||
dialogs/settings/GraphOptionsWidget.cpp \
|
||||
dialogs/settings/SettingCategory.cpp \
|
||||
dialogs/settings/InitializationFileEditor.cpp \
|
||||
widgets/QuickFilterView.cpp \
|
||||
widgets/ClassesWidget.cpp \
|
||||
widgets/ResourcesWidget.cpp \
|
||||
widgets/VTablesWidget.cpp \
|
||||
widgets/TypesWidget.cpp \
|
||||
widgets/HeadersWidget.cpp \
|
||||
widgets/InterfacesWidget.cpp \
|
||||
widgets/SearchWidget.cpp \
|
||||
IaitoApplication.cpp \
|
||||
common/PythonAPI.cpp \
|
||||
common/DeepLink.cpp \
|
||||
common/SamplesDB.cpp \
|
||||
dialogs/R2PluginsDialog.cpp \
|
||||
widgets/IaitoDockWidget.cpp \
|
||||
widgets/IaitoTreeWidget.cpp \
|
||||
widgets/MapsWidget.cpp \
|
||||
widgets/BinariesWidget.cpp \
|
||||
widgets/FilesWidget.cpp \
|
||||
widgets/FilesystemWidget.cpp \
|
||||
common/SourceLineReference.cpp \
|
||||
widgets/GraphWidget.cpp \
|
||||
widgets/OverviewWidget.cpp \
|
||||
common/JsonTreeItem.cpp \
|
||||
@@ -380,6 +267,7 @@ SOURCES += \
|
||||
dialogs/VersionInfoDialog.cpp \
|
||||
widgets/ZignaturesWidget.cpp \
|
||||
common/AsyncTask.cpp \
|
||||
common/DecompileTask.cpp \
|
||||
dialogs/AsyncTaskDialog.cpp \
|
||||
widgets/StackWidget.cpp \
|
||||
widgets/RegistersWidget.cpp \
|
||||
@@ -393,8 +281,10 @@ SOURCES += \
|
||||
dialogs/R2TaskDialog.cpp \
|
||||
widgets/DebugActions.cpp \
|
||||
widgets/MemoryMapWidget.cpp \
|
||||
dialogs/preferences/DebugOptionsWidget.cpp \
|
||||
dialogs/preferences/PluginsOptionsWidget.cpp \
|
||||
dialogs/settings/DebugOptionsWidget.cpp \
|
||||
dialogs/settings/WebserverOptionsWidget.cpp \
|
||||
dialogs/settings/SamplesOptionsWidget.cpp \
|
||||
dialogs/settings/PluginsOptionsWidget.cpp \
|
||||
widgets/BreakpointWidget.cpp \
|
||||
dialogs/BreakpointsDialog.cpp \
|
||||
dialogs/AttachProcDialog.cpp \
|
||||
@@ -402,10 +292,10 @@ SOURCES += \
|
||||
dialogs/SetToDataDialog.cpp \
|
||||
dialogs/EditVariablesDialog.cpp \
|
||||
dialogs/EditFunctionDialog.cpp \
|
||||
dialogs/SwitchJumpTableDialog.cpp \
|
||||
widgets/IaitoTreeView.cpp \
|
||||
widgets/ComboQuickFilterView.cpp \
|
||||
dialogs/HexdumpRangeDialog.cpp \
|
||||
common/QtResImporter.cpp \
|
||||
common/IaitoSeekable.cpp \
|
||||
common/RefreshDeferrer.cpp \
|
||||
dialogs/WelcomeDialog.cpp \
|
||||
@@ -413,7 +303,6 @@ SOURCES += \
|
||||
dialogs/EditMethodDialog.cpp \
|
||||
dialogs/TypesInteractionDialog.cpp \
|
||||
widgets/SdbWidget.cpp \
|
||||
common/PythonManager.cpp \
|
||||
plugins/PluginManager.cpp \
|
||||
common/BasicBlockHighlighter.cpp \
|
||||
common/BasicInstructionHighlighter.cpp \
|
||||
@@ -422,26 +311,40 @@ SOURCES += \
|
||||
common/ColorThemeWorker.cpp \
|
||||
widgets/ColorThemeComboBox.cpp \
|
||||
widgets/ColorThemeListView.cpp \
|
||||
dialogs/preferences/ColorThemeEditDialog.cpp \
|
||||
common/UpdateWorker.cpp \
|
||||
dialogs/settings/ColorThemeEditDialog.cpp \
|
||||
dialogs/settings/InterfaceThemeEditDialog.cpp \
|
||||
widgets/MemoryDockWidget.cpp \
|
||||
common/CrashHandler.cpp \
|
||||
common/BugReporting.cpp \
|
||||
common/HighDpiPixmap.cpp \
|
||||
widgets/GraphGridLayout.cpp \
|
||||
widgets/HexWidget.cpp \
|
||||
widgets/HexPatWidget.cpp \
|
||||
widgets/AddressScrollBar.cpp \
|
||||
widgets/R2AIWidget.cpp \
|
||||
widgets/R2McpWidget.cpp \
|
||||
common/SelectionHighlight.cpp \
|
||||
common/Decompiler.cpp \
|
||||
common/R2GhidraCmdDecompiler.cpp \
|
||||
common/R2JadxDecompiler.cpp \
|
||||
common/ShortcutKeys.cpp \
|
||||
common/ShortcutManager.cpp \
|
||||
dialogs/ShortcutKeysDialog.cpp \
|
||||
common/R2SourceDecompiler.cpp \
|
||||
common/R2pdcCmdDecompiler.cpp \
|
||||
common/R2DecaiDecompiler.cpp \
|
||||
common/R2AiDecompiler.cpp \
|
||||
common/R2AnotesDecompiler.cpp \
|
||||
common/R2HermesDecompiler.cpp \
|
||||
common/R2retdecDecompiler.cpp \
|
||||
menus/AddressableItemContextMenu.cpp \
|
||||
common/AddressableItemModel.cpp \
|
||||
common/NameListModel.cpp \
|
||||
widgets/NameListView.cpp \
|
||||
widgets/ListDockWidget.cpp \
|
||||
dialogs/MultitypeFileSaveDialog.cpp \
|
||||
widgets/BoolToggleDelegate.cpp \
|
||||
common/IOModesController.cpp \
|
||||
common/SettingsUpgrade.cpp \
|
||||
dialogs/LayoutManager.cpp \
|
||||
common/IaitoLayout.cpp \
|
||||
widgets/GraphHorizontalAdapter.cpp \
|
||||
@@ -450,83 +353,130 @@ SOURCES += \
|
||||
widgets/SimpleTextGraphView.cpp \
|
||||
widgets/R2GraphWidget.cpp \
|
||||
widgets/CallGraph.cpp \
|
||||
widgets/CalculatorWidget.cpp \
|
||||
widgets/SyscallsWidget.cpp \
|
||||
widgets/AddressableDockWidget.cpp \
|
||||
dialogs/preferences/AnalOptionsWidget.cpp \
|
||||
common/DecompilerHighlighter.cpp
|
||||
dialogs/settings/AnalOptionsWidget.cpp \
|
||||
dialogs/settings/ShortcutsOptionsWidget.cpp \
|
||||
common/DecompilerHighlighter.cpp \
|
||||
dialogs/PackageManagerDialog.cpp \
|
||||
dialogs/AssemblerDialog.cpp \
|
||||
dialogs/ScriptManagerDialog.cpp \
|
||||
dialogs/ScriptManagerWidget.cpp \
|
||||
widgets/ZoomWidget.cpp \
|
||||
common/DataAnalysis.cpp \
|
||||
common/TypeLayout.cpp \
|
||||
widgets/DataAnalysisView.cpp \
|
||||
widgets/DataAnalysisWidget.cpp
|
||||
|
||||
GRAPHVIZ_SOURCES = \
|
||||
widgets/GraphvizLayout.cpp
|
||||
|
||||
HEADERS += \
|
||||
common/ExceptionInfo.h \
|
||||
widgets/ExceptionBar.h \
|
||||
common/R2Shims.h \
|
||||
core/Iaito.h \
|
||||
core/IaitoCommon.h \
|
||||
core/IaitoDescriptions.h \
|
||||
dialogs/EditStringDialog.h \
|
||||
dialogs/DumpDialog.h \
|
||||
dialogs/WriteCommandsDialogs.h \
|
||||
widgets/ClickableSvgWidget.h \
|
||||
widgets/DisassemblerGraphView.h \
|
||||
widgets/OverviewView.h \
|
||||
common/PreviewTooltip.h \
|
||||
common/RichTextPainter.h \
|
||||
common/CachedFontMetrics.h \
|
||||
common/TypeScriptHighlighter.h \
|
||||
common/Helpers.h \
|
||||
common/ShortcutKeys.h \
|
||||
common/ShortcutManager.h \
|
||||
dialogs/ShortcutKeysDialog.h \
|
||||
common/TextEditDialog.h \
|
||||
common/Highlighter.h \
|
||||
common/MdHighlighter.h \
|
||||
common/Markdown.h \
|
||||
common/DirectionalComboBox.h \
|
||||
common/AnalTask.h \
|
||||
dialogs/AboutDialog.h \
|
||||
dialogs/preferences/AsmOptionsWidget.h \
|
||||
dialogs/AddressSpaceManagerDialog.h \
|
||||
dialogs/settings/AsmOptionsWidget.h \
|
||||
dialogs/CommentsDialog.h \
|
||||
dialogs/EditInstructionDialog.h \
|
||||
dialogs/FlagDialog.h \
|
||||
dialogs/RemoteDebugDialog.h \
|
||||
dialogs/NativeDebugDialog.h \
|
||||
dialogs/XrefsDialog.h \
|
||||
common/Helpers.h \
|
||||
core/MainWindow.h \
|
||||
common/Highlighter.h \
|
||||
common/MdHighlighter.h \
|
||||
common/DirectionalComboBox.h \
|
||||
core/DockManager.h \
|
||||
core/DockBackend.h \
|
||||
core/QtDockBackend.h \
|
||||
dialogs/InitialOptionsDialog.h \
|
||||
dialogs/NewFileDialog.h \
|
||||
common/AnalTask.h \
|
||||
widgets/CommentsWidget.h \
|
||||
widgets/ConsoleWidget.h \
|
||||
widgets/CustomCommandWidget.h \
|
||||
widgets/Dashboard.h \
|
||||
widgets/EntrypointWidget.h \
|
||||
widgets/ExportsWidget.h \
|
||||
widgets/FlagsWidget.h \
|
||||
widgets/FunctionsWidget.h \
|
||||
widgets/GlobalVariablesWidget.h \
|
||||
widgets/ImportsWidget.h \
|
||||
widgets/Omnibar.h \
|
||||
widgets/RelocsWidget.h \
|
||||
widgets/CodeEditor.h \
|
||||
widgets/SectionsWidget.h \
|
||||
widgets/SegmentsWidget.h \
|
||||
widgets/StringsWidget.h \
|
||||
widgets/SymbolsWidget.h \
|
||||
widgets/XrefsWidget.h \
|
||||
widgets/RefsWidget.h \
|
||||
widgets/CodeInfoWidget.h \
|
||||
menus/DisassemblyContextMenu.h \
|
||||
menus/DecompilerContextMenu.h \
|
||||
menus/ContextMenuIcons.h \
|
||||
menus/ColorPickerMenu.h \
|
||||
menus/PinPickerMenu.h \
|
||||
widgets/DisassemblyWidget.h \
|
||||
widgets/HexdumpWidget.h \
|
||||
common/Configuration.h \
|
||||
common/theme/Theme.h \
|
||||
common/theme/IaitoStyle.h \
|
||||
common/Colors.h \
|
||||
dialogs/SaveProjectDialog.h \
|
||||
common/TempConfig.h \
|
||||
common/SvgIconEngine.h \
|
||||
common/SyntaxHighlighter.h \
|
||||
widgets/DecompilerWidget.h \
|
||||
widgets/DecompilerTextEdit.h \
|
||||
widgets/VisualNavbar.h \
|
||||
widgets/GraphView.h \
|
||||
dialogs/preferences/PreferencesDialog.h \
|
||||
dialogs/preferences/AppearanceOptionsWidget.h \
|
||||
dialogs/preferences/PreferenceCategory.h \
|
||||
dialogs/preferences/GraphOptionsWidget.h \
|
||||
dialogs/preferences/InitializationFileEditor.h \
|
||||
dialogs/settings/SettingsDialog.h \
|
||||
dialogs/settings/AppearanceOptionsWidget.h \
|
||||
dialogs/settings/SettingCategory.h \
|
||||
dialogs/settings/GraphOptionsWidget.h \
|
||||
dialogs/settings/InitializationFileEditor.h \
|
||||
widgets/QuickFilterView.h \
|
||||
widgets/ClassesWidget.h \
|
||||
widgets/ResourcesWidget.h \
|
||||
IaitoApplication.h \
|
||||
common/DeepLink.h \
|
||||
common/SamplesDB.h \
|
||||
widgets/VTablesWidget.h \
|
||||
widgets/TypesWidget.h \
|
||||
widgets/HeadersWidget.h \
|
||||
widgets/InterfacesWidget.h \
|
||||
widgets/SearchWidget.h \
|
||||
common/PythonAPI.h \
|
||||
dialogs/R2PluginsDialog.h \
|
||||
widgets/IaitoDockWidget.h \
|
||||
widgets/IaitoTreeWidget.h \
|
||||
widgets/MapsWidget.h \
|
||||
widgets/BinariesWidget.h \
|
||||
widgets/FilesWidget.h \
|
||||
widgets/FilesystemWidget.h \
|
||||
common/SourceLineReference.h \
|
||||
widgets/GraphWidget.h \
|
||||
widgets/OverviewWidget.h \
|
||||
common/JsonTreeItem.h \
|
||||
@@ -534,12 +484,14 @@ HEADERS += \
|
||||
dialogs/VersionInfoDialog.h \
|
||||
widgets/ZignaturesWidget.h \
|
||||
common/AsyncTask.h \
|
||||
common/DecompileTask.h \
|
||||
dialogs/AsyncTaskDialog.h \
|
||||
widgets/StackWidget.h \
|
||||
widgets/RegistersWidget.h \
|
||||
widgets/ThreadsWidget.h \
|
||||
widgets/ProcessesWidget.h \
|
||||
widgets/BacktraceWidget.h \
|
||||
dialogs/FortuneDialog.h \
|
||||
dialogs/MapFileDialog.h \
|
||||
common/StringsTask.h \
|
||||
common/FunctionsTask.h \
|
||||
@@ -550,8 +502,10 @@ HEADERS += \
|
||||
dialogs/R2TaskDialog.h \
|
||||
widgets/DebugActions.h \
|
||||
widgets/MemoryMapWidget.h \
|
||||
dialogs/preferences/DebugOptionsWidget.h \
|
||||
dialogs/preferences/PluginsOptionsWidget.h \
|
||||
dialogs/settings/DebugOptionsWidget.h \
|
||||
dialogs/settings/WebserverOptionsWidget.h \
|
||||
dialogs/settings/SamplesOptionsWidget.h \
|
||||
dialogs/settings/PluginsOptionsWidget.h \
|
||||
widgets/BreakpointWidget.h \
|
||||
dialogs/BreakpointsDialog.h \
|
||||
dialogs/AttachProcDialog.h \
|
||||
@@ -560,10 +514,10 @@ HEADERS += \
|
||||
common/InitialOptions.h \
|
||||
dialogs/EditVariablesDialog.h \
|
||||
dialogs/EditFunctionDialog.h \
|
||||
dialogs/SwitchJumpTableDialog.h \
|
||||
widgets/IaitoTreeView.h \
|
||||
widgets/ComboQuickFilterView.h \
|
||||
dialogs/HexdumpRangeDialog.h \
|
||||
common/QtResImporter.h \
|
||||
common/IaitoSeekable.h \
|
||||
common/RefreshDeferrer.h \
|
||||
dialogs/WelcomeDialog.h \
|
||||
@@ -573,36 +527,48 @@ HEADERS += \
|
||||
common/CrashHandler.h \
|
||||
dialogs/TypesInteractionDialog.h \
|
||||
widgets/SdbWidget.h \
|
||||
common/PythonManager.h \
|
||||
plugins/PluginManager.h \
|
||||
common/BasicBlockHighlighter.h \
|
||||
common/BasicInstructionHighlighter.h \
|
||||
common/UpdateWorker.h \
|
||||
widgets/ColorPicker.h \
|
||||
common/ColorThemeWorker.h \
|
||||
widgets/ColorThemeComboBox.h \
|
||||
widgets/MemoryDockWidget.h \
|
||||
widgets/ColorThemeListView.h \
|
||||
dialogs/preferences/ColorThemeEditDialog.h \
|
||||
dialogs/settings/ColorThemeEditDialog.h \
|
||||
dialogs/settings/InterfaceThemeEditDialog.h \
|
||||
dialogs/settings/ShortcutsOptionsWidget.h \
|
||||
dialogs/LinkTypeDialog.h \
|
||||
common/BugReporting.h \
|
||||
common/HighDpiPixmap.h \
|
||||
widgets/GraphLayout.h \
|
||||
widgets/GraphGridLayout.h \
|
||||
widgets/HexWidget.h \
|
||||
widgets/HexPatWidget.h \
|
||||
common/SparseHexLayout.h \
|
||||
widgets/AddressScrollBar.h \
|
||||
widgets/R2AIWidget.h \
|
||||
widgets/R2McpWidget.h \
|
||||
common/SelectionHighlight.h \
|
||||
common/Decompiler.h \
|
||||
common/R2GhidraCmdDecompiler.h \
|
||||
common/R2JadxDecompiler.h \
|
||||
common/R2DecaiDecompiler.h \
|
||||
common/R2AiDecompiler.h \
|
||||
common/R2AnotesDecompiler.h \
|
||||
common/R2HermesDecompiler.h \
|
||||
common/R2pdcCmdDecompiler.h \
|
||||
common/R2SourceDecompiler.h \
|
||||
common/R2retdecDecompiler.h \
|
||||
menus/AddressableItemContextMenu.h \
|
||||
common/AddressableItemModel.h \
|
||||
common/NameListModel.h \
|
||||
widgets/NameListView.h \
|
||||
widgets/ListDockWidget.h \
|
||||
widgets/AddressableItemList.h \
|
||||
dialogs/MultitypeFileSaveDialog.h \
|
||||
widgets/BoolToggleDelegate.h \
|
||||
common/IOModesController.h \
|
||||
common/SettingsUpgrade.h \
|
||||
dialogs/LayoutManager.h \
|
||||
common/IaitoLayout.h \
|
||||
common/BinaryTrees.h \
|
||||
@@ -613,26 +579,41 @@ HEADERS += \
|
||||
widgets/SimpleTextGraphView.h \
|
||||
widgets/R2GraphWidget.h \
|
||||
widgets/CallGraph.h \
|
||||
widgets/CalculatorWidget.h \
|
||||
widgets/SyscallsWidget.h \
|
||||
widgets/AddressableDockWidget.h \
|
||||
dialogs/preferences/AnalOptionsWidget.h \
|
||||
common/DecompilerHighlighter.h
|
||||
dialogs/settings/AnalOptionsWidget.h \
|
||||
common/DecompilerHighlighter.h \
|
||||
common/CodeMetaRange.h \
|
||||
dialogs/PackageManagerDialog.h \
|
||||
dialogs/AssemblerDialog.h \
|
||||
dialogs/ScriptManagerDialog.h \
|
||||
dialogs/ScriptManagerWidget.h \
|
||||
widgets/ZoomWidget.h \
|
||||
common/DataAnalysis.h \
|
||||
common/TypeLayout.h \
|
||||
widgets/DataAnalysisView.h \
|
||||
widgets/DataAnalysisWidget.h
|
||||
|
||||
GRAPHVIZ_HEADERS = widgets/GraphvizLayout.h
|
||||
|
||||
FORMS += \
|
||||
widgets/GlobalVariablesWidget.ui \
|
||||
widgets/DataAnalysisWidget.ui \
|
||||
dialogs/AboutDialog.ui \
|
||||
dialogs/EditStringDialog.ui \
|
||||
dialogs/Base64EnDecodedWriteDialog.ui \
|
||||
dialogs/DumpDialog.ui \
|
||||
dialogs/DuplicateFromOffsetDialog.ui \
|
||||
dialogs/IncrementDecrementDialog.ui \
|
||||
dialogs/preferences/AsmOptionsWidget.ui \
|
||||
dialogs/settings/AsmOptionsWidget.ui \
|
||||
dialogs/CommentsDialog.ui \
|
||||
dialogs/EditInstructionDialog.ui \
|
||||
dialogs/FlagDialog.ui \
|
||||
dialogs/RemoteDebugDialog.ui \
|
||||
dialogs/NativeDebugDialog.ui \
|
||||
dialogs/XrefsDialog.ui \
|
||||
dialogs/NewfileDialog.ui \
|
||||
dialogs/NewFileDialog.ui \
|
||||
dialogs/InitialOptionsDialog.ui \
|
||||
dialogs/EditFunctionDialog.ui \
|
||||
core/MainWindow.ui \
|
||||
@@ -642,11 +623,12 @@ FORMS += \
|
||||
widgets/FlagsWidget.ui \
|
||||
widgets/StringsWidget.ui \
|
||||
widgets/HexdumpWidget.ui \
|
||||
widgets/HexPatWidget.ui \
|
||||
dialogs/SaveProjectDialog.ui \
|
||||
dialogs/preferences/PreferencesDialog.ui \
|
||||
dialogs/preferences/AppearanceOptionsWidget.ui \
|
||||
dialogs/preferences/GraphOptionsWidget.ui \
|
||||
dialogs/preferences/InitializationFileEditor.ui \
|
||||
dialogs/settings/SettingsDialog.ui \
|
||||
dialogs/settings/AppearanceOptionsWidget.ui \
|
||||
dialogs/settings/GraphOptionsWidget.ui \
|
||||
dialogs/settings/InitializationFileEditor.ui \
|
||||
widgets/QuickFilterView.ui \
|
||||
widgets/DecompilerWidget.ui \
|
||||
widgets/ClassesWidget.ui \
|
||||
@@ -664,7 +646,9 @@ FORMS += \
|
||||
widgets/ProcessesWidget.ui \
|
||||
widgets/BacktraceWidget.ui \
|
||||
dialogs/MapFileDialog.ui \
|
||||
dialogs/preferences/DebugOptionsWidget.ui \
|
||||
dialogs/settings/DebugOptionsWidget.ui \
|
||||
dialogs/settings/WebserverOptionsWidget.ui \
|
||||
dialogs/settings/SamplesOptionsWidget.ui \
|
||||
widgets/BreakpointWidget.ui \
|
||||
dialogs/BreakpointsDialog.ui \
|
||||
dialogs/AttachProcDialog.ui \
|
||||
@@ -672,7 +656,6 @@ FORMS += \
|
||||
dialogs/SetToDataDialog.ui \
|
||||
dialogs/EditVariablesDialog.ui \
|
||||
widgets/IaitoTreeView.ui \
|
||||
widgets/ComboQuickFilterView.ui \
|
||||
dialogs/HexdumpRangeDialog.ui \
|
||||
dialogs/WelcomeDialog.ui \
|
||||
dialogs/EditMethodDialog.ui \
|
||||
@@ -680,18 +663,16 @@ FORMS += \
|
||||
widgets/SdbWidget.ui \
|
||||
dialogs/LinkTypeDialog.ui \
|
||||
widgets/ColorPicker.ui \
|
||||
dialogs/preferences/ColorThemeEditDialog.ui \
|
||||
dialogs/settings/ColorThemeEditDialog.ui \
|
||||
widgets/ListDockWidget.ui \
|
||||
dialogs/LayoutManager.ui \
|
||||
widgets/R2GraphWidget.ui \
|
||||
dialogs/preferences/AnalOptionsWidget.ui
|
||||
widgets/CustomCommandWidget.ui \
|
||||
dialogs/settings/AnalOptionsWidget.ui
|
||||
|
||||
RESOURCES += \
|
||||
resources.qrc \
|
||||
themes/native/native.qrc \
|
||||
themes/qdarkstyle/dark.qrc \
|
||||
themes/midnight/midnight.qrc \
|
||||
themes/lightstyle/light.qrc
|
||||
themes/engine/engine.qrc
|
||||
|
||||
|
||||
DISTFILES += Iaito.astylerc
|
||||
|
||||
@@ -1,33 +1,49 @@
|
||||
#include "common/PythonManager.h"
|
||||
#include "common/CrashHandler.h"
|
||||
#include "IaitoApplication.h"
|
||||
#include "plugins/PluginManager.h"
|
||||
#include "IaitoConfig.h"
|
||||
#include "R2AiDecompiler.h"
|
||||
#include "R2AnotesDecompiler.h"
|
||||
#include "R2DecaiDecompiler.h"
|
||||
#include "R2GhidraCmdDecompiler.h"
|
||||
#include "R2HermesDecompiler.h"
|
||||
#include "R2JadxDecompiler.h"
|
||||
#include "R2SourceDecompiler.h"
|
||||
#include "R2pdcCmdDecompiler.h"
|
||||
#include "R2retdecDecompiler.h"
|
||||
#include "IaitoConfig.h"
|
||||
#include "common/CrashHandler.h"
|
||||
#include "common/Decompiler.h"
|
||||
#include "common/DeepLink.h"
|
||||
#include "common/ResourcePaths.h"
|
||||
#include "common/SamplesDB.h"
|
||||
#include "common/ShortcutManager.h"
|
||||
#include "common/theme/IaitoStyle.h"
|
||||
#include "plugins/PluginManager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileOpenEvent>
|
||||
#include <QCommandLineParser>
|
||||
#include <QEvent>
|
||||
#include <QFileOpenEvent>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QCommandLineParser>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
||||
#include <QProxyStyle>
|
||||
#include <QStyle>
|
||||
#include <QStyleHintReturn>
|
||||
#include <QStyleOption>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
#include <QTextCodec>
|
||||
#endif
|
||||
#include <QStringList>
|
||||
#include <QProcess>
|
||||
#include <QPluginLoader>
|
||||
#include <QDir>
|
||||
#include <QTranslator>
|
||||
#include <QLibraryInfo>
|
||||
#include <QFontDatabase>
|
||||
#include <QLibraryInfo>
|
||||
#include <QPluginLoader>
|
||||
#include <QProcess>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringList>
|
||||
#include <QTranslator>
|
||||
#include <QUrl>
|
||||
#ifdef Q_OS_WIN
|
||||
#include <QtNetwork/QtNetwork>
|
||||
#endif // Q_OS_WIN
|
||||
#include <cstring>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
@@ -35,37 +51,71 @@
|
||||
#include <R2GhidraDecompiler.h>
|
||||
#endif
|
||||
|
||||
static bool versionCheck() {
|
||||
static bool versionCheck()
|
||||
{
|
||||
// Check r2 version
|
||||
QString a = r_core_version (); // runtime library version
|
||||
QString b = "" R2_GITTAP; // compiled version
|
||||
QStringList la = a.split(".");
|
||||
QStringList lb = b.split(".");
|
||||
if (la.size() < 2 && lb.size() < 2) {
|
||||
R_LOG_WARN ("Invalid version string somwhere");
|
||||
return false;
|
||||
const QString a = r_core_version(); // runtime library version
|
||||
const QString b = "" R2_GITTAP; // compiled version
|
||||
const QStringList la = a.split(".");
|
||||
const QStringList lb = b.split(".");
|
||||
if (la.size() < 2 || lb.size() < 2) {
|
||||
R_LOG_WARN("Invalid version string somewhere");
|
||||
return false;
|
||||
}
|
||||
if (la.at(0) != lb.at(0)) {
|
||||
R_LOG_WARN ("Major version differs");
|
||||
return false;
|
||||
R_LOG_WARN("Major version differs");
|
||||
return false;
|
||||
}
|
||||
if (la.at(1) != lb.at(1)) {
|
||||
R_LOG_WARN ("Minor version differs");
|
||||
return false;
|
||||
R_LOG_WARN("Minor version differs");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IaitoApplication::IaitoApplication(int &argc, char **argv) : QApplication(argc, argv)
|
||||
static QtMessageHandler g_previousMessageHandler = nullptr;
|
||||
|
||||
static void iaitoMessageHandler(QtMsgType type, const QMessageLogContext &ctx, const QString &msg)
|
||||
{
|
||||
// The category is on ctx.category, not inside msg. Drop qt.gui.imageio
|
||||
// entirely (libpng IDAT spam from PNGs shipped inside Qt itself) and any
|
||||
// stray "libpng warning:" text that might arrive without a category.
|
||||
const char *cat = ctx.category;
|
||||
if (cat && !strncmp(cat, "qt.gui.imageio", 14)) {
|
||||
return;
|
||||
}
|
||||
if (msg.contains(QLatin1String("libpng warning:"))) {
|
||||
return;
|
||||
}
|
||||
if (g_previousMessageHandler) {
|
||||
g_previousMessageHandler(type, ctx, msg);
|
||||
} else {
|
||||
QByteArray local = msg.toLocal8Bit();
|
||||
fprintf(stderr, "%s\n", local.constData());
|
||||
}
|
||||
}
|
||||
|
||||
IaitoApplication::IaitoApplication(int &argc, char **argv)
|
||||
: QApplication(argc, argv)
|
||||
, m_FileAlreadyDropped(false)
|
||||
{
|
||||
// Install message handler before widgets load to filter Qt's libpng spam.
|
||||
g_previousMessageHandler = qInstallMessageHandler(iaitoMessageHandler);
|
||||
|
||||
// Setup application information
|
||||
setApplicationVersion(IAITO_VERSION_FULL);
|
||||
setWindowIcon(QIcon(":/img/iaito-o.svg"));
|
||||
#ifndef Q_OS_MACOS
|
||||
setWindowIcon(QIcon(":/img/iaito.svg"));
|
||||
#endif
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif
|
||||
setLayoutDirection(Qt::LeftToRight);
|
||||
|
||||
// WARN!!! Put initialization code below this line. Code above this line is mandatory to be run First
|
||||
setStyle(new IaitoStyle());
|
||||
|
||||
// WARN!!! Put initialization code below this line. Code above this line is
|
||||
// mandatory to be run First
|
||||
#ifdef Q_OS_WIN
|
||||
// Hack to force Iaito load internet connection related DLL's
|
||||
QSslSocket s;
|
||||
@@ -90,67 +140,140 @@ IaitoApplication::IaitoApplication(int &argc, char **argv) : QApplication(argc,
|
||||
if (ret == -1) {
|
||||
qWarning() << "Cannot load Incosolata-Regular font.";
|
||||
}
|
||||
|
||||
ret = QFontDatabase::addApplicationFont(":/fonts/IBMPlexMono-Regular.ttf");
|
||||
if (ret == -1) {
|
||||
qWarning() << "Cannot load IBM Plex Mono Regular font.";
|
||||
}
|
||||
ret = QFontDatabase::addApplicationFont(":/fonts/IBMPlexMono-Bold.ttf");
|
||||
if (ret == -1) {
|
||||
qWarning() << "Cannot load IBM Plex Mono Bold font.";
|
||||
}
|
||||
#if 0
|
||||
ret = QFontDatabase::addApplicationFont(":/fonts/W95FA.otf");
|
||||
if (ret == -1) {
|
||||
qWarning() << "Cannot load W95FA font.";
|
||||
}
|
||||
ret = QFontDatabase::addApplicationFont(":/fonts/CourierPixel.otf");
|
||||
if (ret == -1) {
|
||||
qWarning() << "Cannot load Courier Pixel font.";
|
||||
}
|
||||
#endif
|
||||
ret = QFontDatabase::addApplicationFont(":/fonts/windows.ttf");
|
||||
if (ret == -1) {
|
||||
qWarning() << "Cannot load Windows font.";
|
||||
}
|
||||
|
||||
// Set QString codec to UTF-8
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
|
||||
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
#endif
|
||||
if (!parseCommandLineOptions()) {
|
||||
std::exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!versionCheck ()) {
|
||||
if (!versionCheck()) {
|
||||
QMessageBox msg;
|
||||
msg.setIcon(QMessageBox::Critical);
|
||||
msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
msg.setWindowTitle(QObject::tr("Version mismatch!"));
|
||||
QString localVersion = r_core_version ();
|
||||
QString localVersion = r_core_version();
|
||||
QString r2version = R2_GITTAP;
|
||||
msg.setText(QString(
|
||||
QObject::tr("The version used to compile Iaito (%1) does not match the binary version of radare2 (%2). This could result in unexpected behaviour. Are you sure you want to continue?")).arg(
|
||||
localVersion, r2version));
|
||||
QObject::tr(
|
||||
"The version used to compile Iaito (%1) does not match the "
|
||||
"binary version of radare2 (%2). This could result in "
|
||||
"unexpected behaviour. Are you sure you want to continue?"))
|
||||
.arg(localVersion, r2version));
|
||||
if (msg.exec() == QMessageBox::No) {
|
||||
std::exit(1);
|
||||
QCoreApplication::exit();
|
||||
// std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef IAITO_ENABLE_PYTHON
|
||||
// Init python
|
||||
if (!clOptions.pythonHome.isEmpty()) {
|
||||
Python()->setPythonHome(clOptions.pythonHome);
|
||||
}
|
||||
Python()->initialize();
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
// Redefine r_sys_prefix() behaviour
|
||||
qputenv("R_ALT_SRC_DIR", "1");
|
||||
#endif
|
||||
|
||||
#ifdef MACOS_R2_BUNDLED
|
||||
{
|
||||
auto appdir = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS
|
||||
appdir.cdUp(); // Contents
|
||||
|
||||
auto r2prefix = appdir; // Contents
|
||||
r2prefix.cd("Resources/radare2"); // Contents/Resources/radare2
|
||||
qputenv("R2_PREFIX", r2prefix.absolutePath().toLocal8Bit());
|
||||
|
||||
auto r2www = appdir; // Contents
|
||||
r2www.cd("Resources/radare2/share/radare2/last/www");
|
||||
qputenv("R2_WWWROOT", r2www.absolutePath().toLocal8Bit());
|
||||
|
||||
auto r2bin = appdir; // Contents
|
||||
r2bin.cd("Helpers"); // Contents/Helpers
|
||||
auto paths = QStringList(QString::fromLocal8Bit(qgetenv("PATH")));
|
||||
paths.prepend(r2bin.absolutePath());
|
||||
qputenv("PATH", paths.join(QLatin1Char(':')).toLocal8Bit());
|
||||
|
||||
auto sleighHome = appdir; // Contents
|
||||
sleighHome.cd(
|
||||
"Resources/radare2/share/r2ghidra_sleigh"); // Contents/Resources/radare2/share/r2ghidra_sleigh
|
||||
qputenv("SLEIGHHOME", sleighHome.absolutePath().toLocal8Bit());
|
||||
|
||||
// Allow bundled radare2 and its plugins to save its data inside iaito app folders
|
||||
qputenv(
|
||||
"XDG_CACHE_HOME",
|
||||
QStandardPaths::writableLocation(QStandardPaths::CacheLocation).toLocal8Bit());
|
||||
qputenv(
|
||||
"XDG_CONFIG_HOME",
|
||||
QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation).toLocal8Bit());
|
||||
qputenv(
|
||||
"XDG_DATA_HOME",
|
||||
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation).toLocal8Bit());
|
||||
}
|
||||
#endif
|
||||
|
||||
Core()->initialize(clOptions.enableR2Plugins);
|
||||
Core()->setSettings();
|
||||
Config()->loadInitial();
|
||||
Core()->loadIaitoRC();
|
||||
Core()->loadIaitoRC(0);
|
||||
ShortcutMgr()->migrateLegacyCommandKeys();
|
||||
|
||||
Config()->setOutputRedirectionEnabled(clOptions.outputRedirectionEnabled);
|
||||
|
||||
if (R2pdcCmdDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2pdcCmdDecompiler(Core()));
|
||||
}
|
||||
if (R2SourceDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2SourceDecompiler(Core()));
|
||||
}
|
||||
if (R2retdecDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2retdecDecompiler(Core()));
|
||||
}
|
||||
if (R2DecDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2DecDecompiler(Core()));
|
||||
}
|
||||
if (R2JadxDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2JadxDecompiler(Core()));
|
||||
}
|
||||
if (R2DecaiDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2DecaiDecompiler(Core()));
|
||||
}
|
||||
if (R2AiDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2AiDecompiler(Core()));
|
||||
}
|
||||
if (R2GhidraCmdDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2GhidraCmdDecompiler(Core()));
|
||||
}
|
||||
if (R2AnotesDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2AnotesDecompiler(Core()));
|
||||
}
|
||||
if (R2HermesDecompiler::isAvailable()) {
|
||||
Core()->registerDecompiler(new R2HermesDecompiler(Core()));
|
||||
}
|
||||
|
||||
#if IAITO_R2GHIDRA_STATIC
|
||||
Core()->registerDecompiler(new R2GhidraDecompiler(Core()));
|
||||
@@ -165,15 +288,16 @@ IaitoApplication::IaitoApplication(int &argc, char **argv) : QApplication(argc,
|
||||
mainWindow = new MainWindow();
|
||||
installEventFilter(mainWindow);
|
||||
|
||||
// set up context menu shortcut display fix
|
||||
#if QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
|
||||
setStyle(new IaitoProxyStyle());
|
||||
#endif // QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
|
||||
|
||||
if (clOptions.args.empty()) {
|
||||
RCore *kore = iaitoPluginCore();
|
||||
if (kore) {
|
||||
mainWindow->openCurrentCore(clOptions.fileOpenOptions, false);
|
||||
} else if (!clOptions.deepLinkUrl.isEmpty()) {
|
||||
DeepLink::handle(mainWindow, clOptions.deepLinkUrl);
|
||||
} else if (clOptions.args.empty()) {
|
||||
// check if this is the first execution of Iaito in this computer
|
||||
// Note: the execution after the preferences been reset, will be considered as first-execution
|
||||
if (Config()->isFirstExecution()) {
|
||||
// Note: the execution after the settings been reset, will be
|
||||
// considered as first-execution
|
||||
if (clOptions.showWelcomeDialog || Config()->isFirstExecution()) {
|
||||
mainWindow->displayWelcomeDialog();
|
||||
}
|
||||
mainWindow->displayNewFileDialog();
|
||||
@@ -198,22 +322,6 @@ IaitoApplication::IaitoApplication(int &argc, char **argv) : QApplication(argc,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
{
|
||||
auto r2prefix = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS
|
||||
r2prefix.cdUp(); // Contents
|
||||
r2prefix.cd("Resources/r2"); // Contents/Resources/r2
|
||||
|
||||
auto sleighHome = r2prefix;
|
||||
sleighHome.cd("share/radare2/plugins/r2ghidra_sleigh"); // Contents/Resources/r2/share/radare2/plugins/r2ghidra_sleigh
|
||||
Core()->setConfig("r2ghidra.sleighhome", sleighHome.absolutePath());
|
||||
|
||||
auto r2decHome = r2prefix;
|
||||
r2decHome.cd("share/radare2/plugins/r2dec-js"); // Contents/Resources/r2/share/radare2/plugins/r2dec-js
|
||||
qputenv("R2DEC_HOME", r2decHome.absolutePath().toLocal8Bit());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef IAITO_APPVEYOR_R2DEC
|
||||
qputenv("R2DEC_HOME", "lib\\plugins\\r2dec-js");
|
||||
#endif
|
||||
@@ -229,11 +337,11 @@ IaitoApplication::IaitoApplication(int &argc, char **argv) : QApplication(argc,
|
||||
|
||||
IaitoApplication::~IaitoApplication()
|
||||
{
|
||||
Plugins()->destroyPlugins();
|
||||
delete mainWindow;
|
||||
#ifdef IAITO_ENABLE_PYTHON
|
||||
Python()->shutdown();
|
||||
#endif
|
||||
if (mainWindow) {
|
||||
SamplesDB::waitForPending();
|
||||
Plugins()->destroyPlugins();
|
||||
delete mainWindow;
|
||||
}
|
||||
}
|
||||
|
||||
void IaitoApplication::launchNewInstance(const QStringList &args)
|
||||
@@ -254,15 +362,28 @@ void IaitoApplication::launchNewInstance(const QStringList &args)
|
||||
bool IaitoApplication::event(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::FileOpen) {
|
||||
RCore *kore = iaitoPluginCore();
|
||||
if (kore) {
|
||||
return false;
|
||||
}
|
||||
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(e);
|
||||
if (openEvent) {
|
||||
const QUrl url = openEvent->url();
|
||||
const bool isDeep = DeepLink::isDeepLink(url.toString());
|
||||
if (m_FileAlreadyDropped) {
|
||||
// We already dropped a file in macOS, let's spawn another instance
|
||||
// (Like the File -> Open)
|
||||
QString fileName = openEvent->file();
|
||||
launchNewInstance({fileName});
|
||||
// We already dropped a file in macOS, let's spawn another
|
||||
// instance (Like the File -> Open)
|
||||
launchNewInstance({isDeep ? url.toString() : openEvent->file()});
|
||||
} else if (isDeep) {
|
||||
m_FileAlreadyDropped = true;
|
||||
mainWindow->closeNewFileDialog();
|
||||
DeepLink::handle(mainWindow, url.toString());
|
||||
} else {
|
||||
QString fileName = openEvent->file();
|
||||
// eprintf ("FILE %s\n", fileName.toStdString().c_str());
|
||||
if (fileName == "") {
|
||||
return false;
|
||||
}
|
||||
m_FileAlreadyDropped = true;
|
||||
mainWindow->closeNewFileDialog();
|
||||
InitialOptions options;
|
||||
@@ -280,8 +401,8 @@ bool IaitoApplication::loadTranslations()
|
||||
if (language == QStringLiteral("en") || language.startsWith(QStringLiteral("en-"))) {
|
||||
return true;
|
||||
}
|
||||
const auto &allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
|
||||
QLocale::AnyCountry);
|
||||
const auto &allLocales
|
||||
= QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
|
||||
|
||||
bool iaitoTrLoaded = false;
|
||||
|
||||
@@ -296,10 +417,11 @@ bool IaitoApplication::loadTranslations()
|
||||
QTranslator *trQtBase = new QTranslator;
|
||||
QTranslator *trQt = new QTranslator;
|
||||
|
||||
const QStringList &cutterTrPaths = Iaito::getTranslationsDirectories();
|
||||
const QStringList &iaitoTrPaths = Iaito::getTranslationsDirectories();
|
||||
|
||||
for (const auto &trPath : cutterTrPaths) {
|
||||
if (trIaito && trIaito->load(it, QLatin1String("iaito"), QLatin1String("_"), trPath)) {
|
||||
for (const auto &trPath : iaitoTrPaths) {
|
||||
if (trIaito
|
||||
&& trIaito->load(it, QLatin1String("iaito"), QLatin1String("_"), trPath)) {
|
||||
installTranslator(trIaito);
|
||||
iaitoTrLoaded = true;
|
||||
trIaito = nullptr;
|
||||
@@ -344,71 +466,107 @@ bool IaitoApplication::parseCommandLineOptions()
|
||||
cmd_parser.addVersionOption();
|
||||
cmd_parser.addPositionalArgument("filename", QObject::tr("Filename to open."));
|
||||
|
||||
QCommandLineOption analOption({"A", "analysis"},
|
||||
QObject::tr("Automatically open file and optionally start analysis. "
|
||||
"Needs filename to be specified. May be a value between 0 and 3:"
|
||||
" 0 = no analysis, 1 = aa, 2 = aaa, 3 = aaaa (slow)"),
|
||||
QObject::tr("level"));
|
||||
QCommandLineOption environmentOption(
|
||||
"H", QObject::tr("List environment variables, or print the value of a selected variable."));
|
||||
cmd_parser.addOption(environmentOption);
|
||||
|
||||
QCommandLineOption analOption(
|
||||
{"A", "analysis"},
|
||||
QObject::tr(
|
||||
"Automatically open file and optionally start analysis. "
|
||||
"Needs filename to be specified. May be a value between 0 and 3:"
|
||||
" 0 = no analysis, 1 = aa, 2 = aaa, 3 = aaaa (slow)"),
|
||||
QObject::tr("level"));
|
||||
cmd_parser.addOption(analOption);
|
||||
|
||||
QCommandLineOption formatOption({"F", "format"},
|
||||
QObject::tr("Force using a specific file format (bin plugin)"),
|
||||
QObject::tr("name"));
|
||||
QCommandLineOption formatOption(
|
||||
{"F", "format"},
|
||||
QObject::tr("Force using a specific file format (bin plugin)"),
|
||||
QObject::tr("name"));
|
||||
cmd_parser.addOption(formatOption);
|
||||
|
||||
QCommandLineOption baddrOption({"B", "base"},
|
||||
QObject::tr("Load binary at a specific base address"),
|
||||
QObject::tr("base address"));
|
||||
QCommandLineOption baddrOption(
|
||||
{"B", "base"},
|
||||
QObject::tr("Load binary at a specific base address"),
|
||||
QObject::tr("base address"));
|
||||
cmd_parser.addOption(baddrOption);
|
||||
|
||||
QCommandLineOption scriptOption("i",
|
||||
QObject::tr("Run script file"),
|
||||
QObject::tr("file"));
|
||||
QCommandLineOption mapaddrOption(
|
||||
{"m", "map"}, QObject::tr("Map the file at a specific address"), QObject::tr("map address"));
|
||||
cmd_parser.addOption(mapaddrOption);
|
||||
|
||||
QCommandLineOption scriptOption("i", QObject::tr("Run script file"), QObject::tr("file"));
|
||||
cmd_parser.addOption(scriptOption);
|
||||
|
||||
QCommandLineOption writeModeOption({"w", "writemode"}, QObject::tr("Open file in write mode"));
|
||||
cmd_parser.addOption(writeModeOption);
|
||||
|
||||
QCommandLineOption binCacheOption({"c", "bincache"}, QObject::tr("Enable bin.cache to make relocs work"));
|
||||
QCommandLineOption
|
||||
binCacheOption({"c", "bincache"}, QObject::tr("Patch relocs (enable bin.cache)"));
|
||||
cmd_parser.addOption(binCacheOption);
|
||||
|
||||
|
||||
QCommandLineOption pythonHomeOption("pythonhome",
|
||||
QObject::tr("PYTHONHOME to use for embedded python interpreter"),
|
||||
"PYTHONHOME");
|
||||
cmd_parser.addOption(pythonHomeOption);
|
||||
|
||||
QCommandLineOption disableRedirectOption("no-output-redirect",
|
||||
QObject::tr("Disable output redirection."
|
||||
" Some of the output in console widget will not be visible."
|
||||
" Use this option when debuging a crash or freeze and output "
|
||||
" redirection is causing some messages to be lost."));
|
||||
QCommandLineOption disableRedirectOption(
|
||||
"no-output-redirect",
|
||||
QObject::tr(
|
||||
"Disable output redirection."
|
||||
" Some of the output in console widget will not be visible."
|
||||
" Use this option when debuging a crash or freeze and output "
|
||||
" redirection is causing some messages to be lost."));
|
||||
cmd_parser.addOption(disableRedirectOption);
|
||||
|
||||
QCommandLineOption disablePlugins("no-plugins",
|
||||
QObject::tr("Do not load plugins"));
|
||||
QCommandLineOption disablePlugins("no-plugins", QObject::tr("Do not load plugins"));
|
||||
cmd_parser.addOption(disablePlugins);
|
||||
|
||||
QCommandLineOption disableIaitoPlugins("no-iaito-plugins",
|
||||
QObject::tr("Do not load Iaito plugins"));
|
||||
QCommandLineOption
|
||||
disableIaitoPlugins("no-iaito-plugins", QObject::tr("Do not load Iaito plugins"));
|
||||
cmd_parser.addOption(disableIaitoPlugins);
|
||||
|
||||
QCommandLineOption disableR2Plugins("no-r2-plugins",
|
||||
QObject::tr("Do not load radare2 plugins"));
|
||||
QCommandLineOption disableR2Plugins("no-r2-plugins", QObject::tr("Do not load radare2 plugins"));
|
||||
cmd_parser.addOption(disableR2Plugins);
|
||||
|
||||
cmd_parser.process(*this);
|
||||
QCommandLineOption welcomeOption("welcome", QObject::tr("Show welcome dialog."));
|
||||
cmd_parser.addOption(welcomeOption);
|
||||
|
||||
#ifdef IAITO_ENABLE_DEBUGGER
|
||||
QCommandLineOption debugOption(
|
||||
{"d", "debug"},
|
||||
QObject::tr(
|
||||
"Open the positional argument in debug mode. The argument may be a"
|
||||
" path to an executable to run or a numeric PID to attach to."));
|
||||
cmd_parser.addOption(debugOption);
|
||||
#endif
|
||||
|
||||
// process() exits without destroying QApplication for --version.
|
||||
const bool parsed = cmd_parser.parse(arguments());
|
||||
if (parsed && cmd_parser.isSet("version")) {
|
||||
printf("%s %s\n", qPrintable(applicationName()), qPrintable(applicationVersion()));
|
||||
exitCode = 0;
|
||||
return false;
|
||||
}
|
||||
if (!parsed || cmd_parser.isSet("help") || cmd_parser.isSet("help-all")) {
|
||||
cmd_parser.process(*this);
|
||||
}
|
||||
|
||||
IaitoCommandLineOptions opts;
|
||||
opts.args = cmd_parser.positionalArguments();
|
||||
|
||||
// An iaito:// deep link is passed as the positional argument by the OS URI
|
||||
// handler. Pull it out so it is not treated as a regular filename.
|
||||
if (!opts.args.isEmpty() && DeepLink::isDeepLink(opts.args.first())) {
|
||||
opts.deepLinkUrl = opts.args.takeFirst();
|
||||
}
|
||||
|
||||
if (cmd_parser.isSet(analOption)) {
|
||||
bool analLevelSpecified = false;
|
||||
int analLevel = cmd_parser.value(analOption).toInt(&analLevelSpecified);
|
||||
|
||||
if (!analLevelSpecified || analLevel < 0 || analLevel > 2) {
|
||||
fprintf(stderr, "%s\n",
|
||||
QObject::tr("Invalid Analysis Level. May be a value between 0 and 2.").toLocal8Bit().constData());
|
||||
if (!analLevelSpecified || analLevel < 0 || analLevel > 3) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"%s\n",
|
||||
QObject::tr("Invalid Analysis Level. May be a value between 0 and 3.")
|
||||
.toLocal8Bit()
|
||||
.constData());
|
||||
return false;
|
||||
}
|
||||
switch (analLevel) {
|
||||
@@ -421,16 +579,22 @@ bool IaitoApplication::parseCommandLineOptions()
|
||||
case 2:
|
||||
opts.analLevel = AutomaticAnalysisLevel::AAAA;
|
||||
break;
|
||||
case 3:
|
||||
opts.analLevel = AutomaticAnalysisLevel::AAAAA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.args.empty() && opts.analLevel != AutomaticAnalysisLevel::Ask) {
|
||||
fprintf(stderr, "%s\n",
|
||||
QObject::tr("Filename must be specified to start analysis automatically.").toLocal8Bit().constData());
|
||||
fprintf(
|
||||
stderr,
|
||||
"%s\n",
|
||||
QObject::tr("Filename must be specified to start analysis automatically.")
|
||||
.toLocal8Bit()
|
||||
.constData());
|
||||
return false;
|
||||
}
|
||||
|
||||
InitialOptions options;
|
||||
if (!opts.args.isEmpty()) {
|
||||
opts.fileOpenOptions.filename = opts.args[0];
|
||||
opts.fileOpenOptions.forceBinPlugin = cmd_parser.value(formatOption);
|
||||
@@ -438,7 +602,14 @@ bool IaitoApplication::parseCommandLineOptions()
|
||||
bool ok;
|
||||
RVA baddr = cmd_parser.value(baddrOption).toULongLong(&ok, 0);
|
||||
if (ok) {
|
||||
options.binLoadAddr = baddr;
|
||||
opts.fileOpenOptions.binLoadAddr = baddr;
|
||||
}
|
||||
}
|
||||
if (cmd_parser.isSet(mapaddrOption)) {
|
||||
bool ok;
|
||||
RVA mapaddr = cmd_parser.value(mapaddrOption).toULongLong(&ok, 0);
|
||||
if (ok) {
|
||||
opts.fileOpenOptions.mapAddr = mapaddr;
|
||||
}
|
||||
}
|
||||
switch (opts.analLevel) {
|
||||
@@ -448,19 +619,33 @@ bool IaitoApplication::parseCommandLineOptions()
|
||||
opts.fileOpenOptions.analCmd = {};
|
||||
break;
|
||||
case AutomaticAnalysisLevel::AAA:
|
||||
opts.fileOpenOptions.analCmd = { {"aaa", "Auto analysis"} };
|
||||
opts.fileOpenOptions.analCmd = {{"aaa", "Auto analysis"}};
|
||||
break;
|
||||
case AutomaticAnalysisLevel::AAAA:
|
||||
opts.fileOpenOptions.analCmd = { {"aaaa", "Auto analysis (experimental)"} };
|
||||
opts.fileOpenOptions.analCmd = {{"aaaa", "Advanced analysis"}};
|
||||
break;
|
||||
case AutomaticAnalysisLevel::AAAAA:
|
||||
opts.fileOpenOptions.analCmd = {{"aaaaa", "Auto analysis (experimental)"}};
|
||||
break;
|
||||
}
|
||||
opts.fileOpenOptions.script = cmd_parser.value(scriptOption);
|
||||
|
||||
opts.fileOpenOptions.writeEnabled = cmd_parser.isSet(writeModeOption);
|
||||
}
|
||||
|
||||
if (cmd_parser.isSet(pythonHomeOption)) {
|
||||
opts.pythonHome = cmd_parser.value(pythonHomeOption);
|
||||
#ifdef IAITO_ENABLE_DEBUGGER
|
||||
if (cmd_parser.isSet(debugOption)) {
|
||||
// -d: open the target as a debug session. If the positional
|
||||
// argument is numeric, treat it as a PID to attach to; otherwise
|
||||
// treat it as a path to an executable to run under the debugger.
|
||||
const QString &target = opts.args[0];
|
||||
bool isPid = false;
|
||||
target.toLongLong(&isPid);
|
||||
if (isPid) {
|
||||
opts.fileOpenOptions.filename = QStringLiteral("dbg://%1").arg(target);
|
||||
}
|
||||
opts.fileOpenOptions.debug = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
opts.outputRedirectionEnabled = !cmd_parser.isSet(disableRedirectOption);
|
||||
@@ -477,23 +662,24 @@ bool IaitoApplication::parseCommandLineOptions()
|
||||
opts.enableR2Plugins = false;
|
||||
}
|
||||
|
||||
if (cmd_parser.isSet(welcomeOption)) {
|
||||
opts.showWelcomeDialog = true;
|
||||
}
|
||||
|
||||
this->clOptions = opts;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void IaitoProxyStyle::polish(QWidget *widget)
|
||||
bool IaitoApplication::notify(QObject *receiver, QEvent *event)
|
||||
{
|
||||
QProxyStyle::polish(widget);
|
||||
#if QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
|
||||
// HACK: This is the only way I've found to force Qt (5.10 and newer) to
|
||||
// display shortcuts in context menus on all platforms. It's ugly,
|
||||
// but it gets the job done.
|
||||
if (auto menu = qobject_cast<QMenu *>(widget)) {
|
||||
const auto &actions = menu->actions();
|
||||
for (auto action : actions) {
|
||||
action->setShortcutVisibleInContextMenu(true);
|
||||
if (event->type() == QEvent::Polish) {
|
||||
if (auto menu = qobject_cast<QMenu *>(receiver)) {
|
||||
for (auto action : menu->actions()) {
|
||||
action->setShortcutVisibleInContextMenu(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
|
||||
#endif
|
||||
return QApplication::notify(receiver, event);
|
||||
}
|
||||
@@ -1,25 +1,24 @@
|
||||
#ifndef IAITOAPPLICATION_H
|
||||
#define IAITOAPPLICATION_H
|
||||
|
||||
#include <QEvent>
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QList>
|
||||
#include <QProxyStyle>
|
||||
|
||||
#include "core/MainWindow.h"
|
||||
|
||||
enum class AutomaticAnalysisLevel {
|
||||
Ask, None, AAA, AAAA
|
||||
};
|
||||
enum class AutomaticAnalysisLevel { Ask, None, AAA, AAAA, AAAAA };
|
||||
|
||||
struct IaitoCommandLineOptions {
|
||||
struct IaitoCommandLineOptions
|
||||
{
|
||||
QStringList args;
|
||||
AutomaticAnalysisLevel analLevel = AutomaticAnalysisLevel::Ask;
|
||||
InitialOptions fileOpenOptions;
|
||||
QString pythonHome;
|
||||
bool outputRedirectionEnabled = true;
|
||||
bool enableIaitoPlugins = true;
|
||||
bool enableR2Plugins = true;
|
||||
bool showWelcomeDialog = false;
|
||||
QString deepLinkUrl;
|
||||
};
|
||||
|
||||
class IaitoApplication : public QApplication
|
||||
@@ -30,14 +29,14 @@ public:
|
||||
IaitoApplication(int &argc, char **argv);
|
||||
~IaitoApplication();
|
||||
|
||||
MainWindow *getMainWindow()
|
||||
{
|
||||
return mainWindow;
|
||||
}
|
||||
MainWindow *getMainWindow() { return mainWindow; }
|
||||
int getExitCode() const { return exitCode; }
|
||||
|
||||
void launchNewInstance(const QStringList &args = {});
|
||||
|
||||
protected:
|
||||
bool event(QEvent *e);
|
||||
bool event(QEvent *e) override;
|
||||
bool notify(QObject *receiver, QEvent *event) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
@@ -50,24 +49,12 @@ private:
|
||||
* @return false if options have error
|
||||
*/
|
||||
bool parseCommandLineOptions();
|
||||
|
||||
private:
|
||||
bool m_FileAlreadyDropped;
|
||||
MainWindow *mainWindow;
|
||||
MainWindow *mainWindow = nullptr;
|
||||
int exitCode = 1;
|
||||
IaitoCommandLineOptions clOptions;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief IaitoProxyStyle is used to force shortcuts displaying in context menu
|
||||
*/
|
||||
class IaitoProxyStyle : public QProxyStyle
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief it is enough to get notification about QMenu polishing to force shortcut displaying
|
||||
*/
|
||||
void polish(QWidget *widget) override;
|
||||
};
|
||||
|
||||
#endif // IAITOAPPLICATION_H
|
||||
@@ -1,15 +1,78 @@
|
||||
|
||||
#include "IaitoApplication.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "common/UpdateWorker.h"
|
||||
#include "IaitoConfig.h"
|
||||
#include "common/CrashHandler.h"
|
||||
#include "common/SettingsUpgrade.h"
|
||||
#include "core/MainWindow.h"
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <iostream>
|
||||
#include <QDir>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static void connectToConsole();
|
||||
#endif
|
||||
|
||||
static bool printEnvironmentVariables(int argc, char *argv[])
|
||||
{
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!std::strcmp(argv[i], "--")) {
|
||||
return false;
|
||||
}
|
||||
if (std::strncmp(argv[i], "-H", 2)) {
|
||||
continue;
|
||||
}
|
||||
const char *selectedVariable = nullptr;
|
||||
if (argv[i][2]) {
|
||||
selectedVariable = argv[i] + 2;
|
||||
} else if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
selectedVariable = argv[i + 1];
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
connectToConsole();
|
||||
#endif
|
||||
QByteArray extraPluginDirs = IAITO_EXTRA_PLUGIN_DIRS;
|
||||
const QByteArray environmentPluginDirs = qgetenv("IAITO_EXTRA_PLUGIN_DIRS");
|
||||
if (!environmentPluginDirs.isEmpty()) {
|
||||
if (!extraPluginDirs.isEmpty()) {
|
||||
extraPluginDirs.append(QDir::listSeparator().toLatin1());
|
||||
}
|
||||
extraPluginDirs.append(environmentPluginDirs);
|
||||
}
|
||||
struct EnvironmentVariable
|
||||
{
|
||||
const char *name;
|
||||
QByteArray value;
|
||||
};
|
||||
const EnvironmentVariable variables[] = {
|
||||
{"IAITO_VERSION", IAITO_VERSION_FULL},
|
||||
{"IAITO_VERSION_MAJOR", QByteArray::number(IAITO_VERSION_MAJOR)},
|
||||
{"IAITO_VERSION_MINOR", QByteArray::number(IAITO_VERSION_MINOR)},
|
||||
{"IAITO_VERSION_PATCH", QByteArray::number(IAITO_VERSION_PATCH)},
|
||||
{"IAITO_EXTRA_PLUGIN_DIRS", extraPluginDirs},
|
||||
{"R2_DEBUG", qgetenv("R2_DEBUG")},
|
||||
{"R2_NOPLUGINS", qgetenv("R2_NOPLUGINS")},
|
||||
};
|
||||
for (const auto &variable : variables) {
|
||||
const char *shortName = std::strchr(variable.name, '_');
|
||||
shortName = shortName ? shortName + 1 : variable.name;
|
||||
if (selectedVariable && std::strcmp(selectedVariable, variable.name)
|
||||
&& std::strcmp(selectedVariable, shortName)) {
|
||||
continue;
|
||||
}
|
||||
if (selectedVariable) {
|
||||
std::fprintf(stdout, "%s\n", variable.value.constData());
|
||||
} else {
|
||||
std::fprintf(stdout, "%s=%s\n", variable.name, variable.value.constData());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Attempt to connect to a parent console and configure outputs.
|
||||
@@ -23,8 +86,9 @@ static void connectToConsole()
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid reconfiguring stderr/stdout if one of them is already connected to a stream.
|
||||
// This can happen when running with stdout/stderr redirected to a file.
|
||||
// Avoid reconfiguring stderr/stdout if one of them is already connected to
|
||||
// a stream. This can happen when running with stdout/stderr redirected to a
|
||||
// file.
|
||||
if (0 > fileno(stdout)) {
|
||||
// Overwrite FD 1 and 2 for the benefit of any code that uses the FDs
|
||||
// directly. This is safe because the CRT allocates FDs 0, 1 and
|
||||
@@ -34,7 +98,8 @@ static void connectToConsole()
|
||||
_close(1);
|
||||
|
||||
if (freopen("CONOUT$", "a+", stdout)) {
|
||||
// Avoid buffering stdout/stderr since IOLBF is replaced by IOFBF in Win32.
|
||||
// Avoid buffering stdout/stderr since IOLBF is replaced by IOFBF in
|
||||
// Win32.
|
||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
}
|
||||
}
|
||||
@@ -51,9 +116,12 @@ static void connectToConsole()
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (printEnvironmentVariables(argc, argv)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (argc >= 3 && QString::fromLocal8Bit(argv[1]) == "--start-crash-handler") {
|
||||
QApplication app(argc, argv);
|
||||
QString dumpLocation = QString::fromLocal8Bit(argv[2]);
|
||||
@@ -71,37 +139,30 @@ int main(int argc, char *argv[])
|
||||
qRegisterMetaType<QList<FunctionDescription>>();
|
||||
|
||||
QCoreApplication::setOrganizationName("radareorg");
|
||||
QCoreApplication::setOrganizationDomain("radare.org");
|
||||
QCoreApplication::setApplicationName("iaito");
|
||||
QGuiApplication::setDesktopFileName("org.radare.iaito");
|
||||
|
||||
Iaito::initializeSettings();
|
||||
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); // needed for QtWebEngine inside Plugins
|
||||
QCoreApplication::setAttribute(
|
||||
Qt::AA_ShareOpenGLContexts); // needed for QtWebEngine inside Plugins
|
||||
#ifdef Q_OS_WIN
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(
|
||||
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
IaitoApplication a(argc, argv);
|
||||
|
||||
Iaito::migrateThemes();
|
||||
|
||||
if (Config()->getAutoUpdateEnabled()) {
|
||||
#if IAITO_UPDATE_WORKER_AVAILABLE
|
||||
UpdateWorker *updateWorker = new UpdateWorker;
|
||||
QObject::connect(updateWorker, &UpdateWorker::checkComplete,
|
||||
[=](const QVersionNumber &version, const QString & error) {
|
||||
if (error.isEmpty() && version > UpdateWorker::currentVersionNumber()) {
|
||||
updateWorker->showUpdateDialog(true);
|
||||
}
|
||||
updateWorker->deleteLater();
|
||||
});
|
||||
updateWorker->checkCurrentVersion(7000);
|
||||
#endif
|
||||
if (!a.getMainWindow()) {
|
||||
return a.getExitCode();
|
||||
}
|
||||
|
||||
int ret = a.exec();
|
||||
return a.exec();
|
||||
}
|
||||
|
||||
return ret;
|
||||
int main_iaito()
|
||||
{
|
||||
char *argv[] = {(char *) "iaito"};
|
||||
return main(1, argv);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
all: ../build
|
||||
$(MAKE) -C ../build
|
||||
|
||||
../build:
|
||||
$(MAKE) -C ..
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef CUSTOM_ASSERT_H
|
||||
#define CUSTOM_ASSERT_H 1
|
||||
|
||||
#define assert(x) \
|
||||
if ((x)) { \
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
# 😠 https://github.com/mesonbuild/meson/issues/2320
|
||||
|
||||
bindings_src_files = run_command([py3_exe,
|
||||
join_paths(meson.current_source_dir(), '../src_list.py'),
|
||||
'meson']).stdout().split(';')
|
||||
|
||||
bindings_target = custom_target('bindings',
|
||||
input: bindings_txt,
|
||||
depend_files: [bindings_h, bindings_xml],
|
||||
output: bindings_src_files,
|
||||
command: [shiboken_exe, '--project-file=@INPUT@'])
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
#ifndef IAITO_BINDINGS_H
|
||||
#define IAITO_BINDINGS_H
|
||||
|
||||
// #define QT_ANNOTATE_ACCESS_SPECIFIER(a) __attribute__((annotate(#a)))
|
||||
|
||||
#include "../core/Iaito.h"
|
||||
#include "../common/Configuration.h"
|
||||
#include "../core/MainWindow.h"
|
||||
#include "../widgets/IaitoDockWidget.h"
|
||||
#include "../plugins/IaitoPlugin.h"
|
||||
#include "../menus/AddressableItemContextMenu.h"
|
||||
|
||||
#endif //IAITO_BINDINGS_H
|
||||
@@ -1,17 +0,0 @@
|
||||
[generator-project]
|
||||
|
||||
generator-set = shiboken
|
||||
|
||||
header-file = $${BINDINGS_SRC_DIR}/bindings.h
|
||||
typesystem-file = $${BINDINGS_SRC_DIR}/bindings.xml
|
||||
|
||||
output-directory = $${BINDINGS_BUILD_DIR}
|
||||
|
||||
include-path = $${BINDINGS_INCLUDE_DIRS}
|
||||
|
||||
typesystem-paths = $${PYSIDE_TYPESYSTEMS}
|
||||
|
||||
enable-parent-ctor-heuristic
|
||||
enable-pyside-extensions
|
||||
enable-return-value-heuristic
|
||||
use-isnull-as-nb_nonzero
|
||||
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<typesystem package="IaitoBindings">
|
||||
<load-typesystem name="typesystem_core.xml" generate="no" />
|
||||
<load-typesystem name="typesystem_gui.xml" generate="no" />
|
||||
<load-typesystem name="typesystem_widgets.xml" generate="no" />
|
||||
|
||||
<primitive-type name="bool"/>
|
||||
|
||||
<object-type name="IaitoCore">
|
||||
</object-type>
|
||||
<object-type name="Configuration" />
|
||||
<object-type name="MainWindow" >
|
||||
<enum-type name="MenuType" />
|
||||
<enum-type name="ContextMenuType" />
|
||||
</object-type>
|
||||
<object-type name="BasicBlockHighlighter" />
|
||||
<object-type name="AddressableItemContextMenu" />
|
||||
<object-type name="IaitoDockWidget" />
|
||||
|
||||
<template name="plugin_meta_get">
|
||||
SbkObject *wrapper = Shiboken::BindingManager::instance().retrieveWrapper(this);
|
||||
PyObject *classObject = PyObject_GetAttrString(reinterpret_cast<PyObject *>(wrapper), "__class__");
|
||||
if (!classObject) {
|
||||
PyErr_Print();
|
||||
return QString();
|
||||
}
|
||||
PyObject *pyResult = PyObject_GetAttrString(classObject, "VAR_NAME");
|
||||
if (!pyResult) {
|
||||
PyErr_Print();
|
||||
return QString();
|
||||
}
|
||||
PythonToCppFunc pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(SbkPySide2_QtCoreTypeConverters[SBK_QSTRING_IDX], pyResult);
|
||||
if (!pythonToCpp) {
|
||||
Shiboken::warning(PyExc_RuntimeWarning, 2, "Invalid return value for plugin metadata VAR_NAME, expected %s, got %s.", "QString", Py_TYPE(pyResult)->tp_name);
|
||||
return ::QString();
|
||||
}
|
||||
QString cppResult;
|
||||
pythonToCpp(pyResult, &cppResult);
|
||||
return cppResult;
|
||||
</template>
|
||||
<object-type name="IaitoPlugin">
|
||||
<modify-function signature="getName()const">
|
||||
<inject-code class="shell" position="beginning">
|
||||
<insert-template name="plugin_meta_get">
|
||||
<replace from="VAR_NAME" to="name" />
|
||||
</insert-template>
|
||||
</inject-code>
|
||||
</modify-function>
|
||||
<modify-function signature="getAuthor()const">
|
||||
<inject-code class="shell" position="beginning">
|
||||
<insert-template name="plugin_meta_get">
|
||||
<replace from="VAR_NAME" to="author" />
|
||||
</insert-template>
|
||||
</inject-code>
|
||||
</modify-function>
|
||||
<modify-function signature="getDescription()const">
|
||||
<inject-code class="shell" position="beginning">
|
||||
<insert-template name="plugin_meta_get">
|
||||
<replace from="VAR_NAME" to="description" />
|
||||
</insert-template>
|
||||
</inject-code>
|
||||
</modify-function>
|
||||
<modify-function signature="getVersion()const">
|
||||
<inject-code class="shell" position="beginning">
|
||||
<insert-template name="plugin_meta_get">
|
||||
<replace from="VAR_NAME" to="version" />
|
||||
</insert-template>
|
||||
</inject-code>
|
||||
</modify-function>
|
||||
</object-type>
|
||||
</typesystem>
|
||||
@@ -1,20 +0,0 @@
|
||||
|
||||
bindings_xml = configure_file(input: 'bindings.xml',
|
||||
output: 'bindings.xml',
|
||||
copy: true)
|
||||
|
||||
conf_json = '''{"BINDINGS_SRC_DIR":"@0@",
|
||||
"BINDINGS_BUILD_DIR":"@1@",
|
||||
"BINDINGS_INCLUDE_DIRS":"@2@",
|
||||
"PYSIDE_TYPESYSTEMS":"@3@"}'''.format(
|
||||
meson.current_source_dir(),
|
||||
meson.current_build_dir(),
|
||||
':'.join(bindings_generate_inc),
|
||||
pyside_dep.get_pkgconfig_variable('typesystemdir'))
|
||||
bindings_txt = configure_file(input: 'bindings.txt.in',
|
||||
output: 'bindings.txt',
|
||||
command: configure_qmake_cmd + ['@INPUT@', '@OUTPUT0@', conf_json])
|
||||
|
||||
bindings_h = files('bindings.h')
|
||||
|
||||
subdir('IaitoBindings')
|
||||
@@ -1,52 +0,0 @@
|
||||
#!/bin/env python3
|
||||
|
||||
import os
|
||||
import xml.etree.ElementTree as et
|
||||
import sys
|
||||
|
||||
|
||||
script_path = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def get_cpp_files_gen(args, include_package=True):
|
||||
ts_tree = et.parse(os.path.join(script_path, "bindings.xml"))
|
||||
ts_root = ts_tree.getroot()
|
||||
|
||||
package = ts_root.attrib["package"]
|
||||
|
||||
type_tags = ["object-type", "value-type"]
|
||||
types = [child.attrib["name"] for child in ts_root if child.tag in type_tags]
|
||||
|
||||
cpp_files_gen = [f"{package.lower()}_module_wrapper.cpp"]
|
||||
cpp_files_gen.extend([f"{typename.lower()}_wrapper.cpp" for typename in types])
|
||||
|
||||
if include_package:
|
||||
cpp_files_gen = [os.path.join(package, f) for f in cpp_files_gen]
|
||||
|
||||
if len(args) > 0:
|
||||
cpp_files_gen = [os.path.join(args[0], f) for f in cpp_files_gen]
|
||||
|
||||
return cpp_files_gen
|
||||
|
||||
|
||||
def cmd_cmake(args):
|
||||
files = get_cpp_files_gen(args)
|
||||
if sys.platform == "win32":
|
||||
files = map(lambda x: x.replace("\\", "/"), files)
|
||||
sys.stdout.write(";".join(files))
|
||||
|
||||
|
||||
def cmd_qmake(args):
|
||||
sys.stdout.write("\n".join(get_cpp_files_gen(args)) + "\n")
|
||||
|
||||
|
||||
def cmd_meson(args):
|
||||
sys.stdout.write(";".join(get_cpp_files_gen(args, include_package=False)))
|
||||
|
||||
|
||||
cmds = {"cmake": cmd_cmake, "qmake": cmd_qmake, "meson": cmd_meson}
|
||||
|
||||
if len(sys.argv) < 2 or sys.argv[1] not in cmds:
|
||||
print(f"""usage: {sys.argv[0]} [{"/".join(cmds.keys())}] [base path]""")
|
||||
exit(1)
|
||||
cmds[sys.argv[1]](sys.argv[2:])
|
||||
@@ -1,33 +1,79 @@
|
||||
#include <stdexcept>
|
||||
#include "AddressableItemModel.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
AddressableFilterProxyModel::AddressableFilterProxyModel(AddressableItemModelI *sourceModel,
|
||||
QObject *parent) :
|
||||
AddressableItemModel<QSortFilterProxyModel>(parent)
|
||||
AddressableItemModelI::~AddressableItemModelI()
|
||||
{ /* nothing to see */
|
||||
}
|
||||
|
||||
AddressableFilterProxyModel::AddressableFilterProxyModel(
|
||||
AddressableItemModelI *sourceModel, QObject *parent)
|
||||
: AddressableItemModel<QSortFilterProxyModel>(parent)
|
||||
{
|
||||
setSourceModel(sourceModel);
|
||||
addressableSourceModel = sourceModel;
|
||||
}
|
||||
|
||||
RVA AddressableFilterProxyModel::address(const QModelIndex &index) const
|
||||
{
|
||||
return addressableSourceModel->address(this->mapToSource(index));
|
||||
const auto source = mapToSource(index);
|
||||
return addressableSourceModel && source.isValid() ? addressableSourceModel->address(source)
|
||||
: RVA_INVALID;
|
||||
}
|
||||
|
||||
QString AddressableFilterProxyModel::name(const QModelIndex &index) const
|
||||
{
|
||||
return addressableSourceModel->name(this->mapToSource(index));
|
||||
const auto source = mapToSource(index);
|
||||
return addressableSourceModel && source.isValid() ? addressableSourceModel->name(source)
|
||||
: QString();
|
||||
}
|
||||
|
||||
void AddressableFilterProxyModel::setSourceModel(QAbstractItemModel *)
|
||||
{
|
||||
throw new std::runtime_error("Not supported");
|
||||
throw std::runtime_error("Not supported");
|
||||
}
|
||||
|
||||
void AddressableFilterProxyModel::setSourceModel(AddressableItemModelI *sourceModel)
|
||||
{
|
||||
ParentClass::setSourceModel(sourceModel->asItemModel());
|
||||
addressableSourceModel = sourceModel;
|
||||
ParentClass::setSourceModel(sourceModel ? sourceModel->asItemModel() : nullptr);
|
||||
}
|
||||
|
||||
void AddressableFilterProxyModel::setTypeFilterColumn(int column)
|
||||
{
|
||||
if (typeColumn != column) {
|
||||
emit filterAboutToChange();
|
||||
typeColumn = column;
|
||||
invalidateFilter();
|
||||
emit filterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AddressableFilterProxyModel::setTypeFilter(const QVariant &type)
|
||||
{
|
||||
if (selectedType != type) {
|
||||
emit filterAboutToChange();
|
||||
selectedType = type;
|
||||
invalidateFilter();
|
||||
emit filterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AddressableFilterProxyModel::setFilterWildcard(const QString &pattern)
|
||||
{
|
||||
emit filterAboutToChange();
|
||||
ParentClass::setFilterWildcard(pattern);
|
||||
emit filterChanged();
|
||||
}
|
||||
|
||||
bool AddressableFilterProxyModel::filterAcceptsType(int row, const QModelIndex &parent) const
|
||||
{
|
||||
return typeColumn < 0 || !selectedType.isValid()
|
||||
|| sourceModel()->index(row, typeColumn, parent).data().toString()
|
||||
== selectedType.toString();
|
||||
}
|
||||
|
||||
bool AddressableFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const
|
||||
{
|
||||
return filterAcceptsType(row, parent) && ParentClass::filterAcceptsRow(row, parent);
|
||||
}
|
||||
@@ -4,46 +4,75 @@
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "core/IaitoCommon.h"
|
||||
|
||||
class IAITO_EXPORT AddressableItemModelI
|
||||
{
|
||||
public:
|
||||
virtual ~AddressableItemModelI() = 0;
|
||||
virtual RVA address(const QModelIndex &index) const = 0;
|
||||
/**
|
||||
* @brief Get name for item, optional.
|
||||
* @param index item intex
|
||||
* @return Item name or empty QString if item doesn't have short descriptive name.
|
||||
* @return Item name or empty QString if item doesn't have short descriptive
|
||||
* name.
|
||||
*/
|
||||
virtual QString name(const QModelIndex &index) const { Q_UNUSED(index) return QString(); }
|
||||
virtual QString name(const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
return QString();
|
||||
}
|
||||
virtual QAbstractItemModel *asItemModel() = 0;
|
||||
};
|
||||
|
||||
template <class ParentModel = QAbstractItemModel>
|
||||
class IAITO_EXPORT AddressableItemModel : public ParentModel, public AddressableItemModelI
|
||||
template<class ParentModel = QAbstractItemModel>
|
||||
class IAITO_EXPORT AddressableItemModel : public ParentModel, public AddressableItemModelI
|
||||
{
|
||||
static_assert (std::is_base_of<QAbstractItemModel, ParentModel>::value,
|
||||
"ParentModel needs to inherit from QAbstractItemModel");
|
||||
static_assert(
|
||||
std::is_base_of<QAbstractItemModel, ParentModel>::value,
|
||||
"ParentModel needs to inherit from QAbstractItemModel");
|
||||
|
||||
public:
|
||||
explicit AddressableItemModel(QObject *parent = nullptr) : ParentModel(parent) {}
|
||||
explicit AddressableItemModel(QObject *parent = nullptr)
|
||||
: ParentModel(parent)
|
||||
{}
|
||||
virtual ~AddressableItemModel() {}
|
||||
QAbstractItemModel *asItemModel() { return this; }
|
||||
};
|
||||
|
||||
class IAITO_EXPORT AddressableFilterProxyModel : public AddressableItemModel<QSortFilterProxyModel>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
using ParentClass = AddressableItemModel<QSortFilterProxyModel>;
|
||||
|
||||
public:
|
||||
AddressableFilterProxyModel(AddressableItemModelI *sourceModel, QObject *parent);
|
||||
|
||||
RVA address(const QModelIndex &index) const override;
|
||||
QString name(const QModelIndex &) const override;
|
||||
void setSourceModel(AddressableItemModelI *sourceModel);
|
||||
void setTypeFilterColumn(int column);
|
||||
void setTypeFilter(const QVariant &type);
|
||||
QVariant typeFilter() const { return selectedType; }
|
||||
|
||||
public slots:
|
||||
void setFilterWildcard(const QString &pattern);
|
||||
|
||||
signals:
|
||||
void filterAboutToChange();
|
||||
void filterChanged();
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int row, const QModelIndex &parent) const override;
|
||||
bool filterAcceptsType(int row, const QModelIndex &parent) const;
|
||||
|
||||
private:
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override; // Don't use this directly
|
||||
AddressableItemModelI *addressableSourceModel;
|
||||
AddressableItemModelI *addressableSourceModel = nullptr;
|
||||
int typeColumn = -1;
|
||||
QVariant selectedType;
|
||||
};
|
||||
|
||||
#endif // ADDRESSABLEITEMMODEL_H
|
||||
@@ -1,27 +1,25 @@
|
||||
#include "core/Iaito.h"
|
||||
#include "common/AnalTask.h"
|
||||
#include "core/Iaito.h"
|
||||
#include "core/MainWindow.h"
|
||||
#include "dialogs/InitialOptionsDialog.h"
|
||||
#include <QJsonArray>
|
||||
#include <QDebug>
|
||||
#include <QCheckBox>
|
||||
#include <QDebug>
|
||||
#include <QJsonArray>
|
||||
|
||||
AnalTask::AnalTask() :
|
||||
AsyncTask()
|
||||
{
|
||||
}
|
||||
AnalTask::AnalTask()
|
||||
: AsyncTask()
|
||||
{}
|
||||
|
||||
AnalTask::~AnalTask()
|
||||
{
|
||||
}
|
||||
AnalTask::~AnalTask() {}
|
||||
|
||||
void AnalTask::interrupt()
|
||||
{
|
||||
AsyncTask::interrupt();
|
||||
r_cons_singleton()->context->breaked = true;
|
||||
Core()->setConsBreaked();
|
||||
}
|
||||
|
||||
QString AnalTask::getTitle() {
|
||||
QString AnalTask::getTitle()
|
||||
{
|
||||
// If no file is loaded we consider it's Initial Analysis
|
||||
QJsonArray openedFiles = Core()->getOpenedFiles();
|
||||
if (!openedFiles.size()) {
|
||||
@@ -35,7 +33,7 @@ void AnalTask::runTask()
|
||||
int perms = R_PERM_RX;
|
||||
if (options.writeEnabled) {
|
||||
perms |= R_PERM_W;
|
||||
emit Core()->ioModeChanged();
|
||||
emit Core() -> ioModeChanged();
|
||||
}
|
||||
|
||||
// Demangle (must be before file Core()->loadFile)
|
||||
@@ -46,15 +44,17 @@ void AnalTask::runTask()
|
||||
if (!openedFiles.size() && options.filename.length()) {
|
||||
log(tr("Loading the file..."));
|
||||
openFailed = false;
|
||||
bool fileLoaded = Core()->loadFile(options.filename,
|
||||
options.binLoadAddr,
|
||||
options.mapAddr,
|
||||
perms,
|
||||
options.useVA,
|
||||
options.loadBinCache,
|
||||
options.loadBinInfo,
|
||||
options.forceBinPlugin);
|
||||
bool fileLoaded = Core()->loadFile(
|
||||
options.filename,
|
||||
options.binLoadAddr,
|
||||
options.mapAddr,
|
||||
perms,
|
||||
options.useVA,
|
||||
options.loadBinCache,
|
||||
options.loadBinInfo,
|
||||
options.forceBinPlugin);
|
||||
if (!fileLoaded) {
|
||||
log(tr("Cannot open file for some reason"));
|
||||
// Something wrong happened, fallback to open dialog
|
||||
openFailed = true;
|
||||
emit openFileFailed();
|
||||
@@ -63,7 +63,8 @@ void AnalTask::runTask()
|
||||
}
|
||||
}
|
||||
|
||||
// r_core_bin_load might change asm.bits, so let's set that after the bin is loaded
|
||||
// r_core_bin_load might change asm.bits, so let's set that after the bin is
|
||||
// loaded
|
||||
Core()->setCPU(options.arch, options.cpu, options.bits);
|
||||
|
||||
if (isInterrupted()) {
|
||||
@@ -85,7 +86,8 @@ void AnalTask::runTask()
|
||||
|
||||
if (!options.shellcode.isNull() && options.shellcode.size() / 2 > 0) {
|
||||
log(tr("Loading shellcode..."));
|
||||
Core()->cmdRaw("wx " + options.shellcode);
|
||||
Core()->cmd("wx " + options.shellcode + " @e:io.va=0@0");
|
||||
// Core()->cmdRaw("wx " + options.shellcode);
|
||||
}
|
||||
|
||||
if (options.endian != InitialOptions::Endianness::Auto) {
|
||||
@@ -109,7 +111,6 @@ void AnalTask::runTask()
|
||||
if (isInterrupted()) {
|
||||
return;
|
||||
}
|
||||
// log(cmd.description);
|
||||
log(cmd.command + " : " + cmd.description);
|
||||
// use cmd instead of cmdRaw because commands can be unexpected
|
||||
Core()->cmd(cmd.command);
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#define ANALTHREAD_H
|
||||
|
||||
#include "common/AsyncTask.h"
|
||||
#include "core/Iaito.h"
|
||||
#include "common/InitialOptions.h"
|
||||
#include "core/Iaito.h"
|
||||
|
||||
class IaitoCore;
|
||||
class MainWindow;
|
||||
@@ -19,11 +19,11 @@ public:
|
||||
|
||||
QString getTitle() override;
|
||||
|
||||
void setOptions(const InitialOptions &options) { this->options = options; }
|
||||
void setOptions(const InitialOptions &options) { this->options = options; }
|
||||
|
||||
void interrupt() override;
|
||||
|
||||
bool getOpenFileFailed() { return openFailed; }
|
||||
bool getOpenFileFailed() { return openFailed; }
|
||||
|
||||
protected:
|
||||
void runTask() override;
|
||||
|
||||
@@ -1,9 +1,53 @@
|
||||
|
||||
#include "AsyncTask.h"
|
||||
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <thread>
|
||||
|
||||
// On Windows, do not attempt to signal child processes (no POSIX APIs)
|
||||
#if defined(_WIN32)
|
||||
static void signalChildProcessesAsync(int sig)
|
||||
{
|
||||
(void) sig;
|
||||
}
|
||||
#else
|
||||
static void signalChildProcessesAsync(int sig)
|
||||
{
|
||||
// Run in detached thread to keep interrupt non-blocking.
|
||||
std::thread([sig]() {
|
||||
pid_t mypid = getpid();
|
||||
// Use ps to enumerate child processes (portable and simple).
|
||||
FILE *fp = popen("ps -axo pid,ppid", "r");
|
||||
if (!fp) {
|
||||
return;
|
||||
}
|
||||
char *line = nullptr;
|
||||
size_t len = 0;
|
||||
// Skip header line
|
||||
ssize_t read = getline(&line, &len, fp);
|
||||
(void) read;
|
||||
while ((read = getline(&line, &len, fp)) != -1) {
|
||||
// parse two integers
|
||||
long pid = 0, ppid = 0;
|
||||
if (sscanf(line, "%ld %ld", &pid, &ppid) != 2) {
|
||||
continue;
|
||||
}
|
||||
if ((pid_t) ppid == mypid && (pid_t) pid != mypid) {
|
||||
// Send the requested signal to the direct child.
|
||||
kill((pid_t) pid, sig);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
pclose(fp);
|
||||
}).detach();
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
AsyncTask::AsyncTask()
|
||||
: QObject(nullptr),
|
||||
QRunnable()
|
||||
: QObject(nullptr)
|
||||
, QRunnable()
|
||||
{
|
||||
setAutoDelete(false);
|
||||
running = false;
|
||||
@@ -32,6 +76,10 @@ bool AsyncTask::wait(int timeout)
|
||||
void AsyncTask::interrupt()
|
||||
{
|
||||
interrupted = true;
|
||||
// Non-blocking best-effort: signal child processes (e.g., curl spawned by r2js)
|
||||
// with SIGINT so they stop promptly. This is done asynchronously so
|
||||
// interrupt() returns immediately.
|
||||
signalChildProcessesAsync(SIGINT);
|
||||
}
|
||||
|
||||
void AsyncTask::prepareRun()
|
||||
@@ -70,9 +118,7 @@ AsyncTaskManager::AsyncTaskManager(QObject *parent)
|
||||
threadPool = new QThreadPool(this);
|
||||
}
|
||||
|
||||
AsyncTaskManager::~AsyncTaskManager()
|
||||
{
|
||||
}
|
||||
AsyncTaskManager::~AsyncTaskManager() {}
|
||||
|
||||
void AsyncTaskManager::start(AsyncTask::Ptr task)
|
||||
{
|
||||
|
||||
@@ -4,19 +4,19 @@
|
||||
|
||||
#include "core/IaitoCommon.h"
|
||||
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
#include <QMutex>
|
||||
#include <QElapsedTimer>
|
||||
#include <QSharedPointer>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QRunnable>
|
||||
#include <QSharedPointer>
|
||||
#include <QThreadPool>
|
||||
|
||||
class AsyncTaskManager;
|
||||
|
||||
// 8 MB should be enough for deep analysis.. default is 512KB
|
||||
#define R2THREAD_STACK_SIZE 1024*1024*8
|
||||
#define R2THREAD_STACK_SIZE 1024 * 1024 * 8
|
||||
|
||||
class IAITO_EXPORT AsyncTask : public QObject, public QRunnable
|
||||
class IAITO_EXPORT AsyncTask : public QObject, public QRunnable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -33,17 +33,17 @@ public:
|
||||
void wait();
|
||||
bool wait(int timeout);
|
||||
virtual void interrupt();
|
||||
bool isInterrupted() { return interrupted; }
|
||||
bool isRunning() { return running; }
|
||||
bool isInterrupted() { return interrupted; }
|
||||
bool isRunning() { return running; }
|
||||
|
||||
const QString &getLog() { return logBuffer; }
|
||||
const QElapsedTimer &getTimer() { return timer; }
|
||||
qint64 getElapsedTime() { return timer.isValid() ? timer.elapsed() : 0; }
|
||||
const QString &getLog() { return logBuffer; }
|
||||
const QElapsedTimer &getTimer() { return timer; }
|
||||
qint64 getElapsedTime() { return timer.isValid() ? timer.elapsed() : 0; }
|
||||
|
||||
virtual QString getTitle() { return QString(); }
|
||||
virtual QString getTitle() { return QString(); }
|
||||
|
||||
protected:
|
||||
virtual void runTask() =0;
|
||||
virtual void runTask() = 0;
|
||||
|
||||
void log(QString s);
|
||||
|
||||
@@ -81,5 +81,4 @@ signals:
|
||||
void tasksChanged();
|
||||
};
|
||||
|
||||
|
||||
#endif //ASYNCTASK_H
|
||||
#endif // ASYNCTASK_H
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "BasicBlockHighlighter.h"
|
||||
|
||||
BasicBlockHighlighter::BasicBlockHighlighter()
|
||||
{
|
||||
}
|
||||
BasicBlockHighlighter::BasicBlockHighlighter() {}
|
||||
|
||||
BasicBlockHighlighter::~BasicBlockHighlighter()
|
||||
{
|
||||
@@ -16,6 +14,11 @@ BasicBlockHighlighter::~BasicBlockHighlighter()
|
||||
*/
|
||||
void BasicBlockHighlighter::highlight(RVA address, const QColor &color)
|
||||
{
|
||||
auto it = bbMap.find(address);
|
||||
if (it != bbMap.end()) {
|
||||
delete it->second;
|
||||
bbMap.erase(it);
|
||||
}
|
||||
BasicBlock *block = new BasicBlock;
|
||||
block->address = address;
|
||||
block->color = color;
|
||||
@@ -27,7 +30,11 @@ void BasicBlockHighlighter::highlight(RVA address, const QColor &color)
|
||||
*/
|
||||
void BasicBlockHighlighter::clear(RVA address)
|
||||
{
|
||||
bbMap.erase(address);
|
||||
auto it = bbMap.find(address);
|
||||
if (it != bbMap.end()) {
|
||||
delete it->second;
|
||||
bbMap.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +48,7 @@ BasicBlock *BasicBlockHighlighter::getBasicBlock(RVA address)
|
||||
|
||||
it = bbMap.find(address);
|
||||
if (it != bbMap.end()) {
|
||||
return it->second;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
@@ -6,12 +6,13 @@ class BasicBlockHighlighter;
|
||||
#include "Iaito.h"
|
||||
#include <map>
|
||||
|
||||
struct BasicBlock {
|
||||
RVA address;
|
||||
struct BasicBlock
|
||||
{
|
||||
RVA address = 0;
|
||||
QColor color;
|
||||
};
|
||||
|
||||
typedef std::map<RVA, BasicBlock*>::iterator BasicBlockIt;
|
||||
typedef std::map<RVA, BasicBlock *>::iterator BasicBlockIt;
|
||||
|
||||
class BasicBlockHighlighter
|
||||
{
|
||||
@@ -24,7 +25,7 @@ public:
|
||||
BasicBlock *getBasicBlock(RVA address);
|
||||
|
||||
private:
|
||||
std::map<RVA, BasicBlock*> bbMap;
|
||||
std::map<RVA, BasicBlock *> bbMap;
|
||||
};
|
||||
|
||||
#endif // BASICBLOCKHIGHLIGHTER_H
|
||||
#endif // BASICBLOCKHIGHLIGHTER_H
|
||||
@@ -41,7 +41,7 @@ void BasicInstructionHighlighter::clear(RVA address, RVA size)
|
||||
}
|
||||
}
|
||||
|
||||
for ( BasicInstruction newInstr : newInstructions) {
|
||||
for (BasicInstruction newInstr : newInstructions) {
|
||||
biMap[newInstr.address] = newInstr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
#include <map>
|
||||
#include <QColor>
|
||||
|
||||
struct BasicInstruction {
|
||||
RVA address;
|
||||
RVA size;
|
||||
struct BasicInstruction
|
||||
{
|
||||
RVA address = 0;
|
||||
RVA size = 0;
|
||||
QColor color;
|
||||
};
|
||||
|
||||
|
||||
@@ -5,22 +5,24 @@
|
||||
* \brief Utilities to simplify creation of specialized augmented binary trees.
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Not really a segment tree for storing segments as referred in academic literature. Can be considered a
|
||||
* full, almost perfect, augmented binary tree. In the context of competitive programming often called segment tree.
|
||||
* Not really a segment tree for storing segments as referred in academic
|
||||
* literature. Can be considered a full, almost perfect, augmented binary tree.
|
||||
* In the context of competitive programming often called segment tree.
|
||||
*
|
||||
* Child classes are expected to implement updateFromChildren(NodeType&parent, NodeType& left, NodeType& right)
|
||||
* method which calculates inner node values from children nodes.
|
||||
* Child classes are expected to implement updateFromChildren(NodeType&parent,
|
||||
* NodeType& left, NodeType& right) method which calculates inner node values
|
||||
* from children nodes.
|
||||
*
|
||||
* \tparam NodeTypeT type of each tree element
|
||||
* \tparam FinalType final child class used for curiously recurring template pattern
|
||||
* \tparam FinalType final child class used for curiously recurring template
|
||||
* pattern
|
||||
*/
|
||||
template<class NodeTypeT, class FinalType>
|
||||
class SegmentTreeBase
|
||||
@@ -51,33 +53,19 @@ public:
|
||||
{
|
||||
init(initialValue);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Curiously recurring template pattern
|
||||
FinalType &This()
|
||||
{
|
||||
return static_cast<FinalType &>(*this);
|
||||
}
|
||||
FinalType &This() { return static_cast<FinalType &>(*this); }
|
||||
|
||||
// Curiously recurring template pattern
|
||||
const FinalType &This() const
|
||||
{
|
||||
return static_cast<const FinalType &>(*this);
|
||||
}
|
||||
const FinalType &This() const { return static_cast<const FinalType &>(*this); }
|
||||
|
||||
size_t leavePositionToIndex(NodePosition pos) const
|
||||
{
|
||||
return pos - size;
|
||||
}
|
||||
size_t leavePositionToIndex(NodePosition pos) const { return pos - size; }
|
||||
|
||||
NodePosition leaveIndexToPosition(size_t index) const
|
||||
{
|
||||
return index + size;
|
||||
}
|
||||
NodePosition leaveIndexToPosition(size_t index) const { return index + size; }
|
||||
|
||||
bool isLeave(NodePosition position) const
|
||||
{
|
||||
return position >= size;
|
||||
}
|
||||
bool isLeave(NodePosition position) const { return position >= size; }
|
||||
|
||||
/**
|
||||
* @brief Calculate inner node values from leaves.
|
||||
@@ -111,6 +99,7 @@ template<class NodeType, class FinalType>
|
||||
class PointSetSegmentTree : public SegmentTreeBase<NodeType, FinalType>
|
||||
{
|
||||
using BaseType = SegmentTreeBase<NodeType, FinalType>;
|
||||
|
||||
public:
|
||||
using BaseType::BaseType;
|
||||
|
||||
@@ -125,7 +114,8 @@ public:
|
||||
this->nodes[pos] = value;
|
||||
while (pos > 1) {
|
||||
auto parrent = pos >> 1;
|
||||
this->This().updateFromChildren(this->nodes[parrent], this->nodes[pos], this->nodes[pos ^ 1]);
|
||||
this->This()
|
||||
.updateFromChildren(this->nodes[parrent], this->nodes[pos], this->nodes[pos ^ 1]);
|
||||
pos = parrent;
|
||||
}
|
||||
}
|
||||
@@ -141,6 +131,7 @@ public:
|
||||
class PointSetMinTree : public PointSetSegmentTree<int, PointSetMinTree>
|
||||
{
|
||||
using BaseType = PointSetSegmentTree<int, PointSetMinTree>;
|
||||
|
||||
public:
|
||||
using NodeType = int;
|
||||
|
||||
@@ -152,23 +143,24 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find right most position with value than less than given in range [0; position].
|
||||
* @brief Find right most position with value than less than given in range
|
||||
* [0; position].
|
||||
* @param position inclusive right side of query range
|
||||
* @param value search for position less than this
|
||||
* @return returns the position with searched property or -1 if there is no such position.
|
||||
* @return returns the position with searched property or -1 if there is no
|
||||
* such position.
|
||||
*/
|
||||
int rightMostLessThan(size_t position, int value)
|
||||
{
|
||||
auto isGood = [&](size_t pos) {
|
||||
return nodes[pos] < value;
|
||||
};
|
||||
auto isGood = [&](size_t pos) { return nodes[pos] < value; };
|
||||
// right side exclusive range [l;r)
|
||||
size_t goodSubtree = 0;
|
||||
for (size_t l = leaveIndexToPosition(0), r = leaveIndexToPosition(position + 1); l < r;
|
||||
l >>= 1, r >>= 1) {
|
||||
l >>= 1, r >>= 1) {
|
||||
if (l & 1) {
|
||||
if (isGood(l)) {
|
||||
// mark subtree as good but don't stop yet, there might be something good further to the right
|
||||
// mark subtree as good but don't stop yet, there might be
|
||||
// something good further to the right
|
||||
goodSubtree = l;
|
||||
}
|
||||
++l;
|
||||
@@ -195,20 +187,20 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Find left most position with value less than \a value in range [position; size).
|
||||
* @brief Find left most position with value less than \a value in range
|
||||
* [position; size).
|
||||
* @param position inclusive left side of query range
|
||||
* @param value search for position less than this
|
||||
* @return returns the position with searched property or -1 if there is no such position.
|
||||
* @return returns the position with searched property or -1 if there is no
|
||||
* such position.
|
||||
*/
|
||||
int leftMostLessThan(size_t position, int value)
|
||||
{
|
||||
auto isGood = [&](size_t pos) {
|
||||
return nodes[pos] < value;
|
||||
};
|
||||
auto isGood = [&](size_t pos) { return nodes[pos] < value; };
|
||||
// right side exclusive range [l;r)
|
||||
size_t goodSubtree = 0;
|
||||
for (size_t l = leaveIndexToPosition(position), r = leaveIndexToPosition(size); l < r;
|
||||
l >>= 1, r >>= 1) {
|
||||
l >>= 1, r >>= 1) {
|
||||
if (l & 1) {
|
||||
if (isGood(l)) {
|
||||
goodSubtree = l;
|
||||
@@ -220,7 +212,8 @@ public:
|
||||
--r;
|
||||
if (isGood(r)) {
|
||||
goodSubtree = r;
|
||||
// mark subtree as good but don't stop yet, there might be something good further to the left
|
||||
// mark subtree as good but don't stop yet, there might be
|
||||
// something good further to the left
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,19 +234,22 @@ public:
|
||||
/**
|
||||
* \brief Tree that supports lazily applying an operation to range.
|
||||
*
|
||||
* Each inner node has a promise value describing an operation that needs to be applied to corresponding subtree.
|
||||
* Each inner node has a promise value describing an operation that needs to be
|
||||
* applied to corresponding subtree.
|
||||
*
|
||||
* Child classes are expected to implement to pushDown(size_t nodePosition) method. Which applies the applies the
|
||||
* operation stored in \a promise for nodePosition to the direct children nodes.
|
||||
* Child classes are expected to implement to pushDown(size_t nodePosition)
|
||||
* method. Which applies the applies the operation stored in \a promise for
|
||||
* nodePosition to the direct children nodes.
|
||||
*
|
||||
* \tparam NodeType type of tree nodes
|
||||
* \tparam PromiseType type describing operation that needs to be applied to subtree
|
||||
* \tparam FinalType child class type for CRTP. See SegmentTreeBase
|
||||
* \tparam PromiseType type describing operation that needs to be applied to
|
||||
* subtree \tparam FinalType child class type for CRTP. See SegmentTreeBase
|
||||
*/
|
||||
template <class NodeType, class PromiseType, class FinalType>
|
||||
template<class NodeType, class PromiseType, class FinalType>
|
||||
class LazySegmentTreeBase : public SegmentTreeBase<NodeType, FinalType>
|
||||
{
|
||||
using BaseType = SegmentTreeBase<NodeType, FinalType>;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @param size Number of tree leaves.
|
||||
@@ -305,7 +301,8 @@ public:
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Ensure that all the parents of node \a p have the operation applied.
|
||||
* @brief Ensure that all the parents of node \a p have the operation
|
||||
* applied.
|
||||
* @param p Node position
|
||||
*/
|
||||
void pushDownFromRoot(typename BaseType::NodePosition p)
|
||||
@@ -324,7 +321,8 @@ protected:
|
||||
while (p > 1) {
|
||||
auto parent = p >> 1;
|
||||
if (promise[parent] == neutralPromiseElement) {
|
||||
This().updateFromChildren(this->nodes[parent], this->nodes[p & ~size_t(1)], this->nodes[p | 1]);
|
||||
This().updateFromChildren(
|
||||
this->nodes[parent], this->nodes[p & ~size_t(1)], this->nodes[p | 1]);
|
||||
}
|
||||
p = parent;
|
||||
}
|
||||
@@ -337,19 +335,18 @@ protected:
|
||||
std::vector<PromiseType> promise;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Structure supporting range assignment and range maximum operations.
|
||||
*/
|
||||
class RangeAssignMaxTree : public LazySegmentTreeBase<int, uint8_t, RangeAssignMaxTree>
|
||||
{
|
||||
using BaseType = LazySegmentTreeBase<int, uint8_t, RangeAssignMaxTree>;
|
||||
|
||||
public:
|
||||
using ValueType = int;
|
||||
RangeAssignMaxTree(size_t size, ValueType initialValue)
|
||||
: BaseType(size, initialValue, 0)
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
void updateFromChildren(NodeType &parent, const NodeType &left, const NodeType &right)
|
||||
{
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
#include "BugReporting.h"
|
||||
|
||||
#include "Iaito.h"
|
||||
#include <QUrl>
|
||||
#include <QJsonObject>
|
||||
#include "IaitoConfig.h"
|
||||
#include <QDesktopServices>
|
||||
#include <QJsonObject>
|
||||
#include <QUrl>
|
||||
|
||||
void openIssue()
|
||||
{
|
||||
QString url, osInfo, format, arch, type;
|
||||
//Pull in info needed for git issue
|
||||
osInfo = QSysInfo::productType() + " " +
|
||||
(QSysInfo::productVersion() == "unknown"
|
||||
? ""
|
||||
: QSysInfo::productVersion());
|
||||
// Pull in info needed for git issue
|
||||
osInfo = QSysInfo::productType() + " "
|
||||
+ (QSysInfo::productVersion() == "unknown" ? "" : QSysInfo::productVersion());
|
||||
QJsonDocument docu = Core()->getFileInfo();
|
||||
QJsonObject coreObj = docu.object()["core"].toObject();
|
||||
QJsonObject binObj = docu.object()["bin"].toObject();
|
||||
@@ -21,7 +19,7 @@ void openIssue()
|
||||
format = coreObj["format"].toString();
|
||||
arch = binObj["arch"].toString();
|
||||
if (!binObj["type"].isUndefined()) {
|
||||
type = coreObj["type"].toString();
|
||||
type = binObj["type"].toString();
|
||||
} else {
|
||||
type = "N/A";
|
||||
}
|
||||
@@ -30,16 +28,19 @@ void openIssue()
|
||||
arch = "N/A";
|
||||
type = "N/A";
|
||||
}
|
||||
url =
|
||||
"https://github.com/radareorg/iaito/issues/new?&body=**Environment information**\n* Operating System: "
|
||||
+ osInfo + "\n* Iaito version: " + IAITO_VERSION_FULL +
|
||||
"\n* File format: " + format + "\n * Arch: " + arch + "\n * Type: " + type +
|
||||
"\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\n"
|
||||
"Steps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n"
|
||||
"4. See error\n\n**Expected behavior**\n"
|
||||
"A clear and concise description of what you expected to happen.\n\n"
|
||||
"**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n"
|
||||
"**Additional context**\nAdd any other context about the problem here.";
|
||||
url = "https://github.com/radareorg/iaito/issues/new?&body=**Environment "
|
||||
"information**\n* Operating System: "
|
||||
+ osInfo + "\n* Iaito version: " + IAITO_VERSION_FULL + "\n* File format: " + format
|
||||
+ "\n * Arch: " + arch + "\n * Type: " + type
|
||||
+ "\n\n**Describe the bug**\nA clear and concise description of what the "
|
||||
"bug is.\n\n**To Reproduce**\n"
|
||||
"Steps to reproduce the behavior:\n1. Go to '...'\n2. Click on "
|
||||
"'....'\n3. Scroll down to '....'\n"
|
||||
"4. See error\n\n**Expected behavior**\n"
|
||||
"A clear and concise description of what you expected to happen.\n\n"
|
||||
"**Screenshots**\nIf applicable, add screenshots to help explain your "
|
||||
"problem.\n\n"
|
||||
"**Additional context**\nAdd any other context about the problem here.";
|
||||
|
||||
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
|
||||
QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode));
|
||||
}
|
||||
@@ -3,9 +3,12 @@
|
||||
|
||||
#include "common/Metrics.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
#include <QObject>
|
||||
|
||||
template<typename T>
|
||||
class CachedFontMetrics
|
||||
@@ -13,25 +16,45 @@ class CachedFontMetrics
|
||||
public:
|
||||
explicit CachedFontMetrics(const QFont &font)
|
||||
: mFontMetrics(font)
|
||||
, mAsciiWidths{}
|
||||
{
|
||||
memset(mWidths, 0, sizeof(mWidths));
|
||||
mHeight = mFontMetrics.height();
|
||||
}
|
||||
|
||||
static std::shared_ptr<CachedFontMetrics<T>> forFont(const QFont &font)
|
||||
{
|
||||
static std::unordered_map<std::string, std::weak_ptr<CachedFontMetrics<T>>> cache;
|
||||
const std::string key = font.key().toStdString();
|
||||
auto it = cache.find(key);
|
||||
if (it != cache.end()) {
|
||||
if (auto sp = it->second.lock()) {
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
auto sp = std::make_shared<CachedFontMetrics<T>>(font);
|
||||
cache[key] = sp;
|
||||
return sp;
|
||||
}
|
||||
|
||||
T width(const QChar &ch)
|
||||
{
|
||||
//return mFontMetrics.width(ch);
|
||||
auto unicode = ch.unicode();
|
||||
if (unicode >= 0xD800) {
|
||||
if (unicode >= 0xE000)
|
||||
unicode -= 0xE000 - 0xD800;
|
||||
else
|
||||
// is lonely surrogate
|
||||
return fetchWidth(ch);
|
||||
if (unicode < kAsciiCacheSize) {
|
||||
if (!mAsciiWidths[unicode]) {
|
||||
mAsciiWidths[unicode] = fetchWidth(ch);
|
||||
}
|
||||
return mAsciiWidths[unicode];
|
||||
}
|
||||
if (!mWidths[unicode])
|
||||
return mWidths[unicode] = fetchWidth(ch);
|
||||
return mWidths[unicode];
|
||||
if (unicode >= 0xD800 && unicode < 0xE000) {
|
||||
return fetchWidth(ch);
|
||||
}
|
||||
auto it = mWidths.find(unicode);
|
||||
if (it != mWidths.end()) {
|
||||
return it->second;
|
||||
}
|
||||
T w = fetchWidth(ch);
|
||||
mWidths.emplace(unicode, w);
|
||||
return w;
|
||||
}
|
||||
|
||||
T width(const QString &text)
|
||||
@@ -49,10 +72,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
T height()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
T height() { return mHeight; }
|
||||
|
||||
T position(const QString &text, T offset)
|
||||
{
|
||||
@@ -78,13 +98,16 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr int kAsciiCacheSize = 128;
|
||||
|
||||
typename Metrics<T>::FontMetrics mFontMetrics;
|
||||
T mWidths[0x10000 - 0xE000 + 0xD800];
|
||||
T mAsciiWidths[kAsciiCacheSize];
|
||||
std::unordered_map<uint16_t, T> mWidths;
|
||||
T mHeight;
|
||||
|
||||
T fetchWidth(QChar c)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
|
||||
return mFontMetrics.width(c);
|
||||
#else
|
||||
return mFontMetrics.horizontalAdvance(c);
|
||||
@@ -93,7 +116,7 @@ private:
|
||||
|
||||
T fetchWidth(const QString &s)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
|
||||
return mFontMetrics.width(s);
|
||||
#else
|
||||
return mFontMetrics.horizontalAdvance(s);
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#ifndef CODEMETA_RANGE_H
|
||||
#define CODEMETA_RANGE_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QString>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
|
||||
struct CodeMetaRange
|
||||
{
|
||||
size_t start = 0;
|
||||
size_t end = 0;
|
||||
size_t length = 0;
|
||||
};
|
||||
|
||||
inline std::optional<CodeMetaRange> codeMetaRangeFromJson(const QJsonObject &obj, size_t codeLength)
|
||||
{
|
||||
int start = obj["start"].toInt(-1);
|
||||
int end = obj["end"].toInt(-1);
|
||||
if (start < 0 || end < start) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t rangeStart = static_cast<size_t>(start);
|
||||
size_t rangeEnd = std::min(static_cast<size_t>(end), codeLength);
|
||||
if (rangeStart >= codeLength || rangeEnd <= rangeStart) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return CodeMetaRange{rangeStart, rangeEnd, rangeEnd - rangeStart};
|
||||
}
|
||||
|
||||
inline std::optional<CodeMetaRange> codeMetaOffsetRangeFromJson(
|
||||
const QJsonObject &obj, const QString &code)
|
||||
{
|
||||
int start = obj["start"].toInt(-1);
|
||||
int end = obj["end"].toInt(start);
|
||||
if (start < 0 || end < start || start >= code.size()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (end == start) {
|
||||
int lineStart = code.lastIndexOf(QLatin1Char('\n'), start - 1);
|
||||
lineStart = (lineStart < 0) ? 0 : lineStart + 1;
|
||||
int lineEnd = code.indexOf(QLatin1Char('\n'), start);
|
||||
if (lineEnd < 0) {
|
||||
lineEnd = code.size();
|
||||
}
|
||||
if (lineEnd <= lineStart) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return CodeMetaRange{
|
||||
static_cast<size_t>(lineStart),
|
||||
static_cast<size_t>(lineEnd),
|
||||
static_cast<size_t>(lineEnd - lineStart)};
|
||||
}
|
||||
|
||||
size_t rangeStart = static_cast<size_t>(start);
|
||||
size_t rangeEnd = std::min(static_cast<size_t>(end), static_cast<size_t>(code.size()));
|
||||
if (rangeEnd <= rangeStart) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return CodeMetaRange{rangeStart, rangeEnd, rangeEnd - rangeStart};
|
||||
}
|
||||
|
||||
inline std::optional<qulonglong> codeMetaAddressFromJson(const QJsonValue &value)
|
||||
{
|
||||
bool ok = false;
|
||||
qulonglong address = value.toVariant().toULongLong(&ok);
|
||||
if (ok) {
|
||||
return address;
|
||||
}
|
||||
|
||||
QString text = value.toString().trimmed();
|
||||
if (text.isEmpty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
address = text.toULongLong(&ok, 0);
|
||||
if (!ok && text.startsWith(QLatin1String("0x"), Qt::CaseInsensitive)) {
|
||||
address = text.mid(2).toULongLong(&ok, 16);
|
||||
}
|
||||
if (!ok) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
inline std::optional<CodeMetaRange> intersectCodeMetaRange(
|
||||
size_t rangeStart, size_t rangeEnd, size_t scopeStart, size_t scopeEnd)
|
||||
{
|
||||
if (rangeEnd <= rangeStart || scopeEnd <= scopeStart || rangeEnd <= scopeStart
|
||||
|| rangeStart >= scopeEnd) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
size_t start = std::max(rangeStart, scopeStart) - scopeStart;
|
||||
size_t end = std::min(rangeEnd, scopeEnd) - scopeStart;
|
||||
return CodeMetaRange{start, end, end - start};
|
||||
}
|
||||
|
||||
#endif // CODEMETA_RANGE_H
|
||||
@@ -1,94 +1,89 @@
|
||||
#include "ColorThemeWorker.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QColor>
|
||||
#include <QJsonArray>
|
||||
#include <QStandardPaths>
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include "common/Configuration.h"
|
||||
|
||||
const QStringList ColorThemeWorker::cutterSpecificOptions = {
|
||||
"wordHighlight",
|
||||
"lineHighlight",
|
||||
"gui.main",
|
||||
"gui.imports",
|
||||
"highlightPC",
|
||||
"gui.navbar.err",
|
||||
"gui.navbar.seek",
|
||||
"gui.navbar.pc",
|
||||
"gui.navbar.sym",
|
||||
"gui.dataoffset",
|
||||
"gui.navbar.code",
|
||||
"gui.navbar.empty",
|
||||
"angui.navbar.str",
|
||||
"gui.disass_selected",
|
||||
"gui.breakpoint_background",
|
||||
"gui.overview.node",
|
||||
"gui.overview.fill",
|
||||
"gui.overview.border",
|
||||
"gui.border",
|
||||
"gui.background",
|
||||
"gui.alt_background",
|
||||
"gui.disass_selected"
|
||||
};
|
||||
|
||||
const QStringList ColorThemeWorker::radare2UnusedOptions = {
|
||||
"linehl",
|
||||
"wordhl",
|
||||
"graph.box",
|
||||
"graph.box2",
|
||||
"graph.box3",
|
||||
"graph.box4",
|
||||
"graph.current",
|
||||
"graph.box2",
|
||||
"widget_sel",
|
||||
"widget_bg",
|
||||
"label",
|
||||
"ai.write",
|
||||
"invalid",
|
||||
"ai.seq",
|
||||
"args",
|
||||
"ai.read",
|
||||
"ai.exec",
|
||||
"ai.ascii",
|
||||
"prompt",
|
||||
"graph.traced"
|
||||
};
|
||||
|
||||
ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject (parent)
|
||||
namespace {
|
||||
// Convert a QVariant holding a [r, g, b] list into an opaque rgba QJsonArray.
|
||||
// Returns an empty array if the input is not a 3+ element list of ints.
|
||||
static QJsonArray variantToRgba(const QVariant &v)
|
||||
{
|
||||
#if R2_VERSION_NUMBER < 50709
|
||||
char* szThemes = r_str_home (R2_HOME_THEMES);
|
||||
#else
|
||||
char* szThemes = r_xdg_datadir ("cons");
|
||||
#endif
|
||||
customR2ThemesLocationPath = szThemes;
|
||||
r_mem_free (szThemes);
|
||||
if (!QDir (customR2ThemesLocationPath).exists ()) {
|
||||
QDir().mkpath (customR2ThemesLocationPath);
|
||||
const auto arr = v.toList();
|
||||
if (arr.size() < 3 || !arr[0].canConvert<int>() || !arr[1].canConvert<int>()
|
||||
|| !arr[2].canConvert<int>()) {
|
||||
return {};
|
||||
}
|
||||
return {arr[0].toInt(), arr[1].toInt(), arr[2].toInt(), 255};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
QDir currDir {
|
||||
QStringLiteral("%1%2%3")
|
||||
.arg(r_sys_prefix(nullptr))
|
||||
.arg(R_SYS_DIR)
|
||||
.arg(R2_THEMES)
|
||||
};
|
||||
if (currDir.exists ()) {
|
||||
standardR2ThemesLocationPath = currDir.absolutePath ();
|
||||
const QStringList ColorThemeWorker::iaitoSpecificOptions
|
||||
= {"wordHighlight",
|
||||
"lineHighlight",
|
||||
"gui.main",
|
||||
"gui.imports",
|
||||
"highlightPC",
|
||||
"gui.navbar.err",
|
||||
"gui.navbar.seek",
|
||||
"gui.navbar.pc",
|
||||
"gui.navbar.sym",
|
||||
"gui.dataoffset",
|
||||
"gui.navbar.code",
|
||||
"gui.navbar.data",
|
||||
"gui.navbar.empty",
|
||||
"gui.navbar.str",
|
||||
"gui.disass_selected",
|
||||
"gui.breakpoint_background",
|
||||
"gui.overview.node",
|
||||
"gui.overview.fill",
|
||||
"gui.overview.border",
|
||||
"gui.border",
|
||||
"gui.background",
|
||||
"gui.alt_background",
|
||||
"gui.disass_selected"};
|
||||
|
||||
const QStringList ColorThemeWorker::radare2UnusedOptions
|
||||
= {"linehl", "wordhl", "graph.box", "graph.box2", "graph.box3",
|
||||
"graph.box4", "graph.current", "graph.box2", "widget_sel", "widget_bg",
|
||||
"label", "ai.write", "invalid", "ai.seq", "args",
|
||||
"ai.read", "ai.exec", "ai.ascii", "prompt", "graph.traced"};
|
||||
|
||||
ColorThemeWorker::ColorThemeWorker(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
char *szThemes = r_xdg_datadir("cons");
|
||||
customR2ThemesLocationPath = szThemes;
|
||||
r_mem_free(szThemes);
|
||||
if (!QDir(customR2ThemesLocationPath).exists()) {
|
||||
// let the user place their color themes here
|
||||
QDir().mkpath(customR2ThemesLocationPath);
|
||||
}
|
||||
// resolve system path (version specific)
|
||||
QDir currDir{QStringLiteral("%1%2%3").arg(r_sys_prefix(nullptr)).arg(R_SYS_DIR).arg(R2_THEMES)};
|
||||
if (currDir.exists()) {
|
||||
standardR2ThemesLocationPath = currDir.absolutePath();
|
||||
} else {
|
||||
QMessageBox::critical (nullptr,
|
||||
tr("Standard themes not found"),
|
||||
tr("The radare2 standard themes could not be found in '%1'. "
|
||||
"Most likely, radare2 is not properly installed.")
|
||||
.arg(currDir.path())
|
||||
);
|
||||
// if not found just use /last/ instead of the version
|
||||
QDir currDir{
|
||||
QStringLiteral("%1/%3").arg(r_sys_prefix(nullptr)).arg("share/radare2/last/cons")};
|
||||
if (currDir.exists()) {
|
||||
standardR2ThemesLocationPath = currDir.absolutePath();
|
||||
} else {
|
||||
QMessageBox::critical(
|
||||
nullptr,
|
||||
tr("Standard themes not found"),
|
||||
tr("Cannot find radare2 console themes in '%1'. ").arg(currDir.path()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QColor ColorThemeWorker::mergeColors(const QColor& upper, const QColor& lower) const
|
||||
QColor ColorThemeWorker::mergeColors(const QColor &upper, const QColor &lower) const
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
// not implemented Qt::SHIFT doesnt exist
|
||||
@@ -114,12 +109,10 @@ QColor ColorThemeWorker::mergeColors(const QColor& upper, const QColor& lower) c
|
||||
return res;
|
||||
}
|
||||
|
||||
QString ColorThemeWorker::copy(const QString &srcThemeName,
|
||||
const QString ©ThemeName) const
|
||||
QString ColorThemeWorker::copy(const QString &srcThemeName, const QString ©ThemeName) const
|
||||
{
|
||||
if (!isThemeExist(srcThemeName)) {
|
||||
return tr("Theme <b>%1</b> does not exist.")
|
||||
.arg(srcThemeName);
|
||||
return tr("Theme <b>%1</b> does not exist.").arg(srcThemeName);
|
||||
}
|
||||
|
||||
return save(getTheme(srcThemeName), copyThemeName);
|
||||
@@ -129,13 +122,12 @@ QString ColorThemeWorker::save(const QJsonDocument &theme, const QString &themeN
|
||||
{
|
||||
QFile fOut(QDir(customR2ThemesLocationPath).filePath(themeName));
|
||||
if (!fOut.open(QFile::WriteOnly | QFile::Truncate)) {
|
||||
return tr("The file <b>%1</b> cannot be opened.")
|
||||
.arg(QFileInfo(fOut).filePath());
|
||||
return tr("The file <b>%1</b> cannot be opened.").arg(QFileInfo(fOut).filePath());
|
||||
}
|
||||
|
||||
QByteArray buf;
|
||||
QJsonObject obj = theme.object();
|
||||
for (auto it = obj.constBegin(); it != obj.constEnd(); it++) {
|
||||
|
||||
QJsonArray arr = it.value().toArray();
|
||||
QColor color;
|
||||
if (arr.isEmpty()) {
|
||||
@@ -147,17 +139,21 @@ QString ColorThemeWorker::save(const QJsonDocument &theme, const QString &themeN
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (cutterSpecificOptions.contains(it.key())) {
|
||||
fOut.write(QString("#~%1 rgb:%2\n")
|
||||
if (iaitoSpecificOptions.contains(it.key())) {
|
||||
buf += QStringLiteral("#~%1 rgb:%2\n")
|
||||
.arg(it.key(), color.name(QColor::HexArgb).remove('#'))
|
||||
.toUtf8());
|
||||
.toUtf8();
|
||||
} else {
|
||||
fOut.write(QString("ec %1 rgb:%2\n")
|
||||
buf += QStringLiteral("ec %1 rgb:%2\n")
|
||||
.arg(it.key(), color.name(QColor::HexRgb).remove('#'))
|
||||
.toUtf8());
|
||||
.toUtf8();
|
||||
}
|
||||
}
|
||||
|
||||
if (fOut.write(buf) != buf.size() || !fOut.flush()) {
|
||||
fOut.close();
|
||||
return tr("Failed to write theme <b>%1</b>.").arg(themeName);
|
||||
}
|
||||
fOut.close();
|
||||
return "";
|
||||
}
|
||||
@@ -173,24 +169,25 @@ bool ColorThemeWorker::isThemeExist(const QString &name) const
|
||||
return themes.contains(name);
|
||||
}
|
||||
|
||||
QJsonDocument ColorThemeWorker::getTheme(const QString& themeName) const
|
||||
QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const
|
||||
{
|
||||
int r, g, b, a;
|
||||
QVariantMap theme;
|
||||
QString curr = Config()->getColorTheme();
|
||||
|
||||
if (themeName != curr) {
|
||||
Core()->cmdRaw(QString("eco %1").arg(themeName));
|
||||
Core()->cmdRaw(QStringLiteral("eco %1").arg(themeName));
|
||||
theme = Core()->cmdj("ecj").object().toVariantMap();
|
||||
Core()->cmdRaw(QString("eco %1").arg(curr));
|
||||
Core()->cmdRaw(QStringLiteral("eco %1").arg(curr));
|
||||
} else {
|
||||
theme = Core()->cmdj("ecj").object().toVariantMap();
|
||||
}
|
||||
|
||||
for (auto it = theme.begin(); it != theme.end(); it++) {
|
||||
auto arr = it.value().toList();
|
||||
QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt()).getRgb(&r, &g, &b, &a);
|
||||
theme[it.key()] = QJsonArray({r, g, b, a});
|
||||
const QJsonArray rgba = variantToRgba(it.value());
|
||||
if (!rgba.isEmpty()) {
|
||||
theme[it.key()] = rgba;
|
||||
}
|
||||
}
|
||||
|
||||
ColorFlags colorFlags = ColorFlags::DarkFlag;
|
||||
@@ -198,8 +195,8 @@ QJsonDocument ColorThemeWorker::getTheme(const QString& themeName) const
|
||||
colorFlags = Configuration::relevantThemes[themeName];
|
||||
}
|
||||
|
||||
for (auto& it : cutterSpecificOptions) {
|
||||
Configuration::cutterOptionColors[it][colorFlags].getRgb(&r, &g, &b, &a);
|
||||
for (auto &it : iaitoSpecificOptions) {
|
||||
Configuration::iaitoOptionColors[it][colorFlags].getRgb(&r, &g, &b, &a);
|
||||
theme.insert(it, QJsonArray{r, g, b, a});
|
||||
}
|
||||
|
||||
@@ -214,8 +211,10 @@ QJsonDocument ColorThemeWorker::getTheme(const QString& themeName) const
|
||||
if (sl.size() != 3 || sl[0][0] == '#') {
|
||||
continue;
|
||||
}
|
||||
QString optionName = sl[1] == "angui.navbar.str" ? QStringLiteral("gui.navbar.str")
|
||||
: sl[1];
|
||||
QColor(sl[2]).getRgb(&r, &g, &b, &a);
|
||||
theme.insert(sl[1], QJsonArray({r, g, b, a}));
|
||||
theme.insert(optionName, QJsonArray({r, g, b, a}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,8 +223,9 @@ QJsonDocument ColorThemeWorker::getTheme(const QString& themeName) const
|
||||
}
|
||||
|
||||
// manualy converting instead of using QJsonObject::fromVariantMap because
|
||||
// Qt < 5.6 QJsonValue.fromVariant doesn't expect QVariant to already contain
|
||||
// QJson values like QJsonArray. https://github.com/qt/qtbase/commit/26237f0a2d8db80024b601f676bbce54d483e672
|
||||
// Qt < 5.6 QJsonValue.fromVariant doesn't expect QVariant to already
|
||||
// contain QJson values like QJsonArray.
|
||||
// https://github.com/qt/qtbase/commit/26237f0a2d8db80024b601f676bbce54d483e672
|
||||
QJsonObject obj;
|
||||
for (auto it = theme.begin(); it != theme.end(); it++) {
|
||||
auto &value = it.value();
|
||||
@@ -234,7 +234,6 @@ QJsonDocument ColorThemeWorker::getTheme(const QString& themeName) const
|
||||
} else {
|
||||
obj[it.key()] = QJsonValue::fromVariant(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return QJsonDocument(obj);
|
||||
@@ -250,34 +249,28 @@ QString ColorThemeWorker::deleteTheme(const QString &themeName) const
|
||||
}
|
||||
|
||||
QFile file(QDir(customR2ThemesLocationPath).filePath(themeName));
|
||||
if (file.isWritable()) {
|
||||
return tr("You have no permission to write to <b>%1</b>")
|
||||
.arg(QFileInfo(file).filePath());
|
||||
}
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
return tr("File <b>%1</b> can not be opened.")
|
||||
.arg(QFileInfo(file).filePath());
|
||||
if (!QFileInfo(file).isWritable()) {
|
||||
return tr("You have no permission to write to <b>%1</b>").arg(QFileInfo(file).filePath());
|
||||
}
|
||||
if (!file.remove()) {
|
||||
return tr("File <b>%1</b> can not be removed.")
|
||||
.arg(QFileInfo(file).filePath());
|
||||
return tr("File <b>%1</b> can not be removed.").arg(QFileInfo(file).filePath());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
QString ColorThemeWorker::importTheme(const QString& file) const
|
||||
QString ColorThemeWorker::importTheme(const QString &file) const
|
||||
{
|
||||
QFileInfo src(file);
|
||||
if (!src.exists()) {
|
||||
return tr("File <b>%1</b> does not exist.").arg(file);
|
||||
}
|
||||
if (!src.exists()) {
|
||||
return tr("File <b>%1</b> does not exist.").arg(file);
|
||||
}
|
||||
|
||||
bool ok;
|
||||
bool isTheme = isFileTheme(file, &ok);
|
||||
if (!ok) {
|
||||
return tr("File <b>%1</b> could not be opened. "
|
||||
"Please make sure you have access to it and try again.")
|
||||
.arg(file);
|
||||
.arg(file);
|
||||
} else if (!isTheme) {
|
||||
return tr("File <b>%1</b> is not a Iaito color theme").arg(file);
|
||||
}
|
||||
@@ -288,35 +281,43 @@ QString ColorThemeWorker::importTheme(const QString& file) const
|
||||
}
|
||||
|
||||
if (QFile::copy(file, QDir(customR2ThemesLocationPath).filePath(name))) {
|
||||
return "";
|
||||
} else {
|
||||
return tr("Error occurred during importing. "
|
||||
"Please make sure you have an access to "
|
||||
"the directory <b>%1</b> and try again.")
|
||||
.arg(src.dir().path());
|
||||
return "";
|
||||
} else {
|
||||
return tr("Error occurred during importing. "
|
||||
"Please make sure you have an access to "
|
||||
"the directory <b>%1</b> and try again.")
|
||||
.arg(src.dir().path());
|
||||
}
|
||||
}
|
||||
|
||||
QString ColorThemeWorker::renameTheme(const QString& themeName, const QString& newName) const
|
||||
QString ColorThemeWorker::renameTheme(const QString &themeName, const QString &newName) const
|
||||
{
|
||||
// Reject path traversal / separators via radare2's strict name check.
|
||||
if (!r_name_check(themeName.toUtf8().constData())
|
||||
|| !r_name_check(newName.toUtf8().constData())) {
|
||||
return tr("Invalid theme name.");
|
||||
}
|
||||
|
||||
if (isThemeExist(newName)) {
|
||||
return tr("A color theme named <b>\"%1\"</b> already exists.").arg(newName);
|
||||
}
|
||||
return tr("A color theme named <b>\"%1\"</b> already exists.").arg(newName);
|
||||
}
|
||||
|
||||
if (!isCustomTheme(themeName)) {
|
||||
return tr("You can not rename standard radare2 themes.");
|
||||
}
|
||||
if (!isCustomTheme(themeName)) {
|
||||
return tr("You can not rename standard radare2 themes.");
|
||||
}
|
||||
|
||||
QDir dir = customR2ThemesLocationPath;
|
||||
bool ok = QFile::rename(dir.filePath(themeName), dir.filePath(newName));
|
||||
if (!ok) {
|
||||
return tr("Something went wrong during renaming. "
|
||||
"Please make sure you have access to the directory <b>\"%1\"</b>.").arg(dir.path());
|
||||
}
|
||||
return "";
|
||||
QDir dir = customR2ThemesLocationPath;
|
||||
bool ok = QFile::rename(dir.filePath(themeName), dir.filePath(newName));
|
||||
if (!ok) {
|
||||
return tr("Something went wrong during renaming. "
|
||||
"Please make sure you have access to the directory "
|
||||
"<b>\"%1\"</b>.")
|
||||
.arg(dir.path());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool ColorThemeWorker::isFileTheme(const QString& filePath, bool* ok) const
|
||||
bool ColorThemeWorker::isFileTheme(const QString &filePath, bool *ok) const
|
||||
{
|
||||
QFile f(filePath);
|
||||
if (!f.open(QFile::ReadOnly)) {
|
||||
@@ -325,12 +326,16 @@ bool ColorThemeWorker::isFileTheme(const QString& filePath, bool* ok) const
|
||||
}
|
||||
|
||||
const QString colors = "black|red|white|green|magenta|yellow|cyan|blue|gray|none";
|
||||
QString options = (Core()->cmdj("ecj").object().keys() << cutterSpecificOptions)
|
||||
.join('|')
|
||||
.replace(".", "\\.");
|
||||
QString options = (Core()->cmdj("ecj").object().keys()
|
||||
<< iaitoSpecificOptions << QStringLiteral("angui.navbar.str"))
|
||||
.join('|')
|
||||
.replace(".", "\\.");
|
||||
|
||||
QString pattern = QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*").arg(options).arg(colors);
|
||||
// The below construct mimics the behaviour of QRegexP::exactMatch(), which was here before
|
||||
QString pattern = QStringLiteral("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*")
|
||||
.arg(options)
|
||||
.arg(colors);
|
||||
// The below construct mimics the behaviour of QRegexP::exactMatch(), which
|
||||
// was here before
|
||||
QRegularExpression regexp("\\A(?:" + pattern + ")\\z");
|
||||
|
||||
for (auto &line : QString(f.readAll()).split('\n', IAITO_QT_SKIP_EMPTY_PARTS)) {
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
#ifndef COLORTHEMEWORKER_H
|
||||
#define COLORTHEMEWORKER_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QColor>
|
||||
#include <QObject>
|
||||
#include "Iaito.h"
|
||||
#include <QColor>
|
||||
#include <QFile>
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
|
||||
#define ThemeWorker() (ColorThemeWorker::instance())
|
||||
|
||||
/**
|
||||
* @brief The ColorThemeWorker class is a singletone that provides API for working with
|
||||
* color themes.
|
||||
* @brief The ColorThemeWorker class is a singletone that provides API for
|
||||
* working with color themes.
|
||||
*/
|
||||
class ColorThemeWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief radare2SpecificOptions is list of all available radare2-only color options.
|
||||
* @brief radare2SpecificOptions is list of all available radare2-only color
|
||||
* options.
|
||||
*/
|
||||
const QStringList radare2SpecificOptions = Core()->cmdj("ecj").object().keys();
|
||||
|
||||
/**
|
||||
* @brief cutterSpecificOptions is list of all available Iaito-only color options.
|
||||
* @brief iaitoSpecificOptions is list of all available Iaito-only color
|
||||
* options.
|
||||
*/
|
||||
static const QStringList cutterSpecificOptions;
|
||||
static const QStringList iaitoSpecificOptions;
|
||||
|
||||
/**
|
||||
* @brief radare2UnusedOptions is a list of all radare2 options that Iaito does not use.
|
||||
* @brief radare2UnusedOptions is a list of all radare2 options that Iaito
|
||||
* does not use.
|
||||
*/
|
||||
static const QStringList radare2UnusedOptions;
|
||||
|
||||
@@ -40,7 +43,6 @@ public:
|
||||
|
||||
virtual ~ColorThemeWorker() {}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copies @a srcThemeName with name @a copyThemeName.
|
||||
* @param srcThemeName
|
||||
@@ -59,10 +61,11 @@ public:
|
||||
* Name of theme to save.
|
||||
* @return "" on success or error message.
|
||||
*/
|
||||
QString save(const QJsonDocument& theme, const QString &themeName) const;
|
||||
QString save(const QJsonDocument &theme, const QString &themeName) const;
|
||||
|
||||
/**
|
||||
* @brief Returns whether or not @a themeName theme is custom (created by user or imported) or not.
|
||||
* @brief Returns whether or not @a themeName theme is custom (created by
|
||||
* user or imported) or not.
|
||||
* @param themeName
|
||||
* Name of theme to check.
|
||||
*/
|
||||
@@ -75,7 +78,8 @@ public:
|
||||
bool isThemeExist(const QString &name) const;
|
||||
|
||||
/**
|
||||
* @brief Returns theme as Json where key is option name and value is array of 3 Ints (Red, Green, Blue).
|
||||
* @brief Returns theme as Json where key is option name and value is array
|
||||
* of 3 Ints (Red, Green, Blue).
|
||||
* @param themeName
|
||||
* Theme to get.
|
||||
*/
|
||||
@@ -93,13 +97,13 @@ public:
|
||||
* @brief Imports theme from @a file.
|
||||
* @return "" on success or error message.
|
||||
*/
|
||||
QString importTheme(const QString& file) const;
|
||||
QString importTheme(const QString &file) const;
|
||||
|
||||
/**
|
||||
* @brief Renames theme from @a themeName to @a newName.
|
||||
* @return "" on success or error message.
|
||||
*/
|
||||
QString renameTheme(const QString& themeName, const QString& newName) const;
|
||||
QString renameTheme(const QString &themeName, const QString &newName) const;
|
||||
|
||||
/**
|
||||
* @brief Returns whether or not file at @a filePath is a color theme.
|
||||
@@ -107,7 +111,8 @@ public:
|
||||
* Path to file to check.
|
||||
* @param ok
|
||||
* Output parameter. Indicates wheter or not check was successful.
|
||||
* @return true if given file is color theme and ok == true, otherwise returns false.
|
||||
* @return true if given file is color theme and ok == true, otherwise
|
||||
* returns false.
|
||||
*/
|
||||
bool isFileTheme(const QString &filePath, bool *ok) const;
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#include "Colors.h"
|
||||
#include "common/Configuration.h"
|
||||
#include <vector>
|
||||
|
||||
Colors::Colors()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Colors::Colors() {}
|
||||
|
||||
void Colors::colorizeAssembly(RichTextPainter::List &list, QString opcode, ut64 type_num)
|
||||
{
|
||||
@@ -13,7 +10,8 @@ void Colors::colorizeAssembly(RichTextPainter::List &list, QString opcode, ut64
|
||||
assembly.highlight = false;
|
||||
assembly.flags = RichTextPainter::FlagColor;
|
||||
|
||||
// TODO cut opcode and use op["ptr"] to colorate registers and immediate values
|
||||
// TODO cut opcode and use op["ptr"] to colorate registers and immediate
|
||||
// values
|
||||
assembly.text = opcode;
|
||||
|
||||
QString colorName = Colors::getColor(type_num);
|
||||
@@ -22,7 +20,8 @@ void Colors::colorizeAssembly(RichTextPainter::List &list, QString opcode, ut64
|
||||
}
|
||||
|
||||
// Temporary solution
|
||||
// Copied from R_API const char* r_print_color_op_type(RPrint *p, ut64 anal_type) {
|
||||
// Copied from R_API const char* r_print_color_op_type(RPrint *p, ut64
|
||||
// anal_type) {
|
||||
QString Colors::getColor(ut64 type)
|
||||
{
|
||||
switch (type & R_ANAL_OP_TYPE_MASK) {
|
||||
@@ -102,3 +101,20 @@ QString Colors::getColor(ut64 type)
|
||||
}
|
||||
}
|
||||
|
||||
QColor colorForIndex(unsigned int i)
|
||||
{
|
||||
static const std::vector<QColor> palette = {
|
||||
QColor("#1ABC9C"), // TURQUOISE
|
||||
QColor("#2ECC71"), // EMERALD
|
||||
QColor("#3498DB"), // PETER RIVER
|
||||
QColor("#9B59B6"), // AMETHYST
|
||||
QColor("#34495E"), // WET ASPHALT
|
||||
QColor("#F1C40F"), // SUN FLOWER
|
||||
QColor("#E67E22"), // CARROT
|
||||
QColor("#E74C3C"), // ALIZARIN
|
||||
QColor("#ECF0F1"), // CLOUDS
|
||||
QColor("#BDC3C7"), // SILVER
|
||||
QColor("#95A5A6") // CONCRETE
|
||||
};
|
||||
return palette[i % palette.size()];
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef COLORS_H
|
||||
#define COLORS_H
|
||||
|
||||
#include "core/Iaito.h"
|
||||
#include "common/Radare2Compat.h"
|
||||
#include "common/RichTextPainter.h"
|
||||
#include <r_anal.h>
|
||||
#include "core/Iaito.h"
|
||||
#include <QColor>
|
||||
|
||||
class Colors
|
||||
{
|
||||
@@ -13,4 +14,7 @@ public:
|
||||
static QString getColor(ut64 type);
|
||||
};
|
||||
|
||||
// Return a consistent QColor for the given index (round-robin over a palette)
|
||||
QColor colorForIndex(unsigned int i);
|
||||
|
||||
#endif // COLORS_H
|
||||
@@ -2,15 +2,19 @@
|
||||
#include "CommandTask.h"
|
||||
#include "TempConfig.h"
|
||||
|
||||
CommandTask::CommandTask(const QString &cmd, ColorMode colorMode, bool outFormatHtml)
|
||||
: cmd(cmd), colorMode(colorMode), outFormatHtml(outFormatHtml)
|
||||
{
|
||||
}
|
||||
CommandTask::CommandTask(
|
||||
const QString &cmd, ColorMode colorMode, bool outFormatHtml, ExecutionMode executionMode)
|
||||
: cmd(cmd)
|
||||
, colorMode(colorMode)
|
||||
, outFormatHtml(outFormatHtml)
|
||||
, executionMode(executionMode)
|
||||
{}
|
||||
|
||||
void CommandTask::runTask() {
|
||||
void CommandTask::runTask()
|
||||
{
|
||||
TempConfig tempConfig;
|
||||
tempConfig.set("scr.color", colorMode);
|
||||
auto res = Core()->cmdTask(cmd);
|
||||
auto res = executionMode == ExecutionMode::DIRECT_CMD ? Core()->cmd(cmd) : Core()->cmdTask(cmd);
|
||||
if (outFormatHtml) {
|
||||
res = IaitoCore::ansiEscapeToHtml(res);
|
||||
}
|
||||
|
||||
@@ -5,16 +5,27 @@
|
||||
#include "common/AsyncTask.h"
|
||||
#include "core/Iaito.h"
|
||||
|
||||
class IAITO_EXPORT CommandTask : public AsyncTask
|
||||
class IAITO_EXPORT CommandTask : public AsyncTask
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ColorMode {DISABLED=COLOR_MODE_DISABLED, MODE_16=COLOR_MODE_16, MODE_256=COLOR_MODE_256, MODE_16M=COLOR_MODE_16M};
|
||||
enum ColorMode {
|
||||
DISABLED = COLOR_MODE_DISABLED,
|
||||
MODE_16 = COLOR_MODE_16,
|
||||
MODE_256 = COLOR_MODE_256,
|
||||
MODE_16M = COLOR_MODE_16M
|
||||
};
|
||||
|
||||
CommandTask(const QString &cmd, ColorMode colorMode=ColorMode::DISABLED, bool outFormatHtml=false);
|
||||
enum ExecutionMode { CORE_TASK, DIRECT_CMD };
|
||||
|
||||
QString getTitle() override { return tr("Running Command"); }
|
||||
CommandTask(
|
||||
const QString &cmd,
|
||||
ColorMode colorMode = ColorMode::DISABLED,
|
||||
bool outFormatHtml = false,
|
||||
ExecutionMode executionMode = ExecutionMode::CORE_TASK);
|
||||
|
||||
QString getTitle() override { return tr("Running Command"); }
|
||||
|
||||
signals:
|
||||
void finished(const QString &result);
|
||||
@@ -26,6 +37,7 @@ private:
|
||||
QString cmd;
|
||||
ColorMode colorMode;
|
||||
bool outFormatHtml;
|
||||
ExecutionMode executionMode;
|
||||
};
|
||||
|
||||
#endif //COMMANDTASK_H
|
||||
#endif // COMMANDTASK_H
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef IAITO_COMPILER_WORKAROUNDS_H
|
||||
#define IAITO_COMPILER_WORKAROUNDS_H
|
||||
|
||||
#if defined(__APPLE__) && defined(__aarch64__) && defined(__clang__)
|
||||
#if __has_include(<arm_acle.h>)
|
||||
#include <arm_acle.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // IAITO_COMPILER_WORKAROUNDS_H
|
||||
@@ -1,64 +1,92 @@
|
||||
#ifndef CONFIGURATION_H
|
||||
#define CONFIGURATION_H
|
||||
|
||||
#include <QSettings>
|
||||
#include <QFont>
|
||||
#include <core/Iaito.h>
|
||||
#include <QFont>
|
||||
#include <QSettings>
|
||||
|
||||
#define Config() (Configuration::instance())
|
||||
#define ConfigColor(x) Config()->getColor(x)
|
||||
|
||||
#ifdef IAITO_ENABLE_KSYNTAXHIGHLIGHTING
|
||||
namespace KSyntaxHighlighting {
|
||||
class Repository;
|
||||
class Theme;
|
||||
}
|
||||
class Repository;
|
||||
class Theme;
|
||||
} // namespace KSyntaxHighlighting
|
||||
#endif
|
||||
|
||||
class QSyntaxHighlighter;
|
||||
class QTextDocument;
|
||||
|
||||
class Theme;
|
||||
|
||||
enum ColorFlags {
|
||||
LightFlag = 1,
|
||||
DarkFlag = 2,
|
||||
};
|
||||
|
||||
struct IaitoInterfaceTheme {
|
||||
struct IaitoInterfaceTheme
|
||||
{
|
||||
QString name;
|
||||
ColorFlags flag;
|
||||
};
|
||||
|
||||
|
||||
class IAITO_EXPORT Configuration : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class VisualNavbarLocation { Top = 0, Bottom, Left, Right, SuperTop, SuperBottom };
|
||||
Q_ENUM(VisualNavbarLocation)
|
||||
enum class MemoryScrollBarMode { Spring = 0, Bounded, Hidden };
|
||||
Q_ENUM(MemoryScrollBarMode)
|
||||
|
||||
private:
|
||||
QPalette nativePalette;
|
||||
QFont defaultAppFont;
|
||||
QSettings s;
|
||||
QHash<QString, QColor> m_interfaceChrome;
|
||||
static Configuration *mPtr;
|
||||
|
||||
#ifdef IAITO_ENABLE_KSYNTAXHIGHLIGHTING
|
||||
KSyntaxHighlighting::Repository *kSyntaxHighlightingRepository;
|
||||
#endif
|
||||
bool outputRedirectEnabled = true;
|
||||
// True while the most recent colorsUpdated signal represents only an
|
||||
// interface palette refresh (no radare2 color theme change). Heavy slots
|
||||
// can use isInterfacePaletteOnlyUpdate() to skip expensive content reloads.
|
||||
bool paletteOnlyUpdate = false;
|
||||
// Reentrancy guard to ignore palette change notifications triggered by us.
|
||||
bool applyingTheme = false;
|
||||
|
||||
Configuration();
|
||||
// Colors
|
||||
void loadBaseThemeNative();
|
||||
void loadBaseThemeDark();
|
||||
void loadNativeStylesheet();
|
||||
void loadLightStylesheet();
|
||||
void loadDarkStylesheet();
|
||||
void loadMidnightStylesheet();
|
||||
Theme nativeEngineTheme();
|
||||
bool loadUserStylesheet(const QString &name);
|
||||
|
||||
void onSystemColorSchemeChanged();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
// Asm Options
|
||||
void applySavedAsmOptions();
|
||||
|
||||
public:
|
||||
static const QList<IaitoInterfaceTheme>& cutterInterfaceThemesList();
|
||||
static const QList<IaitoInterfaceTheme> &iaitoInterfaceThemesList();
|
||||
static QString userThemesDir();
|
||||
static bool isCustomInterfaceTheme(const QString &name);
|
||||
static bool interfaceThemeIsDark(const QString &name);
|
||||
static bool isValidThemeName(const QString &name);
|
||||
static const QStringList &interfaceThemeVariableKeys();
|
||||
static QHash<QString, QColor> defaultInterfaceThemeVariables();
|
||||
static QHash<QString, QColor> loadInterfaceThemeVariables(const QString &name);
|
||||
static void saveInterfaceThemeVariables(
|
||||
const QString &name, const QHash<QString, QColor> &vars, bool dark);
|
||||
void applyInterfaceVariables(const QHash<QString, QColor> &vars, bool dark);
|
||||
void loadEngineTheme(const Theme &theme);
|
||||
static const QHash<QString, ColorFlags> relevantThemes;
|
||||
static const QHash<QString, QHash<ColorFlags, QColor>> cutterOptionColors;
|
||||
static const QHash<QString, QHash<ColorFlags, QColor>> iaitoOptionColors;
|
||||
|
||||
// Functions
|
||||
static Configuration *instance();
|
||||
@@ -67,10 +95,6 @@ public:
|
||||
|
||||
void resetAll();
|
||||
|
||||
// Auto update
|
||||
bool getAutoUpdateEnabled() const;
|
||||
void setAutoUpdateEnabled(bool au);
|
||||
|
||||
// Languages
|
||||
QLocale getCurrLocale() const;
|
||||
void setLocale(const QLocale &l);
|
||||
@@ -83,28 +107,47 @@ public:
|
||||
* @brief Gets the configured font set by the font selection box
|
||||
* @return the configured font
|
||||
*/
|
||||
const QFont getBaseFont() const;
|
||||
const QFont getBaseFont() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the configured font with the point size adjusted by the configured zoom
|
||||
* level (minimum of 10%)
|
||||
* @brief Gets the configured font with the point size adjusted by the
|
||||
* configured zoom level (minimum of 10%)
|
||||
* @return the configured font size adjusted by zoom level
|
||||
*/
|
||||
const QFont getFont() const;
|
||||
|
||||
/**
|
||||
* @brief Gets a smaller variant of the configured font, suitable for
|
||||
* list/tree views. Uses 85% of the normal font size.
|
||||
* @return the configured font at reduced size, adjusted by zoom level
|
||||
* unless zoomed is false
|
||||
*/
|
||||
const QFont getSmallFont(bool zoomed = true) const;
|
||||
void setFont(const QFont &font);
|
||||
qreal getZoomFactor() const;
|
||||
void setZoomFactor(qreal zoom);
|
||||
VisualNavbarLocation getVisualNavbarLocation() const;
|
||||
void setVisualNavbarLocation(VisualNavbarLocation location);
|
||||
int getVisualNavbarThickness() const;
|
||||
void setVisualNavbarThickness(int thickness);
|
||||
int getVisualNavbarResolution() const;
|
||||
void setVisualNavbarResolution(int divisor);
|
||||
MemoryScrollBarMode getMemoryScrollBarMode() const;
|
||||
void setMemoryScrollBarMode(MemoryScrollBarMode mode);
|
||||
|
||||
// Colors
|
||||
bool windowColorIsDark();
|
||||
static bool nativeWindowIsDark();
|
||||
/**
|
||||
* @brief Whether the current colorsUpdated signal only represents an
|
||||
* interface palette change, in which case widgets can skip costly
|
||||
* content reloads and just repaint.
|
||||
*/
|
||||
bool isInterfacePaletteOnlyUpdate() const { return paletteOnlyUpdate; }
|
||||
void setLastThemeOf(const IaitoInterfaceTheme &currInterfaceTheme, const QString &theme);
|
||||
QString getLastThemeOf(const IaitoInterfaceTheme &currInterfaceTheme) const;
|
||||
void setInterfaceTheme(int theme);
|
||||
int getInterfaceTheme()
|
||||
{
|
||||
return s.value("ColorPalette", 0).toInt();
|
||||
}
|
||||
int getInterfaceTheme() { return s.value("ColorPalette", 0).toInt(); }
|
||||
|
||||
const IaitoInterfaceTheme *getCurrentTheme();
|
||||
|
||||
@@ -120,6 +163,9 @@ public:
|
||||
QString getRecentFolder();
|
||||
void setRecentFolder(const QString &dir);
|
||||
|
||||
QString getSha256LookupBaseUrl() const;
|
||||
void setSha256LookupBaseUrl(const QString &url);
|
||||
|
||||
void setNewFileLastClicked(int lastClicked);
|
||||
int getNewFileLastClicked();
|
||||
|
||||
@@ -128,11 +174,16 @@ public:
|
||||
|
||||
// Asm Options
|
||||
void resetToDefaultAsmOptions();
|
||||
bool getDisassemblyJumpLineAdaptiveSpacingEnabled() const;
|
||||
void setDisassemblyJumpLineAdaptiveSpacingEnabled(bool enabled);
|
||||
int getDisassemblyJumpLineSpacing() const;
|
||||
void setDisassemblyJumpLineSpacing(int spacing);
|
||||
|
||||
QString getColorTheme() const { return s.value("theme", "iaito").toString(); }
|
||||
QString getColorTheme() const { return s.value("theme", "iaito").toString(); }
|
||||
void setColorTheme(const QString &theme);
|
||||
/**
|
||||
* @brief Change current color theme if it doesn't much native theme's darkness.
|
||||
* @brief Change current color theme if it doesn't much native theme's
|
||||
* darkness.
|
||||
*/
|
||||
void adjustColorThemeDarkness();
|
||||
int colorThemeDarkness(const QString &colorTheme) const;
|
||||
@@ -141,7 +192,8 @@ public:
|
||||
const QColor getColor(const QString &name) const;
|
||||
|
||||
/**
|
||||
* @brief Get the value of a config var either from r2 or settings, depending on the key.
|
||||
* @brief Get the value of a config var either from r2 or settings,
|
||||
* depending on the key.
|
||||
*/
|
||||
QVariant getConfigVar(const QString &key);
|
||||
bool getConfigBool(const QString &key);
|
||||
@@ -149,13 +201,29 @@ public:
|
||||
QString getConfigString(const QString &key);
|
||||
|
||||
/**
|
||||
* @brief Set the value of a config var either to r2 or settings, depending on the key.
|
||||
* @brief Set the value of a config var either to r2 or settings, depending
|
||||
* on the key.
|
||||
*/
|
||||
void setConfig(const QString &key, const QVariant &value);
|
||||
bool isFirstExecution();
|
||||
|
||||
/**
|
||||
* @return id of the last selected decompiler (see IaitoCore::getDecompilerById)
|
||||
* @brief Numeric base used to render addresses (asm.addr.base).
|
||||
* @return the current base value (e.g. "8", "10", "16", "36").
|
||||
*/
|
||||
QString getAddrBase();
|
||||
void setAddrBase(const QString &base);
|
||||
/**
|
||||
* @brief Ordered (value, label) pairs for the available address bases.
|
||||
*
|
||||
* Queried from radare2 via "e asm.addr.base=?", falling back to the
|
||||
* known set (8/10/16/36) when the option is unavailable.
|
||||
*/
|
||||
static QList<QPair<QString, QString>> getAddrBaseOptions();
|
||||
|
||||
/**
|
||||
* @return id of the last selected decompiler (see
|
||||
* IaitoCore::getDecompilerById)
|
||||
*/
|
||||
QString getSelectedDecompiler();
|
||||
void setSelectedDecompiler(const QString &id);
|
||||
@@ -163,21 +231,24 @@ public:
|
||||
bool getDecompilerAutoRefreshEnabled();
|
||||
void setDecompilerAutoRefreshEnabled(bool enabled);
|
||||
|
||||
void enableDecompilerAnnotationHighlighter(bool useDecompilerHighlighter);
|
||||
bool isDecompilerAnnotationHighlighterEnabled();
|
||||
// Decompiler execution mode
|
||||
bool getDecompilerRunInBackground();
|
||||
void setDecompilerRunInBackground(bool enabled);
|
||||
bool getDecompilerShowAddresses();
|
||||
void setDecompilerShowAddresses(bool enabled);
|
||||
bool getDecompilerShowDisassembly();
|
||||
void setDecompilerShowDisassembly(bool enabled);
|
||||
|
||||
bool getAddressRangeSelectionSyncEnabled() const;
|
||||
void setAddressRangeSelectionSyncEnabled(bool enabled);
|
||||
|
||||
// Graph
|
||||
int getGraphBlockMaxChars() const
|
||||
{
|
||||
return s.value("graph.maxcols", 100).toInt();
|
||||
}
|
||||
void setGraphBlockMaxChars(int ch)
|
||||
{
|
||||
s.setValue("graph.maxcols", ch);
|
||||
}
|
||||
int getGraphBlockMaxChars() const { return s.value("graph.maxcols", 100).toInt(); }
|
||||
void setGraphBlockMaxChars(int ch) { s.setValue("graph.maxcols", ch); }
|
||||
|
||||
/**
|
||||
* @brief Getters and setters for the transaparent option state and scale factor for bitmap graph exports.
|
||||
* @brief Getters and setters for the transaparent option state and scale
|
||||
* factor for bitmap graph exports.
|
||||
*/
|
||||
bool getBitmapTransparentState();
|
||||
double getBitmapExportScaleFactor();
|
||||
@@ -188,21 +259,27 @@ public:
|
||||
QPoint getGraphEdgeSpacing();
|
||||
|
||||
/**
|
||||
* @brief Gets whether the entry offset of each block has to be displayed or not
|
||||
* @brief Gets whether the entry offset of each block has to be displayed or
|
||||
* not
|
||||
* @return true if the entry offset has to be displayed, false otherwise
|
||||
*/
|
||||
bool getGraphBlockEntryOffset();
|
||||
|
||||
/**
|
||||
* @brief Enable or disable the displaying of the entry offset in each graph block
|
||||
* @param enabled set this to true for displaying the entry offset in each graph block, false otherwise
|
||||
* @brief Enable or disable the displaying of the entry offset in each graph
|
||||
* block
|
||||
* @param enabled set this to true for displaying the entry offset in each
|
||||
* graph block, false otherwise
|
||||
*/
|
||||
void setGraphBlockEntryOffset(bool enabled);
|
||||
|
||||
bool getGraphBlockShadow();
|
||||
void setGraphBlockShadow(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable Iaito output redirection.
|
||||
* Output redirection state can only be changed early during Iaito initialization.
|
||||
* Changing it later will have no effect
|
||||
* Output redirection state can only be changed early during Iaito
|
||||
* initialization. Changing it later will have no effect
|
||||
* @param enabled set this to false for disabling output redirection
|
||||
*/
|
||||
void setOutputRedirectionEnabled(bool enabled);
|
||||
@@ -213,7 +290,18 @@ public slots:
|
||||
signals:
|
||||
void fontsUpdated();
|
||||
void colorsUpdated();
|
||||
/**
|
||||
* @brief Emitted in addition to colorsUpdated when only the interface
|
||||
* palette changed (no radare2 color theme switch). Listeners can use
|
||||
* this as a lightweight hint to repaint without re-fetching content.
|
||||
*/
|
||||
void interfacePaletteUpdated();
|
||||
void interfaceThemeChanged();
|
||||
void visualNavbarLocationChanged(VisualNavbarLocation location);
|
||||
void visualNavbarThicknessChanged(int thickness);
|
||||
void visualNavbarResolutionChanged(int divisor);
|
||||
void memoryScrollBarModeChanged(MemoryScrollBarMode mode);
|
||||
void addressRangeSelectionSyncEnabledChanged(bool enabled);
|
||||
#ifdef IAITO_ENABLE_KSYNTAXHIGHLIGHTING
|
||||
void kSyntaxHighlightingThemeChanged();
|
||||
#endif
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
#include "CrashHandler.h"
|
||||
#include "BugReporting.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QFileDialog>
|
||||
#include <QStandardPaths>
|
||||
#include <QTime>
|
||||
|
||||
#ifdef IAITO_ENABLE_CRASH_REPORTS
|
||||
|
||||
#include <QApplication>
|
||||
#include <QString>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QMap>
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
|
||||
#if defined (Q_OS_LINUX)
|
||||
#if defined(Q_OS_LINUX)
|
||||
#include "client/linux/handler/exception_handler.h"
|
||||
#elif defined (Q_OS_WIN32)
|
||||
#elif defined(Q_OS_WIN32)
|
||||
#include "client/windows/handler/exception_handler.h"
|
||||
#elif defined (Q_OS_MACOS)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
#include "client/mac/handler/exception_handler.h"
|
||||
#endif // Q_OS
|
||||
|
||||
@@ -34,38 +34,42 @@ static void finishCrashHandler()
|
||||
#ifdef Q_OS_WIN32
|
||||
// Called if crash dump was successfully created
|
||||
// Saves path to file
|
||||
bool callback(const wchar_t *_dump_dir,
|
||||
const wchar_t *_minidump_id,
|
||||
void *context, EXCEPTION_POINTERS *exinfo,
|
||||
MDRawAssertionInfo *assertion,
|
||||
bool success)
|
||||
bool callback(
|
||||
const wchar_t *_dump_dir,
|
||||
const wchar_t *_minidump_id,
|
||||
void *context,
|
||||
EXCEPTION_POINTERS *exinfo,
|
||||
MDRawAssertionInfo *assertion,
|
||||
bool success)
|
||||
{
|
||||
const QDir dir = QString::fromWCharArray(_dump_dir);
|
||||
const QString id = QString::fromWCharArray(_minidump_id);
|
||||
QProcess::startDetached(QCoreApplication::applicationFilePath(),
|
||||
{ "--start-crash-handler", dir.filePath(id + ".dmp") });
|
||||
QProcess::startDetached(
|
||||
QCoreApplication::applicationFilePath(),
|
||||
{"--start-crash-handler", dir.filePath(id + ".dmp")});
|
||||
_exit(1);
|
||||
return true;
|
||||
}
|
||||
#elif defined (Q_OS_LINUX)
|
||||
#elif defined(Q_OS_LINUX)
|
||||
// Called if crash dump was successfully created
|
||||
// Saves path to file
|
||||
bool callback(const google_breakpad::MinidumpDescriptor &md, void *context, bool b)
|
||||
{
|
||||
QProcess::startDetached(QCoreApplication::applicationFilePath(),
|
||||
{ "--start-crash-handler", md.path() });
|
||||
QProcess::startDetached(
|
||||
QCoreApplication::applicationFilePath(), {"--start-crash-handler", md.path()});
|
||||
_exit(1);
|
||||
return true;
|
||||
}
|
||||
#elif defined (Q_OS_MACOS)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
// Called if crash dump was successfully created
|
||||
// Saves path to file
|
||||
bool callback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded)
|
||||
{
|
||||
const QDir dir = QString::fromUtf8(dump_dir);
|
||||
const QString id = QString::fromUtf8(minidump_id);
|
||||
QProcess::startDetached(QCoreApplication::applicationFilePath(),
|
||||
{ "--start-crash-handler", dir.filePath(id + ".dmp") });
|
||||
QProcess::startDetached(
|
||||
QCoreApplication::applicationFilePath(),
|
||||
{"--start-crash-handler", dir.filePath(id + ".dmp")});
|
||||
_exit(1);
|
||||
return true;
|
||||
}
|
||||
@@ -79,49 +83,39 @@ void initCrashHandler()
|
||||
// Here will be placed crash dump at the first place
|
||||
// and then moved if needed
|
||||
|
||||
#if defined (Q_OS_LINUX)
|
||||
static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString();
|
||||
exceptionHandler = new google_breakpad::ExceptionHandler(google_breakpad::MinidumpDescriptor(tmpLocation),
|
||||
nullptr,
|
||||
callback,
|
||||
nullptr,
|
||||
true,
|
||||
-1);
|
||||
#elif defined (Q_OS_MACOS)
|
||||
static std::string tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString();
|
||||
exceptionHandler = new google_breakpad::ExceptionHandler(tmpLocation,
|
||||
nullptr,
|
||||
callback,
|
||||
nullptr,
|
||||
true,
|
||||
nullptr);
|
||||
#if defined(Q_OS_LINUX)
|
||||
static std::string tmpLocation
|
||||
= QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString();
|
||||
exceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
google_breakpad::MinidumpDescriptor(tmpLocation), nullptr, callback, nullptr, true, -1);
|
||||
#elif defined(Q_OS_MACOS)
|
||||
static std::string tmpLocation
|
||||
= QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString();
|
||||
exceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
tmpLocation, nullptr, callback, nullptr, true, nullptr);
|
||||
#else
|
||||
static std::wstring tmpLocation = QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdWString();
|
||||
exceptionHandler = new google_breakpad::ExceptionHandler(tmpLocation,
|
||||
nullptr,
|
||||
callback,
|
||||
nullptr,
|
||||
google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||
static std::wstring tmpLocation
|
||||
= QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdWString();
|
||||
exceptionHandler = new google_breakpad::ExceptionHandler(
|
||||
tmpLocation, nullptr, callback, nullptr, google_breakpad::ExceptionHandler::HANDLER_ALL);
|
||||
#endif
|
||||
atexit(finishCrashHandler);
|
||||
}
|
||||
|
||||
#else // IAITO_ENABLE_CRASH_REPORTS
|
||||
|
||||
void initCrashHandler()
|
||||
{
|
||||
|
||||
}
|
||||
void initCrashHandler() {}
|
||||
|
||||
#endif // IAITO_ENABLE_CRASH_REPORTS
|
||||
|
||||
|
||||
void showCrashDialog(const QString &dumpFile)
|
||||
{
|
||||
QMessageBox mb;
|
||||
mb.setWindowTitle(QObject::tr("Crash"));
|
||||
mb.setText(QObject::tr("Iaito received a signal it can't handle and will close.<br/>"
|
||||
"Would you like to create a crash dump for a bug report?"));
|
||||
mb.setText(
|
||||
QObject::tr(
|
||||
"Iaito received a signal it can't handle and will close.<br/>"
|
||||
"Would you like to create a crash dump for a bug report?"));
|
||||
mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
mb.button(QMessageBox::Yes)->setText(QObject::tr("Create a Crash Dump"));
|
||||
mb.button(QMessageBox::No)->setText(QObject::tr("Quit"));
|
||||
@@ -137,34 +131,38 @@ void showCrashDialog(const QString &dumpFile)
|
||||
if (placementFailCounter == 4) {
|
||||
break;
|
||||
}
|
||||
dumpSaveFileName = QFileDialog::getSaveFileName(nullptr,
|
||||
QObject::tr("Choose a directory to save the crash dump in"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) +
|
||||
QDir::separator() +
|
||||
"Iaito_crash_dump_"
|
||||
+ QDate::currentDate().toString("dd.MM.yy") + "_"
|
||||
+ QTime::currentTime().toString("HH.mm.ss") + ".dmp",
|
||||
QObject::tr("Minidump (*.dmp)"));
|
||||
dumpSaveFileName = QFileDialog::getSaveFileName(
|
||||
nullptr,
|
||||
QObject::tr("Choose a directory to save the crash dump in"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator()
|
||||
+ "Iaito_crash_dump_" + QDate::currentDate().toString("dd.MM.yy") + "_"
|
||||
+ QTime::currentTime().toString("HH.mm.ss") + ".dmp",
|
||||
QObject::tr("Minidump (*.dmp)"));
|
||||
|
||||
if (dumpSaveFileName.isEmpty()) {
|
||||
QFile(dumpFile).remove();
|
||||
return;
|
||||
}
|
||||
if (QFile::rename(dumpFile, dumpSaveFileName)) {
|
||||
ok = true;
|
||||
break;
|
||||
}
|
||||
QMessageBox::critical(nullptr,
|
||||
QObject::tr("Save Crash Dump"),
|
||||
QObject::tr("Failed to write to %1.<br/>"
|
||||
"Please make sure you have access to that directory "
|
||||
"and try again.").arg(QFileInfo(dumpSaveFileName).dir().path()));
|
||||
QMessageBox::critical(
|
||||
nullptr,
|
||||
QObject::tr("Save Crash Dump"),
|
||||
QObject::tr(
|
||||
"Failed to write to %1.<br/>"
|
||||
"Please make sure you have access to that directory "
|
||||
"and try again.")
|
||||
.arg(QFileInfo(dumpSaveFileName).dir().path()));
|
||||
} while (true);
|
||||
|
||||
if (ok) {
|
||||
QMessageBox info;
|
||||
info.setWindowTitle(QObject::tr("Success"));
|
||||
info.setText(QObject::tr("<a href=\"%1\">Crash dump</a> was successfully created.")
|
||||
.arg(QFileInfo(dumpSaveFileName).dir().path()));
|
||||
info.setText(
|
||||
QObject::tr("<a href=\"%1\">Crash dump</a> was successfully created.")
|
||||
.arg(QFileInfo(dumpSaveFileName).dir().path()));
|
||||
info.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
info.button(QMessageBox::Yes)->setText(QObject::tr("Open an Issue"));
|
||||
@@ -176,9 +174,11 @@ void showCrashDialog(const QString &dumpFile)
|
||||
openIssue();
|
||||
}
|
||||
} else {
|
||||
QMessageBox::critical(nullptr,
|
||||
QObject::tr("Error"),
|
||||
QObject::tr("Error occurred during crash dump creation."));
|
||||
QFile(dumpFile).remove();
|
||||
QMessageBox::critical(
|
||||
nullptr,
|
||||
QObject::tr("Error"),
|
||||
QObject::tr("Error occurred during crash dump creation."));
|
||||
}
|
||||
} else {
|
||||
QFile f(dumpFile);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* If IAITO_ENABLE_CRASH_REPORTS is true, initializes
|
||||
* crash handling and reporting, otherwise does nothing.
|
||||
*/
|
||||
*/
|
||||
void initCrashHandler();
|
||||
|
||||
void showCrashDialog(const QString &dumpFile);
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
#include "DataAnalysis.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace DataAnalysis {
|
||||
|
||||
Range sizedRange(RVA start, RVA size)
|
||||
{
|
||||
return {start, start + qMin(size, RVA_MAX - start)};
|
||||
}
|
||||
|
||||
Range intersect(Range a, Range b)
|
||||
{
|
||||
const RVA start = qMax(a.start, b.start);
|
||||
return {start, qMax(start, qMin(a.end, b.end))};
|
||||
}
|
||||
|
||||
Range bucket(Range range, int index, int count)
|
||||
{
|
||||
if (!range.valid() || count <= 0 || index < 0 || index >= count) {
|
||||
return {};
|
||||
}
|
||||
// Avoid both floating point address rounding and multiplication overflow.
|
||||
auto boundary = [range, count](RVA i) {
|
||||
return range.start + (range.size() / count) * i + (range.size() % count) * i / count;
|
||||
};
|
||||
return {boundary(index), boundary(index + 1)};
|
||||
}
|
||||
|
||||
Range centered(Range domain, RVA address, RVA size)
|
||||
{
|
||||
if (!domain.valid()) {
|
||||
return {};
|
||||
}
|
||||
size = qBound<RVA>(1, size, domain.size());
|
||||
address = qBound(domain.start, address, domain.end - 1);
|
||||
const RVA start = address - qMin(address - domain.start, size / 2);
|
||||
const RVA clamped = qMin(start, domain.end - size);
|
||||
return {clamped, clamped + size};
|
||||
}
|
||||
|
||||
QVector<Range> mergeRanges(QVector<Range> ranges)
|
||||
{
|
||||
std::sort(ranges.begin(), ranges.end(), [](Range a, Range b) { return a.start < b.start; });
|
||||
QVector<Range> result;
|
||||
for (auto range : ranges) {
|
||||
if (!range.valid()) {
|
||||
continue;
|
||||
}
|
||||
if (result.isEmpty() || result.last().end < range.start) {
|
||||
result.append(range);
|
||||
} else {
|
||||
result.last().end = qMax(result.last().end, range.end);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Sample sample(
|
||||
Range range,
|
||||
const QVector<Range> &readable,
|
||||
const std::function<QByteArray(RVA, int)> &read,
|
||||
int budget)
|
||||
{
|
||||
Sample result;
|
||||
result.range = range;
|
||||
if (!range.valid() || budget <= 0) {
|
||||
return result;
|
||||
}
|
||||
QVector<Range> spans;
|
||||
for (auto candidate : readable) {
|
||||
const Range span = intersect(range, candidate);
|
||||
if (span.valid()) {
|
||||
spans.append(span);
|
||||
result.covered += span.size();
|
||||
}
|
||||
}
|
||||
std::array<int, 256> histogram{};
|
||||
RVA remaining = result.covered;
|
||||
for (auto span : spans) {
|
||||
if (budget <= 0) {
|
||||
break;
|
||||
}
|
||||
// Allocate the budget proportionally among disjoint readable spans.
|
||||
const int share = qMax(1, int((long double) span.size() / remaining * budget));
|
||||
const int length = int(qMin<RVA>(span.size(), qMin(budget, share)));
|
||||
const RVA address = span.start + (span.size() - length) / 2;
|
||||
const QByteArray data = read(address, length).left(length);
|
||||
for (unsigned char byte : data) {
|
||||
++histogram[byte];
|
||||
}
|
||||
result.bytes += data.size();
|
||||
budget -= length;
|
||||
remaining -= span.size();
|
||||
}
|
||||
if (!result.bytes) {
|
||||
return result;
|
||||
}
|
||||
auto &v = result.values;
|
||||
for (int byte = 0; byte < 256; ++byte) {
|
||||
const int n = histogram[byte];
|
||||
if (!n) {
|
||||
continue;
|
||||
}
|
||||
const double p = double(n) / result.bytes;
|
||||
v[Entropy] -= p * std::log2(p) / 8.0;
|
||||
v[Printable] += (byte >= 32 && byte <= 126) ? p : 0;
|
||||
v[Zero] += byte == 0 ? p : 0;
|
||||
v[FF] += byte == 255 ? p : 0;
|
||||
v[Unique] += 1.0 / 256;
|
||||
v[Mean] += p * byte / 255;
|
||||
v[Alpha] += ((byte >= 'a' && byte <= 'z') || (byte >= 'A' && byte <= 'Z')) ? p : 0;
|
||||
v[Digit] += (byte >= '0' && byte <= '9') ? p : 0;
|
||||
v[Space] += (byte == ' ' || (byte >= 9 && byte <= 13)) ? p : 0;
|
||||
v[Control] += (byte < 32 || byte == 127) ? p : 0;
|
||||
v[High] += byte >= 128 ? p : 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace DataAnalysis
|
||||