Compare commits

...

490 Commits

Author SHA1 Message Date
WerWolv
dc8245ce4c build: Bumped version to 1.29.0 2023-05-21 10:44:41 +02:00
WerWolv
1b88b3704d feat: Allow layouts to be deleted again 2023-05-21 10:43:35 +02:00
WerWolv
6dbaac4283 impr: Make sure hex editor popups have their input focused 2023-05-21 10:35:14 +02:00
WerWolv
180a27fdc9 fix: Local keybindings not working correctly 2023-05-21 10:28:55 +02:00
WerWolv
c02465b892 fix: Byte type and Entropy graph being shifted 2023-05-21 10:23:33 +02:00
WerWolv
f503a89f98 fix: Typo in IEEE754 tool 2023-05-20 21:49:45 +02:00
WerWolv
f94e5488d4 fix: Mouse cursor not adjusting anymore properly 2023-05-20 21:36:15 +02:00
WerWolv
87621e9337 impr: Disable some Import... options when the provider isn't writable 2023-05-20 21:23:15 +02:00
WerWolv
3219ba68de impr: Better layout of ImHex subtitle on welcome screen 2023-05-20 21:20:32 +02:00
WerWolv
5d608603cb fix: Selection in diff view being retained 2023-05-20 21:13:40 +02:00
WerWolv
7336c8dddc fix: Cursor types on Windows sometimes getting stuck 2023-05-20 21:10:12 +02:00
WerWolv
c91e3875d4 build: Updated libwolv 2023-05-20 19:27:00 +02:00
WerWolv
0181325b64 build: Updated libwolv 2023-05-20 18:10:26 +02:00
WerWolv
11f55a7561 fix: File handles not being closed correctly 2023-05-20 18:07:15 +02:00
WerWolv
9bb3a92e12 build: Updated libwolv 2023-05-20 15:47:21 +02:00
KOLANICH
3e9ba8c636 build: Add EOLs to the end of all "own" CMakeLists.txt files (#1093)
Text editors on Unix-like OSes add them automatically and it is usually
considered to be a good practice.
2023-05-20 13:38:24 +02:00
KOLANICH
4faebf435c impr: Remove an unused std::mutex in TaskManager::runner (#1088) 2023-05-20 13:38:12 +02:00
KOLANICH
749823e044 build: Move -s additional compiler flags into linker flags, and enable it only when gcc/clang are used. (#1087)
Compiler when compiling doesn't use them in those cases and emit a
warning, which is turned into an error by `-Werror`. Unfortunately,
CPack doesn't expose the logic it uses for stripping binaries.
2023-05-20 13:37:57 +02:00
KOLANICH
608c9e2e7a fix: WASM disassembler not being available in Capstone < 5 (#1086)
This fixes build on Debian with Capstone from packages.
2023-05-20 13:37:45 +02:00
WerWolv
96ee544538 build: Updated libwolv 2023-05-20 13:31:41 +02:00
WerWolv
7ea7c531e2 fix: Logs not being written to disk on Windows 2023-05-20 13:10:35 +02:00
WerWolv
969a37877a fix: Crash on exit 2023-05-20 13:10:24 +02:00
WerWolv
3cb8e37182 fix: Broken file open logic
Closes #1090
2023-05-20 11:52:24 +02:00
paxcut
3e4c4430d5 feat: Greatly improved the IEEE754 tool (#1047)
I just realized one feature request existed about this tool and have
added a comment to it referring this pr. Errors and additions are
described in the fork commit already. I'm not sure if I should repeat
them here again. I have tested the changes thoroughly, but it is always
possible some fringe case was not tested and is incorrect. The tests
were done using the many similar online calculators for IEEE 754
floating point formats.
IEEE 745 floating point tool redesign modeled after 'float toy' web app
(http://evanw.github.io/float-toy/)

Streamlined output using colors and compact layout which can be further
simplified.
Chosen display mode (detailed or simplified) is automatically saved and
set on new sessions.
Edit the binary bits, the integer hexadecimal or the floating point
decimal values and the entire app will update with the change.
Supports the main IEEE745 standard formats (half, single and double
precision) together with custom formats of size <= 64 bits.
Each format choice uses and displays the number of significant decimal
digits defined by the mantissa size.
Added labels to identify the location of each bit box inside the binary
representation.
Satisfies round trip / idempotent (reproducing) conversion property
Added theme colors, radio buttons for display mode and a clear button
that resets the tool.
Removed previously and incorrectly added locale translation to various
labels and languages
Attempted to adhere to code style formatting using existing code as
example.
An effort was made to use preferred variable types and functions from
std namespace when appropriate.
Attempted to document code using comments. 

Not implemented / left to complete at an later time

Arbitrary width and precision formats. 
Extended precision formats.
Shortest string property.
hexadecimal floating point display and conversions.
2023-05-19 21:18:38 +02:00
WerWolv
4ad66365d0 fix: Crash when saving patches
Fixes #1077
2023-05-19 20:01:42 +02:00
WerWolv
39276e123e patterns: Allow bitfield values to be edited 2023-05-19 19:56:55 +02:00
WerWolv
0f9434740f fix: Crash when deleting last environment variable in pattern editor 2023-05-19 17:15:37 +02:00
WerWolv
7ed153a47b patterns: Updated pattern language 2023-05-19 16:14:54 +02:00
WerWolv
c9d673ce40 patterns: Updated pattern language 2023-05-19 15:29:18 +02:00
WerWolv
0be610f1cd patterns: Updated pattern language 2023-05-18 23:20:10 +02:00
WerWolv
f75aa1f1b0 git: Fixed color of docs shield 2023-05-18 11:46:51 +02:00
Justus Garbe
5ef58cdf76 feat: Added bit and byte reverse and bit display data processor nodes (#1082)
#1081
2023-05-18 10:25:59 +02:00
WerWolv
511375feb5 patterns: Updated pattern language 2023-05-18 09:51:24 +02:00
WerWolv
8119929ece fix: Don't wait for services on exit 2023-05-16 14:59:14 +02:00
iTrooz
e1620966e5 feat: Keep only 10 latest logs on exit (#1079)
Co-authored-by: Nik <werwolv98@gmail.com>
2023-05-16 14:45:24 +02:00
WerWolv
a5b0a8614a impr: Automatically re-evaluate pattern when changing provider and code sync is on
Closes #1078
2023-05-16 14:45:04 +02:00
WerWolv
e28f2dfea1 fix: Only 5 patterns per byte being highlighted
Fixes #1076
2023-05-16 14:41:02 +02:00
WerWolv
0dcfeaefb3 fix: Build when git commit hash or branch is not available 2023-05-16 12:02:17 +02:00
WerWolv
3bd4a3ba8b impr: Better JSON error handling in many places 2023-05-16 11:33:00 +02:00
WerWolv
7e9b23de7d impr: Improve network interface error handling 2023-05-16 11:20:46 +02:00
WerWolv
a758676b0d fix: Change network interface port to 31337 2023-05-16 11:01:59 +02:00
WerWolv
636ed0095d feat: Added new imhex/capabilities network interface 2023-05-16 11:01:40 +02:00
WerWolv
14341d611d impr: Handle macOS Open with... correctly 2023-05-15 18:07:49 +02:00
WerWolv
07565eea63 build: Updated libwolv 2023-05-15 18:07:35 +02:00
WerWolv
c006062540 feat: Added basic network interface support 2023-05-15 11:30:24 +02:00
WerWolv
e685d65be8 fix: Scrolling not working correctly on welcome screen
Fixes #1071
2023-05-15 08:33:35 +02:00
WerWolv
ab67e274b2 fix: Hex editor editing value not updating correctly 2023-05-15 08:17:16 +02:00
WerWolv
7656fd7a4e patterns: Updated pattern language 2023-05-15 08:17:02 +02:00
WerWolv
60a2b30e91 fix: Another wrong include on macOS 2023-05-14 22:53:52 +02:00
WerWolv
7ec7e562d1 fix: Wrong editing values in hex editor in some circumstances 2023-05-14 22:52:47 +02:00
WerWolv
c50d52d0a6 fix: Crash when reading from modified bytes 2023-05-14 22:46:19 +02:00
WerWolv
2b765617ce impr: Disallow saving pattern files if they're empty 2023-05-14 22:24:16 +02:00
WerWolv
79cdf51588 fix: Wrong include on macOS 2023-05-14 22:23:05 +02:00
WerWolv
7b048d9b96 fix: Compile on macOS _again_ 2023-05-14 22:03:04 +02:00
WerWolv
d96fc6d41b fix: Compilation on macOS 2023-05-14 21:50:58 +02:00
WerWolv
610f109e2a fix: Crash when too many entries are being logged at once 2023-05-14 21:39:18 +02:00
WerWolv
609afebc55 fix: Updated build script 2023-05-14 20:20:40 +02:00
WerWolv
3bd9ab6349 fix: Hopefully open files now on macOS 2023-05-14 20:20:22 +02:00
WerWolv
5027f36d95 fix: Open with crashing on macOS
#1070
2023-05-14 18:35:35 +02:00
WerWolv
a5498995ff impr: Hopefully allow macOS to open any file type
#1070
2023-05-14 09:58:15 +02:00
WerWolv
f40b5d9811 fix: Search button in numeric find option being active by default 2023-05-13 17:51:16 +02:00
WerWolv
d00fae03a9 fix: Diff table not being cleared when closing providers 2023-05-13 17:50:33 +02:00
WerWolv
3c4e1b2f27 impr: Various cleanup 2023-05-13 17:50:16 +02:00
WerWolv
6e5d6810e7 build: Disable assertions in release builds 2023-05-13 17:49:53 +02:00
WerWolv
4afd5a7905 patterns: Updated pattern language
#1069
2023-05-13 17:21:44 +02:00
WerWolv
6709baa710 patterns: Updated pattern language 2023-05-13 15:43:37 +02:00
WerWolv
aa1bf0b764 impr: Make about page resizable 2023-05-13 12:26:13 +02:00
WerWolv
a7327290ea fix: Only save custom encoding to project file when necessary 2023-05-13 11:17:27 +02:00
WerWolv
857e90a37b fix: ImHex freezing when evaluating patterns 2023-05-13 11:12:38 +02:00
WerWolv
aaeebd3fe9 fix: Various pattern execution race conditions 2023-05-12 15:46:13 +02:00
WerWolv
0a7a190b04 impr: Added tooltips to pattern data view when name or value is too long 2023-05-12 08:49:08 +02:00
WerWolv
21d922113d impr: Make sure to clear selections when all providers are deleted 2023-05-12 08:38:52 +02:00
WerWolv
b0876e1c35 impr: Move some options into a new Extras menu 2023-05-12 08:38:32 +02:00
WerWolv
18bc5de169 fix: Copy-as options not being disabled correctly 2023-05-12 08:38:07 +02:00
WerWolv
0321743f1e fix: Missing save layout localization keys 2023-05-12 08:37:43 +02:00
WerWolv
f2af90fe06 fix: Help hover icon issues 2023-05-11 23:56:51 +02:00
WerWolv
2f511ec4fa impr: Improve frame cap handling 2023-05-11 23:22:06 +02:00
WerWolv
0649e0dcd3 impr: Clean up old layout stuff 2023-05-11 23:21:52 +02:00
WerWolv
0b21e30e44 fix: White border around maximized window on WIndows 2023-05-11 20:49:07 +02:00
WerWolv
ceeaca1a4b feat: Added layout manager to save and restore custom layouts 2023-05-11 18:44:50 +02:00
WerWolv
2da89f4b9b fix: Position of restore layout button being wrong with different scalings 2023-05-11 18:44:33 +02:00
WerWolv
49371398bc fix: Resizing on windows still being janky 2023-05-11 18:43:19 +02:00
iTrooz
2e73d74cea impr: Open .hexproj files as projects when opened though the Open File option (#1061) 2023-05-11 12:38:22 +02:00
WerWolv
688471fd61 build: Updated libfmt to 10.0 2023-05-11 12:06:58 +02:00
WerWolv
ea482ff0f5 fix: Crash when closing providers too quickly 2023-05-11 12:01:06 +02:00
WerWolv
5c9d0e29c2 fix: Left/Right resizing not working correctly on Windows 2023-05-11 12:00:56 +02:00
WerWolv
8f07f0f8ae impr: Better look and feel of the welcome screen close button 2023-05-11 12:00:45 +02:00
WerWolv
4f17a96707 build: Updated libwolv 2023-05-11 10:04:09 +02:00
iTrooz
b0ab8698ec fix: Loading data processor nodes from project thowing errors (#1065)
This will correct the errors `cannot use operator[] with a string
argument with string[..]` when loading a project
2023-05-11 09:57:29 +02:00
WerWolv
ab41899cc2 build: Updated libwolv 2023-05-11 09:54:06 +02:00
WerWolv
50c3cf8272 build: Replace old interval tree in favour of custom libwolv one 2023-05-11 09:27:23 +02:00
WerWolv
1d2b8ac1f3 fix: Closing popups using Esc causing them to re-appear 2023-05-10 22:29:17 +02:00
WerWolv
0b29719fe9 patterns: Updated pattern language 2023-05-10 19:15:01 +02:00
WerWolv
5a6e5d2255 build: Switch to better interval tree implementation 2023-05-07 23:27:43 +02:00
WerWolv
82111617a4 patterns: Updated pattern language 2023-05-06 10:09:33 +02:00
WerWolv
0574387ee1 fix: Properly use absolute paths when compiling magic files 2023-05-06 10:09:23 +02:00
WerWolv
2d1381860d fix: Corrected build issues with GCC 13 2023-05-06 10:07:22 +02:00
classabbyamp
82f5900759 build: Added option to disable update checking (#1036)
This is aimed at use by linux distros, where package updates come from a
central location, and users shouldn't need to worry about updating ImHex
on their own. This disables parts of the ImHex UI that would not be
useful in that case.

Tested and confirmed that this works in both states of the of the
`-DIMHEX_DISABLE_UPDATE_CHECK` switch.
2023-05-05 22:03:45 +02:00
iTrooz
e44eb2aa8e impr: Added more documentation to libimhex (#1052)
This PR adds some documentation. It's actually pretty random, I followed
the function calls I was curious about and commented whenever I wasn't
sure/I thought it needed clarification

You might want to make sure to squash them, because the commits are kind
of a mess, I didn't went through the effort of interactive rebase
2023-05-05 22:02:18 +02:00
iTrooz
34e12e2515 feat: Added a button to restore default layout when there are no views open (#1053)
Co-authored-by: Nik <werwolv98@gmail.com>
2023-05-05 22:00:17 +02:00
iTrooz
980e4cad06 fix: Handle errors in Tar::readVector() (#1059) 2023-05-05 21:57:37 +02:00
WerWolv
5680b90549 fix: Project files failing to save when no custom encoding is loaded 2023-05-04 23:23:44 +02:00
WerWolv
bec655a8c6 impr: Added event logging in debug mode 2023-05-02 20:35:30 +02:00
WerWolv
0c8b3e31e7 fix: Dangerous function call popup not showing up 2023-05-02 20:34:37 +02:00
WerWolv
a33c7135d1 fix: Crash when closing some popups 2023-05-01 14:15:00 +02:00
iTrooz
13a3942f8f impr: Show an error message when ImHex can't open a file (#1050)
This PR does two correlated things:

- Show a generic error message (Failed to open provider) rather than a
file-specific message (Failed to open file) when a provider fails to
open
- Set the error to something more specific when opening a file fails
2023-04-30 18:37:22 +02:00
WerWolv
1bdc1d7241 build: Added CMakePresets.json file to make configuring/building easier 2023-04-30 11:53:51 +02:00
iTrooz
fe9026b68d build: Update my (iTrooz) email in PKGBUILD (#1049) 2023-04-28 18:01:30 +02:00
XorTroll
b0028b0e51 lang: Added Spanish translations (#1042)
This translates ImHex for the Spanish language

(made a new PR since I got a bit messed up on the other one, this was
faster to fix)
2023-04-21 17:44:36 +02:00
WerWolv
f54617e92f patterns: Updated pattern language 2023-04-21 11:02:12 +02:00
WerWolv
306690762c impr: Drastically improve file read speeds 2023-04-21 10:52:10 +02:00
WerWolv
58a0fe8109 patterns: Updated pattern language 2023-04-20 14:32:45 +02:00
WerWolv
1e39f4354f fix: Provider reader being broken 2023-04-20 13:46:44 +02:00
WerWolv
e1b12546da build: Updated dependencies 2023-04-20 10:48:17 +02:00
WerWolv
1b28bf1474 patterns: Updated pattern language
Fixes #1037
2023-04-20 10:41:27 +02:00
WerWolv
8245f3d4c9 build: Updated libwolv 2023-04-19 21:56:34 +02:00
Nik
5fc8e710a5 git: Added vulnearability report info file 2023-04-18 16:15:48 +02:00
Nik
b8636a8589 git: Added Code of Conduct 2023-04-18 16:11:41 +02:00
WerWolv
bb8b4afb85 patterns: Updated pattern language 2023-04-18 10:32:38 +02:00
WerWolv
d5b1ef7875 patterns: Updated pattern language 2023-04-18 10:17:37 +02:00
WerWolv
6c122e5fbe patterns: Updated to new API 2023-04-18 10:06:47 +02:00
WerWolv
7ae814f7fb fix: Various localization issues 2023-04-17 22:18:50 +02:00
WerWolv
bdc51dd8a5 patterns: Updated pattern language 2023-04-17 17:06:52 +02:00
WerWolv
04a5efc7a3 fix: Crash when evaluating patterns to quickly 2023-04-17 17:02:10 +02:00
WerWolv
99a736df27 impr: Replace horrible pattern extra data class with a more modular system 2023-04-17 16:18:48 +02:00
WerWolv
535aeb5e39 impr: Give access to a console in clion in debug mode 2023-04-17 16:06:06 +02:00
WerWolv
07bef10092 patterns: Updated pattern language 2023-04-17 09:22:21 +02:00
WerWolv
c32515bc44 impr: Clean up some more clang-tidy issues 2023-04-16 22:12:35 +02:00
WerWolv
1690cd2740 fix: Various issues with the new popup system 2023-04-16 21:34:29 +02:00
WerWolv
52925c99e8 impr: Default to monitor synchronized FPS limit 2023-04-13 17:12:40 +02:00
WerWolv
1367e9cebe build: Fixed Objective-C compiler flags 2023-04-13 17:07:34 +02:00
WerWolv
3e87022da1 fix: Provider undo stack not being handled correctly 2023-04-13 16:12:00 +02:00
WerWolv
143fe36d35 build: Fixed various build warnings 2023-04-13 16:11:39 +02:00
WerWolv
18d5fd5d3e fix: Commit link in about page not working correctly 2023-04-13 16:10:55 +02:00
WerWolv
2829bf2640 fix: New lines appearing in pattern editor when switching provider 2023-04-13 15:03:50 +02:00
WerWolv
ffafb05d3d fix: Providers with the same name not being selectable in diff view
Fixes #1034
2023-04-13 15:03:14 +02:00
WerWolv
cf72b5ec5c fix: Some shortcuts triggering twice 2023-04-12 19:50:03 +02:00
WerWolv
803b99f2a9 impr: Immensely improve provider read speeds 2023-04-12 19:21:48 +02:00
WerWolv
86b49f34d9 patterns: Updated pattern language
Fixes #1031
2023-04-12 17:18:46 +02:00
WerWolv
7e144b136b patterns: Updated pattern language
Fixes #1030
2023-04-12 16:03:58 +02:00
WerWolv
aa7c5422c0 fix: Make sure provider data is properly cleared when deleting provider 2023-04-11 15:26:18 +02:00
WerWolv
5512585cc5 fix: Make sure docs question request is always properly formatted 2023-04-10 23:05:44 +02:00
WerWolv
013eaae715 fix: Disable multi window support on Linux by default as it causes issues
Fixes #1026
2023-04-10 22:51:21 +02:00
WerWolv
349b5da810 fix: Prevent constants view from growing past the size of the screen
Fixes #1025
2023-04-10 21:30:27 +02:00
WerWolv
e7494be5e7 fix: Last line of patterns going missing in projects with multiple files
Fixes #1012
2023-04-10 16:50:23 +02:00
WerWolv
320629931c fix: Yet another popup centering issue 2023-04-10 14:10:35 +02:00
WerWolv
87d0aae608 feat: Added selection range radio button to various views
Closes #1024
2023-04-10 14:08:21 +02:00
WerWolv
391c8acfe4 impr: Added path tooltips to accept pattern popup 2023-04-10 01:46:55 +02:00
WerWolv
dc77d81e1b feat: Added documentation helper AI 2023-04-10 01:42:53 +02:00
WerWolv
00c9a92977 fix: Localization being broken in the content store 2023-04-10 01:42:28 +02:00
WerWolv
af4dd9f5b0 fix: Popup positioning being wrong 2023-04-09 23:24:48 +02:00
WerWolv
09f1b56964 fix: Popups not being centered correctly 2023-04-09 15:28:48 +02:00
WerWolv
f9a08f5c11 feat: Allow custom alignment to be used in binary sequence search 2023-04-09 15:28:31 +02:00
WerWolv
e79664256a patterns: Updated pattern language 2023-04-09 12:26:13 +02:00
WerWolv
70f3014390 fix: Some more popup rendering issues 2023-04-08 23:34:46 +02:00
WerWolv
b4d0f984a4 build: Updated libwolv 2023-04-08 21:13:19 +02:00
WerWolv
d4ad457af1 fix: Crash when closing provider that was used in view provider 2023-04-08 21:07:57 +02:00
WerWolv
cb5d197700 impr: Added tooltips to icon buttons in bookmarks view 2023-04-08 21:07:41 +02:00
WerWolv
78e66f8959 feat: Added non-ranged and aligned search to sequence and value finder 2023-04-08 20:59:33 +02:00
WerWolv
f562260e42 fix: Build error again 2023-04-08 12:30:38 +02:00
WerWolv
21f38974a8 impr: Use smart pointers to allocate Views 2023-04-08 12:08:45 +02:00
WerWolv
dfca7e923c feat: Make pins in data processor nodes more visible 2023-04-08 11:58:49 +02:00
WerWolv
6913598de4 fix: Build error 2023-04-08 11:58:12 +02:00
WerWolv
ac858b37ed fix: Main Menu items not being clickable at the outer most pixel
Closes #1020
2023-04-08 11:37:42 +02:00
WerWolv
80edaea392 impr: Update all of ImHex to the new popup system 2023-04-08 00:58:53 +02:00
WerWolv
9c9ac23818 feat: Added a much more flexible popup system 2023-04-07 10:21:27 +02:00
WerWolv
51e615095e fix: Make sure placing a type through the Edit menu re-evaluates the pattern 2023-04-06 23:01:45 +02:00
WerWolv
d92e7d19cc fix: Submenu items ignoring enabled flag 2023-04-06 22:33:02 +02:00
WerWolv
248b93f41a patterns: Updated pattern language 2023-04-06 19:23:16 +02:00
WerWolv
c73f33aac2 impr: Added various new events 2023-04-06 17:36:28 +02:00
WerWolv
7c18ad49ae impr: Allow windows that overlap the main window title bar to be movable 2023-04-06 14:58:05 +02:00
WerWolv
5f713882d4 fix: Occasional crash when loading project files 2023-04-06 12:44:25 +02:00
WerWolv
1698f1599b impr: Allow file chooser to open files using double click 2023-04-05 18:33:05 +02:00
WerWolv
24e584c77b fix: Crash when trying to place pattern language variable through the Edit menu
Fixes #1013
2023-04-05 18:29:30 +02:00
WerWolv
a5568d09d8 patterns: Updated pattern language
Fixes #1011
2023-04-05 18:03:30 +02:00
WerWolv
7a4f909c68 fix: Disassembler arch names not correctly corresponding to their ids
Fixes #1010
2023-04-05 18:02:47 +02:00
WerWolv
89aee456c6 patterns: Updated pattern language
Fixes #1011
2023-04-05 07:26:44 +02:00
WerWolv
4cf92103d8 fix: Names of disassembler architectures not corresponding to their actual type
Fixes #1010
2023-04-05 07:20:06 +02:00
WerWolv
e3b1ebb826 patterns: Updated pattern language 2023-04-04 23:42:39 +02:00
WerWolv
3658d8d96e fix: Disassembler not supporting any Capstone 5 features anymore
Fixes #1010
2023-04-04 23:08:10 +02:00
WerWolv
6c047f01f9 git: Fixed release CI not reading version correctly 2023-04-04 21:59:43 +02:00
WerWolv
fc105ecc3d build: Bumped version to 1.28.0 2023-04-04 12:04:22 +02:00
WerWolv
649f6c28bf patterns: Updated pattern language 2023-04-04 11:20:09 +02:00
WerWolv
867972b7f5 patterns: Updated pattern language 2023-04-04 10:23:01 +02:00
WerWolv
efe3227ef2 patterns: Updated pattern language 2023-04-04 09:34:50 +02:00
H1X4
aab8c88a96 feat: allow loading and saving pattern code via events (#1004)
Currently there is no way to save the pattern code progamically from a
plugin unless the builtin plugin is modified to add those events. This
pull request will be adding ability to load and save pattern code from
specified file.
2023-04-01 11:18:52 +02:00
Thomas
af18ca011b fix: Modified bytes visually reverting back after saving (#1003)
Fix #988

Co-authored-by: Nik <werwolv98@gmail.com>
2023-04-01 11:18:03 +02:00
Thomas
24106b860a impr: Added some documentation to providers (#1001) 2023-04-01 11:17:19 +02:00
WerWolv
60efb6973b fix: Filtering of long strings in find view not working correctly 2023-04-01 11:04:07 +02:00
WerWolv
cffd55bdda fix: UTF-16BE search being broken 2023-03-31 22:20:00 +02:00
WerWolv
88e767aaaf fix: Crash when loading big encoding files 2023-03-31 19:56:20 +02:00
WerWolv
d6cda43618 fix: Modified bytes visually reverting back after saving 2023-03-31 19:18:31 +02:00
WerWolv
3b229cd5cb impr: Added path tooltips to entries in the file chooser popup 2023-03-31 19:17:27 +02:00
WerWolv
72c4dbdb2f patterns: Updated pattern language 2023-03-31 13:49:59 +02:00
WerWolv
4da18d3630 fix: Custom encoding and text padding setting not applying to custom encoding column
Actually fixes #1005
2023-03-31 13:49:33 +02:00
WerWolv
2f04cfd5c6 fix: Entering decimal and float values in hex editor cells being broken 2023-03-31 11:34:08 +02:00
WerWolv
8195db6d4c fix: Prevent occasional crash when having ImHex open and connecting to the computer over RDP 2023-03-31 11:08:53 +02:00
WerWolv
722f6315c4 impr: Make sure shortcuts can't be used when popups are open 2023-03-31 11:07:53 +02:00
WerWolv
173ed5475c fix: Remove empty column when ASCII row is off and custom encoding is on
Fixes #1005
2023-03-31 11:07:32 +02:00
WerWolv
1460044e91 impr: Save custom encoding file to project
Fixes #1005
2023-03-31 11:06:51 +02:00
WerWolv
06a7b6e446 patterns: Fixed namespace of hex::prv:: functions 2023-03-28 10:27:49 +02:00
WerWolv
28b7b4b7f1 fix: File -> Open Others... menu not working correctly 2023-03-28 10:13:41 +02:00
WerWolv
8930adf532 patterns: Updated pattern language 2023-03-28 09:29:49 +02:00
WerWolv
f44b8a5618 patterns: Updated pattern language 2023-03-27 22:40:19 +02:00
WerWolv
6a9f79628e impr: Don't try to apply patches if there are none 2023-03-26 12:48:22 +02:00
Jonathan Wright
245c56ba8a build: Added Fedora 38 build (#928)
Co-authored-by: Thomas <hey@itrooz.fr>
2023-03-26 11:37:46 +02:00
WerWolv
98846421f6 build: Update dependencies 2023-03-26 11:23:32 +02:00
WerWolv
0aaeeffff7 build: Fixed capitalization of ImHex in MSI installer 2023-03-26 11:22:50 +02:00
Thomas
c2823facc2 lang: Fix weblate (#997)
This should (hopefully) fix weblate. I tried to fix merge conflicts
using instructions at
https://weblate.werwolv.net/projects/imhex/windows-plugin/#alerts

---------

Co-authored-by: xtex <xtexchooser@duck.com>
2023-03-26 11:03:30 +02:00
Thomas
fabb1596e5 impr: Handle and show NFD errors (#995)
This PR handles errors that NFD might encounter (both in Init() and the
other method to open the dialog), and log them in the logs and in the
GUI

This (among other) fix the crash I had running ImHex as root and opening
a file
2023-03-26 11:02:51 +02:00
Thomas
725e32250b fix: Move config files to XDG_CONFIG_HOME (#993)
This pull request changes Config Directories on Linux to only include
the XDG_CONFIG_HOME directory, as opposed to all directories in
XDG_DATA_DIRS before (introduced in
https://github.com/WerWolv/ImHex/pull/644/files#diff-c1a4d2b63fed168a9a3568944e9cadeae096f2ddcec3649e4a9b2d29fd104be0L162-L166).

Reasons:
- This changes the location of the config file to the standard directory
meant for configurations
- This prevents the config file from being read/written in system
locations, like /usr/share

This PR also includes a migration task that will run on Linux and move
config/GUI dimensions to the new directory

as a bonus, as discussed on discord, it writes the logs to a Data
directory instead of a Config directory
2023-03-26 11:02:23 +02:00
Zaggy1024
5fa264ea18 patterns: Update pattern_language and implement support for new bitfield features (#992)
This requires https://github.com/WerWolv/PatternLanguage/pull/34 to be
merged first, and then this can be amended to update the submodule and
merged to add support for the new features.
2023-03-26 11:01:37 +02:00
WerWolv
5e175b118d build: Updated libwolv 2023-03-25 11:24:24 +01:00
WerWolv
635173e55a impr: Make sure themes are added correctly when downloaded from the store 2023-03-23 20:35:16 +01:00
WerWolv
eb2ed6852c build: Make SSL work when using system curl on WIndows 2023-03-23 20:12:33 +01:00
WerWolv
2296766746 build: Allow building with capstone 4.X again 2023-03-23 16:45:00 +01:00
WerWolv
13be499510 build: Pull in latest version of libyara and libcurl 2023-03-23 16:30:55 +01:00
WerWolv
fec5c567e1 ui: Improve look and feel of content store 2023-03-23 13:32:47 +01:00
WerWolv
8ef863cae1 fix: Progress not working with with new http wrapper 2023-03-23 13:32:35 +01:00
WerWolv
9463105172 fix: Header memory leak in http requests class 2023-03-23 12:08:33 +01:00
WerWolv
bb4819bce4 sys: Fixed http request stack overflow 2023-03-23 11:43:07 +01:00
WerWolv
15be24db62 sys: Updated to use the new HttpRequest helper instead of Net 2023-03-23 11:23:07 +01:00
WerWolv
e7e2af9f91 patterns: Updated pattern language 2023-03-23 09:41:32 +01:00
WerWolv
8c5fd021f7 api: Hook up new http wrapper to the rest of ImHex 2023-03-22 23:05:18 +01:00
WerWolv
1a1ba19770 api: Added new, more flexible curl http wrapper 2023-03-22 21:48:14 +01:00
WerWolv
f95214d8fe patterns: Updated pattern language 2023-03-22 17:43:45 +01:00
WerWolv
631cfce2f8 impr: Added tooltip informing about font size if no custom font was selected 2023-03-22 16:30:49 +01:00
WerWolv
45649264f9 patterns: Updated pattern language 2023-03-22 13:12:57 +01:00
WerWolv
0fd3cb0c4a fix: Don't jump to previous editing position when selecting new region in hex editor
Potenially fixes issues mentioned in #924
2023-03-22 13:11:09 +01:00
Jacob Creedon
3cfec69020 feat: Added additional CRC hash types (#991)
This adds some common CRC types.

---------

Signed-off-by: Jacob Creedon <jcreedon@gmail.com>
2023-03-22 10:53:57 +01:00
WerWolv
cec62d23b0 fix: Window resizing causing freezes in some cases 2023-03-21 22:39:35 +01:00
WerWolv
f3f0dda3d4 fix: Properly clear valid region when switching to a different provider 2023-03-21 16:11:40 +01:00
WerWolv
be16b66ac0 fix: Make sure files don't get truncated when using Save As on itself
Fixes #987
2023-03-21 15:42:10 +01:00
WerWolv
b9059aaa01 fix: Make find process in the find view more easily cancelable 2023-03-21 15:37:49 +01:00
WerWolv
57a62d0544 impr: Clean up entire API and added doc comments 2023-03-21 15:33:43 +01:00
WerWolv
d82f0e952f fix: Custom data inspector rows not being writable correctly 2023-03-21 13:16:22 +01:00
Thomas
8731b7582b impr: Display a more detailed errors when opening a raw disk provider failed (#970)
PR title is self explaining

I may modify other providers implementations to display a detailed error
message later

I'm not sure how to deal with other locales because the format changed.
Before, I had to add and comment the key in all locale files, now I'm
not so sure.
2023-03-21 10:33:00 +01:00
WerWolv
e6959dc572 patterns: Updated pattern language
Fixes #954
2023-03-21 10:31:13 +01:00
WerWolv
a36b4d65e3 build: Make sure commit hash and branch end up in nightly builds 2023-03-21 10:14:09 +01:00
WerWolv
060ff56f9d impr: Improve file reading performance if opening of files is slow 2023-03-21 09:47:42 +01:00
WerWolv
0a0c0c0d07 feat: Added bytes swapper tool 2023-03-20 22:25:27 +01:00
WerWolv
17c4e405a6 impr: Update the command palette for the modern ages 2023-03-20 17:05:26 +01:00
WerWolv
53afa6ea43 fix: Crash on exit 2023-03-20 15:18:48 +01:00
WerWolv
a182e8daf2 patterns: Updated pattern language
Fixes #983
2023-03-20 15:12:27 +01:00
WerWolv
a4dfaba03f fix: All menu item shortcuts being global 2023-03-20 15:12:12 +01:00
WerWolv
6e23560e80 feat: Added all menu items to command palette 2023-03-20 14:11:43 +01:00
WerWolv
39e8d557e8 sys: Completely revamped main menu item system 2023-03-20 13:11:43 +01:00
WerWolv
677c989664 feat: Allow custom data inspector rows to be edited 2023-03-20 08:30:34 +01:00
WerWolv
c9342d90fb fix: Prevent new line from appearing on every pl code save
Fixes #982
2023-03-20 08:29:00 +01:00
WerWolv
0693bb8d51 git: Fixed documentation shield style 2023-03-18 16:10:39 +01:00
WerWolv
5cd3c305d0 git: Added documentation link to readme 2023-03-18 16:09:45 +01:00
WerWolv
e00b59c393 fix: Properly discard reopened stderr 2023-03-18 11:47:42 +01:00
WerWolv
7c1e33dde6 sys: Prevent libraries from printing garbage to the console through stderr 2023-03-18 11:35:01 +01:00
WerWolv
367bd76046 ui: Mae sure all theme scaling values are scaled correctly 2023-03-18 10:52:50 +01:00
WerWolv
1a1bf98905 impr: Look for magic files recursively 2023-03-17 21:18:28 +01:00
WerWolv
4c1a24058c ui: Fixed various scaling inconsistencies on higher scaling factors 2023-03-17 19:58:08 +01:00
WerWolv
294e95caf8 fix: Store page not clearing nodes and themes section correctly 2023-03-17 17:55:39 +01:00
WerWolv
031884c327 patterns: Updated pattern language
Fixes #979
2023-03-17 17:28:17 +01:00
WerWolv
466dacaab4 ui: Improve the look and feel of the information view 2023-03-17 17:07:39 +01:00
WerWolv
1f8645fd43 fix: Occasional crash when multiple threads are reading data from a file provider 2023-03-17 11:43:50 +01:00
WerWolv
880568cc60 impr: Better find view result filter speeds 2023-03-17 11:32:08 +01:00
WerWolv
f10fb56042 impr: Drastically improve file reading performance 2023-03-17 11:31:50 +01:00
WerWolv
64be6d89ee fix: Moving cursor around using arrow keys behaving weirdly 2023-03-17 09:17:44 +01:00
WerWolv
5442c32a3f impr: Allow non-continuous provider values to be saved 2023-03-17 08:38:38 +01:00
WerWolv
4ee53701e6 impr: Allow Regex find strategy specify string type and minimum length 2023-03-17 08:16:13 +01:00
WerWolv
5097a223e3 impr: Added default saveAs implementation for all providers 2023-03-17 08:15:43 +01:00
WerWolv
7cdba75bef fix: Crash when not making a valid selection in provider load interfaces 2023-03-16 16:48:15 +01:00
WerWolv
0312027ca8 impr: Modernize look and feel of bookmarks 2023-03-16 14:40:26 +01:00
WerWolv
c726c96286 impr: Make comment field in bookmark tooltip more readable 2023-03-16 13:35:29 +01:00
WerWolv
5a2b2e0813 feat: Make yara match list sortable 2023-03-16 13:35:09 +01:00
WerWolv
4271b2e9fd fix: Yara view filtering out all but one match 2023-03-14 17:02:59 +01:00
WerWolv
13ef4c04d1 patterns: Updated pattern language
Closes #961
2023-03-14 14:41:32 +01:00
WerWolv
96c3bb1e38 feat: Limit recent files to 5 files, add option to disable saving them
Closes #950
2023-03-14 14:07:18 +01:00
WerWolv
a0b36925ed fix: Custom styles not being scaled correctly 2023-03-14 13:19:04 +01:00
WerWolv
daadc2ea71 impr: Attempt loading of full unicode plane from font if possible 2023-03-14 12:30:28 +01:00
WerWolv
ec2934b4b8 fix: Advancing to next row when editing bytes loading wrong value
Fixes #973
2023-03-14 10:24:25 +01:00
WerWolv
3a840c4ced impr: Properly display custom encoding characters that are split between lines 2023-03-14 09:35:43 +01:00
WerWolv
bd190d2b65 patterns: Updated pattern language 2023-03-13 11:36:11 +01:00
qux-bbb
9b05a36529 fix: Find view string filters filtering for some wrong characters (#972)
`\r` and `\n` need to be filtered.
2023-03-13 11:06:30 +01:00
WerWolv
d9a498e8ec build: Make sure libwolv is compiled with -fPIC 2023-03-13 10:39:34 +01:00
WerWolv
7d86b277a7 build: Updated curl and libyara 2023-03-13 10:24:56 +01:00
WerWolv
d463b3235e tests: Fixed building of tests 2023-03-13 10:24:48 +01:00
WerWolv
5a8433ede4 build: Updated libwolv 2023-03-13 09:31:24 +01:00
WerWolv
00a5fd2d7c sys: Fixed more build issues 2023-03-13 09:25:07 +01:00
WerWolv
55f9faea10 sys: Updated more code to libwolv 2023-03-13 08:58:08 +01:00
WerWolv
fb2e668589 sys: Moved more functions to libwolv 2023-03-12 18:43:05 +01:00
WerWolv
0dafb3d230 sys: Replaced many helper functions with libwolv 2023-03-12 18:27:33 +01:00
qux-bbb
e958934a22 fix: String search not including string at end of data (#963)
Before:  

![before](https://user-images.githubusercontent.com/18598419/222937056-fec74305-21a3-4bbf-a439-e8df7031bca9.png)

After:  

![after](https://user-images.githubusercontent.com/18598419/222937069-a04cb748-4266-4fbb-8182-727bb8858329.png)
2023-03-11 14:39:50 +01:00
Fenrisfulsur
069221757f feat: Added chunk based entropy analysis to information view (#933)
Issue: https://github.com/WerWolv/ImHex/issues/522

Implementation of chunk based entropy analysis in diagram.hpp available
from the data information view and in the pattern language.

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
2023-03-10 16:06:18 +01:00
WerWolv
505c1bc274 build: Fix Fedora build errors 2023-03-10 14:46:15 +01:00
qux-bbb
cdd5d33e89 feat: Make CTRL + N automatically create a memory provider (#966)
"CTRL + N" can open a mem_file directly.
2023-03-07 16:05:03 +01:00
WerWolv
f661f4d1d6 fix: GDB provider not working nicely anymore 2023-03-07 16:04:04 +01:00
Mimi1337
f435191585 fix: Dockerfile syntax error (#945) 2023-02-21 11:29:21 +01:00
WerWolv
00c2d7ea71 patterns: Updated pattern language 2023-02-20 11:35:33 +01:00
WerWolv
cddcc1e85d patterns: Updated pattern language 2023-02-19 10:49:57 +01:00
WerWolv
91928b45d8 fix: Try to fix build again 2023-02-19 10:25:39 +01:00
WerWolv
277c83e6d8 fix: Uninitialized value build issue 2023-02-19 09:18:17 +01:00
WerWolv
0017cd2e40 feat: Added binary hex cell visualizer
Closes #939
2023-02-18 22:20:02 +01:00
WerWolv
774803492c fix: Editing binary value in data inspector not working correctly
Fixes #941
2023-02-18 21:44:43 +01:00
WerWolv
83a9655772 patterns: Updated pattern language 2023-02-17 20:30:41 +01:00
WerWolv
58324b4539 build: Fixed linking against execinfo 2023-02-17 17:56:27 +01:00
WerWolv
09b7794d71 build: Added option to disable stack traces 2023-02-17 17:52:10 +01:00
WerWolv
9e3fe9beb1 patterns: Updated pattern language 2023-02-17 17:35:41 +01:00
WerWolv
ff525fe750 impr: Properly sort choose file dialog entries
Fixes #938
2023-02-17 14:59:19 +01:00
WerWolv
94977ad216 patterns: Updated pattern language 2023-02-17 14:55:56 +01:00
WerWolv
64e34e42b8 patterns: Fixed highlighting of custom sections 2023-02-17 14:53:15 +01:00
WerWolv
21dc65f42a impr: Added comments everywhere in main application 2023-02-17 12:03:53 +01:00
WerWolv
279e085887 impr: Don't create a new font texture for no reason 2023-02-17 12:03:00 +01:00
WerWolv
d84dfa2c42 feat: Allow custom CA Certs to be loaded
Fixes #907
2023-02-17 12:01:46 +01:00
WerWolv
bf8089dc7e impr: Don't memory map files, never keep a write handle open for long
Closes #592
2023-02-17 10:26:09 +01:00
WerWolv
e48761b5c0 fix: Plot lines being invisible 2023-02-17 10:02:43 +01:00
WerWolv
35437c0300 patterns: Added rotation and scale sliders to 3D visualizer 2023-02-16 23:24:24 +01:00
WerWolv
6cecc12d04 patterns: Updated pattern language 2023-02-16 22:20:03 +01:00
WerWolv
dec4231d49 impr: Make sure fonts don't get blurry on non-integer scalings 2023-02-16 20:53:58 +01:00
WerWolv
fb1d12ebf3 sys: Remove some problematic (and rarely used) scaling settings 2023-02-16 20:19:55 +01:00
WerWolv
b19276a3e9 patterns: Added match keyword to syntax highlighting 2023-02-16 19:10:08 +01:00
WerWolv
5ccbfc1ff8 feat: Allow themes and nodes to be downloaded from the content store 2023-02-16 18:55:21 +01:00
WerWolv
d3d6a8a838 patterns: Updated pattern language 2023-02-16 18:23:49 +01:00
WerWolv
ac83bbeb0e feat: Added a theme manager view to make it easier to make new themes 2023-02-16 18:06:40 +01:00
WerWolv
8cb76a26c1 fix: Font being scaled too big 2023-02-16 16:29:41 +01:00
WerWolv
20da22d59e sys: Make sure scrolling counts as an input event 2023-02-16 08:53:23 +01:00
WerWolv
d9fa4b452c impr: Clean up diff view 2023-02-16 08:53:05 +01:00
WerWolv
6216d72aa6 fix: Format string compile issues 2023-02-15 22:22:13 +01:00
WerWolv
851f132188 impr: Make Text Editor word selector also consider underlines 2023-02-15 17:12:16 +01:00
WerWolv
3067ff08ec feat: Greatly improved diff view
Fixes #631
2023-02-15 17:01:36 +01:00
WerWolv
07fd86fc9d git: Split release workflows into multiple steps 2023-02-15 10:21:56 +01:00
WerWolv
504037c115 build: Bumped version to 1.27.1 2023-02-15 09:39:23 +01:00
WerWolv
0fad21a980 patterns: Updated pattern language 2023-02-15 09:39:16 +01:00
WerWolv
8afd698284 impr: Correct some ugly code 2023-02-14 15:43:44 +01:00
WerWolv
9ec7b90192 patterns: Updated pattern language 2023-02-14 15:10:52 +01:00
WerWolv
08f0fff34b patterns: Updated pattern language 2023-02-14 12:53:37 +01:00
WerWolv
2c1073eda9 fix: Safety backup restore popup getting hidden by tip of the day 2023-02-14 11:45:32 +01:00
WerWolv
c9348f0651 patterns: Updated pattern language 2023-02-13 23:27:12 +01:00
WerWolv
accb461c08 impr: Better word select and delete in text editor
Closes #931
2023-02-13 10:21:57 +01:00
Thomas
75adcc0a96 build: Fix Arch package name in release CI (#929)
* Fix Arch package name in release CI

* update email address
2023-02-13 09:05:52 +01:00
WerWolv
61ce88ba9b build: Fix build on systems that have no backtrace or execinfo
Fixes #932
2023-02-13 08:27:08 +01:00
WerWolv
4b451fd1d3 patterns: Fixed pattern data rows not being selectable when color column is hidden 2023-02-13 08:26:43 +01:00
WerWolv
a87190960f build: Fixed one more missing imhex target name 2023-02-12 22:08:35 +01:00
WerWolv
45558027a6 git: Fixed release workflow 2023-02-12 21:55:22 +01:00
WerWolv
e426606542 build: Fixed flatpak build issues 2023-02-12 21:55:09 +01:00
WerWolv
4d60942fea build: Bumped version to 1.27.0 2023-02-12 19:24:04 +01:00
WerWolv
3003dea409 fix: Occasional error when loading recent files 2023-02-12 17:52:09 +01:00
WerWolv
0b18930017 fix: Invalid theme load error 2023-02-12 17:39:47 +01:00
WerWolv
54ef5785cd fix: ImNodes double free 2023-02-12 17:38:13 +01:00
WerWolv
d084ec78e9 nodes: Allow immediate values on integer and float inputs
Closes #427
2023-02-12 17:33:53 +01:00
WerWolv
a59c17aa83 nodes: Fixed loading saved nodes multiple times 2023-02-10 11:22:11 +01:00
WerWolv
6281adc7c3 nodes: Added a few new nodes 2023-02-10 08:18:06 +01:00
WerWolv
5cc01ae89d nodes: Added support for nested, shareable, custom data processor nodes 2023-02-09 23:07:04 +01:00
WerWolv
303dd28c7c fix: Fix macOS build again 2023-02-08 14:11:42 +01:00
WerWolv
dd87dc7046 fix: Building on macOS 2023-02-08 13:51:56 +01:00
WerWolv
235a64deef sys: One more attempt to fix macOS scaling issues 2023-02-08 12:53:34 +01:00
WerWolv
89a96c6d25 sys: Improve pattern visualizer API 2023-02-07 14:18:59 +01:00
WerWolv
4f0e5b99a8 pattern: Make visualizer button actually accessible again 2023-02-06 17:24:06 +01:00
WerWolv
f75f3f4661 pattern: Fixed wrong number of required parameters for image visualizer 2023-02-06 17:23:50 +01:00
WerWolv
b936a28921 fix: Opening files from command line not working 2023-02-06 07:11:21 +01:00
Jonathan Wright
d02507ae4b build: Re-enable Fedora rawhide builds (#920)
* re-enable rawhide builds

* Update build.yml

* Update imhex.spec

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2023-02-02 21:42:13 +01:00
WerWolv
0b576adcf8 fix: Another P2468R2 issue 2023-02-02 21:26:46 +01:00
WerWolv
22ff033b5e fix: More P2468R2 issues 2023-02-02 21:13:56 +01:00
WerWolv
b1edede53a fix: Invalid json comparison 2023-02-02 20:54:38 +01:00
WerWolv
3877f0853d patterns: Updated pattern language 2023-02-02 20:41:51 +01:00
WerWolv
9af8a0113a patterns: Updated pattern language 2023-02-02 19:06:00 +01:00
WerWolv
0d01f0c9d7 feat: Added function to import patches from a modified file 2023-02-02 14:13:37 +01:00
WerWolv
9911166c24 git: Added translation status batch to readme 2023-02-02 13:12:48 +01:00
WerWolvTranslationBot
01736d6409 lang: Updated German translation (#916)
Currently translated at 100.0% (842 of 842 strings)

Translation: ImHex/Built-in Plugin
Translate-URL: https://weblate.werwolv.net/projects/imhex/built-in-plugin/de/

Co-authored-by: Nik <werwolv98@gmail.com>
2023-02-02 11:58:09 +01:00
WerWolv
4ea8971adf lang: Added base translation files 2023-02-02 10:08:47 +01:00
WerWolv
8da072b602 lang: Get codebase ready for the use with Weblate 2023-02-02 09:41:58 +01:00
Berylskid
f6823d5f13 lang: Updated Japanese translation (#915) 2023-02-02 09:39:40 +01:00
WerWolv
941c7ee61d fix: Still properly divide scaling by 2.0 on macOS 2023-02-01 23:47:22 +01:00
WerWolv
fd259dcde3 fix: Prevent native scaling from going below 1.0 on macOS 2023-02-01 23:45:07 +01:00
WerWolv
79ecf7fa59 build: Fix non-Windows build 2023-02-01 09:38:03 +01:00
WerWolv
4c761df181 build: Improve build script a bit 2023-02-01 09:20:46 +01:00
WerWolv
94dc688324 ui: Change feedback link 2023-02-01 09:20:32 +01:00
WerWolv
357dd883db fix: Hexadecimal string inputs in data processor nodes behaving weirdly 2023-01-31 11:39:08 +01:00
WerWolv
3bad5e1d9c fix: ImHex still opening files when multiple builtin plugins are detected 2023-01-31 11:38:26 +01:00
WerWolv
d09982d99f fix: Crash when opening selection view
Fixes #913
2023-01-30 18:15:42 +01:00
Nik
fe7eb582a4 git: Added code quality tag to readme 2023-01-30 11:36:34 +01:00
WerWolv
c76b4bc9e9 impr: Removed a bunch of trailing white spaces 2023-01-30 11:11:30 +01:00
WerWolv
55d7d7c026 impr: Improve code quality 2023-01-30 10:42:07 +01:00
WerWolv
6b645192d4 fix: Diff view highlighting issues 2023-01-30 10:26:37 +01:00
WerWolv
d6bb408078 fix: All bytes being selected when opening a new provider 2023-01-30 10:10:37 +01:00
WerWolv
434ced44f0 fix: Build failing on macOS 2023-01-28 21:30:17 +01:00
WerWolv
c6e1f45dc3 feat: Added option to copy custom encoding strings from hex view 2023-01-28 21:12:35 +01:00
WerWolv
c861bf9a5e fix: Copying strings and bad names 2023-01-28 21:12:08 +01:00
WerWolv
86be1ef1ec impr: Make find view string filter case insensitive 2023-01-28 20:55:11 +01:00
WerWolv
c4d52da924 ui: Added cancel button to task running popup 2023-01-28 14:36:39 +01:00
WerWolv
a142d4fe20 ui: Make file chooser popup bigger 2023-01-28 14:28:06 +01:00
WerWolv
197e86f327 fix: Duplicate highlightings for every yara rule 2023-01-28 14:27:51 +01:00
WerWolv
b1aa58d446 feat: Allow selected yara rules to be saved to Project file 2023-01-28 14:15:15 +01:00
WerWolv
60a178f75e fix: Last column of diff view displaying all zeros
Fixes #908
2023-01-28 12:44:40 +01:00
WerWolv
6799263317 sys: Added a info popup when closing ImHex while tasks are still running 2023-01-28 12:16:41 +01:00
WerWolv
9b80486285 fix: Process Memory provider search not being case insensitive 2023-01-28 11:41:09 +01:00
WerWolv
3254376d28 fix: Editing static array values being broken 2023-01-28 00:03:20 +01:00
WerWolv
29c1a0cb78 feat: Allow multiple yara files to be selected at once 2023-01-28 00:01:53 +01:00
WerWolv
800ffb5e56 feat: Make it easier to apply multiple yara rules at once 2023-01-27 12:17:10 +01:00
WerWolv
1cf9f7e990 patterns: Updated pattern language 2023-01-27 10:45:07 +01:00
WerWolv
d928325fdf fix: Loading of Intel Hex and Motorola SREC files with new lines inbetween
Fixes #906
2023-01-26 11:06:00 +01:00
WerWolv
b3556c7c91 lang: Updated language files 2023-01-25 10:56:13 +01:00
WerWolv
4b112321d2 feat: Added base64 exporter
Closes #900
2023-01-25 10:51:00 +01:00
WerWolv
fee1b985c0 feat: Added better error messages for generating and importing ips patches 2023-01-25 10:38:04 +01:00
WerWolv
111eabb84c feat: Added scatter plot visualizer 2023-01-25 10:16:46 +01:00
WerWolv
f9bb4d828a ui: Improve visualizer button layout and error messages 2023-01-25 10:16:31 +01:00
WerWolv
434b7649c3 fix: CRC8 hashing algorithm displaying 16 bits result 2023-01-25 00:06:48 +01:00
WerWolv
fc44dd4592 build: Fixed building of miniaudio on macOS 2023-01-24 23:57:43 +01:00
WerWolv
8ea0e9ce9c fix: Sound visualizer being really laggy 2023-01-24 23:57:29 +01:00
WerWolv
94cd83e0dc feat: Added sound visualizer 2023-01-24 23:27:35 +01:00
WerWolv
27790532f8 fix: Crash when closing provider that had pattern loaded in some cases 2023-01-24 23:27:15 +01:00
WerWolv
90d9c91717 build: Cleanup opengl and glfw linking 2023-01-24 14:59:19 +01:00
WerWolv
32ed2c30c0 fix: Flickering task bar progress bar 2023-01-24 13:42:08 +01:00
WerWolv
cf9df6e36d feat: Added ability to query provider information from pattern language 2023-01-24 09:07:11 +01:00
WerWolv
915106f360 patterns: Fixed various issues with the 3d visualizer 2023-01-23 16:25:23 +01:00
WerWolv
a51e4afb05 patterns: Updated pattern language 2023-01-23 13:53:29 +01:00
WerWolv
c30f8fa459 patterns: Updated pattern language 2023-01-23 07:25:44 +01:00
WerWolv
46221e936f feat: Allow the 3d visualizer to use index buffers 2023-01-22 16:17:10 +01:00
WerWolv
c86891e0c3 fix: Custom encodings not rendering correctly on non-zero page 2023-01-22 14:17:55 +01:00
WerWolv
acf6b839e5 patterns: Updated pattern language 2023-01-22 12:16:22 +01:00
WerWolv
1f50e834fc fix: Copying bytes from non-zero page not working 2023-01-22 11:28:17 +01:00
WerWolv
6322dbf46a fix: Revert back macOS scaling fix as it made it worse 2023-01-21 22:59:08 +01:00
WerWolv
0e1aeee3fb patterns: Display bitfield field bit addresses from the start of the bitfield 2023-01-21 22:32:16 +01:00
WerWolv
173f279ac8 fix: Find view not correctly accepting hexadecimal values 2023-01-21 18:44:12 +01:00
WerWolv
89e0df86a2 feat: Added scaling and rotation to 3D visualizer 2023-01-21 13:00:02 +01:00
WerWolv
7ba9349de2 patterns: Updated pattern language 2023-01-21 12:31:33 +01:00
WerWolv
15fb288a5b fix: Yara view only loading in .yar files and not .yara files 2023-01-21 10:10:05 +01:00
WerWolv
f17e04273d fix: IPS patch applying being broken 2023-01-21 00:29:16 +01:00
WerWolv
76d47bf856 fix: MacOS Build errors because of khronos includes 2023-01-21 00:11:33 +01:00
WerWolv
d4967018c2 feat: Added basic lighting and rotations to 3d visualizer model 2023-01-20 23:32:51 +01:00
WerWolv
8e759d9b5f feat: Added basic 3D visualizer, moved visualizers to separate file 2023-01-20 21:16:28 +01:00
WerWolv
a9cebed903 ui: Disable Jump To command when too many bytes are selected 2023-01-19 17:08:17 +01:00
WerWolv
58a70f6ad8 ui: Move around File menu items to make more logical sense 2023-01-19 17:05:54 +01:00
WerWolv
05c8158716 feat: Added a new division by invariant multiplication tool 2023-01-19 17:01:41 +01:00
WerWolv
17b0f2ae77 feat: Added a description to the IEEE754 decoder tool 2023-01-19 17:01:19 +01:00
WerWolv
b54e6ea531 ui: Always add a spacing at the end of all tools 2023-01-19 16:59:59 +01:00
WerWolv
b702ad4190 fix: Occasional crash when loading a provider 2023-01-19 16:59:34 +01:00
WerWolv
4fb544d59d fix: Views starting out super tiny 2023-01-19 16:59:09 +01:00
WerWolv
e37a73ae58 patterns: Updated pattern language 2023-01-19 12:19:09 +01:00
WerWolv
c5d2739a39 fix: File provider sometimes not saving path to project file 2023-01-19 11:09:24 +01:00
WerWolv
def40c908e patterns: Added basic disassembler visualizer 2023-01-18 17:17:34 +01:00
WerWolv
ef12798fe2 feat: Allow custom hashes to be saved to projects 2023-01-18 14:30:56 +01:00
WerWolv
c747c15567 fix: Buffer overflow caused by hex input boxes 2023-01-18 14:30:44 +01:00
Nik
48a57cd981 feat: Added stacktrace printing on crashes (#892)
* feat: Added simple stack trace output

* feat: Added backtrace wrapper

* build: Added libbacktrace include dirs to build

* build: Fixed libbacktrace variables

* build: More backtrace variable fixes

* build: Try to find backtrace include

* build: Get backtrace header from cmake script

* feat: Added backtrace support for execinfo

* feat: Added support for StackWalk on Windows
2023-01-17 21:38:56 +01:00
WerWolv
3ddef07284 fix: ImHex failing to load in Portable mode from a folder with no permissions
Fixes #881
2023-01-17 09:59:57 +01:00
Kuruyia
a65f0a5238 feat: Support macOS keyboard shortcuts (#889) 2023-01-17 08:16:02 +01:00
birdstakes
ca68150970 fix: Frame rate not unlocking correctly (#890)
m_hadEvent could be set during glfwWaitEventsTimeout and then
immediately cleared before ever being checked.
2023-01-17 08:14:40 +01:00
WerWolv
92f0aa9593 fix: Logs always being saved to user folders
Fixes #888
2023-01-16 19:39:00 +01:00
WerWolv
b368b9c6d1 git: Make install instructions reflect actual release names 2023-01-16 18:20:22 +01:00
WerWolv
7e17059154 sys: Improved exception debug output 2023-01-16 18:17:13 +01:00
WerWolv
e078d810de git: Added install instructions for all release builds
#887
2023-01-16 13:41:24 +01:00
WerWolv
62bf877046 patterns: Updated pattern language
Fixes #880, Fixes #863
2023-01-15 22:59:15 +01:00
WerWolv
1b56c7ffae ui: Show task progress in task bar 2023-01-14 14:21:16 +01:00
WerWolv
f7e22ce651 patterns: Updated pattern language 2023-01-14 14:20:48 +01:00
WerWolv
b9c2b1de5f patterns: Updated pattern language 2023-01-13 22:30:57 +01:00
WerWolv
0c302da0db build: Add option to use the GTK file picker instead of portals on Linux
Fixes #882
2023-01-13 20:11:27 +01:00
WerWolv
45492365be fix: Potentially fix scaling issues on macOS 2023-01-13 20:06:03 +01:00
WerWolv
b497e9d867 git: Switch to different repo dispatch action 2023-01-13 08:58:03 +01:00
Nik
2840935f3d build: Added glfw to Brewfile 2023-01-13 01:01:43 +01:00
Thomas
69c0e6ee6e git: Do not run make install for tests (#879)
Co-authored-by: Nik <werwolv98@gmail.com>
2023-01-13 00:32:17 +01:00
Thomas
78b07e0a46 git: Make runner cache keys unique (#878) 2023-01-13 00:10:28 +01:00
Thomas
5a865774d1 git: Cleanup build CI + separate Ubuntu and AppImage builds (#873)
* remove flatpak

rationale: if we need it again we can always get it back from old commits

* remove double spaces

* remove Fedora rawhide

* remove Windows installer signing

* separate Ubuntu and AppImage builds
2023-01-12 23:50:59 +01:00
WerWolv
8d9667c2e0 fix: Yara rules being unable to include files
Fixes #875
2023-01-12 23:29:48 +01:00
WerWolv
1f6acc101f feat: Allow OTF fonts to be selected 2023-01-12 11:37:19 +01:00
WerWolv
0d91db68db patterns: Added bitmap visualizer 2023-01-12 11:18:36 +01:00
WerWolv
825e788646 git: Added more information to the readme requirements section 2023-01-12 08:50:16 +01:00
Thomas
f3815673c0 git: Fix typo on 'Chocolatey' + add uppercase on 'Winget' (#870)
* Fix typo on 'Chocolatey'

* add uppercase on 'Winget'
2023-01-12 08:25:51 +01:00
Thomas
b070092a64 git: Add architecture to build artifacts (#869)
* rename win64 artifact to Windows

* add architecture to all artifact names
2023-01-12 08:25:28 +01:00
WerWolv
25ede7ad18 fix: List all intel hex and motorola srec file extensions manually
Fixes #871
2023-01-12 08:20:15 +01:00
WerWolv
03d216f116 feat: Allow most resources to be loaded relative to the current project 2023-01-11 23:31:25 +01:00
WerWolv
b1cab5ccd2 patterns: Updated pattern language 2023-01-11 11:22:01 +01:00
Jonathan Wright
04d0458ae7 build: Improve Fedora builds and add EL9 build. (#861) 2023-01-10 23:10:34 +01:00
WerWolv
3b5d54dd96 fix: Text Editor behaving a bit weirdly now 2023-01-10 19:27:27 +01:00
WerWolv
87571450f4 patterns: Updated pattern language 2023-01-10 16:20:54 +01:00
WerWolv
766fd626f2 fix: Hex editor editing cursor not advancing on non-zero pages 2023-01-10 13:48:50 +01:00
WerWolv
be1f711fda fix: Pattern editor not scrolling all the way to the right when typing 2023-01-10 13:27:16 +01:00
WerWolv
ef3627321c sys: Clear project after loading crash backup 2023-01-10 08:57:29 +01:00
WerWolv
dbcb13f473 patterns: Disallow application/octet-stream to be used as MIME type 2023-01-09 08:38:19 +01:00
WerWolv
c1359a71d6 feat: Added options to automatically expand or flatten the pattern tree 2023-01-08 16:06:26 +01:00
WerWolv
b1a26d02c1 patterns: Updated pattern language 2023-01-08 10:20:54 +01:00
WerWolv
ceae23eab1 fix: Crash when opening a project file when already having providers open 2023-01-07 22:43:48 +01:00
Thomas
ab29303c2e sys: Clear project context when closing all providers, Display project name in window title (#860)
* clear project context when closing all providers

* Show project name on window title

* refactor RequestChangeWindowTitle to RequestUpdateWindowTitle

* add spaces
2023-01-07 17:31:22 +01:00
Thomas
ed831c6fc9 fix: Do not check for writable provider to save project, disable shortcut when unavailable (#859)
* do not check for writable provider to save project

* disable save project shortcut when we can't save it

* log when project is saved
2023-01-07 17:16:43 +01:00
WerWolv
d86be9d9b3 sys: putenv sucks. Use setenv instead 2023-01-07 10:56:03 +01:00
WerWolv
c26bed894b sys: Add imhex/lib path to plugin libraries search paths 2023-01-07 10:32:01 +01:00
Chien Wong
27cf5953ae fix: Typo of IEEE 754 (#856) 2023-01-06 13:12:10 +01:00
WerWolv
d0b3a60a09 build: Bumped version to 1.26.2 2023-01-05 16:37:53 +01:00
WerWolv
15f2376c62 sys: Fixed some variable names 2023-01-05 16:27:52 +01:00
WerWolv
efeeea37f6 build: Updated libromfs properly 2023-01-05 16:27:16 +01:00
WerWolv
5726e52df2 ui: Make content store resizable again 2023-01-05 13:23:08 +01:00
WerWolv
a1b596adc0 build: Bumped version to 1.26.1 2023-01-05 09:53:49 +01:00
WerWolv
763196f0cc feat: Added filtering to Process Memory Provider 2023-01-05 09:30:15 +01:00
WerWolv
ff9048fcf0 fix: Crash on exit
Fixes #854
2023-01-05 09:29:33 +01:00
WerWolv
7d9c86f584 fix: Crash when loading themes on Linux and MacOS 2023-01-04 23:56:36 +01:00
WerWolv
6129360b06 patterns: Updated pattern language
Fixed #853
2023-01-04 19:39:01 +01:00
252 changed files with 113298 additions and 8156 deletions

68
.clang-tidy Normal file
View File

@@ -0,0 +1,68 @@
# Generated from CLion Inspection settings
---
Checks: '-*,
mpi-*,
bugprone-*,
-bugprone-signal-handler,
-bugprone-narrowing-conversions,
-bugprone-redundant-branch-condition,
-bugprone-exception-escape,
-bugprone-shared-ptr-array-mismatch,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-signed-char-misuse,
-bugprone-unhandled-exception-at-new,
-bugprone-infinite-loop,
-bugprone-easily-swappable-parameters,
cert-err52-cpp,
cert-err60-cpp,
cert-err34-c,
cert-str34-c,
cert-dcl21-cpp,
cert-msc50-cpp,
cert-msc51-cpp,
cert-dcl58-cpp,
cert-flp30-c,
cppcoreguidelines-avoid-const-or-ref-data-members,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-slicing,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-narrowing-conversions,
google-default-arguments,
google-runtime-operator,
google-explicit-constructor,
hicpp-multiway-paths-covered,
hicpp-exception-baseclass,
misc-*,
-misc-definitions-in-headers,
-misc-unused-parameters,
-misc-unused-alias-decls,
-misc-use-anonymous-namespace,
-misc-misleading-identifier,
-misc-confusable-identifiers,
-misc-misleading-bidirectional,
-misc-static-assert,
-misc-no-recursion,
-misc-const-correctness,
modernize-*,
-modernize-use-trailing-return-type,
openmp-use-default-none,
performance-*,
-performance-no-int-to-ptr,
portability-*,
-portability-restrict-system-includes,
readability-*,
-readability-redundant-preprocessor,
-readability-named-parameter,
-readability-function-size,
-readability-use-anyofallof,
-readability-identifier-length,
-readability-magic-numbers,
-readability-braces-around-statements,
-readability-suspicious-call-argument,
-readability-isolate-declaration,
-readability-else-after-return,
-readability-redundant-access-specifiers,
-readability-function-cognitive-complexity,
-readability-identifier-naming,
-readability-qualified-auto'

View File

@@ -28,8 +28,8 @@ jobs:
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
@@ -37,8 +37,8 @@ jobs:
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update

View File

@@ -58,6 +58,7 @@ jobs:
mbedtls:p
freetype:p
dlfcn:p
libbacktrace:p
- name: 📜 Set version variable
run: |
@@ -69,45 +70,39 @@ jobs:
mkdir -p build
cd build
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
..
mingw32-make -j4 install
cpack
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
#- name: 🗝️ Sign Windows Installer
# if: github.event_name == 'push' && github.ref == 'refs/heads/master'
# shell: powershell
# env:
# WIN_SIGN_CERT: ${{ secrets.WIN_SIGN_CERT }}
# WIN_SIGN_PW: ${{ secrets.WIN_SIGN_PW }}
# run: |
# $buffer = [System.Convert]::FromBase64String($env:WIN_SIGN_CERT)
# $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($buffer, $env:WIN_SIGN_PW)
# Get-ChildItem -Path ./build -Filter *.msi -Recurse | Set-AuthenticodeSignature -HashAlgorithm SHA256 -Certificate $certificate -TimestampServer http://timestamp.digicert.com
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
- name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v3
with:
name: Windows Installer
name: Windows Installer x86_64
path: |
build/*.msi
imhex-*.msi
- name: ⬆️ Upload Portable ZIP
uses: actions/upload-artifact@v3
with:
name: Windows Portable
name: Windows Portable x86_64
path: |
build/install/*
- name: ⬇️ Download Mesa3D for NoGPU version
shell: bash
run: |
@@ -119,7 +114,7 @@ jobs:
- name: ⬆️ Upload NoGPU Portable ZIP
uses: actions/upload-artifact@v3
with:
name: Windows Portable NoGPU
name: Windows Portable NoGPU x86_64
path: |
build/install/*
@@ -134,7 +129,7 @@ jobs:
custom_glfw: true
- suffix: ""
custom_glfw: false
name: 🍎 macOS 11.0${{matrix.suffix}}
steps:
@@ -146,7 +141,7 @@ jobs:
- name: 📜 Set version variable
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
@@ -154,7 +149,6 @@ jobs:
restore-keys: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
@@ -172,7 +166,6 @@ jobs:
run: |
brew install glfw
- name: 🧰 Checkout glfw
if: ${{matrix.custom_glfw}}
uses: actions/checkout@v3
@@ -189,12 +182,15 @@ jobs:
mkdir build
cd build
cmake \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
cmake \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
..
make -j 4 install
@@ -203,30 +199,33 @@ jobs:
run: |
mkdir -p build
cd build
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.10" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}" \
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.10" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
..
make -j4 package
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v3
with:
name: macOS DMG${{matrix.suffix}}
name: macOS DMG${{matrix.suffix}} x86_64
path: build/*.dmg
# Ubuntu build
@@ -246,43 +245,34 @@ jobs:
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore other caches
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
build-appimage/CMakeCache.txt
.flatpak-builder
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo rm -rf /usr/share/dotnet
sudo rm -rf /opt/ghc
sudo rm -rf "/usr/local/share/boost"
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
sudo apt update
sudo bash dist/get_deps_debian.sh
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
sudo chmod +x /usr/local/bin/appimagetool
sudo pip3 install git+https://github.com/iTrooz/appimage-builder@dpkg-package-versions
# Ubuntu cmake build
- name: 🛠️ Build
run: |
mkdir -p build
cd build
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
..
make -j 4 install DESTDIR=DebDir
@@ -290,35 +280,74 @@ jobs:
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
#- name: 📦 Bundle Flatpak
# run: |
# sudo apt install flatpak flatpak-builder
# flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
# flatpak --user install -y flathub org.freedesktop.Platform//20.08
# flatpak --user install -y flathub org.freedesktop.Sdk//20.08
# flatpak-builder --jobs=4 --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
# flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
- name: 📦 Bundle DEB
run: |
cp -r build/DEBIAN build/DebDir
dpkg-deb -Zgzip --build build/DebDir
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04.deb
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04-x86_64.deb
- name: ⬆️ Upload DEB
uses: actions/upload-artifact@v3
with:
name: Ubuntu 22.04 DEB x86_64
path: '*.deb'
# AppImage build
appimage:
runs-on: ubuntu-22.04
name: ⬇️ AppImage
steps:
- name: 🧰 Checkout
uses: actions/checkout@v3
with:
submodules: recursive
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build-appimage/CMakeCache.txt
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update
sudo bash dist/get_deps_debian.sh
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
sudo chmod +x /usr/local/bin/appimagetool
sudo pip3 install git+https://github.com/iTrooz/appimage-builder@dpkg-package-versions
- name: 📜 Set version variable
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
# AppImage cmake build
- name: 🛠️ Reconfigure build for AppImage
- name: 🛠️ Build
run: |
mkdir -p build-appimage
cd build-appimage
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DIMHEX_PLUGINS_IN_SHARE=ON \
-DIMHEX_USE_BUNDLED_CA=ON \
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DIMHEX_PLUGINS_IN_SHARE=ON \
-DIMHEX_USE_BUNDLED_CA=ON \
..
make -j 4 install DESTDIR=AppDir
@@ -328,36 +357,23 @@ jobs:
export VERSION=${{env.IMHEX_VERSION}}
appimage-builder --recipe ../dist/AppImageBuilder.yml
#- name: ⬆️ Upload Flatpak
# uses: actions/upload-artifact@v3
# with:
# name: Linux Flatpak
# path: |
# imhex.flatpak
- name: ⬆️ Upload DEB
uses: actions/upload-artifact@v3
with:
name: Ubuntu 22.04 DEB
path: '*.deb'
- name: ⬆️ Upload AppImage
uses: actions/upload-artifact@v3
with:
name: Linux AppImage
name: Linux AppImage x86_64
path: 'build-appimage/*.AppImage'
- name: ⬆️ Upload AppImage zsync
uses: actions/upload-artifact@v3
with:
name: Linux AppImage zsync
name: Linux AppImage zsync x86_64
path: 'build-appimage/*.AppImage.zsync'
# ArchLinux build
archlinux-build:
name: 🐧 ArchLinux
runs-on: ubuntu-latest
container:
image: archlinux:base-devel
@@ -369,7 +385,7 @@ jobs:
- name: ⬇️ Install setup dependencies
run: |
pacman -Syu git ccache --noconfirm
- name: 🧰 Checkout
uses: actions/checkout@v3
with:
@@ -385,38 +401,41 @@ jobs:
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
# ArchLinux cmake build
- name: 🛠️ Build
run: |
mkdir -p build
cd build
CC=gcc CXX=g++ cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SYSTEM_FMT=ON \
-DUSE_SYSTEM_YARA=ON \
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
-DUSE_SYSTEM_CAPSTONE=OFF \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
CC=gcc CXX=g++ cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SYSTEM_FMT=ON \
-DUSE_SYSTEM_YARA=ON \
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
-DUSE_SYSTEM_CAPSTONE=OFF \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
..
make -j 4 install DESTDIR=installDir
- name: 📜 Set version variable
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
- name: ✒️ Prepare PKGBUILD
run: |
cp dist/Arch/PKGBUILD build
@@ -426,91 +445,146 @@ jobs:
- name: 📦 Package ArchLinux .pkg.tar.zst
run: |
cd build
# the name is a small trick to make makepkg recognize it as the source
# else, it would try to download the file from the release
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst -C installDir .
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
chmod -R 777 .
sudo -u nobody makepkg
# Replace the old file
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
uses: actions/upload-artifact@v3
with:
name: ArchLinux .pkg.tar.zst
name: ArchLinux .pkg.tar.zst x86_64
path: |
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
# Fedora build
fedora-build:
# RPM distro builds
rpm-build:
strategy:
matrix:
include:
- docker_image: fedora:latest
release: Latest
- docker_image: fedora:rawhide
release: Rawhide
- name: Fedora
mock_release: rawhide
release_num: rawhide
mock_config: fedora-rawhide
- name: Fedora
mock_release: f38
release_num: 38
mock_config: fedora-38
- name: Fedora
mock_release: f37
release_num: 37
mock_config: fedora-37
- name: Fedora
mock_release: f36
release_num: 36
mock_config: fedora-36
- name: RHEL-AlmaLinux
mock_release: epel9
release_num: 9
mock_config: "alma+epel-9"
name: 🐧 Fedora ${{ matrix.release }}
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
runs-on: ubuntu-latest
container:
image: "${{ matrix.docker_image }}"
image: "fedora:latest"
options: --privileged
steps:
- name: ⬇️ Update all packages
run: |
dnf upgrade -y
- name: ⬇️ Install git-core
run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y
- name: ⬇️ Install setup dependencies
run: |
dnf install -y \
ccache \
desktop-file-utils \
fmt-devel \
git \
json-devel \
libcurl-devel \
llvm-devel \
mbedtls-devel \
rpm-build \
yara-devel
- name: 🧰 Checkout
uses: actions/checkout@v3
with:
path: ImHex
submodules: recursive
- name: ⬇️ Install ImHex dependencies
- name: 📜 Setup DNF Cache
uses: actions/cache@v3
with:
path: /var/cache/dnf
key: ${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-${{ github.run_id }}
restore-keys: |
${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-
- name: ⬇️ Update all packages and install dependencies
run: |
dist/get_deps_fedora.sh
dnf upgrade --disablerepo="*" --enablerepo="fedora,updates" -y
dnf install --disablerepo="*" --enablerepo="fedora,updates" -y \
fedpkg \
ccache
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
uses: hendrikmuhs/ccache-action@v1.2.5
with:
key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
key: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build
max-size: 1G
- name: 📜 Set version variable
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
echo "IMHEX_VERSION=`cat ImHex/VERSION`" >> $GITHUB_ENV
- name: 🗜️ Create tarball from sources with dependencies
run: tar --exclude-vcs -czf $GITHUB_WORKSPACE/imhex-$IMHEX_VERSION.tar.gz ImHex
- name: ✒️ Modify spec file
run: |
sed -i \
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
-e '/%files/a %{_datadir}/%{name}/' \
$GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
- name: 📜 Fix ccache on EL9
if: matrix.mock_release == 'epel9'
run: sed -i '/\. \/opt\/rh\/gcc-toolset-12\/enable/a PATH=/usr/lib64/ccache:$PATH' $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
- name: 🟩 Copy spec file to build root
run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec
- name: 📜 Enable ccache for mock
run: |
cat <<EOT > $GITHUB_WORKSPACE/mock.cfg
include('${{ matrix.mock_config }}-x86_64.cfg')
config_opts['plugin_conf']['ccache_enable'] = True
config_opts['plugin_conf']['ccache_opts']['max_cache_size'] = '1G'
config_opts['plugin_conf']['ccache_opts']['compress'] = True
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
EOT
- name: 📜 Setup Mock Cache
uses: actions/cache@v3
with:
path: /var/cache/mock
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
restore-keys: |
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-
# Fedora cmake build (in imhex.spec)
- name: 📦 Build RPM
run: |
rpmbuild -ba --define "_version ${{env.IMHEX_VERSION}}" --define "_src_path $GITHUB_WORKSPACE" --define "_build_type $BUILD_TYPE" $GITHUB_WORKSPACE/dist/rpm/imhex.spec
mv ~/rpmbuild/RPMS/x86_64/*.rpm imhex-${{env.IMHEX_VERSION}}-Fedora-${{matrix.release}}.rpm
fedpkg --path $GITHUB_WORKSPACE --release ${{ matrix.mock_release }} mockbuild --enable-network -N --root $GITHUB_WORKSPACE/mock.cfg extra_args -- -v
- name: 🟩 Move and rename finished RPM
run: |
mv $GITHUB_WORKSPACE/results_imhex/${{env.IMHEX_VERSION}}/*/imhex-${{env.IMHEX_VERSION}}-0.*.x86_64.rpm \
$GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
- name: ⬆️ Upload RPM
uses: actions/upload-artifact@v3
with:
name: Fedora ${{ matrix.release }} RPM
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
path: |
imhex-${{env.IMHEX_VERSION}}-Fedora-${{matrix.release}}.rpm
imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm

View File

@@ -9,9 +9,66 @@ on:
workflow_dispatch:
jobs:
release-common:
release-update-repos:
runs-on: ubuntu-latest
name: Release Common
name: Release Update Repos
steps:
- name: 📜 Verify version and set version variable
run: |
project_version=`cat ImHex/VERSION`
tag_version="${{github.event.release.tag_name}}"
tag_version="${tag_version:1}"
if [ "$project_version" != "$tag_version" ]; then
echo "::warning::$project_version and $tag_version are not the same ! Refusing to populate release"
exit 1
fi
echo "IMHEX_VERSION=$project_version" >> $GITHUB_ENV
- name: 🎫 Create PatternLanguage release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{ env.IMHEX_VERSION }}
repo: PatternLanguage
token: ${{ secrets.RELEASE_TOKEN }}
- name: 🎫 Create ImHex-Patterns release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{ env.IMHEX_VERSION }}
repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }}
- name: ✉️ Update C++ Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Cpp-Plugin-Template
event-type: update_submodule
- name: ✉️ Update Rust Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Rust-Plugin-Template
event-type: update_submodule
release-upload-artifacts:
runs-on: ubuntu-latest
name: Release Upload Artifacts
steps:
- name: 🧰 Checkout
@@ -34,7 +91,7 @@ jobs:
- name: 🗜️ Create tarball from sources with dependencies
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
- name: ⬇️ Download artifacts from latest workflow
uses: dawidd6/action-download-artifact@v2
with:
@@ -43,7 +100,7 @@ jobs:
branch: ${{ github.event.release.target_commitish }}
workflow_conclusion: success
skip_unpack: true
- name: 🗜️ Unzip files when needed
run: |
for zipfile in ./*.zip
@@ -60,8 +117,8 @@ jobs:
- name: 🟩 Rename artifacts when needed
run: |
mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
mv "Windows Portable NoGPU.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-NoGPU.zip
mv "Windows Portable x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-x86_64.zip
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip
- name: ⬆️ Upload everything to release
uses: softprops/action-gh-release@v1
@@ -72,14 +129,13 @@ jobs:
run: |
cp ImHex/dist/Arch/PKGBUILD .
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst | cut -d ' ' -f 1`
hash=`md5sum imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
sed -i 's/%version%/${{env.IMHEX_VERSION}}/g' PKGBUILD
sed -i 's/%version%/${{ env.IMHEX_VERSION }}/g' PKGBUILD
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
- name: ⬆️ Publish AUR package
# I couldn't make the condition in the env directly for some reason
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
if: "${{ env.AUR_SSH_PRIVATE_KEY != '' }}"
@@ -91,60 +147,18 @@ jobs:
commit_username: iTrooz
commit_email: itrooz@protonmail.com
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: Bump to version ${{env.IMHEX_VERSION}}
commit_message: Bump to version ${{ env.IMHEX_VERSION }}
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
- name: 🎫 Create PatternLanguage release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: PatternLanguage
token: ${{ secrets.RELEASE_TOKEN }}
- name: 🎫 Create ImHex-Patterns release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }}
- name: ✉️ Update C++ Plugin Template
uses: mvasigh/dispatch-action@main
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repo: ImHex-Cpp-Plugin-Template
owner: WerWolv
event_type: update_submodule
- name: ✉️ Update Rust Plugin Template
uses: mvasigh/dispatch-action@main
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repo: ImHex-Rust-Plugin-Template
owner: WerWolv
event_type: update_submodule
release-windows:
name: Release Windows
needs: release-common
runs-on: windows-2022
release-update-winget:
name: Release update winget package
needs: release-upload-artifacts
runs-on: windows-latest
steps:
- name: ⬇️ Download dependencies
shell: pwsh
run: |
iwr https://github.com/microsoft/winget-create/releases/download/v1.1.2.0/wingetcreate.exe -OutFile wingetcreate.exe
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
- name: ⬆️ Update winget manifest
shell: pwsh
env:
@@ -153,7 +167,7 @@ jobs:
run: |
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
$version = $tagname.Replace("v", "")
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-win64.msi"
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-Windows-x86_64.msi"
.\wingetcreate.exe update WerWolv.ImHex -u $url --version $version
if ($version -notmatch "-") {
.\wingetcreate.exe submit .\manifests\w\WerWolv\ImHex\${version}\ --token $env:WINGET_GITHUB_TOKEN

View File

@@ -25,18 +25,18 @@ jobs:
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update
@@ -48,14 +48,13 @@ jobs:
cd build
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
-DIMHEX_OFFLINE_BUILD=ON \
..
make -j4 unit_tests install
make -j4 unit_tests
- name: 🧪 Perform Unit Tests
run: |

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ venv/
*.mgc
imgui.ini
.DS_Store
./CMakeUserPresets.json

3
.gitmodules vendored
View File

@@ -29,3 +29,6 @@
[submodule "lib/external/pattern_language"]
path = lib/external/pattern_language
url = https://github.com/WerWolv/PatternLanguage
[submodule "lib/external/libwolv"]
path = lib/external/libwolv
url = https://github.com/WerWolv/libwolv

View File

@@ -8,6 +8,9 @@ option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
option(IMHEX_DISABLE_UPDATE_CHECK "Disables built-in update check" OFF)
# Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23)
@@ -19,7 +22,11 @@ include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
# Setup project
loadVersion(IMHEX_VERSION)
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
project(imhex VERSION ${IMHEX_VERSION})
project(imhex
LANGUAGES C CXX VERSION ${IMHEX_VERSION}
DESCRIPTION "The ImHex Hex Editor"
HOMEPAGE_URL "https://imhex.werwolv.net"
)
# Make sure project is configured correctly
setDefaultBuiltTypeIfUnset()
@@ -35,7 +42,7 @@ set(PLUGINS
# Add various defines
detectOS()
detectArch()
addVersionDefines()
addDefines()
configurePackingResources()
setUninstallTarget()
addBundledLibraries()
@@ -43,7 +50,7 @@ addBundledLibraries()
# Add ImHex sources
add_subdirectory(lib/libimhex)
add_subdirectory(main)
add_custom_target(imhex_all ALL DEPENDS main)
add_custom_target(imhex_all ALL DEPENDS main libimhex)
# Add unit tests
enable_testing()

47
CMakePresets.json Normal file
View File

@@ -0,0 +1,47 @@
{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "base",
"displayName": "Base",
"description": "Base configuration for all builds",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"generator": "Ninja",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
"CMAKE_C_FLAGS": "-fuse-ld=lld",
"CMAKE_CXX_FLAGS": "-fuse-ld=lld",
"IMHEX_PATTERNS_PULL_MASTER": "ON",
"CMAKE_INSTALL_PREFIX": "./install",
"USE_SYSTEM_CURL": "ON"
}
},
{
"name": "x86_64",
"displayName": "x86_64 Build",
"description": "x86_64 build",
"inherits": [ "base" ]
}
],
"buildPresets": [
{
"name": "x86_64",
"description": "x86_64 build",
"configurePreset": "x86_64",
"targets": [ "imhex_all" ]
}
],
"testPresets": [
]
}

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
Discord @WerWolv#1337.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

View File

@@ -6,6 +6,55 @@ The easiest way to install ImHex is to download the latest release from the [Git
There's also a NoGPU version available for users who don't have a GPU or want to run ImHex in a VM without GPU passthrough.
### Windows
#### Installer
Simply run the installer to install ImHex on your system
#### Portable
Extract the zip file to any location on your system.
### macOS
Simply use the drag-n-drop dmg package to install ImHex on your system. It's possible that you need to allow the app to run in the security settings.
### Linux
#### AppImage
To run the AppImage, make sure it's executable. Then simply run it.
```bash
chmod +x imhex-*.AppImage
./imhex-*.AppImage
```
#### Flatpak
To install the Flatpak, make sure you have the Flathub repository added to your system. Then simply run the following command:
```bash
flatpak install flathub net.werwolv.ImHex
```
#### Ubuntu DEB Package
To install the DEB package, simply run the following command:
```bash
sudo apt install ./imhex-*.deb
```
#### Arch Linux
To install the Arch Linux package, simply run the following command:
```bash
sudo pacman -U imhex-*.pkg.tar.zst
```
#### Fedora / RHEL / AlmaLinux RPM Package
To install the RPM package, simply run the following command:
```bash
sudo dnf install ./imhex-*.rpm
```
## Nightly Builds
The GitHub Actions CI builds a new release package on every commit made to repository. These builds are available on the [GitHub Actions page](https://github.com/WerWolv/ImHex/actions?query=workflow%3A%22Build%22).
@@ -24,10 +73,10 @@ ImHex is also available on various package managers. The officially supported on
### Windows
- **Cocolatey**
- **Chocolatey**
- [imhex](https://community.chocolatey.org/packages/imhex) (Thanks to @Jarcho)
- `choco install imhex`
- **winget**
- **Winget**
- [WerWolv.ImHex](https://github.com/microsoft/winget-pkgs/tree/master/manifests/w/WerWolv/ImHex)
- `winget install WerWolv.ImHex`

View File

@@ -1,16 +1,33 @@
<a href="https://imhex.werwolv.net">
<h1 align="center">
<img height="100px" src="./resources/projects/logo_text_light.svg#gh-dark-mode-only">
<img height="100px" src="./resources/projects/logo_text_dark.svg#gh-light-mode-only">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./resources/projects/logo_text_light.svg">
<img height="100px" src="./resources/projects/logo_text_dark.svg">
</picture>
</h1>
</a>
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
<p align="center">
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master"></a>
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&style=for-the-badge"></a>
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest"><img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub"></a>
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild">
<img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master">
</a>
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY">
<img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge">
</a>
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest">
<img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub">
</a>
<a title="Code Quality" href="https://www.codefactor.io/repository/github/werwolv/imhex">
<img alt="Code Quality" src="https://img.shields.io/codefactor/grade/github/WerWolv/ImHex?longCache=true&style=for-the-badge&label=Code%20Quality&logoColor=fff&logo=CodeFactor&branch=master">
</a>
<a title="Translation" href="https://weblate.werwolv.net/projects/imhex/">
<img alt="Translation" src="https://img.shields.io/weblate/progress/imhex?logo=weblate&logoColor=%23FFFFFF&server=https%3A%2F%2Fweblate.werwolv.net&style=for-the-badge">
</a>
<a title="Documentation" href="https://imhex.werwolv.net/docs">
<img alt="Documentation" src="https://img.shields.io/badge/Docs-Available-brightgreen?logo=gitbook&logoColor=%23FFFFFF&style=for-the-badge">
</a>
</p>
## Supporting
@@ -125,10 +142,12 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
To use ImHex, the following minimal system requirements need to be met:
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora Stable/Rawhide, and Arch Linux have official packages, other distributions can use the AppImage)
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora 36/37, RHEL/AlmaLinux 9, and Arch Linux have official packages, other and older distributions can use the AppImage)
- **CPU**: x86_64 (64 Bit)
- **GPU**: OpenGL 3.0 or higher (preferable a dedicated GPU and not Intel HD Graphics)
- **RAM**: 512MB, more may be required for more complicated analysis
- **GPU**: OpenGL 3.0 or higher
- Intel HD drivers are really buggy and often cause graphic artifacts
- In case you don't have a GPU available, there are software rendered releases available for Windows and macOS
- **RAM**: 256MB, more may be required for more complicated analysis
- **Storage**: 100MB
## Installing

10
SECURITY.md Normal file
View File

@@ -0,0 +1,10 @@
# Security Policy
## Supported Versions
Supported is generally only the latest version that can be downloaded from the Release tab. If you have issues, you might get instructed to use the Nightly release version instead.
If you built ImHex yourself and experience issues that are not present in the version built by GitHub, you're on your own.
## Reporting a Vulnerability
Any critical vulnearabilities can be reported through Discord @WerWolv#1337

View File

@@ -1 +1 @@
1.26.0
1.29.0

View File

@@ -1,37 +1,58 @@
include(FetchContent)
if(IMHEX_STRIP_RELEASE)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
if(CMAKE_BUILD_TYPE STREQUAL "Release")
set(CPACK_STRIP_FILES TRUE)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_link_options($<$<CONFIG:RELEASE>:-s>)
endif()
endif()
macro(addVersionDefines)
macro(addDefines)
if (NOT IMHEX_VERSION)
message(FATAL_ERROR "IMHEX_VERSION is not defined")
endif ()
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/.git")
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_HASH_SHORT AND DEFINED IMHEX_COMMIT_BRANCH)
add_compile_definitions(
GIT_COMMIT_HASH_LONG="${IMHEX_COMMIT_HASH_LONG}"
IMHEX_COMMIT_HASH_SHORT="${IMHEX_COMMIT_HASH_SHORT}"
GIT_BRANCH="${IMHEX_COMMIT_BRANCH}"
)
else()
# Get the current working branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_BRANCH
)
# Get the latest abbreviated commit hash of the working branch
execute_process(
COMMAND git log -1 --format=%h
COMMAND git log -1 --format=%h --abbrev=7
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_VARIABLE GIT_COMMIT_HASH_SHORT
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_SHORT
)
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
execute_process(
COMMAND git log -1 --format=%H
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_LONG
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_LONG
)
if (RESULT_BRANCH EQUAL 0 AND RESULT_HASH_LONG EQUAL 0 AND RESULT_HASH_SHORT EQUAL 0)
add_compile_definitions(
GIT_COMMIT_HASH_SHORT="${GIT_COMMIT_HASH_SHORT}"
GIT_COMMIT_HASH_LONG="${GIT_COMMIT_HASH_LONG}"
GIT_BRANCH="${GIT_BRANCH}")
endif ()
endif ()
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
@@ -39,17 +60,23 @@ macro(addVersionDefines)
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
add_compile_definitions(NDEBUG)
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
add_compile_definitions(DEBUG _GLIBCXX_DEBUG)
add_compile_definitions(DEBUG _GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-RelWithDebInfo)
add_compile_definitions(NDEBUG)
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-MinSizeRel)
add_compile_definitions(NDEBUG)
endif ()
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
if (NOT IMHEX_DISABLE_UPDATE_CHECK)
add_compile_definitions(HEX_UPDATE_CHECK)
endif()
endmacro()
# Detect current OS / System
@@ -60,7 +87,9 @@ macro(detectOS)
set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins")
SET(IMHEX_USE_BUNDLED_CA ON)
if (NOT USE_SYSTEM_CURL)
SET(IMHEX_USE_BUNDLED_CA ON)
endif ()
elseif (APPLE)
add_compile_definitions(OS_MACOS)
set(CMAKE_INSTALL_BINDIR ".")
@@ -114,7 +143,7 @@ macro(configurePackingResources)
if (CREATE_PACKAGE)
set(CPACK_GENERATOR "WIX")
set(CPACK_PACKAGE_NAME "imhex")
set(CPACK_PACKAGE_NAME "ImHex")
set(CPACK_PACKAGE_VENDOR "WerWolv")
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
@@ -139,7 +168,7 @@ macro(configurePackingResources)
set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/dist/macos/Info.plist.in")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH_SHORT}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
string(TIMESTAMP CURR_YEAR "%Y")
@@ -384,7 +413,7 @@ endfunction()
macro(setupCompilerWarnings target)
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow")
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-array-bounds -Wno-dangling-reference")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
@@ -416,8 +445,13 @@ macro(addBundledLibraries)
add_subdirectory(${EXTERN_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${EXTERN_LIBS_FOLDER}/intervaltree EXCLUDE_FROM_ALL)
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${EXTERN_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-containers PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-net PROPERTY POSITION_INDEPENDENT_CODE ON)
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
set(CURL_USE_MBEDTLS ON)
@@ -433,8 +467,13 @@ macro(addBundledLibraries)
set(FMT_LIBRARIES fmt::fmt)
endif()
if (IMHEX_USE_GTK_FILE_PICKER)
set(NFD_PORTAL OFF CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
else ()
set(NFD_PORTAL ON CACHE BOOL "Use GTK for Linux file dialogs" FORCE)
endif ()
if (NOT USE_SYSTEM_NFD)
set(NFD_PORTAL ON CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
add_subdirectory(${EXTERN_LIBS_FOLDER}/nativefiledialog EXCLUDE_FROM_ALL)
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(NFD_LIBRARIES nfd)
@@ -454,6 +493,7 @@ macro(addBundledLibraries)
if(NOT USE_SYSTEM_CURL)
add_subdirectory(${EXTERN_LIBS_FOLDER}/curl EXCLUDE_FROM_ALL)
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_compile_options(libcurl PRIVATE -Wno-deprecated-declarations)
set(LIBCURL_LIBRARIES libcurl)
else()
find_package(PkgConfig REQUIRED)
@@ -476,6 +516,15 @@ macro(addBundledLibraries)
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
endif()
if (NOT USE_SYSTEM_MINIAUDIO)
add_subdirectory(${EXTERN_LIBS_FOLDER}/miniaudio EXCLUDE_FROM_ALL)
set_target_properties(miniaudio PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(MINIAUDIO_LIBRARIES miniaudio)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(miniaudio REQUIRED IMPORTED_TARGET miniaudio)
endif()
if (NOT USE_SYSTEM_CAPSTONE)
set(CAPSTONE_BUILD_STATIC_RUNTIME OFF CACHE BOOL "Disable shared library building")
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
@@ -500,4 +549,28 @@ macro(addBundledLibraries)
else()
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
endif()
if (NOT IMHEX_DISABLE_STACKTRACE)
if (WIN32)
message(STATUS "StackWalk enabled!")
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
else ()
find_package(Backtrace)
if (${Backtrace_FOUND})
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
if (Backtrace_HEADER STREQUAL "execinfo.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(HEX_HAS_EXECINFO)
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(HEX_HAS_BACKTRACE)
endif ()
endif()
endif ()
endif ()
endmacro()

View File

@@ -0,0 +1,91 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindBacktrace
-------------
Find provider for `backtrace(3) <https://man7.org/linux/man-pages/man3/backtrace.3.html>`__.
Checks if OS supports ``backtrace(3)`` via either ``libc`` or custom library.
This module defines the following variables:
``Backtrace_HEADER``
The header file needed for ``backtrace(3)``. Cached.
Could be forcibly set by user.
``Backtrace_INCLUDE_DIRS``
The include directories needed to use ``backtrace(3)`` header.
``Backtrace_LIBRARIES``
The libraries (linker flags) needed to use ``backtrace(3)``, if any.
``Backtrace_FOUND``
Is set if and only if ``backtrace(3)`` support detected.
The following cache variables are also available to set or use:
``Backtrace_LIBRARY``
The external library providing backtrace, if any.
``Backtrace_INCLUDE_DIR``
The directory holding the ``backtrace(3)`` header.
Typical usage is to generate of header file using :command:`configure_file`
with the contents like the following::
#cmakedefine01 Backtrace_FOUND
#if Backtrace_FOUND
# include <${Backtrace_HEADER}>
#endif
And then reference that generated header file in actual source.
#]=======================================================================]
include(CMakePushCheckState)
include(CheckSymbolExists)
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
# List of variables to be provided to find_package_handle_standard_args()
set(_Backtrace_STD_ARGS Backtrace_INCLUDE_DIR)
if(Backtrace_HEADER)
set(_Backtrace_HEADER_TRY "${Backtrace_HEADER}")
else(Backtrace_HEADER)
set(_Backtrace_HEADER_TRY "execinfo.h")
endif(Backtrace_HEADER)
find_path(Backtrace_INCLUDE_DIR "${_Backtrace_HEADER_TRY}")
set(Backtrace_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
if (NOT DEFINED Backtrace_LIBRARY)
# First, check if we already have backtrace(), e.g., in libc
cmake_push_check_state(RESET)
set(CMAKE_REQUIRED_INCLUDES ${Backtrace_INCLUDE_DIRS})
set(CMAKE_REQUIRED_QUIET ${Backtrace_FIND_QUIETLY})
check_symbol_exists("backtrace" "${_Backtrace_HEADER_TRY}" _Backtrace_SYM_FOUND)
cmake_pop_check_state()
endif()
if(_Backtrace_SYM_FOUND)
# Avoid repeating the message() call below each time CMake is run.
if(NOT Backtrace_FIND_QUIETLY AND NOT DEFINED Backtrace_LIBRARY)
message(STATUS "backtrace facility detected in default set of libraries")
endif()
set(Backtrace_LIBRARY "" CACHE FILEPATH "Library providing backtrace(3), empty for default set of libraries")
else()
# Check for external library, for non-glibc systems
if(Backtrace_INCLUDE_DIR)
# OpenBSD has libbacktrace renamed to libexecinfo
find_library(Backtrace_LIBRARY "execinfo")
else() # respect user wishes
set(_Backtrace_HEADER_TRY "backtrace.h")
find_path(Backtrace_INCLUDE_DIR ${_Backtrace_HEADER_TRY})
find_library(Backtrace_LIBRARY "backtrace")
endif()
# Prepend list with library path as it's more common practice
set(_Backtrace_STD_ARGS Backtrace_LIBRARY ${_Backtrace_STD_ARGS})
endif()
set(Backtrace_LIBRARIES ${Backtrace_LIBRARY})
set(Backtrace_HEADER "${_Backtrace_HEADER_TRY}" CACHE STRING "Header providing backtrace(3) facility")
find_package_handle_standard_args(Backtrace FOUND_VAR Backtrace_FOUND REQUIRED_VARS ${_Backtrace_STD_ARGS})
mark_as_advanced(Backtrace_HEADER Backtrace_INCLUDE_DIR Backtrace_LIBRARY)

View File

@@ -0,0 +1,611 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindPackageHandleStandardArgs
-----------------------------
This module provides functions intended to be used in :ref:`Find Modules`
implementing :command:`find_package(<PackageName>)` calls.
.. command:: find_package_handle_standard_args
This command handles the ``REQUIRED``, ``QUIET`` and version-related
arguments of :command:`find_package`. It also sets the
``<PackageName>_FOUND`` variable. The package is considered found if all
variables listed contain valid results, e.g. valid filepaths.
There are two signatures:
.. code-block:: cmake
find_package_handle_standard_args(<PackageName>
(DEFAULT_MSG|<custom-failure-message>)
<required-var>...
)
find_package_handle_standard_args(<PackageName>
[FOUND_VAR <result-var>]
[REQUIRED_VARS <required-var>...]
[VERSION_VAR <version-var>]
[HANDLE_VERSION_RANGE]
[HANDLE_COMPONENTS]
[CONFIG_MODE]
[NAME_MISMATCHED]
[REASON_FAILURE_MESSAGE <reason-failure-message>]
[FAIL_MESSAGE <custom-failure-message>]
)
The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all
the variables ``<required-var>...`` are valid and any optional
constraints are satisfied, and ``FALSE`` otherwise. A success or
failure message may be displayed based on the results and on
whether the ``REQUIRED`` and/or ``QUIET`` option was given to
the :command:`find_package` call.
The options are:
``(DEFAULT_MSG|<custom-failure-message>)``
In the simple signature this specifies the failure message.
Use ``DEFAULT_MSG`` to ask for a default message to be computed
(recommended). Not valid in the full signature.
``FOUND_VAR <result-var>``
.. deprecated:: 3.3
Specifies either ``<PackageName>_FOUND`` or
``<PACKAGENAME>_FOUND`` as the result variable. This exists only
for compatibility with older versions of CMake and is now ignored.
Result variables of both names are always set for compatibility.
``REQUIRED_VARS <required-var>...``
Specify the variables which are required for this package.
These may be named in the generated failure message asking the
user to set the missing variable values. Therefore these should
typically be cache entries such as ``FOO_LIBRARY`` and not output
variables like ``FOO_LIBRARIES``.
.. versionchanged:: 3.18
If ``HANDLE_COMPONENTS`` is specified, this option can be omitted.
``VERSION_VAR <version-var>``
Specify the name of a variable that holds the version of the package
that has been found. This version will be checked against the
(potentially) specified required version given to the
:command:`find_package` call, including its ``EXACT`` option.
The default messages include information about the required
version and the version which has been actually found, both
if the version is ok or not.
``HANDLE_VERSION_RANGE``
.. versionadded:: 3.19
Enable handling of a version range, if one is specified. Without this
option, a developer warning will be displayed if a version range is
specified.
``HANDLE_COMPONENTS``
Enable handling of package components. In this case, the command
will report which components have been found and which are missing,
and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``
if any of the required components (i.e. not the ones listed after
the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are
missing.
``CONFIG_MODE``
Specify that the calling find module is a wrapper around a
call to ``find_package(<PackageName> NO_MODULE)``. This implies
a ``VERSION_VAR`` value of ``<PackageName>_VERSION``. The command
will automatically check whether the package configuration file
was found.
``REASON_FAILURE_MESSAGE <reason-failure-message>``
.. versionadded:: 3.16
Specify a custom message of the reason for the failure which will be
appended to the default generated message.
``FAIL_MESSAGE <custom-failure-message>``
Specify a custom failure message instead of using the default
generated message. Not recommended.
``NAME_MISMATCHED``
.. versionadded:: 3.17
Indicate that the ``<PackageName>`` does not match
``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a
warning, but it may be intentional for usage of the command for components
of a larger package.
Example for the simple signature:
.. code-block:: cmake
find_package_handle_standard_args(LibXml2 DEFAULT_MSG
LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
The ``LibXml2`` package is considered to be found if both
``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.
Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found
and ``REQUIRED`` was used, it fails with a
:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was
used or not. If it is found, success will be reported, including
the content of the first ``<required-var>``. On repeated CMake runs,
the same message will not be printed again.
.. note::
If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the
calling module, a warning that there is a mismatch is given. The
``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using
the old signature and the ``NAME_MISMATCHED`` argument using the new
signature. To avoid forcing the caller to require newer versions of CMake for
usage, the variable's value will be used if defined when the
``NAME_MISMATCHED`` argument is not passed for the new signature (but using
both is an error)..
Example for the full signature:
.. code-block:: cmake
find_package_handle_standard_args(LibArchive
REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
VERSION_VAR LibArchive_VERSION)
In this case, the ``LibArchive`` package is considered to be found if
both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.
Also the version of ``LibArchive`` will be checked by using the version
contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given,
the default messages will be printed.
Another example for the full signature:
.. code-block:: cmake
find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
find_package_handle_standard_args(Automoc4 CONFIG_MODE)
In this case, a ``FindAutmoc4.cmake`` module wraps a call to
``find_package(Automoc4 NO_MODULE)`` and adds an additional search
directory for ``automoc4``. Then the call to
``find_package_handle_standard_args`` produces a proper success/failure
message.
.. command:: find_package_check_version
.. versionadded:: 3.19
Helper function which can be used to check if a ``<version>`` is valid
against version-related arguments of :command:`find_package`.
.. code-block:: cmake
find_package_check_version(<version> <result-var>
[HANDLE_VERSION_RANGE]
[RESULT_MESSAGE_VARIABLE <message-var>]
)
The ``<result-var>`` will hold a boolean value giving the result of the check.
The options are:
``HANDLE_VERSION_RANGE``
Enable handling of a version range, if one is specified. Without this
option, a developer warning will be displayed if a version range is
specified.
``RESULT_MESSAGE_VARIABLE <message-var>``
Specify a variable to get back a message describing the result of the check.
Example for the usage:
.. code-block:: cmake
find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE
RESULT_MESSAGE_VARIABLE reason)
if (result)
message (STATUS "${reason}")
else()
message (FATAL_ERROR "${reason}")
endif()
#]=======================================================================]
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
cmake_policy(PUSH)
# numbers and boolean constants
cmake_policy (SET CMP0012 NEW)
# IN_LIST operator
cmake_policy (SET CMP0057 NEW)
# internal helper macro
macro(_FPHSA_FAILURE_MESSAGE _msg)
set (__msg "${_msg}")
if (FPHSA_REASON_FAILURE_MESSAGE)
string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n")
endif()
if (${_NAME}_FIND_REQUIRED)
message(FATAL_ERROR "${__msg}")
else ()
if (NOT ${_NAME}_FIND_QUIETLY)
message(STATUS "${__msg}")
endif ()
endif ()
endmacro()
# internal helper macro to generate the failure message when used in CONFIG_MODE:
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
# <PackageName>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
if(${_NAME}_CONFIG)
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
else()
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
# List them all in the error message:
if(${_NAME}_CONSIDERED_CONFIGS)
set(configsText "")
list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
math(EXPR configsCount "${configsCount} - 1")
foreach(currentConfigIndex RANGE ${configsCount})
list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
string(APPEND configsText "\n ${filename} (version ${version})")
endforeach()
if (${_NAME}_NOT_FOUND_MESSAGE)
if (FPHSA_REASON_FAILURE_MESSAGE)
string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ")
else()
set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}")
endif()
else()
string(APPEND configsText "\n")
endif()
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}")
else()
# Simple case: No Config-file was found at all:
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
endif()
endif()
endmacro()
function(FIND_PACKAGE_CHECK_VERSION version result)
cmake_parse_arguments (PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "")
if (FPCV_UNPARSED_ARGUMENTS)
message (FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments")
endif()
if ("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES)
message (FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument")
endif()
set (${result} FALSE PARENT_SCOPE)
if (FPCV_RESULT_MESSAGE_VARIABLE)
unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE)
endif()
if (_CMAKE_FPHSA_PACKAGE_NAME)
set (package "${_CMAKE_FPHSA_PACKAGE_NAME}")
elseif (CMAKE_FIND_PACKAGE_NAME)
set (package "${CMAKE_FIND_PACKAGE_NAME}")
else()
message (FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'")
endif()
if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE
AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE)
message(AUTHOR_WARNING
"`find_package()` specify a version range but the option "
"HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. "
"Only the lower endpoint of the range will be used.")
endif()
set (version_ok FALSE)
unset (version_msg)
if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE)
if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN)
AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX)
OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
AND version VERSION_LESS ${package}_FIND_VERSION_MAX)))
set (version_ok TRUE)
set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")")
else()
set(version_msg "Found unsuitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\"")
endif()
elseif (DEFINED ${package}_FIND_VERSION)
if(${package}_FIND_VERSION_EXACT) # exact version required
# count the dots in the version string
string(REGEX REPLACE "[^.]" "" version_dots "${version}")
# add one dot because there is one dot more than there are components
string(LENGTH "${version_dots}." version_dots)
if (version_dots GREATER ${package}_FIND_VERSION_COUNT)
# Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT
# is at most 4 here. Therefore a simple lookup table is used.
if (${package}_FIND_VERSION_COUNT EQUAL 1)
set(version_regex "[^.]*")
elseif (${package}_FIND_VERSION_COUNT EQUAL 2)
set(version_regex "[^.]*\\.[^.]*")
elseif (${package}_FIND_VERSION_COUNT EQUAL 3)
set(version_regex "[^.]*\\.[^.]*\\.[^.]*")
else()
set(version_regex "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
endif()
string(REGEX REPLACE "^(${version_regex})\\..*" "\\1" version_head "${version}")
if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head)
set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
else ()
set(version_ok TRUE)
set(version_msg "(found suitable exact version \"${_FOUND_VERSION}\")")
endif ()
else ()
if (NOT ${package}_FIND_VERSION VERSION_EQUAL version)
set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
else ()
set(version_ok TRUE)
set(version_msg "(found suitable exact version \"${version}\")")
endif ()
endif ()
else() # minimum version
if (${package}_FIND_VERSION VERSION_GREATER version)
set(version_msg "Found unsuitable version \"${version}\", but required is at least \"${${package}_FIND_VERSION}\"")
else()
set(version_ok TRUE)
set(version_msg "(found suitable version \"${version}\", minimum required is \"${${package}_FIND_VERSION}\")")
endif()
endif()
else ()
set(version_ok TRUE)
set(version_msg "(found version \"${version}\")")
endif()
set (${result} ${version_ok} PARENT_SCOPE)
if (FPCV_RESULT_MESSAGE_VARIABLE)
set (${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE)
endif()
endfunction()
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
# Set up the arguments for `cmake_parse_arguments`.
set(options CONFIG_MODE HANDLE_COMPONENTS NAME_MISMATCHED HANDLE_VERSION_RANGE)
set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR)
set(multiValueArgs REQUIRED_VARS)
# Check whether we are in 'simple' or 'extended' mode:
set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
unset(FPHSA_NAME_MISMATCHED_override)
if (DEFINED FPHSA_NAME_MISMATCHED)
# If the variable NAME_MISMATCHED variable is set, error if it is passed as
# an argument. The former is for old signatures, the latter is for new
# signatures.
list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx)
if (NOT name_mismatched_idx EQUAL "-1")
message(FATAL_ERROR
"The `NAME_MISMATCHED` argument may only be specified by the argument or "
"the variable, not both.")
endif ()
# But use the variable if it is not an argument to avoid forcing minimum
# CMake version bumps for calling modules.
set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}")
endif ()
if(${INDEX} EQUAL -1)
set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
set(FPHSA_REQUIRED_VARS ${ARGN})
set(FPHSA_VERSION_VAR)
else()
cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
if(FPHSA_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
endif()
if(NOT FPHSA_FAIL_MESSAGE)
set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
endif()
# In config-mode, we rely on the variable <PackageName>_CONFIG, which is set by find_package()
# when it successfully found the config-file, including version checking:
if(FPHSA_CONFIG_MODE)
list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
endif()
if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS)
message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
endif()
endif()
if (DEFINED FPHSA_NAME_MISMATCHED_override)
set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}")
endif ()
if (DEFINED CMAKE_FIND_PACKAGE_NAME
AND NOT FPHSA_NAME_MISMATCHED
AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME)
message(AUTHOR_WARNING
"The package name passed to `find_package_handle_standard_args` "
"(${_NAME}) does not match the name of the calling package "
"(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling "
"code that expects `find_package` result variables (e.g., `_FOUND`) "
"to follow a certain pattern.")
endif ()
if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE)
message(AUTHOR_WARNING
"`find_package()` specify a version range but the module ${_NAME} does "
"not support this capability. Only the lower endpoint of the range "
"will be used.")
endif()
# to propagate package name to FIND_PACKAGE_CHECK_VERSION
set(_CMAKE_FPHSA_PACKAGE_NAME "${_NAME}")
# now that we collected all arguments, process them
if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
endif()
if (FPHSA_REQUIRED_VARS)
list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
endif()
string(TOUPPER ${_NAME} _NAME_UPPER)
string(TOLOWER ${_NAME} _NAME_LOWER)
if(FPHSA_FOUND_VAR)
set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)
set(_FOUND_VAR_MIXED ${_NAME}_FOUND)
if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
else()
message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.")
endif()
else()
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
endif()
# collect all variables which were not found, so they can be printed, so the
# user knows better what went wrong (#6375)
set(MISSING_VARS "")
set(DETAILS "")
# check if all passed variables are valid
set(FPHSA_FOUND_${_NAME} TRUE)
foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
if(NOT ${_CURRENT_VAR})
set(FPHSA_FOUND_${_NAME} FALSE)
string(APPEND MISSING_VARS " ${_CURRENT_VAR}")
else()
string(APPEND DETAILS "[${${_CURRENT_VAR}}]")
endif()
endforeach()
if(FPHSA_FOUND_${_NAME})
set(${_NAME}_FOUND TRUE)
set(${_NAME_UPPER}_FOUND TRUE)
else()
set(${_NAME}_FOUND FALSE)
set(${_NAME_UPPER}_FOUND FALSE)
endif()
# component handling
unset(FOUND_COMPONENTS_MSG)
unset(MISSING_COMPONENTS_MSG)
if(FPHSA_HANDLE_COMPONENTS)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(${_NAME}_${comp}_FOUND)
if(NOT DEFINED FOUND_COMPONENTS_MSG)
set(FOUND_COMPONENTS_MSG "found components:")
endif()
string(APPEND FOUND_COMPONENTS_MSG " ${comp}")
else()
if(NOT DEFINED MISSING_COMPONENTS_MSG)
set(MISSING_COMPONENTS_MSG "missing components:")
endif()
string(APPEND MISSING_COMPONENTS_MSG " ${comp}")
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
string(APPEND MISSING_VARS " ${comp}")
endif()
endif()
endforeach()
set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
string(APPEND DETAILS "[c${COMPONENT_MSG}]")
endif()
# version handling:
set(VERSION_MSG "")
set(VERSION_OK TRUE)
# check that the version variable is not empty to avoid emitting a misleading
# message (i.e. `Found unsuitable version ""`)
if (DEFINED ${_NAME}_FIND_VERSION)
if(DEFINED ${FPHSA_VERSION_VAR})
if(NOT "${${FPHSA_VERSION_VAR}}" STREQUAL "")
set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}})
if (FPHSA_HANDLE_VERSION_RANGE)
set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE)
else()
set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE)
endif()
find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG
${FPCV_HANDLE_VERSION_RANGE})
else()
set(VERSION_OK FALSE)
endif()
endif()
if("${${FPHSA_VERSION_VAR}}" STREQUAL "")
# if the package was not found, but a version was given, add that to the output:
if(${_NAME}_FIND_VERSION_EXACT)
set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE)
set(VERSION_MSG "(Required is version range \"${${_NAME}_FIND_VERSION_RANGE}\")")
else()
set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
endif()
endif()
else ()
# Check with DEFINED as the found version may be 0.
if(DEFINED ${FPHSA_VERSION_VAR})
set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")")
endif()
endif ()
if(VERSION_OK)
string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]")
else()
set(${_NAME}_FOUND FALSE)
endif()
# print the result:
if (${_NAME}_FOUND)
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
else ()
if(FPHSA_CONFIG_MODE)
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
else()
if(NOT VERSION_OK)
set(RESULT_MSG)
if (_FIRST_REQUIRED_VAR)
string (APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}")
endif()
if (COMPONENT_MSG)
if (RESULT_MSG)
string (APPEND RESULT_MSG ", ")
endif()
string (APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}")
endif()
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})")
else()
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}")
endif()
endif()
endif ()
set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
endfunction()
cmake_policy(POP)

View File

@@ -0,0 +1,48 @@
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
# file Copyright.txt or https://cmake.org/licensing for details.
#[=======================================================================[.rst:
FindPackageMessage
------------------
.. code-block:: cmake
find_package_message(<name> "message for user" "find result details")
This function is intended to be used in FindXXX.cmake modules files.
It will print a message once for each unique find result. This is
useful for telling the user where a package was found. The first
argument specifies the name (XXX) of the package. The second argument
specifies the message to display. The third argument lists details
about the find result so that if they change the message will be
displayed again. The macro also obeys the QUIET argument to the
find_package command.
Example:
.. code-block:: cmake
if(X11_FOUND)
find_package_message(X11 "Found X11: ${X11_X11_LIB}"
"[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
else()
...
endif()
#]=======================================================================]
function(find_package_message pkg msg details)
# Avoid printing a message repeatedly for the same find result.
if(NOT ${pkg}_FIND_QUIETLY)
string(REPLACE "\n" "" details "${details}")
set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
# The message has not yet been printed.
message(STATUS "${msg}")
# Save the find details in the cache to avoid printing the same
# message again.
set("${DETAILS_VAR}" "${details}"
CACHE INTERNAL "Details about finding ${pkg}")
endif()
endif()
endfunction()

View File

@@ -135,5 +135,5 @@ AppDir:
- usr/share/doc/*/TODO.*
AppImage:
arch: x86_64
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*.AppImage.zsync
file_name: imhex-{{VERSION}}.AppImage
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*-x86_64.AppImage.zsync
file_name: imhex-{{VERSION}}-x86_64.AppImage

4
dist/Arch/PKGBUILD vendored
View File

@@ -1,4 +1,4 @@
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
# Maintainer: iTrooz_ <aur at itrooz dot fr>
# Contributor: Morten Linderud <foxboron@archlinux.org>
pkgname=imhex-bin
@@ -12,7 +12,7 @@ depends=(glfw mbedtls freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara n
makedepends=(git)
provides=(imhex)
conflicts=(imhex)
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux-x86_64.pkg.tar.zst")
md5sums=(SKIP)
package() {

1
dist/Brewfile vendored
View File

@@ -7,3 +7,4 @@ brew "libmagic"
brew "pkg-config"
brew "gcc@12"
brew "llvm"
brew "glfw"

2
dist/Dockerfile vendored
View File

@@ -1,6 +1,6 @@
FROM archlinux:latest
LABEL maintainer="hey@werwolv.net" = WerWolv
LABEL maintainer="hey@werwolv.net WerWolv"
# Install dependencies
RUN pacman -Syy --needed --noconfirm

2
dist/langtool.py vendored
View File

@@ -3,7 +3,7 @@ import sys
import json
DEFAULT_LANG = "en_US"
INVALID_TRANSLATION = "***** MISSING TRANSLATION *****"
INVALID_TRANSLATION = ""
def handle_missing_key(command, lang_data, key, value):

107
dist/rpm/imhex.spec vendored
View File

@@ -1,10 +1,14 @@
Name: imhex
Version: %{_version}
Version: 1.26.2
Release: 0%{?dist}
Summary: A hex editor for reverse engineers and programmers
License: GPL-2.0-only
License: GPL-2.0-only AND Zlib AND MIT AND Apache-2.0
# imhex is gplv2. capstone is custom. nativefiledialog is Zlib.
# see license dir for full breakdown
URL: https://imhex.werwolv.net/
# We need the archive with deps bundled
Source0: https://github.com/WerWolv/%{name}/releases/download/v%{version}/Full.Sources.tar.gz#/%{name}-%{version}.tar.gz
BuildRequires: cmake
BuildRequires: desktop-file-utils
@@ -13,16 +17,33 @@ BuildRequires: file-devel
BuildRequires: freetype-devel
BuildRequires: fmt-devel
BuildRequires: gcc-c++
BuildRequires: mesa-libGL-devel
BuildRequires: libappstream-glib
BuildRequires: libglvnd-devel
BuildRequires: glfw-devel
BuildRequires: json-devel
BuildRequires: libcurl-devel
BuildRequires: llvm-devel
BuildRequires: mbedtls-devel
%if 0%{?fedora} >= 37
BuildRequires: yara-devel
BuildRequires: nativefiledialog-extended-devel
%if 0%{?rhel}
BuildRequires: gcc-toolset-12
%endif
Provides: bundled(gnulib)
Provides: bundled(capstone) = 5.0-rc2
Provides: bundled(imgui)
Provides: bundled(libromfs)
Provides: bundled(microtar)
Provides: bundled(libpl)
Provides: bundled(xdgpp)
# ftbfs on these arches. armv7hl might compile when capstone 5.x
# is released upstream and we can build against it
# [7:02 PM] WerWolv: We're not supporting 32 bit anyways soooo
# [11:38 AM] WerWolv: Officially supported are x86_64 and aarch64
ExclusiveArch: x86_64 %{arm64} ppc64le
%description
ImHex is a Hex Editor, a tool to display, decode and analyze binary data to
@@ -37,26 +58,26 @@ same time ImHex is completely free and open source under the GPLv2 language.
%prep
# don't use the setup macro since we're pulling from git
cp -r %{_src_path}/* %{_builddir}/
%autosetup -n ImHex
# remove bundled libs we aren't using
rm -rf lib/external/{curl,fmt,llvm,nlohmann_json,yara}
%build
%cmake \
-DCMAKE_BUILD_TYPE=%{_build_type} \
-D USE_SYSTEM_NLOHMANN_JSON=ON \
-D USE_SYSTEM_FMT=ON \
-D USE_SYSTEM_CURL=ON \
-D USE_SYSTEM_LLVM=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-D IMHEX_PATTERNS_PULL_MASTER=ON \
%if 0%{?fedora} >= 37
-D USE_SYSTEM_YARA=ON \
# if fedora <= 36 get updated to yara 4.2.x then they should \
# be able to build against system libs \
# https://bugzilla.redhat.com/show_bug.cgi?id=2112508 \
%if 0%{?rhel}
. /opt/rh/gcc-toolset-12/enable
%set_build_flags
CXXFLAGS+=" -std=gnu++2b"
%endif
%cmake \
-D CMAKE_BUILD_TYPE=Release \
-D IMHEX_STRIP_RELEASE=OFF \
-D IMHEX_OFFLINE_BUILD=ON \
-D USE_SYSTEM_NLOHMANN_JSON=ON \
-D USE_SYSTEM_FMT=ON \
-D USE_SYSTEM_CURL=ON \
-D USE_SYSTEM_LLVM=ON \
-D USE_SYSTEM_YARA=ON \
-D USE_SYSTEM_NFD=ON \
# when capstone >= 5.x is released we should be able to build against \
# system libs of it \
# -D USE_SYSTEM_CAPSTONE=ON
@@ -64,23 +85,45 @@ cp -r %{_src_path}/* %{_builddir}/
%cmake_build
%check
%if 0%{?rhel}
. /opt/rh/gcc-toolset-12/enable
%set_build_flags
CXXFLAGS+=" -std=gnu++2b"
%endif
# build binaries required for tests
%cmake_build --target unit_tests
%ctest --exclude-regex '(Helpers/StoreAPI|Helpers/TipsAPI|Helpers/ContentAPI)'
# Helpers/*API exclude tests that require network access
%install
%cmake_install
desktop-file-validate %{buildroot}%{_datadir}/applications/imhex.desktop
desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop
# this is a symlink for the old appdata name that we don't need
rm -f %{buildroot}%{_metainfodir}/net.werwolv.%{name}.appdata.xml
# AppData
appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
# install licenses
cp -a lib/external/nativefiledialog/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/nativefiledialog-LICENSE
cp -a lib/external/capstone/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
cp -a lib/external/capstone/suite/regress/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/capstone-regress-LICENSE
cp -a lib/external/microtar/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/microtar-LICENSE
cp -a lib/external/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
%files
%dir %{_datadir}/licenses/imhex
%license %{_datadir}/licenses/imhex/LICENSE
%license %{_datadir}/licenses/%{name}/
%doc README.md
%{_bindir}/imhex
%dir %{_datadir}/imhex
%{_datadir}/imhex/*
%{_datadir}/pixmaps/imhex.png
%{_datadir}/applications/imhex.desktop
%{_prefix}/lib64/libimhex.so.%{_version}
%{_prefix}/lib64/imhex/plugins/*
%{_metainfodir}/net.werwolv.imhex.metainfo.xml
%{_metainfodir}/net.werwolv.imhex.appdata.xml
%{_datadir}/pixmaps/%{name}.png
%{_datadir}/applications/%{name}.desktop
%{_libdir}/libimhex.so*
%{_libdir}/%{name}/
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
%changelog

View File

@@ -8,10 +8,6 @@ find_package(Freetype REQUIRED)
find_package(OpenGL REQUIRED)
pkg_search_module(GLFW REQUIRED glfw3)
if (UNIX)
find_package(OpenGL REQUIRED)
endif ()
add_library(imgui OBJECT
source/imgui.cpp
source/imgui_demo.cpp
@@ -37,14 +33,9 @@ add_library(imgui OBJECT
source/fonts/unifont_font.c
)
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
target_compile_definitions(imgui PUBLIC IMGUI_IMPL_OPENGL_LOADER_GLAD)
target_compile_options(imgui PRIVATE -Wno-stringop-overflow)
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS})
if (WIN32)
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw3 opengl32.lib)
elseif (UNIX)
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw OpenGL::GL)
endif()
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS} ${OpenGL_INCLUDE_DIRS})
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
target_link_libraries(imgui PUBLIC Freetype::Freetype ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})

File diff suppressed because it is too large Load Diff

View File

@@ -314,7 +314,7 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
while (cindex > 0 && isspace(line[cindex].mChar))
--cindex;
auto cstart = (PaletteIndex)line[cindex].mColorIndex;
auto cstart = line[cindex].mChar;
while (cindex > 0) {
auto c = line[cindex].mChar;
if ((c & 0xC0) != 0x80) // not UTF code sequence 10xxxxxx
@@ -323,8 +323,15 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
cindex++;
break;
}
if (cstart != (PaletteIndex)line[size_t(cindex - 1)].mColorIndex)
if (isalnum(cstart) || cstart == '_') {
if (!isalnum(c) && c != '_') {
cindex++;
break;
}
} else {
break;
}
}
--cindex;
}
@@ -632,10 +639,24 @@ void TextEditor::HandleKeyboardInputs() {
MoveEnd(shift);
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
Delete();
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete))) {
auto wordStart = GetCursorPosition();
MoveRight();
auto wordEnd = FindWordEnd(GetCursorPosition());
SetSelection(wordStart, wordEnd);
Backspace();
}
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
Backspace();
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace))) {
auto wordEnd = GetCursorPosition();
MoveLeft();
auto wordStart = FindWordStart(GetCursorPosition());
SetSelection(wordStart, wordEnd);
Backspace();
}
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
mOverwrite ^= true;
mOverwrite = !mOverwrite;
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
Copy();
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
@@ -2123,7 +2144,7 @@ void TextEditor::EnsureCursorVisible() {
if (len + mTextStart < left + 4)
ImGui::SetScrollX(std::max(0.0f, len + mTextStart - 4));
if (len + mTextStart > right - 4)
ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width));
ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width + mCharAdvance.x * 2));
}
int TextEditor::GetPageSize() const {

View File

@@ -750,12 +750,41 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
else
{
// IMHEX PATCH BEGIN
if (!bd->BorderlessWindow) {
/*if (!bd->BorderlessWindow) {*/
// Show OS mouse cursor
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
#if defined(_WIN32)
switch (imgui_cursor) {
case ImGuiMouseCursor_Hand:
SetCursor(LoadCursor(nullptr, IDC_HAND));
break;
case ImGuiMouseCursor_ResizeEW:
SetCursor(LoadCursor(nullptr, IDC_SIZEWE));
break;
case ImGuiMouseCursor_ResizeNS:
SetCursor(LoadCursor(nullptr, IDC_SIZENS));
break;
case ImGuiMouseCursor_ResizeNWSE:
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
break;
case ImGuiMouseCursor_ResizeNESW:
SetCursor(LoadCursor(nullptr, IDC_SIZENESW));
break;
case ImGuiMouseCursor_ResizeAll:
SetCursor(LoadCursor(nullptr, IDC_SIZEALL));
break;
case ImGuiMouseCursor_NotAllowed:
SetCursor(LoadCursor(nullptr, IDC_NO));
break;
case ImGuiMouseCursor_TextInput:
SetCursor(LoadCursor(nullptr, IDC_IBEAM));
break;
}
#else
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
#endif
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
/*}*/
// IMHEX PATCH END
}
}
@@ -820,7 +849,12 @@ static void ImGui_ImplGlfw_UpdateMonitors()
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
int monitors_count = 0;
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
platform_io.Monitors.resize(0);
// IMHEX PATCH BEGIN
if (monitors_count > 0)
platform_io.Monitors.resize(0);
// IMHEX PATCH END
for (int n = 0; n < monitors_count; n++)
{
ImGuiPlatformMonitor monitor;

View File

@@ -1565,8 +1565,8 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
width_excess += items[n].Width - width_rounded;
items[n].Width = width_rounded;
}
while (width_excess > 0.0f)
for (int n = 0; n < count; n++)
while (width_excess >= 1.0f)
for (int n = 0; n < count && width_excess >= 1.0f; n++)
if (items[n].Width + 1.0f <= items[n].InitialWidth)
{
items[n].Width += 1.0f;
@@ -7638,7 +7638,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section
// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore
if (width_excess > 0.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
{
int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);
int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);

View File

@@ -1,9 +0,0 @@
cmake_minimum_required(VERSION 3.16)
project(intervaltree)
set(CMAKE_CXX_STANDARD20)
add_library(intervaltree INTERFACE)
target_include_directories(intervaltree INTERFACE include)
target_compile_options(intervaltree INTERFACE "-DUSE_INTERVAL_TREE_NAMESPACE")

View File

@@ -1,19 +0,0 @@
Copyright (c) 2011 Erik Garrison
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,37 +0,0 @@
# intervaltree
## Overview
An interval tree can be used to efficiently find a set of numeric intervals overlapping or containing another interval.
This library provides a basic implementation of an interval tree using C++ templates, allowing the insertion of arbitrary types into the tree.
## Usage
Add `#include "IntervalTree.h"` to the source files in which you will use the interval tree.
To make an IntervalTree to contain objects of class T, use:
```c++
vector<Interval<T> > intervals;
T a, b, c;
intervals.push_back(Interval<T>(2, 10, a));
intervals.push_back(Interval<T>(3, 4, b));
intervals.push_back(Interval<T>(20, 100, c));
IntervalTree<T> tree;
tree = IntervalTree<T>(intervals);
```
Now, it's possible to query the tree and obtain a set of intervals which are contained within the start and stop coordinates.
```c++
vector<Interval<T> > results;
tree.findContained(start, stop, results);
cout << "found " << results.size() << " overlapping intervals" << endl;
```
The function IntervalTree::findOverlapping provides a method to find all those intervals which are contained or partially overlap the interval (start, stop).
### Author: Erik Garrison <erik.garrison@gmail.com>
### License: MIT

View File

@@ -1,325 +0,0 @@
#ifndef __INTERVAL_TREE_H
#define __INTERVAL_TREE_H
#include <vector>
#include <algorithm>
#include <iostream>
#include <memory>
#include <cassert>
#include <limits>
#ifdef USE_INTERVAL_TREE_NAMESPACE
namespace interval_tree {
#endif
template <class Scalar, typename Value>
class Interval {
public:
Scalar start;
Scalar stop;
Value value;
Interval(const Scalar& s, const Scalar& e, const Value& v)
: start(std::min(s, e))
, stop(std::max(s, e))
, value(v)
{}
};
template <class Scalar, typename Value>
Value intervalStart(const Interval<Scalar,Value>& i) {
return i.start;
}
template <class Scalar, typename Value>
Value intervalStop(const Interval<Scalar, Value>& i) {
return i.stop;
}
template <class Scalar, typename Value>
std::ostream& operator<<(std::ostream& out, const Interval<Scalar, Value>& i) {
out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
return out;
}
template <class Scalar, class Value>
class IntervalTree {
public:
typedef Interval<Scalar, Value> interval;
typedef std::vector<interval> interval_vector;
struct IntervalStartCmp {
bool operator()(const interval& a, const interval& b) {
return a.start < b.start;
}
};
struct IntervalStopCmp {
bool operator()(const interval& a, const interval& b) {
return a.stop < b.stop;
}
};
IntervalTree()
: left(nullptr)
, right(nullptr)
, center(0)
{}
~IntervalTree() = default;
std::unique_ptr<IntervalTree> clone() const {
return std::unique_ptr<IntervalTree>(new IntervalTree(*this));
}
IntervalTree(const IntervalTree& other)
: intervals(other.intervals),
left(other.left ? other.left->clone() : nullptr),
right(other.right ? other.right->clone() : nullptr),
center(other.center)
{}
IntervalTree& operator=(IntervalTree&&) = default;
IntervalTree(IntervalTree&&) = default;
IntervalTree& operator=(const IntervalTree& other) {
center = other.center;
intervals = other.intervals;
left = other.left ? other.left->clone() : nullptr;
right = other.right ? other.right->clone() : nullptr;
return *this;
}
IntervalTree(
interval_vector&& ivals,
std::size_t depth = 16,
std::size_t minbucket = 64,
std::size_t maxbucket = 512,
Scalar leftextent = 0,
Scalar rightextent = 0)
: left(nullptr)
, right(nullptr)
{
--depth;
const auto minmaxStop = std::minmax_element(ivals.begin(), ivals.end(),
IntervalStopCmp());
const auto minmaxStart = std::minmax_element(ivals.begin(), ivals.end(),
IntervalStartCmp());
if (!ivals.empty()) {
center = (minmaxStart.first->start + minmaxStop.second->stop) / 2;
}
if (leftextent == 0 && rightextent == 0) {
// sort intervals by start
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
} else {
assert(std::is_sorted(ivals.begin(), ivals.end(), IntervalStartCmp()));
}
if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) {
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
intervals = std::move(ivals);
assert(is_valid().first);
return;
} else {
Scalar leftp = 0;
Scalar rightp = 0;
if (leftextent || rightextent) {
leftp = leftextent;
rightp = rightextent;
} else {
leftp = ivals.front().start;
rightp = std::max_element(ivals.begin(), ivals.end(),
IntervalStopCmp())->stop;
}
interval_vector lefts;
interval_vector rights;
for (typename interval_vector::const_iterator i = ivals.begin();
i != ivals.end(); ++i) {
const interval& interval = *i;
if (interval.stop < center) {
lefts.push_back(interval);
} else if (interval.start > center) {
rights.push_back(interval);
} else {
assert(interval.start <= center);
assert(center <= interval.stop);
intervals.push_back(interval);
}
}
if (!lefts.empty()) {
left.reset(new IntervalTree(std::move(lefts),
depth, minbucket, maxbucket,
leftp, center));
}
if (!rights.empty()) {
right.reset(new IntervalTree(std::move(rights),
depth, minbucket, maxbucket,
center, rightp));
}
}
assert(is_valid().first);
}
// Call f on all intervals near the range [start, stop]:
template <class UnaryFunction>
void visit_near(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
if (!intervals.empty() && ! (stop < intervals.front().start)) {
for (auto & i : intervals) {
f(i);
}
}
if (left && start <= center) {
left->visit_near(start, stop, f);
}
if (right && stop >= center) {
right->visit_near(start, stop, f);
}
}
// Call f on all intervals crossing pos
template <class UnaryFunction>
void visit_overlapping(const Scalar& pos, UnaryFunction f) const {
visit_overlapping(pos, pos, f);
}
// Call f on all intervals overlapping [start, stop]
template <class UnaryFunction>
void visit_overlapping(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
auto filterF = [&](const interval& interval) {
if (interval.stop >= start && interval.start <= stop) {
// Only apply f if overlapping
f(interval);
}
};
visit_near(start, stop, filterF);
}
// Call f on all intervals contained within [start, stop]
template <class UnaryFunction>
void visit_contained(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
auto filterF = [&](const interval& interval) {
if (start <= interval.start && interval.stop <= stop) {
f(interval);
}
};
visit_near(start, stop, filterF);
}
interval_vector findOverlapping(const Scalar& start, const Scalar& stop) const {
interval_vector result;
visit_overlapping(start, stop,
[&](const interval& interval) {
result.emplace_back(interval);
});
return result;
}
interval_vector findContained(const Scalar& start, const Scalar& stop) const {
interval_vector result;
visit_contained(start, stop,
[&](const interval& interval) {
result.push_back(interval);
});
return result;
}
bool empty() const {
if (left && !left->empty()) {
return false;
}
if (!intervals.empty()) {
return false;
}
if (right && !right->empty()) {
return false;
}
return true;
}
template <class UnaryFunction>
void visit_all(UnaryFunction f) const {
if (left) {
left->visit_all(f);
}
std::for_each(intervals.begin(), intervals.end(), f);
if (right) {
right->visit_all(f);
}
}
std::pair<Scalar, Scalar> extentBruitForce() const {
struct Extent {
std::pair<Scalar, Scalar> x = {std::numeric_limits<Scalar>::max(),
std::numeric_limits<Scalar>::min() };
void operator()(const interval & interval) {
x.first = std::min(x.first, interval.start);
x.second = std::max(x.second, interval.stop);
}
};
Extent extent;
visit_all([&](const interval & interval) { extent(interval); });
return extent.x;
}
// Check all constraints.
// If first is false, second is invalid.
std::pair<bool, std::pair<Scalar, Scalar>> is_valid() const {
const auto minmaxStop = std::minmax_element(intervals.begin(), intervals.end(),
IntervalStopCmp());
const auto minmaxStart = std::minmax_element(intervals.begin(), intervals.end(),
IntervalStartCmp());
std::pair<bool, std::pair<Scalar, Scalar>> result = {true, { std::numeric_limits<Scalar>::max(),
std::numeric_limits<Scalar>::min() }};
if (!intervals.empty()) {
result.second.first = std::min(result.second.first, minmaxStart.first->start);
result.second.second = std::min(result.second.second, minmaxStop.second->stop);
}
if (left) {
auto valid = left->is_valid();
result.first &= valid.first;
result.second.first = std::min(result.second.first, valid.second.first);
result.second.second = std::min(result.second.second, valid.second.second);
if (!result.first) { return result; }
if (valid.second.second >= center) {
result.first = false;
return result;
}
}
if (right) {
auto valid = right->is_valid();
result.first &= valid.first;
result.second.first = std::min(result.second.first, valid.second.first);
result.second.second = std::min(result.second.second, valid.second.second);
if (!result.first) { return result; }
if (valid.second.first <= center) {
result.first = false;
return result;
}
}
if (!std::is_sorted(intervals.begin(), intervals.end(), IntervalStartCmp())) {
result.first = false;
}
return result;
}
void clear() {
left.reset();
right.reset();
intervals.clear();
center = 0;
}
private:
interval_vector intervals;
std::unique_ptr<IntervalTree> left;
std::unique_ptr<IntervalTree> right;
Scalar center;
};
#ifdef USE_INTERVAL_TREE_NAMESPACE
}
#endif
#endif

1
lib/external/libwolv vendored Submodule

Submodule lib/external/libwolv added at 433d230331

12
lib/external/miniaudio/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.16)
project(miniaudio)
add_library(miniaudio STATIC
source/miniaudio.c
)
target_include_directories(miniaudio PUBLIC include)
if (APPLE)
set_source_files_properties(source/miniaudio.c PROPERTIES LANGUAGE OBJC)
endif ()

47
lib/external/miniaudio/LICENSE vendored Normal file
View File

@@ -0,0 +1,47 @@
This software is available as a choice of the following licenses. Choose
whichever you prefer.
===============================================================================
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
===============================================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
===============================================================================
ALTERNATIVE 2 - MIT No Attribution
===============================================================================
Copyright 2020 David Reid
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7509
lib/external/miniaudio/include/miniaudio.h vendored Normal file

File diff suppressed because it is too large Load Diff

80169
lib/external/miniaudio/source/miniaudio.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -34,6 +34,8 @@ set(LIBYARA_INCLUDES
${LIBYARA_SOURCE_PATH}/include/yara/types.h
${LIBYARA_SOURCE_PATH}/include/yara/utils.h
${LIBYARA_SOURCE_PATH}/crypto.h
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_impl.h
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_util.h
)
set(LIBYARA_SOURCE
@@ -66,6 +68,7 @@ set(LIBYARA_SOURCE
${LIBYARA_SOURCE_PATH}/scan.c
${LIBYARA_SOURCE_PATH}/scanner.c
${LIBYARA_SOURCE_PATH}/sizedstr.c
${LIBYARA_SOURCE_PATH}/simple_str.c
${LIBYARA_SOURCE_PATH}/stack.c
${LIBYARA_SOURCE_PATH}/stopwatch.c
${LIBYARA_SOURCE_PATH}/strutils.c
@@ -78,6 +81,9 @@ set(LIBYARA_SOURCE
${LIBYARA_SOURCE_PATH}/hex_grammar.c
${LIBYARA_SOURCE_PATH}/re_grammar.c
${LIBYARA_SOURCE_PATH}/proc/none.c
${LIBYARA_SOURCE_PATH}/tlshc/tlsh.c
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_impl.c
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_util.c
)
set(LIBYARA_MODULES
@@ -91,6 +97,7 @@ set(LIBYARA_MODULES
${LIBYARA_SOURCE_PATH}/modules/math/math.c
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
${LIBYARA_SOURCE_PATH}/modules/string/string.c
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
${LIBYARA_SOURCE_PATH}/modules/time/time.c
)
@@ -101,17 +108,13 @@ add_library(libyara STATIC ${LIBYARA_SOURCE} ${LIBYARA_INCLUDES} ${LIBYARA_MODUL
set_property(TARGET libyara PROPERTY POSITION_INDEPENDENT_CODE ON)
# Add mbedtls crypto wrappers
target_compile_definitions(libyara PRIVATE HAVE_MBEDTLS)
target_compile_definitions(libyara PRIVATE
HAVE_MBEDTLS
USE_NO_PROC BUCKETS_256 CHECKSUM_3B
HASH_MODULE DOTNET_MODULE MAGIC_MODULE MACHO_MODULE DEX_MODULE
)
target_compile_definitions(libyara PRIVATE USE_NO_PROC)
target_compile_definitions(libyara PRIVATE HASH_MODULE)
target_compile_definitions(libyara PRIVATE DOTNET_MODULE)
target_compile_definitions(libyara PRIVATE MAGIC_MODULE)
target_compile_definitions(libyara PRIVATE MACHO_MODULE)
target_compile_definitions(libyara PRIVATE DEX_MODULE)
target_compile_options(libyara PRIVATE "-Wno-shift-count-overflow")
target_compile_options(libyara PRIVATE -Wno-shift-count-overflow -Wno-stringop-overflow)
target_include_directories(
libyara
@@ -128,6 +131,6 @@ else ()
endif ()
include(GNUInstallDirs)
configure_file(${LIBYARA_SOURCE_PATH}/yara.pc.in
${LIBYARA_SOURCE_PATH}/yara.pc @ONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc.in
${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc @ONLY)
set(CMAKE_STATIC_LIBRARY_PREFIX "")

View File

@@ -5,37 +5,39 @@ set(CMAKE_CXX_STANDARD 23)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
set(LIBIMHEX_SOURCES
source/api/event.cpp
source/api/imhex_api.cpp
source/api/content_registry.cpp
source/api/task.cpp
source/api/keybinding.cpp
source/api/plugin_manager.cpp
source/api/localization.cpp
source/api/project_file_manager.cpp
source/api/theme_manager.cpp
source/api/event.cpp
source/api/imhex_api.cpp
source/api/content_registry.cpp
source/api/task.cpp
source/api/keybinding.cpp
source/api/plugin_manager.cpp
source/api/localization.cpp
source/api/project_file_manager.cpp
source/api/theme_manager.cpp
source/api/layout_manager.cpp
source/data_processor/attribute.cpp
source/data_processor/link.cpp
source/data_processor/node.cpp
source/data_processor/attribute.cpp
source/data_processor/link.cpp
source/data_processor/node.cpp
source/helpers/utils.cpp
source/helpers/fs.cpp
source/helpers/magic.cpp
source/helpers/crypto.cpp
source/helpers/net.cpp
source/helpers/file.cpp
source/helpers/socket.cpp
source/helpers/patches.cpp
source/helpers/encoding_file.cpp
source/helpers/logger.cpp
source/helpers/tar.cpp
source/helpers/utils.cpp
source/helpers/fs.cpp
source/helpers/magic.cpp
source/helpers/crypto.cpp
source/helpers/http_requests.cpp
source/helpers/opengl.cpp
source/helpers/patches.cpp
source/helpers/encoding_file.cpp
source/helpers/logger.cpp
source/helpers/stacktrace.cpp
source/helpers/tar.cpp
source/providers/provider.cpp
source/providers/provider.cpp
source/ui/imgui_imhex_extensions.cpp
source/ui/view.cpp
)
source/ui/imgui_imhex_extensions.cpp
source/ui/view.cpp
source/ui/popup.cpp
)
if (APPLE)
set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk)
@@ -47,9 +49,7 @@ if (APPLE)
endif ()
endif ()
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
source/helpers/fs_macos.m
source/helpers/utils_macos.m)
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_macos.m)
endif ()
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
@@ -59,7 +59,7 @@ set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
setupCompilerWarnings(libimhex)
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS})
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
if (WIN32)
@@ -70,4 +70,4 @@ elseif (APPLE)
endif ()
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} libpl intervaltree)
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers)

View File

@@ -1,7 +1,4 @@
#pragma once
#include <hex/helpers/types.hpp>
#include <hex/helpers/intrinsics.hpp>
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
#include <hex/helpers/intrinsics.hpp>

View File

@@ -9,9 +9,11 @@
#include <functional>
#include <map>
#include <unordered_map>
#include <span>
#include <string>
#include <string_view>
#include <thread>
#include <unordered_map>
#include <vector>
#include <nlohmann/json_fwd.hpp>
@@ -40,78 +42,197 @@ namespace hex {
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
namespace Settings {
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
struct Entry {
std::string name;
bool requiresRestart;
Callback callback;
};
namespace impl {
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
struct Category {
std::string name;
size_t slot = 0;
struct Entry {
std::string name;
bool requiresRestart;
Callback callback;
};
bool operator<(const Category &other) const {
return name < other.name;
}
struct Category {
std::string name;
size_t slot = 0;
explicit operator const std::string &() const {
return name;
}
};
bool operator<(const Category &other) const {
return name < other.name;
}
void load();
void store();
void clear();
explicit operator const std::string &() const {
return name;
}
};
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart = false);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart = false);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart = false);
void load();
void store();
void clear();
std::map<Category, std::vector<Entry>> &getEntries();
std::map<std::string, std::string> &getCategoryDescriptions();
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
nlohmann::json &getSettingsData();
}
/**
* @brief Adds a new integer setting entry
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @param callback The callback that will be called when the settings item in the preferences window is rendered
* @param requiresRestart Whether the setting requires a restart to take effect
*/
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart = false);
/**
* @brief Adds a new string setting entry
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @param callback The callback that will be called when the settings item in the preferences window is rendered
* @param requiresRestart Whether the setting requires a restart to take effect
*/
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
/**
* @brief Adds a new string list setting entry
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @param callback The callback that will be called when the settings item in the preferences window is rendered
* @param requiresRestart Whether the setting requires a restart to take effect
*/
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
/**
* @brief Adds a description to a given category
* @param unlocalizedCategory The name of the category
* @param unlocalizedCategoryDescription The description of the category
*/
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription);
/**
* @brief Writes a integer value to the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param value The value to write
*/
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value);
/**
* @brief Writes a string value to the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param value The value to write
*/
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
/**
* @brief Writes a string list value to the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param value The value to write
*/
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value);
/**
* @brief Reads an integer value from the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @return The value of the setting
*/
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue);
/**
* @brief Reads a string value from the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @return The value of the setting
*/
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
/**
* @brief Reads a string list value from the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @return The value of the setting
*/
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue = {});
std::map<Category, std::vector<Entry>> &getEntries();
std::map<std::string, std::string> &getCategoryDescriptions();
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
nlohmann::json &getSettingsData();
}
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
namespace CommandPaletteCommands {
enum class Type : u32
{
enum class Type : u32 {
SymbolCommand,
KeywordCommand
};
using DisplayCallback = std::function<std::string(std::string)>;
using ExecuteCallback = std::function<void(std::string)>;
namespace impl {
struct Entry {
Type type;
std::string command;
std::string unlocalizedDescription;
DisplayCallback displayCallback;
ExecuteCallback executeCallback;
};
struct QueryResult {
std::string name;
std::function<void(std::string)> callback;
};
using DisplayCallback = std::function<std::string(std::string)>;
using ExecuteCallback = std::function<void(std::string)>;
using QueryCallback = std::function<std::vector<QueryResult>(std::string)>;
struct Entry {
Type type;
std::string command;
std::string unlocalizedDescription;
DisplayCallback displayCallback;
ExecuteCallback executeCallback;
};
struct Handler {
Type type;
std::string command;
QueryCallback queryCallback;
DisplayCallback displayCallback;
};
std::vector<impl::Entry> &getEntries();
std::vector<impl::Handler> &getHandlers();
}
/**
* @brief Adds a new command to the command palette
* @param type The type of the command
* @param command The command to add
* @param unlocalizedDescription The description of the command
* @param displayCallback The callback that will be called when the command is displayed in the command palette
* @param executeCallback The callback that will be called when the command is executed
*/
void add(
Type type,
const std::string &command,
const std::string &unlocalizedDescription,
const DisplayCallback &displayCallback,
const ExecuteCallback &executeCallback = [](auto) {});
std::vector<Entry> &getEntries();
const impl::DisplayCallback &displayCallback,
const impl::ExecuteCallback &executeCallback = [](auto) {});
/**
* @brief Adds a new command handler to the command palette
* @param type The type of the command
* @param command The command to add
* @param unlocalizedDescription The description of the command
* @param queryCallback The callback that will be called when the command palette wants to load the name and callback items
* @param displayCallback The callback that will be called when the command is displayed in the command palette
*/
void addHandler(
Type type,
const std::string &command,
const impl::QueryCallback &queryCallback,
const impl::DisplayCallback &displayCallback);
}
/* Pattern Language Function Registry. Allows adding of new functions that may be used inside the pattern language */
@@ -119,6 +240,8 @@ namespace hex {
namespace impl {
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::IIterable&, bool, std::span<const pl::core::Token::Literal>)>;
struct FunctionDefinition {
pl::api::Namespace ns;
std::string name;
@@ -129,17 +252,70 @@ namespace hex {
bool dangerous;
};
struct Visualizer {
u32 parameterCount;
VisualizerFunctionCallback callback;
};
std::map<std::string, Visualizer> &getVisualizers();
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
std::vector<impl::FunctionDefinition> &getFunctions();
}
/**
* @brief Provides access to the current provider's pattern language runtime
* @return Runtime
*/
pl::PatternLanguage& getRuntime();
/**
* @brief Provides access to the current provider's pattern language runtime's lock
* @return Lock
*/
std::mutex& getRuntimeLock();
/**
* @brief Configures the pattern language runtime using ImHex's default settings
* @param runtime The pattern language runtime to configure
* @param provider The provider to use for data access
*/
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider);
/**
* @brief Adds a new pragma to the pattern language
* @param name The name of the pragma
* @param handler The handler that will be called when the pragma is encountered
*/
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
/**
* @brief Adds a new function to the pattern language
* @param ns The namespace of the function
* @param name The name of the function
* @param parameterCount The amount of parameters the function takes
* @param func The function callback
*/
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
/**
* @brief Adds a new dangerous function to the pattern language
* @note Dangerous functions are functions that require the user to explicitly allow them to be used
* @param ns The namespace of the function
* @param name The name of the function
* @param parameterCount The amount of parameters the function takes
* @param func The function callback
*/
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
std::vector<impl::FunctionDefinition> &getFunctions();
/**
* @brief Adds a new visualizer to the pattern language
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
* @param name The name of the visualizer
* @param func The function callback
* @param parameterCount The amount of parameters the function takes
*/
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &func, u32 parameterCount);
}
@@ -148,19 +324,28 @@ namespace hex {
namespace impl {
void add(View *view);
void add(std::unique_ptr<View> &&view);
std::map<std::string, std::unique_ptr<View>> &getEntries();
}
/**
* @brief Adds a new view to ImHex
* @tparam T The custom view class that extends View
* @tparam Args Arguments types
* @param args Arguments passed to the constructor of the view
*/
template<std::derived_from<View> T, typename... Args>
void add(Args &&...args) {
return impl::add(new T(std::forward<Args>(args)...));
return impl::add(std::make_unique<T>(std::forward<Args>(args)...));
}
std::map<std::string, View *> &getEntries();
View *getViewByName(const std::string &unlocalizedName);
/**
* @brief Gets a view by its unlocalized name
* @param unlocalizedName The unlocalized name of the view
* @return The view if it exists, nullptr otherwise
*/
View* getViewByName(const std::string &unlocalizedName);
}
/* Tools Registry. Allows adding new entries to the tools window */
@@ -176,11 +361,16 @@ namespace hex {
bool detached;
};
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new tool to the tools window
* @param unlocalizedName The unlocalized name of the tool
* @param function The function that will be called to draw the tool
*/
void add(const std::string &unlocalizedName, const impl::Callback &function);
std::vector<impl::Entry> &getEntries();
}
/* Data Inspector Registry. Allows adding of new types to the data inspector */
@@ -207,12 +397,28 @@ namespace hex {
std::optional<impl::EditingFunction> editingFunction;
};
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new entry to the data inspector
* @param unlocalizedName The unlocalized name of the entry
* @param requiredSize The minimum required number of bytes available for the entry to appear
* @param displayGeneratorFunction The function that will be called to generate the display function
* @param editingFunction The function that will be called to edit the data
*/
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
std::vector<impl::Entry> &getEntries();
/**
* @brief Adds a new entry to the data inspector
* @param unlocalizedName The unlocalized name of the entry
* @param requiredSize The minimum required number of bytes available for the entry to appear
* @param maxSize The maximum number of bytes to read from the data
* @param displayGeneratorFunction The function that will be called to generate the display function
* @param editingFunction The function that will be called to edit the data
*/
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
}
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
@@ -230,15 +436,24 @@ namespace hex {
void add(const Entry &entry);
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new node to the data processor
* @tparam T The custom node class that extends dp::Node
* @tparam Args Arguments types
* @param unlocalizedCategory The unlocalized category name of the node
* @param unlocalizedName The unlocalized name of the node
* @param args Arguments passed to the constructor of the node
*/
template<std::derived_from<dp::Node> T, typename... Args>
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
add(impl::Entry {
unlocalizedCategory.c_str(),
unlocalizedName.c_str(),
[=] {
[=, ...args = std::forward<Args>(args)] mutable {
auto node = std::make_unique<T>(std::forward<Args>(args)...);
node->setUnlocalizedName(unlocalizedName);
return node;
@@ -246,18 +461,29 @@ namespace hex {
});
}
/**
* @brief Adds a separator to the data processor right click menu
*/
void addSeparator();
std::vector<impl::Entry> &getEntries();
}
/* Language Registry. Allows together with the LangEntry class and the _lang user defined literal to add new languages */
namespace Language {
/**
* @brief Loads localization information from json data
* @param data The language data
*/
void addLocalization(const nlohmann::json &data);
std::map<std::string, std::string> &getLanguages();
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
namespace impl {
std::map<std::string, std::string> &getLanguages();
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
}
}
/* Interface Registry. Allows adding new items to various interfaces */
@@ -265,22 +491,20 @@ namespace hex {
namespace impl {
using DrawCallback = std::function<void()>;
using LayoutFunction = std::function<void(u32)>;
using ClickCallback = std::function<void()>;
struct Layout {
std::string unlocalizedName;
LayoutFunction callback;
};
using DrawCallback = std::function<void()>;
using MenuCallback = std::function<void()>;
using EnabledCallback = std::function<bool()>;
using ClickCallback = std::function<void()>;
struct MainMenuItem {
std::string unlocalizedName;
};
struct MenuItem {
std::string unlocalizedName;
DrawCallback callback;
std::vector<std::string> unlocalizedNames;
Shortcut shortcut;
MenuCallback callback;
EnabledCallback enabledCallback;
};
struct SidebarItem {
@@ -294,29 +518,89 @@ namespace hex {
ClickCallback callback;
};
constexpr static auto SeparatorValue = "$SEPARATOR$";
constexpr static auto SubMenuValue = "$SUBMENU$";
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems();
std::multimap<u32, impl::MenuItem> &getMenuItems();
std::vector<impl::DrawCallback> &getWelcomeScreenEntries();
std::vector<impl::DrawCallback> &getFooterItems();
std::vector<impl::DrawCallback> &getToolbarItems();
std::vector<impl::SidebarItem> &getSidebarItems();
std::vector<impl::TitleBarButton> &getTitleBarButtons();
}
/**
* @brief Adds a new top-level main menu entry
* @param unlocalizedName The unlocalized name of the entry
* @param priority The priority of the entry. Lower values are displayed first
*/
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority);
void addMenuItem(const std::string &unlocalizedMainMenuName, u32 priority, const impl::DrawCallback &function);
/**
* @brief Adds a new main menu entry
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
* @param priority The priority of the entry. Lower values are displayed first
* @param shortcut The shortcut to use for the entry
* @param function The function to call when the entry is clicked
* @param enabledCallback The function to call to determine if the entry is enabled
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
*/
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; }, View *view = nullptr);
/**
* @brief Adds a new main menu sub-menu entry
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
* @param priority The priority of the entry. Lower values are displayed first
* @param function The function to call when the entry is clicked
* @param enabledCallback The function to call to determine if the entry is enabled
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
*/
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; });
/**
* @brief Adds a new main menu separator
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
* @param priority The priority of the entry. Lower values are displayed first
*/
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority);
/**
* @brief Adds a new welcome screen entry
* @param function The function to call to draw the entry
*/
void addWelcomeScreenEntry(const impl::DrawCallback &function);
/**
* @brief Adds a new footer item
* @param function The function to call to draw the item
*/
void addFooterItem(const impl::DrawCallback &function);
/**
* @brief Adds a new toolbar item
* @param function The function to call to draw the item
*/
void addToolbarItem(const impl::DrawCallback &function);
/**
* @brief Adds a new sidebar item
* @param icon The icon to use for the item
* @param function The function to call to draw the item
*/
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function);
/**
* @brief Adds a new title bar button
* @param icon The icon to use for the button
* @param unlocalizedTooltip The unlocalized tooltip to use for the button
* @param function The function to call when the button is clicked
*/
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function);
void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function);
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems();
std::multimap<u32, impl::MenuItem> &getMenuItems();
std::vector<impl::DrawCallback> &getWelcomeScreenEntries();
std::vector<impl::DrawCallback> &getFooterItems();
std::vector<impl::DrawCallback> &getToolbarItems();
std::vector<impl::SidebarItem> &getSidebarItems();
std::vector<impl::TitleBarButton> &getTitleBarButtons();
std::vector<impl::Layout> &getLayouts();
}
/* Provider Registry. Allows adding new data providers to be created from the UI */
@@ -326,8 +610,15 @@ namespace hex {
void addProviderName(const std::string &unlocalizedName);
std::vector<std::string> &getEntries();
}
/**
* @brief Adds a new provider to the list of providers
* @tparam T The provider type that extends hex::prv::Provider
* @param addToList Whether to display the provider in the Other Providers list in the welcome screen and File menu
*/
template<std::derived_from<hex::prv::Provider> T>
void add(bool addToList = true) {
auto typeName = T().getTypeName();
@@ -347,10 +638,9 @@ namespace hex {
impl::addProviderName(typeName);
}
std::vector<std::string> &getEntries();
}
/* Data Formatter Registry. Allows adding formatters that are used in the Copy-As menu for example */
namespace DataFormatter {
namespace impl {
@@ -361,32 +651,45 @@ namespace hex {
Callback callback;
};
std::vector<impl::Entry> &getEntries();
}
void add(const std::string &unlocalizedName, const impl::Callback &callback);
std::vector<impl::Entry> &getEntries();
/**
* @brief Adds a new data formatter
* @param unlocalizedName The unlocalized name of the formatter
* @param callback The function to call to format the data
*/
void add(const std::string &unlocalizedName, const impl::Callback &callback);
}
/* File Handler Registry. Allows adding handlers for opening files specific file types */
namespace FileHandler {
namespace impl {
using Callback = std::function<bool(std::filesystem::path)>;
using Callback = std::function<bool(std::fs::path)>;
struct Entry {
std::vector<std::string> extensions;
Callback callback;
};
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new file handler
* @param extensions The file extensions to handle
* @param callback The function to call to handle the file
*/
void add(const std::vector<std::string> &extensions, const impl::Callback &callback);
std::vector<impl::Entry> &getEntries();
}
/* Hex Editor Registry. Allows adding new functionality to the hex editor */
namespace HexEditor {
class DataVisualizer {
@@ -405,7 +708,8 @@ namespace hex {
protected:
const static int TextInputFlags;
bool drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
bool drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
bool drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const;
private:
u16 m_bytesPerCell;
u16 m_maxCharsPerCell;
@@ -419,6 +723,12 @@ namespace hex {
}
/**
* @brief Adds a new cell data visualizer
* @tparam T The data visualizer type that extends hex::DataVisualizer
* @param unlocalizedName The unlocalized name of the data visualizer
* @param args The arguments to pass to the constructor of the data visualizer
*/
template<std::derived_from<DataVisualizer> T, typename... Args>
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
@@ -426,6 +736,7 @@ namespace hex {
}
/* Hash Registry. Allows adding new hashes to the Hash view */
namespace Hashes {
class Hash {
@@ -436,11 +747,12 @@ namespace hex {
public:
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
Function(const Hash *type, std::string name, Callback callback)
Function(Hash *type, std::string name, Callback callback)
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {
}
[[nodiscard]] Hash *getType() { return this->m_type; }
[[nodiscard]] const Hash *getType() const { return this->m_type; }
[[nodiscard]] const std::string &getName() const { return this->m_name; }
@@ -457,7 +769,7 @@ namespace hex {
}
private:
const Hash *m_type;
Hash *m_type;
std::string m_name;
Callback m_callback;
@@ -467,12 +779,15 @@ namespace hex {
virtual void draw() { }
[[nodiscard]] virtual Function create(std::string name) = 0;
[[nodiscard]] virtual nlohmann::json store() const = 0;
virtual void load(const nlohmann::json &json) = 0;
[[nodiscard]] const std::string &getUnlocalizedName() const {
return this->m_unlocalizedName;
}
protected:
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const {
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) {
return { this, name, callback };
}
@@ -487,12 +802,47 @@ namespace hex {
void add(Hash* hash);
}
/**
* @brief Adds a new hash
* @tparam T The hash type that extends hex::Hash
* @param args The arguments to pass to the constructor of the hash
*/
template<typename T, typename ... Args>
void add(Args && ... args) {
impl::add(new T(std::forward<Args>(args)...));
}
}
namespace BackgroundServices {
namespace impl {
using Callback = std::function<void()>;
struct Service {
std::string name;
std::jthread thread;
};
std::vector<Service> &getServices();
void stopServices();
}
void registerService(const std::string &unlocalizedName, const impl::Callback &callback);
}
namespace CommunicationInterface {
namespace impl {
using NetworkCallback = std::function<nlohmann::json(const nlohmann::json &)>;
std::map<std::string, NetworkCallback> &getNetworkEndpoints();
}
void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback);
}
}
}

View File

@@ -9,73 +9,110 @@
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#define EVENT_DEF(event_name, ...) \
struct event_name final : public hex::Event<__VA_ARGS__> { \
constexpr static auto id = [] { return hex::EventId(); }(); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
#include <wolv/types/type_name.hpp>
#define EVENT_DEF_IMPL(event_name, should_log, ...) \
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
constexpr static auto Id = [] { return hex::impl::EventId(); }(); \
constexpr static auto ShouldLog = (should_log); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
}
#define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, true, __VA_ARGS__)
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, false, __VA_ARGS__)
struct GLFWwindow;
namespace hex {
class EventId {
public:
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
this->m_hash = line ^ 987654321;
for (auto c : std::string_view(func)) {
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
this->m_hash ^= c;
namespace impl {
class EventId {
public:
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
this->m_hash = line ^ 987654321;
for (auto c : std::string_view(func)) {
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
this->m_hash ^= c;
}
}
}
constexpr bool operator==(const EventId &rhs) const = default;
constexpr bool operator==(const EventId &rhs) const = default;
private:
u32 m_hash;
};
private:
u32 m_hash;
};
struct EventBase {
EventBase() noexcept = default;
};
struct EventBase {
EventBase() noexcept = default;
};
template<typename... Params>
struct Event : public EventBase {
using Callback = std::function<void(Params...)>;
template<typename... Params>
struct Event : public EventBase {
using Callback = std::function<void(Params...)>;
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
void operator()(Params... params) const noexcept {
this->m_func(params...);
}
void operator()(Params... params) const noexcept {
this->m_func(params...);
}
private:
Callback m_func;
};
private:
Callback m_func;
};
}
/**
* @brief The EventManager allows subscribing to and posting events to different parts of the program.
* To create a new event, use the EVENT_DEF macro. This will create a new event type with the given name and parameters
*/
class EventManager {
public:
using EventList = std::list<std::pair<EventId, EventBase *>>;
using EventList = std::list<std::pair<impl::EventId, impl::EventBase *>>;
/**
* @brief Subscribes to an event
* @tparam E Event
* @param function Function to call when the event is posted
* @return Token to unsubscribe from the event
*/
template<typename E>
static EventList::iterator subscribe(typename E::Callback function) {
return s_events.insert(s_events.end(), std::make_pair(E::id, new E(function)));
return s_events.insert(s_events.end(), std::make_pair(E::Id, new E(function)));
}
/**
* @brief Subscribes to an event
* @tparam E Event
* @param token Unique token to register the event to. Later required to unsubscribe again
* @param function Function to call when the event is posted
*/
template<typename E>
static void subscribe(void *token, typename E::Callback function) {
s_tokenStore.insert(std::make_pair(token, subscribe<E>(function)));
}
static void unsubscribe(EventList::iterator iter) noexcept {
s_events.remove(*iter);
/**
* @brief Unsubscribes from an event
* @param token Token returned by subscribe
*/
static void unsubscribe(const EventList::iterator &token) noexcept {
s_events.erase(token);
}
/**
* @brief Unsubscribes from an event
* @tparam E Event
* @param token Token passed to subscribe
*/
template<typename E>
static void unsubscribe(void *token) noexcept {
auto iter = std::find_if(s_tokenStore.begin(), s_tokenStore.end(), [&](auto &item) {
return item.first == token && item.second->first == E::id;
return item.first == token && item.second->first == E::Id;
});
if (iter != s_tokenStore.end()) {
@@ -85,14 +122,28 @@ namespace hex {
}
/**
* @brief Posts an event to all subscribers of it
* @tparam E Event
* @param args Arguments to pass to the event
*/
template<typename E>
static void post(auto &&...args) noexcept {
for (const auto &[id, event] : s_events) {
if (id == E::id)
if (id == E::Id) {
(*static_cast<E *const>(event))(std::forward<decltype(args)>(args)...);
}
}
#if defined (DEBUG)
if (E::ShouldLog)
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
#endif
}
/**
* @brief Unsubscribe all subscribers from all events
*/
static void clear() noexcept {
s_events.clear();
s_tokenStore.clear();
@@ -112,32 +163,61 @@ namespace hex {
EVENT_DEF(EventSettingsChanged);
EVENT_DEF(EventAbnormalTermination, int);
EVENT_DEF(EventOSThemeChanged);
/**
* @brief Called when the provider is created.
* This event is responsible for (optionally) initializing the provider and calling EventProviderOpened
* (although the event can also be called manually without problem)
*/
EVENT_DEF(EventProviderCreated, prv::Provider *);
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
/**
* @brief Called as a continuation of EventProviderCreated
* this event is normally called immediately after EventProviderCreated successfully initialized the provider.
* If no initialization (Provider::skipLoadInterface() has been set), this event should be called manually
* If skipLoadInterface failed, this event is not called
*
* @note this is not related to Provider::open()
*/
EVENT_DEF(EventProviderOpened, prv::Provider *);
EVENT_DEF(EventProviderClosing, prv::Provider *, bool *);
EVENT_DEF(EventProviderClosed, prv::Provider *);
EVENT_DEF(EventProviderDeleted, prv::Provider *);
EVENT_DEF(EventFrameBegin);
EVENT_DEF(EventFrameEnd);
EVENT_DEF(EventProviderSaved, prv::Provider *);
EVENT_DEF(EventWindowInitialized);
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
EVENT_DEF(EventPatchCreated, u64, u8, u8);
EVENT_DEF(EventPatternExecuted, const std::string&);
EVENT_DEF(EventPatternEditorChanged, const std::string&);
EVENT_DEF(EventStoreContentDownloaded, const std::fs::path&);
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
EVENT_DEF(EventImHexClosing);
EVENT_DEF_NO_LOG(EventFrameBegin);
EVENT_DEF_NO_LOG(EventFrameEnd);
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
EVENT_DEF(RequestOpenWindow, std::string);
EVENT_DEF(RequestSelectionChange, Region);
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t);
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
EVENT_DEF(RequestChangeWindowTitle, std::string);
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
EVENT_DEF(RequestUpdateWindowTitle);
EVENT_DEF(RequestCloseImHex, bool);
EVENT_DEF(RequestRestartImHex);
EVENT_DEF(RequestOpenFile, std::fs::path);
EVENT_DEF(RequestChangeTheme, std::string);
EVENT_DEF(RequestOpenPopup, std::string);
/**
* @brief Creates a provider from it's unlocalized name, and add it to the provider list
*/
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);
EVENT_DEF(RequestInitThemeHandlers);
EVENT_DEF(RequestShowInfoPopup, std::string);
EVENT_DEF(RequestShowErrorPopup, std::string);
EVENT_DEF(RequestShowFatalErrorPopup, std::string);
EVENT_DEF(RequestShowYesNoQuestionPopup, std::string, std::function<void()>, std::function<void()>);
EVENT_DEF(RequestShowFileChooserPopup, std::vector<std::fs::path>, std::vector<nfdfilteritem_t>, std::function<void(std::fs::path)>);
EVENT_DEF(RequestOpenInfoPopup, const std::string);
EVENT_DEF(RequestOpenErrorPopup, const std::string);
EVENT_DEF(RequestOpenFatalPopup, const std::string);
}

View File

@@ -8,12 +8,12 @@
#include <vector>
#include <variant>
#include <map>
#include <filesystem>
#include <hex/helpers/concepts.hpp>
#include <hex/api/task.hpp>
#include <hex/api/keybinding.hpp>
#include <wolv/io/fs.hpp>
using ImGuiID = unsigned int;
struct ImVec2;
@@ -25,13 +25,7 @@ namespace hex {
namespace ImHexApi {
namespace Common {
void closeImHex(bool noQuestions = false);
void restartImHex();
}
/* Functions to query information from the Hex Editor and interact with it */
namespace HexEditor {
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
@@ -86,32 +80,132 @@ namespace hex {
void setCurrentSelection(std::optional<ProviderRegion> region);
}
/**
* @brief Adds a background color highlighting to the Hex Editor
* @param region The region to highlight
* @param color The color to use for the highlighting
* @return Unique ID used to remove the highlighting again later
*/
u32 addBackgroundHighlight(const Region &region, color_t color);
/**
* @brief Removes a background color highlighting from the Hex Editor
* @param id The ID of the highlighting to remove
*/
void removeBackgroundHighlight(u32 id);
/**
* @brief Adds a foreground color highlighting to the Hex Editor
* @param region The region to highlight
* @param color The color to use for the highlighting
* @return Unique ID used to remove the highlighting again later
*/
u32 addForegroundHighlight(const Region &region, color_t color);
/**
* @brief Removes a foreground color highlighting from the Hex Editor
* @param id The ID of the highlighting to remove
*/
void removeForegroundHighlight(u32 id);
/**
* @brief Adds a hover tooltip to the Hex Editor
* @param region The region to add the tooltip to
* @param value Text to display in the tooltip
* @param color The color of the tooltip
* @return Unique ID used to remove the tooltip again later
*/
u32 addTooltip(Region region, std::string value, color_t color);
/**
* @brief Removes a hover tooltip from the Hex Editor
* @param id The ID of the tooltip to remove
*/
void removeTooltip(u32 id);
/**
* @brief Adds a background color highlighting to the Hex Editor using a callback function
* @param function Function that draws the highlighting based on the hovered region
* @return Unique ID used to remove the highlighting again later
*/
u32 addTooltipProvider(TooltipFunction function);
/**
* @brief Removes a background color highlighting from the Hex Editor
* @param id The ID of the highlighting to remove
*/
void removeTooltipProvider(u32 id);
/**
* @brief Adds a background color highlighting to the Hex Editor using a callback function
* @param function Function that draws the highlighting based on the hovered region
* @return Unique ID used to remove the highlighting again later
*/
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function);
/**
* @brief Removes a background color highlighting from the Hex Editor
* @param id The ID of the highlighting to remove
*/
void removeBackgroundHighlightingProvider(u32 id);
/**
* @brief Adds a foreground color highlighting to the Hex Editor using a callback function
* @param function Function that draws the highlighting based on the hovered region
* @return Unique ID used to remove the highlighting again later
*/
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function);
/**
* @brief Removes a foreground color highlighting from the Hex Editor
* @param id The ID of the highlighting to remove
*/
void removeForegroundHighlightingProvider(u32 id);
/**
* @brief Checks if there's a valid selection in the Hex Editor right now
*/
bool isSelectionValid();
/**
* @brief Clears the current selection in the Hex Editor
*/
void clearSelection();
/**
* @brief Gets the current selection in the Hex Editor
* @return The current selection
*/
std::optional<ProviderRegion> getSelection();
/**
* @brief Sets the current selection in the Hex Editor
* @param region The region to select
* @param provider The provider to select the region in
*/
void setSelection(const Region &region, prv::Provider *provider = nullptr);
/**
* @brief Sets the current selection in the Hex Editor
* @param region The region to select
*/
void setSelection(const ProviderRegion &region);
/**
* @brief Sets the current selection in the Hex Editor
* @param address The address to select
* @param size The size of the selection
* @param provider The provider to select the region in
*/
void setSelection(u64 address, size_t size, prv::Provider *provider = nullptr);
}
/* Functions to interact with Bookmarks */
namespace Bookmarks {
struct Entry {
@@ -123,10 +217,23 @@ namespace hex {
bool locked;
};
/**
* @brief Adds a new bookmark
* @param address The address of the bookmark
* @param size The size of the bookmark
* @param name The name of the bookmark
* @param comment The comment of the bookmark
* @param color The color of the bookmark or 0x00 for the default color
*/
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
}
/**
* Helper methods about the providers
* @note the "current provider" or "currently selected provider" refers to the currently selected provider in the UI;
* the provider the user is actually editing.
*/
namespace Provider {
namespace impl {
@@ -136,30 +243,82 @@ namespace hex {
}
/**
* @brief Gets the currently selected data provider
* @return The currently selected data provider, or nullptr is there is none
*/
prv::Provider *get();
/**
* @brief Gets a list of all currently loaded data providers
* @return The currently loaded data providers
*/
const std::vector<prv::Provider *> &getProviders();
/**
* @brief Sets the currently selected data provider
* @param index Index of the provider to select
*/
void setCurrentProvider(u32 index);
/**
* @brief Checks whether the currently selected data provider is valid
* @return Whether the currently selected data provider is valid
*/
bool isValid();
/**
* @brief Marks the **currently selected** data provider as dirty
*/
void markDirty();
/**
* @brief Marks **all data providers** as clean
*/
void resetDirty();
/**
* @brief Checks whether **any of the data providers** is dirty
* @return Whether any data provider is dirty
*/
bool isDirty();
/**
* @brief Adds a newly created provider to the list of providers, and mark it as the selected one.
* @param provider The provider to add
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
*/
void add(prv::Provider *provider, bool skipLoadInterface = false);
/**
* @brief Creates a new provider and adds it to the list of providers
* @tparam T The type of the provider to create
* @param args Arguments to pass to the provider's constructor
*/
template<std::derived_from<prv::Provider> T>
void add(auto &&...args) {
add(new T(std::forward<decltype(args)>(args)...));
}
/**
* @brief Removes a provider from the list of providers
* @param provider The provider to remove
* @param noQuestions Whether to skip asking the user for confirmation
*/
void remove(prv::Provider *provider, bool noQuestions = false);
/**
* @brief Creates a new provider using its unlocalized name and add it to the list of providers
* @param unlocalizedName The unlocalized name of the provider to create
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
*/
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false);
}
/* Functions to interact with various ImHex system settings */
namespace System {
namespace impl {
@@ -175,7 +334,7 @@ namespace hex {
void setBorderlessWindowMode(bool enabled);
void setCustomFontPath(const std::filesystem::path &path);
void setCustomFontPath(const std::fs::path &path);
void setFontSize(float size);
void setGPUVendor(const std::string &vendor);
@@ -191,35 +350,160 @@ namespace hex {
char **envp;
};
enum class TaskProgressState {
Reset,
Progress,
Flash
};
enum class TaskProgressType {
Normal,
Warning,
Error
};
/**
* @brief Closes ImHex
* @param noQuestions Whether to skip asking the user for confirmation
*/
void closeImHex(bool noQuestions = false);
/**
* @brief Restarts ImHex
*/
void restartImHex();
/**
* @brief Sets the progress bar in the task bar
* @param state The state of the progress bar
* @param type The type of the progress bar progress
* @param progress The progress of the progress bar
*/
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress);
/**
* @brief Gets the current program arguments
* @return The current program arguments
*/
const ProgramArguments &getProgramArguments();
/**
* @brief Gets a program argument
* @param index The index of the argument to get
* @return The argument at the given index
*/
std::optional<std::u8string> getProgramArgument(int index);
/**
* @brief Gets the current target FPS
* @return The current target FPS
*/
float getTargetFPS();
/**
* @brief Sets the target FPS
* @param fps The target FPS
*/
void setTargetFPS(float fps);
/**
* @brief Gets the current global scale
* @return The current global scale
*/
float getGlobalScale();
/**
* @brief Gets the current native scale
* @return The current native scale
*/
float getNativeScale();
/**
* @brief Gets the current main window position
* @return Position of the main window
*/
ImVec2 getMainWindowPosition();
/**
* @brief Gets the current main window size
* @return Size of the main window
*/
ImVec2 getMainWindowSize();
/**
* @brief Gets the current main dock space ID
* @return ID of the main dock space
*/
ImGuiID getMainDockSpaceId();
/**
* @brief Checks if borderless window mode is enabled currently
* @return Whether borderless window mode is enabled
*/
bool isBorderlessWindowModeEnabled();
/**
* @brief Gets the init arguments passed to ImHex from the splash screen
* @return Init arguments
*/
std::map<std::string, std::string> &getInitArguments();
constexpr static float DefaultFontSize = 13.0;
/**
* @brief Gets the current custom font path
* @return The current custom font path
*/
const std::filesystem::path &getCustomFontPath();
/**
* @brief Gets the current font size
* @return The current font size
*/
float getFontSize();
/**
* @brief Sets if ImHex should follow the system theme
* @param enabled Whether to follow the system theme
*/
void enableSystemThemeDetection(bool enabled);
/**
* @brief Checks if ImHex follows the system theme
* @return Whether ImHex follows the system theme
*/
bool usesSystemThemeDetection();
/**
* @brief Gets the currently set additional folder paths
* @return The currently set additional folder paths
*/
const std::vector<std::filesystem::path> &getAdditionalFolderPaths();
/**
* @brief Sets the additional folder paths
* @param paths The additional folder paths
*/
void setAdditionalFolderPaths(const std::vector<std::filesystem::path> &paths);
/**
* @brief Gets the current GPU vendor
* @return The current GPU vendor
*/
const std::string &getGPUVendor();
/**
* @brief Checks if ImHex is running in portable mode
* @return Whether ImHex is running in portable mode
*/
bool isPortableVersion();
}

View File

@@ -5,7 +5,9 @@
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string>
struct ImGuiWindow;
@@ -136,15 +138,31 @@ namespace hex {
auto operator<=>(const Key &) const = default;
[[nodiscard]] constexpr u32 getKeyCode() const { return this->m_key; }
private:
u32 m_key;
};
constexpr static auto CTRL = Key(static_cast<Keys>(0x0100'0000));
constexpr static auto ALT = Key(static_cast<Keys>(0x0200'0000));
constexpr static auto SHIFT = Key(static_cast<Keys>(0x0400'0000));
constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000));
constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000));
#if defined (OS_MACOS)
constexpr static auto CTRLCMD = SUPER;
#else
constexpr static auto CTRLCMD = CTRL;
#endif
class Shortcut {
public:
Shortcut() = default;
Shortcut(Keys key) : m_keys({ key }) { }
const static inline auto None = Keys(0);
Shortcut operator+(const Key &other) const {
Shortcut result = *this;
result.m_keys.insert(other);
@@ -166,6 +184,173 @@ namespace hex {
return this->m_keys == other.m_keys;
}
bool isLocal() const {
return this->m_keys.contains(CurrentView);
}
std::string toString() const {
std::string result;
#if defined(OS_MACOS)
constexpr static auto CTRL_NAME = "CTRL";
constexpr static auto ALT_NAME = "OPT";
constexpr static auto SHIFT_NAME = "SHIFT";
constexpr static auto SUPER_NAME = "CMD";
#else
constexpr static auto CTRL_NAME = "CTRL";
constexpr static auto ALT_NAME = "ALT";
constexpr static auto SHIFT_NAME = "SHIFT";
constexpr static auto SUPER_NAME = "SUPER";
#endif
constexpr static auto Concatination = " + ";
auto keys = this->m_keys;
if (keys.erase(CTRL) > 0) {
result += CTRL_NAME;
result += Concatination;
}
if (keys.erase(ALT) > 0) {
result += ALT_NAME;
result += Concatination;
}
if (keys.erase(SHIFT) > 0) {
result += SHIFT_NAME;
result += Concatination;
}
if (keys.erase(SUPER) > 0) {
result += SUPER_NAME;
result += Concatination;
}
keys.erase(CurrentView);
for (const auto &key : keys) {
switch (Keys(key.getKeyCode())) {
case Keys::Space: result += "SPACE"; break;
case Keys::Apostrophe: result += "'"; break;
case Keys::Comma: result += ","; break;
case Keys::Minus: result += "-"; break;
case Keys::Period: result += "."; break;
case Keys::Slash: result += "/"; break;
case Keys::Num0: result += "0"; break;
case Keys::Num1: result += "1"; break;
case Keys::Num2: result += "2"; break;
case Keys::Num3: result += "3"; break;
case Keys::Num4: result += "4"; break;
case Keys::Num5: result += "5"; break;
case Keys::Num6: result += "6"; break;
case Keys::Num7: result += "7"; break;
case Keys::Num8: result += "8"; break;
case Keys::Num9: result += "9"; break;
case Keys::Semicolon: result += ";"; break;
case Keys::Equals: result += "="; break;
case Keys::A: result += "A"; break;
case Keys::B: result += "B"; break;
case Keys::C: result += "C"; break;
case Keys::D: result += "D"; break;
case Keys::E: result += "E"; break;
case Keys::F: result += "F"; break;
case Keys::G: result += "G"; break;
case Keys::H: result += "H"; break;
case Keys::I: result += "I"; break;
case Keys::J: result += "J"; break;
case Keys::K: result += "K"; break;
case Keys::L: result += "L"; break;
case Keys::M: result += "M"; break;
case Keys::N: result += "N"; break;
case Keys::O: result += "O"; break;
case Keys::P: result += "P"; break;
case Keys::Q: result += "Q"; break;
case Keys::R: result += "R"; break;
case Keys::S: result += "S"; break;
case Keys::T: result += "T"; break;
case Keys::U: result += "U"; break;
case Keys::V: result += "V"; break;
case Keys::W: result += "W"; break;
case Keys::X: result += "X"; break;
case Keys::Y: result += "Y"; break;
case Keys::Z: result += "Z"; break;
case Keys::LeftBracket: result += "["; break;
case Keys::Backslash: result += "\\"; break;
case Keys::RightBracket: result += "]"; break;
case Keys::GraveAccent: result += "`"; break;
case Keys::World1: result += "WORLD1"; break;
case Keys::World2: result += "WORLD2"; break;
case Keys::Escape: result += "ESC"; break;
case Keys::Enter: result += "ENTER"; break;
case Keys::Tab: result += "TAB"; break;
case Keys::Backspace: result += "BACKSPACE"; break;
case Keys::Insert: result += "INSERT"; break;
case Keys::Delete: result += "DELETE"; break;
case Keys::Right: result += "RIGHT"; break;
case Keys::Left: result += "LEFT"; break;
case Keys::Down: result += "DOWN"; break;
case Keys::Up: result += "UP"; break;
case Keys::PageUp: result += "PAGEUP"; break;
case Keys::PageDown: result += "PAGEDOWN"; break;
case Keys::Home: result += "HOME"; break;
case Keys::End: result += "END"; break;
case Keys::CapsLock: result += "CAPSLOCK"; break;
case Keys::ScrollLock: result += "SCROLLLOCK"; break;
case Keys::NumLock: result += "NUMLOCK"; break;
case Keys::PrintScreen: result += "PRINTSCREEN"; break;
case Keys::Pause: result += "PAUSE"; break;
case Keys::F1: result += "F1"; break;
case Keys::F2: result += "F2"; break;
case Keys::F3: result += "F3"; break;
case Keys::F4: result += "F4"; break;
case Keys::F5: result += "F5"; break;
case Keys::F6: result += "F6"; break;
case Keys::F7: result += "F7"; break;
case Keys::F8: result += "F8"; break;
case Keys::F9: result += "F9"; break;
case Keys::F10: result += "F10"; break;
case Keys::F11: result += "F11"; break;
case Keys::F12: result += "F12"; break;
case Keys::F13: result += "F13"; break;
case Keys::F14: result += "F14"; break;
case Keys::F15: result += "F15"; break;
case Keys::F16: result += "F16"; break;
case Keys::F17: result += "F17"; break;
case Keys::F18: result += "F18"; break;
case Keys::F19: result += "F19"; break;
case Keys::F20: result += "F20"; break;
case Keys::F21: result += "F21"; break;
case Keys::F22: result += "F22"; break;
case Keys::F23: result += "F23"; break;
case Keys::F24: result += "F24"; break;
case Keys::F25: result += "F25"; break;
case Keys::KeyPad0: result += "KP0"; break;
case Keys::KeyPad1: result += "KP1"; break;
case Keys::KeyPad2: result += "KP2"; break;
case Keys::KeyPad3: result += "KP3"; break;
case Keys::KeyPad4: result += "KP4"; break;
case Keys::KeyPad5: result += "KP5"; break;
case Keys::KeyPad6: result += "KP6"; break;
case Keys::KeyPad7: result += "KP7"; break;
case Keys::KeyPad8: result += "KP8"; break;
case Keys::KeyPad9: result += "KP9"; break;
case Keys::KeyPadDecimal: result += "KPDECIMAL"; break;
case Keys::KeyPadDivide: result += "KPDIVIDE"; break;
case Keys::KeyPadMultiply: result += "KPMULTIPLY"; break;
case Keys::KeyPadSubtract: result += "KPSUBTRACT"; break;
case Keys::KeyPadAdd: result += "KPADD"; break;
case Keys::KeyPadEnter: result += "KPENTER"; break;
case Keys::KeyPadEqual: result += "KPEQUAL"; break;
case Keys::Menu: result += "MENU"; break;
default:
continue;
}
result += " + ";
}
if (result.ends_with(" + "))
result = result.substr(0, result.size() - 3);
return result;
}
private:
friend Shortcut operator+(const Key &lhs, const Key &rhs);
@@ -179,19 +364,54 @@ namespace hex {
return result;
}
constexpr static auto CTRL = Key(static_cast<Keys>(0x1000'0000));
constexpr static auto ALT = Key(static_cast<Keys>(0x2000'0000));
constexpr static auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
constexpr static auto SUPER = Key(static_cast<Keys>(0x8000'0000));
/**
* @brief The ShortcutManager handles global and view-specific shortcuts.
* New shortcuts can be constructed using the + operator on Key objects. For example: CTRL + ALT + Keys::A
*/
class ShortcutManager {
public:
/**
* @brief Add a global shortcut. Global shortcuts can be triggered regardless of what view is currently focused
* @param shortcut The shortcut to add.
* @param callback The callback to call when the shortcut is triggered.
*/
static void addGlobalShortcut(const Shortcut &shortcut, const std::function<void()> &callback);
/**
* @brief Add a view-specific shortcut. View-specific shortcuts can only be triggered when the specified view is focused.
* @param view The view to add the shortcut to.
* @param shortcut The shortcut to add.
* @param callback The callback to call when the shortcut is triggered.
*/
static void addShortcut(View *view, const Shortcut &shortcut, const std::function<void()> &callback);
static void process(View *currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode);
/**
* @brief Process a key event. This should be called from the main loop.
* @param currentView Current view to process
* @param ctrl Whether the CTRL key is pressed
* @param alt Whether the ALT key is pressed
* @param shift Whether the SHIFT key is pressed
* @param super Whether the SUPER key is pressed
* @param focused Whether the current view is focused
* @param keyCode The key code of the key that was pressed
*/
static void process(const std::unique_ptr<View> &currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode);
/**
* @brief Process a key event. This should be called from the main loop.
* @param ctrl Whether the CTRL key is pressed
* @param alt Whether the ALT key is pressed
* @param shift Whether the SHIFT key is pressed
* @param super Whether the SUPER key is pressed
* @param keyCode The key code of the key that was pressed
*/
static void processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode);
/**
* @brief Clear all shortcuts
*/
static void clearShortcuts();
private:

View File

@@ -0,0 +1,39 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/fs.hpp>
#include <string>
#include <variant>
#include <nlohmann/json_fwd.hpp>
#include <imgui.h>
namespace hex {
class LayoutManager {
public:
struct Layout {
std::string name;
std::fs::path path;
};
static void save(const std::string &name);
static void load(const std::fs::path &path);
static void loadString(const std::string &content);
static std::vector<Layout> getLayouts();
static void process();
static void reload();
static void reset();
private:
LayoutManager() = default;
static std::optional<std::fs::path> s_layoutPathToLoad;
static std::optional<std::string> s_layoutStringToLoad;
static std::vector<Layout> s_layouts;
};
}

View File

@@ -5,6 +5,8 @@
#include <string>
#include <string_view>
#include <fmt/format.h>
namespace hex {
class LanguageDefinition {
@@ -56,4 +58,12 @@ namespace hex {
return LangEntry(string);
}
}
}
template<>
struct fmt::formatter<hex::LangEntry> : fmt::formatter<std::string_view> {
template<typename FormatContext>
auto format(const hex::LangEntry &entry, FormatContext &ctx) {
return fmt::formatter<std::string_view>::format(entry, ctx);
}
};

View File

@@ -14,39 +14,104 @@
namespace hex {
/**
* @brief Project file manager
*
* The project file manager is used to load and store project files. It is used by all features of ImHex
* that want to store any data to a Project File.
*
*/
class ProjectFile {
public:
struct Handler {
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
std::fs::path basePath;
bool required;
Function load, store;
std::fs::path basePath; //< Base path for where to store the files in the project file
bool required; //< If true, ImHex will display an error if this handler fails to load or store data
Function load, store; //< Functions to load and store data
};
struct ProviderHandler {
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
std::fs::path basePath;
bool required;
Function load, store;
std::fs::path basePath; //< Base path for where to store the files in the project file
bool required; //< If true, ImHex will display an error if this handler fails to load or store data
Function load, store; //< Functions to load and store data
};
/**
* @brief Load a project file
*
* @param filePath Path to the project file
* @return true if the project file was loaded successfully
* @return false if the project file was not loaded successfully
*/
static bool load(const std::fs::path &filePath);
/**
* @brief Store a project file
*
* @param filePath Path to the project file
* @return true if the project file was stored successfully
* @return false if the project file was not stored successfully
*/
static bool store(std::optional<std::fs::path> filePath = std::nullopt);
/**
* @brief Check if a project file is currently loaded
*
* @return true if a project file is currently loaded
* @return false if no project file is currently loaded
*/
static bool hasPath();
/**
* @brief Clear the currently loaded project file
*/
static void clearPath();
/**
* @brief Get the path to the currently loaded project file
* @return Path to the currently loaded project file
*/
static std::fs::path getPath();
/**
* @brief Set the path to the currently loaded project file
* @param path Path to the currently loaded project file
*/
static void setPath(const std::fs::path &path);
/**
* @brief Register a handler for storing and loading global data from a project file
*
* @param handler The handler to register
*/
static void registerHandler(const Handler &handler) {
getHandlers().push_back(handler);
}
/**
* @brief Register a handler for storing and loading per-provider data from a project file
*
* @param handler The handler to register
*/
static void registerPerProviderHandler(const ProviderHandler &handler) {
getProviderHandlers().push_back(handler);
}
/**
* @brief Get the list of registered handlers
* @return List of registered handlers
*/
static std::vector<Handler>& getHandlers() {
return s_handlers;
}
/**
* @brief Get the list of registered per-provider handlers
* @return List of registered per-provider handlers
*/
static std::vector<ProviderHandler>& getProviderHandlers() {
return s_providerHandlers;
}

View File

@@ -17,6 +17,9 @@ namespace hex {
class TaskHolder;
class TaskManager;
/**
* @brief A type representing a running asynchronous task
*/
class Task {
public:
Task() = default;
@@ -26,14 +29,38 @@ namespace hex {
Task(Task &&other) noexcept;
~Task();
/**
* @brief Updates the current process value of the task
* @param value Current value
*/
void update(u64 value = 0);
/**
* @brief Sets the maximum value of the task
* @param value Maximum value of the task
*/
void setMaxValue(u64 value);
/**
* @brief Interrupts the task
* For regular Tasks, this just throws an exception to stop the task.
* If a custom interrupt callback is set, an exception is thrown and the callback is called.
*/
void interrupt();
/**
* @brief Sets a callback that is called when the task is interrupted
* @param callback Callback to be called
*/
void setInterruptCallback(std::function<void()> callback);
[[nodiscard]] bool isBackgroundTask() const;
[[nodiscard]] bool isFinished() const;
[[nodiscard]] bool hadException() const;
[[nodiscard]] bool wasInterrupted() const;
[[nodiscard]] bool shouldInterrupt() const;
void clearException();
[[nodiscard]] std::string getExceptionMessage() const;
@@ -41,10 +68,6 @@ namespace hex {
[[nodiscard]] u64 getValue() const;
[[nodiscard]] u64 getMaxValue() const;
void interrupt();
void setInterruptCallback(std::function<void()> callback);
private:
void finish();
void interruption();
@@ -72,6 +95,9 @@ namespace hex {
friend class TaskManager;
};
/**
* @brief A type holding a weak reference to a Task
*/
class TaskHolder {
public:
TaskHolder() = default;
@@ -82,11 +108,16 @@ namespace hex {
[[nodiscard]] bool wasInterrupted() const;
[[nodiscard]] bool shouldInterrupt() const;
[[nodiscard]] u32 getProgress() const;
void interrupt();
private:
std::weak_ptr<Task> m_task;
};
/**
* @brief The Task Manager is responsible for running and managing asynchronous tasks
*/
class TaskManager {
public:
TaskManager() = delete;
@@ -96,19 +127,45 @@ namespace hex {
constexpr static auto NoProgress = 0;
/**
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
* @param name Name of the task
* @param maxValue Maximum value of the task
* @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task
*/
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
/**
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager
* @param name Name of the task
* @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task
*/
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
/**
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
* @param function Function to be executed
*/
static void doLater(const std::function<void()> &function);
/**
* @brief Creates a callback that will be executed when all tasks are finished
* @param function Function to be executed
*/
static void runWhenTasksFinished(const std::function<void()> &function);
static void collectGarbage();
static size_t getRunningTaskCount();
static size_t getRunningBackgroundTaskCount();
static std::list<std::shared_ptr<Task>> &getRunningTasks();
static void doLater(const std::function<void()> &function);
static std::list<std::shared_ptr<Task>> &getRunningTasks();
static void runDeferredCalls();
static void runWhenTasksFinished(const std::function<void()> &function);
private:
static std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;

View File

@@ -4,32 +4,92 @@
#include <hex/helpers/fs.hpp>
#include <string>
#include <variant>
#include <nlohmann/json_fwd.hpp>
#include <imgui.h>
namespace hex::api {
namespace hex {
/**
* @brief The Theme Manager takes care of loading and applying themes
*/
class ThemeManager {
public:
constexpr static auto NativeTheme = "Native";
using ColorMap = std::map<std::string, u32>;
struct Style {
std::variant<ImVec2*, float*> value;
float min;
float max;
bool needsScaling;
};
using StyleMap = std::map<std::string, Style>;
/**
* @brief Changes the current theme to the one with the given name
* @param name Name of the theme to change to
*/
static void changeTheme(std::string name);
/**
* @brief Adds a theme from json data
* @param content JSON data of the theme
*/
static void addTheme(const std::string &content);
static void addThemeHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler);
static void addStyleHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler);
/**
* @brief Adds a theme handler to handle color values loaded from a theme file
* @param name Name of the handler
* @param colorMap Map of color names to their respective constants
* @param getFunction Function to get the color value of a constant
* @param setFunction Function to set the color value of a constant
*/
static void addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction);
/**
* @brief Adds a style handler to handle style values loaded from a theme file
* @param name Name of the handler
* @param styleMap Map of style names to their respective constants
*/
static void addStyleHandler(const std::string &name, const StyleMap &styleMap);
static std::vector<std::string> getThemeNames();
static const std::string &getThemeImagePostfix();
static std::optional<ImColor> parseColorString(const std::string &colorString);
static nlohmann::json exportCurrentTheme(const std::string &name);
static void reset();
public:
struct ThemeHandler {
ColorMap colorMap;
std::function<ImColor(u32)> getFunction;
std::function<void(u32, ImColor)> setFunction;
};
struct StyleHandler {
StyleMap styleMap;
};
static std::map<std::string, ThemeHandler>& getThemeHandlers() { return s_themeHandlers; }
static std::map<std::string, StyleHandler>& getStyleHandlers() { return s_styleHandlers; }
private:
ThemeManager() = default;
static std::map<std::string, nlohmann::json> s_themes;
static std::map<std::string, std::function<void(std::string, std::string)>> s_themeHandlers, s_styleHandlers;
static std::map<std::string, ThemeHandler> s_themeHandlers;
static std::map<std::string, StyleHandler> s_styleHandlers;
static std::string s_imagePostfix;
static std::string s_currTheme;
};
}

View File

@@ -0,0 +1,2 @@
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";

View File

@@ -38,9 +38,18 @@ namespace hex::dp {
void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
[[nodiscard]] Node *getParentNode() { return this->m_parentNode; }
[[nodiscard]] Node *getParentNode() const { return this->m_parentNode; }
[[nodiscard]] std::optional<std::vector<u8>> &getOutputData() { return this->m_outputData; }
[[nodiscard]] std::vector<u8>& getOutputData() {
if (!this->m_outputData.empty())
return this->m_outputData;
else
return this->m_defaultData;
}
void clearOutputData() { this->m_outputData.clear(); }
[[nodiscard]] std::vector<u8>& getDefaultData() { return this->m_defaultData; }
static void setIdCounter(int id) {
if (id > Attribute::s_idCounter)
@@ -55,7 +64,8 @@ namespace hex::dp {
std::map<int, Attribute *> m_connectedAttributes;
Node *m_parentNode = nullptr;
std::optional<std::vector<u8>> m_outputData;
std::vector<u8> m_outputData;
std::vector<u8> m_defaultData;
friend class Node;
void setParentNode(Node *node) { this->m_parentNode = node; }

View File

@@ -9,7 +9,7 @@ namespace hex::dp {
Link(int from, int to);
[[nodiscard]] int getId() const { return this->m_id; }
void setID(int id) { this->m_id = id; }
void setId(int id) { this->m_id = id; }
[[nodiscard]] int getFromId() const { return this->m_from; }
[[nodiscard]] int getToId() const { return this->m_to; }

View File

@@ -5,6 +5,7 @@
#include <hex/data_processor/attribute.hpp>
#include <set>
#include <span>
#include <string_view>
#include <vector>
@@ -31,7 +32,10 @@ namespace hex::dp {
void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
[[nodiscard]] const std::string &getUnlocalizedTitle() const { return this->m_unlocalizedTitle; }
void setUnlocalizedTitle(std::string title) { this->m_unlocalizedTitle = std::move(title); }
[[nodiscard]] std::vector<Attribute> &getAttributes() { return this->m_attributes; }
[[nodiscard]] const std::vector<Attribute> &getAttributes() const { return this->m_attributes; }
void setCurrentOverlay(prv::Overlay *overlay) {
this->m_overlay = overlay;
@@ -40,8 +44,8 @@ namespace hex::dp {
virtual void drawNode() { }
virtual void process() = 0;
virtual void store(nlohmann::json &j) { hex::unused(j); }
virtual void load(nlohmann::json &j) { hex::unused(j); }
virtual void store(nlohmann::json &j) const { hex::unused(j); }
virtual void load(const nlohmann::json &j) { hex::unused(j); }
struct NodeError {
Node *node;
@@ -50,7 +54,7 @@ namespace hex::dp {
void resetOutputData() {
for (auto &attribute : this->m_attributes)
attribute.getOutputData().reset();
attribute.clearOutputData();
}
void resetProcessedInputs() {
@@ -70,6 +74,14 @@ namespace hex::dp {
Node::s_idCounter = id;
}
const std::vector<u8>& getBufferOnInput(u32 index);
const i128& getIntegerOnInput(u32 index);
const long double& getFloatOnInput(u32 index);
void setBufferOnOutput(u32 index, std::span<const u8> data);
void setIntegerOnOutput(u32 index, i128 integer);
void setFloatOnOutput(u32 index, long double floatingPoint);
private:
int m_id;
std::string m_unlocalizedTitle, m_unlocalizedName;
@@ -80,11 +92,15 @@ namespace hex::dp {
static int s_idCounter;
Attribute *getConnectedInputAttribute(u32 index) {
Attribute& getAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");
auto &connectedAttribute = this->getAttributes()[index].getConnectedAttributes();
return this->getAttributes()[index];
}
Attribute *getConnectedInputAttribute(u32 index) {
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
if (connectedAttribute.empty())
return nullptr;
@@ -103,15 +119,14 @@ namespace hex::dp {
throw NodeError { this, message };
}
std::vector<u8> getBufferOnInput(u32 index);
i128 getIntegerOnInput(u32 index);
long double getFloatOnInput(u32 index);
void setBufferOnOutput(u32 index, const std::vector<u8> &data);
void setIntegerOnOutput(u32 index, i128 integer);
void setFloatOnOutput(u32 index, long double floatingPoint);
void setOverlayData(u64 address, const std::vector<u8> &data);
void setAttributes(std::vector<Attribute> attributes) {
this->m_attributes = std::move(attributes);
for (auto &attr : this->m_attributes)
attr.setParentNode(this);
}
};
}

View File

@@ -16,7 +16,7 @@ namespace hex {
concept has_size = sizeof(T) == Size;
template<typename T>
class Cloneable {
class ICloneable {
public:
[[nodiscard]] virtual std::unique_ptr<T> clone() const = 0;
};

View File

@@ -16,7 +16,7 @@ namespace hex::crypt {
void initialize();
void exit();
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
u8 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
u16 crc16(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
u32 crc32(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);

View File

@@ -8,25 +8,28 @@ namespace hex {
enum class Architecture : i32
{
ARM,
ARM64,
MIPS,
X86,
PPC,
SPARC,
SYSZ,
XCORE,
M68K,
TMS320C64X,
M680X,
EVM,
MOS65XX,
WASM,
BPF,
RISCV,
ARM = CS_ARCH_ARM,
ARM64 = CS_ARCH_ARM64,
MIPS = CS_ARCH_MIPS,
X86 = CS_ARCH_X86,
PPC = CS_ARCH_PPC,
SPARC = CS_ARCH_SPARC,
SYSZ = CS_ARCH_SYSZ,
XCORE = CS_ARCH_XCORE,
M68K = CS_ARCH_M68K,
TMS320C64X = CS_ARCH_TMS320C64X,
M680X = CS_ARCH_M680X,
EVM = CS_ARCH_EVM,
MAX,
MIN = ARM
#if CS_API_MAJOR >= 5
WASM = CS_ARCH_WASM,
RISCV = CS_ARCH_RISCV,
MOS65XX = CS_ARCH_MOS65XX,
BPF = CS_ARCH_BPF,
#endif
MAX = CS_ARCH_MAX,
MIN = ARM
};
class Disassembler {
@@ -39,7 +42,31 @@ namespace hex {
return cs_support(toCapstoneArchitecture(architecture));
}
constexpr static const char *const ArchitectureNames[] = { "ARM32", "ARM64", "MIPS", "x86", "PowerPC", "Sparc", "SystemZ", "XCore", "68K", "TMS320C64x", "680X", "Ethereum", "MOS65XX", "WebAssembly", "Berkeley Packet Filter", "RISC-V" };
constexpr static auto ArchitectureNames = [](){
std::array<const char *, static_cast<u32>(Architecture::MAX)> names = { };
names[CS_ARCH_ARM] = "ARM";
names[CS_ARCH_ARM64] = "AArch64";
names[CS_ARCH_MIPS] = "MIPS";
names[CS_ARCH_X86] = "Intel x86";
names[CS_ARCH_PPC] = "PowerPC";
names[CS_ARCH_SPARC] = "SPARC";
names[CS_ARCH_SYSZ] = "SystemZ";
names[CS_ARCH_XCORE] = "XCore";
names[CS_ARCH_M68K] = "Motorola 68K";
names[CS_ARCH_TMS320C64X] = "TMS320C64x";
names[CS_ARCH_M680X] = "M680X";
names[CS_ARCH_EVM] = "Ethereum Virtual Machine";
#if CS_API_MAJOR >= 5
names[CS_ARCH_WASM] = "WebAssembly";
names[CS_ARCH_RISCV] = "RISC-V";
names[CS_ARCH_MOS65XX] = "MOS Technology 65xx";
names[CS_ARCH_BPF] = "Berkeley Packet Filter";
#endif
return names;
}();
static inline i32 getArchitectureSupportedCount() {
static i32 supportedCount = -1;

View File

@@ -5,9 +5,11 @@
#include <map>
#include <string_view>
#include <vector>
#include <span>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/file.hpp>
#include <wolv/io/file.hpp>
namespace hex {
@@ -20,17 +22,22 @@ namespace hex {
EncodingFile() = default;
EncodingFile(Type type, const std::fs::path &path);
EncodingFile(Type type, const std::string &path);
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(const std::vector<u8> &buffer) const;
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const;
[[nodiscard]] size_t getEncodingLengthFor(std::span<u8> buffer) const;
[[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
[[nodiscard]] bool valid() const { return this->m_valid; }
[[nodiscard]] const std::string& getTableContent() const { return this->m_tableContent; }
private:
void parseThingyFile(fs::File &file);
void parse(const std::string &content);
bool m_valid = false;
std::string m_tableContent;
std::map<size_t, std::map<std::vector<u8>, std::string>> m_mapping;
size_t m_longestSequence = 0;
};

View File

@@ -1,73 +0,0 @@
#pragma once
#include <hex.hpp>
#include <cstdio>
#include <string>
#include <vector>
#include <hex/helpers/fs.hpp>
#if defined(OS_MACOS)
#define off64_t off_t
#define fopen64 fopen
#define fseeko64 fseek
#define ftello64 ftell
#define ftruncate64 ftruncate
#endif
namespace hex::fs {
class File {
public:
enum class Mode
{
Read,
Write,
Create
};
explicit File(const std::fs::path &path, Mode mode) noexcept;
File() noexcept;
File(const File &) = delete;
File(File &&other) noexcept;
~File();
File &operator=(File &&other) noexcept;
[[nodiscard]] bool isValid() const {
return this->m_file != nullptr && fs::exists(this->m_path) && !fs::isDirectory(this->m_path);
}
void seek(u64 offset);
void close();
size_t readBuffer(u8 *buffer, size_t size);
std::vector<u8> readBytes(size_t numBytes = 0);
std::string readString(size_t numBytes = 0);
std::u8string readU8String(size_t numBytes = 0);
void write(const u8 *buffer, size_t size);
void write(const std::vector<u8> &bytes);
void write(const std::string &string);
void write(const std::u8string &string);
[[nodiscard]] size_t getSize() const;
void setSize(u64 size);
void flush();
bool remove();
auto getHandle() { return this->m_file; }
const std::fs::path &getPath() { return this->m_path; }
void disableBuffering();
private:
FILE *m_file;
std::fs::path m_path;
};
}

View File

@@ -10,81 +10,18 @@
#include <nfd.hpp>
namespace std::fs {
using namespace std::filesystem;
}
#include <wolv/io/fs.hpp>
namespace hex::fs {
[[maybe_unused]]
static inline bool exists(const std::fs::path &path) {
std::error_code error;
return std::filesystem::exists(path, error) && !error;
}
[[maybe_unused]]
static inline bool createDirectories(const std::fs::path &path) {
std::error_code error;
return std::filesystem::create_directories(path, error) && !error;
}
[[maybe_unused]]
static inline bool isRegularFile(const std::fs::path &path) {
std::error_code error;
return std::filesystem::is_regular_file(path, error) && !error;
}
[[maybe_unused]]
static inline bool copyFile(const std::fs::path &from, const std::fs::path &to, std::fs::copy_options = std::fs::copy_options::none) {
std::error_code error;
return std::filesystem::copy_file(from, to, error) && !error;
}
[[maybe_unused]]
static inline bool isDirectory(const std::fs::path &path) {
std::error_code error;
return std::filesystem::is_directory(path, error) && !error;
}
[[maybe_unused]]
static inline bool remove(const std::fs::path &path) {
std::error_code error;
return std::filesystem::remove(path, error) && !error;
}
[[maybe_unused]]
static inline bool removeAll(const std::fs::path &path) {
std::error_code error;
return std::filesystem::remove_all(path, error) && !error;
}
[[maybe_unused]]
static inline uintmax_t getFileSize(const std::fs::path &path) {
std::error_code error;
auto size = std::filesystem::file_size(path, error);
if (error) return 0;
else return size;
}
static inline bool isSubPath(const std::fs::path& base, const std::fs::path& destination) {
const auto relative = std::fs::relative(destination, base).u8string();
return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.');
}
bool isPathWritable(const std::fs::path &path);
std::fs::path toShortPath(const std::fs::path &path);
enum class DialogMode {
Open,
Save,
Folder
};
void setFileBrowserErrorCallback(const std::function<void()> &callback);
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {});
void setFileBrowserErrorCallback(const std::function<void(const std::string&)> &callback);
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {}, bool multiple = false);
enum class ImHexPath : u32 {
Patterns = 0,
@@ -101,12 +38,18 @@ namespace hex::fs {
Scripts,
Inspectors,
Themes,
Libraries,
Nodes,
Layouts,
END
};
std::optional<std::fs::path> getExecutablePath();
bool isPathWritable(const std::fs::path &path);
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
// temporarily expose these for the migration function
std::vector<std::fs::path> getDataPaths();
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder);
}

View File

@@ -1,12 +0,0 @@
#pragma once
#if defined(OS_MACOS)
#include <hex/helpers/fs.hpp>
extern "C" char * getMacExecutableDirectoryPath();
extern "C" char * getMacApplicationSupportDirectoryPath();
extern "C" void macFree(void *ptr);
#endif

View File

@@ -0,0 +1,325 @@
#pragma once
#include <hex.hpp>
#include <future>
#include <map>
#include <string>
#include <vector>
#include <curl/curl.h>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/fmt.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/core.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/utils/string.hpp>
#include <mbedtls/ssl.h>
namespace hex {
class HttpRequest {
public:
class ResultBase {
public:
ResultBase() = default;
explicit ResultBase(u32 statusCode) : m_statusCode(statusCode), m_valid(true) { }
[[nodiscard]] u32 getStatusCode() const {
return this->m_statusCode;
}
[[nodiscard]] bool isSuccess() const {
return this->getStatusCode() == 200;
}
[[nodiscard]] bool isValid() const {
return this->m_valid;
}
private:
u32 m_statusCode = 0;
bool m_valid = false;
};
template<typename T>
class Result : public ResultBase {
public:
Result() = default;
Result(u32 statusCode, T data) : ResultBase(statusCode), m_data(std::move(data)) { }
[[nodiscard]]
const T& getData() const {
return this->m_data;
}
private:
T m_data;
};
HttpRequest(std::string method, std::string url);
~HttpRequest();
HttpRequest(const HttpRequest&) = delete;
HttpRequest& operator=(const HttpRequest&) = delete;
HttpRequest(HttpRequest &&other) noexcept {
this->m_curl = other.m_curl;
other.m_curl = nullptr;
this->m_method = std::move(other.m_method);
this->m_url = std::move(other.m_url);
this->m_headers = std::move(other.m_headers);
this->m_body = std::move(other.m_body);
this->m_caCert = std::move(other.m_caCert);
}
HttpRequest& operator=(HttpRequest &&other) noexcept {
this->m_curl = other.m_curl;
other.m_curl = nullptr;
this->m_method = std::move(other.m_method);
this->m_url = std::move(other.m_url);
this->m_headers = std::move(other.m_headers);
this->m_body = std::move(other.m_body);
this->m_caCert = std::move(other.m_caCert);
return *this;
}
static void setCACert(std::string data) {
HttpRequest::s_caCertData = std::move(data);
}
static void setProxy(std::string proxy) {
HttpRequest::s_proxyUrl = std::move(proxy);
}
void setMethod(std::string method) {
this->m_method = std::move(method);
}
void setUrl(std::string url) {
this->m_url = std::move(url);
}
void addHeader(std::string key, std::string value) {
this->m_headers[std::move(key)] = std::move(value);
}
void setBody(std::string body) {
this->m_body = std::move(body);
}
void setTimeout(u32 timeout) {
this->m_timeout = timeout;
}
float getProgress() const {
return this->m_progress;
}
void cancel() {
this->m_canceled = true;
}
template<typename T = std::string>
std::future<Result<T>> downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
wolv::io::File file(path, wolv::io::File::Mode::Create);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &file);
return this->executeImpl<T>(response);
});
}
std::future<Result<std::vector<u8>>> downloadFile() {
return std::async(std::launch::async, [this] {
std::vector<u8> response;
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &response);
return this->executeImpl<std::vector<u8>>(response);
});
}
template<typename T = std::string>
std::future<Result<T>> uploadFile(const std::fs::path &path, const std::string &mimeName = "filename") {
return std::async(std::launch::async, [this, path, mimeName]{
auto fileName = wolv::util::toUTF8String(path.filename());
curl_mime *mime = curl_mime_init(this->m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
wolv::io::File file(path, wolv::io::File::Mode::Read);
curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto file = static_cast<FILE*>(arg);
return fread(buffer, size, nitems, file);
},
[](void *arg, curl_off_t offset, int origin) -> int {
auto file = static_cast<FILE*>(arg);
if (fseek(file, offset, origin) != 0)
return CURL_SEEKFUNC_CANTSEEK;
else
return CURL_SEEKFUNC_OK;
},
[](void *arg) {
auto file = static_cast<FILE*>(arg);
fclose(file);
},
file.getHandle());
curl_mime_filename(part, fileName.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T = std::string>
std::future<Result<T>> uploadFile(std::vector<u8> data, const std::string &mimeName = "filename") {
return std::async(std::launch::async, [this, data = std::move(data), mimeName]{
curl_mime *mime = curl_mime_init(this->m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
curl_mime_filename(part, "data.bin");
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T = std::string>
std::future<Result<T>> execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
std::string urlEncode(const std::string &input) {
auto escapedString = curl_easy_escape(this->m_curl, input.c_str(), std::strlen(input.c_str()));
if (escapedString != nullptr) {
std::string output = escapedString;
curl_free(escapedString);
return output;
}
return {};
}
std::string urlDecode(const std::string &input) {
auto unescapedString = curl_easy_unescape(this->m_curl, input.c_str(), std::strlen(input.c_str()), nullptr);
if (unescapedString != nullptr) {
std::string output = unescapedString;
curl_free(unescapedString);
return output;
}
return {};
}
protected:
void setDefaultConfig();
template<typename T>
Result<T> executeImpl(std::vector<u8> &data) {
curl_easy_setopt(this->m_curl, CURLOPT_URL, this->m_url.c_str());
curl_easy_setopt(this->m_curl, CURLOPT_CUSTOMREQUEST, this->m_method.c_str());
setDefaultConfig();
if (!this->m_body.empty()) {
curl_easy_setopt(this->m_curl, CURLOPT_POSTFIELDS, this->m_body.c_str());
}
curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Cache-Control: no-cache");
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
for (auto &[key, value] : this->m_headers) {
std::string header = hex::format("{}: {}", key, value);
headers = curl_slist_append(headers, header.c_str());
}
curl_easy_setopt(this->m_curl, CURLOPT_HTTPHEADER, headers);
{
std::scoped_lock lock(this->m_transmissionMutex);
auto result = curl_easy_perform(this->m_curl);
if (result != CURLE_OK){
char *url = nullptr;
curl_easy_getinfo(this->m_curl, CURLINFO_EFFECTIVE_URL, &url);
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", this->m_method, url, u32(result), curl_easy_strerror(result));
if (!HttpRequest::s_proxyUrl.empty()){
log::info("A custom proxy '{0}' is in use. Is it working correctly?", HttpRequest::s_proxyUrl);
}
return { };
}
}
long statusCode = 0;
curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
return Result<T>(statusCode, { data.begin(), data.end() });
}
[[maybe_unused]] static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData);
static size_t writeToVector(void *contents, size_t size, size_t nmemb, void *userdata);
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata);
static int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
private:
CURL *m_curl;
std::mutex m_transmissionMutex;
std::string m_method;
std::string m_url;
std::string m_body;
std::map<std::string, std::string> m_headers;
u32 m_timeout = 1000;
std::atomic<float> m_progress = 0.0F;
std::atomic<bool> m_canceled = false;
[[maybe_unused]] std::unique_ptr<mbedtls_x509_crt> m_caCert;
static std::string s_caCertData, s_proxyUrl;
};
}

View File

@@ -2,10 +2,6 @@
namespace hex {
[[noreturn]] inline void unreachable() {
__builtin_unreachable();
}
inline void unused(auto && ... x) {
((void)x, ...);
}

View File

@@ -17,7 +17,7 @@ namespace hex::log {
namespace {
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
const auto now = fmt::localtime(std::chrono::system_clock::now());
const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
@@ -31,9 +31,6 @@ namespace hex::log {
template<typename... T>
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
static std::mutex logMutex;
std::scoped_lock lock(logMutex);
auto dest = getDestination();
printPrefix(dest, ts, level);

View File

@@ -21,4 +21,6 @@ namespace hex::magic {
std::string getMIMEType(const std::vector<u8> &data);
std::string getMIMEType(prv::Provider *provider, size_t size = 100_KiB);
bool isValidMIMEType(const std::string &mimeType);
}

View File

@@ -1,78 +0,0 @@
#pragma once
#include <hex.hpp>
#include <cstring>
#include <future>
#include <optional>
#include <string>
#include <filesystem>
#include <atomic>
#include <nlohmann/json_fwd.hpp>
#include <curl/curl.h>
#include <curl/system.h>
#include <mbedtls/ssl.h>
#include <hex/helpers/fs.hpp>
namespace hex {
template<typename T>
struct Response {
i32 code;
T body;
};
template<>
struct Response<void> {
i32 code;
};
class Net {
public:
Net();
~Net();
constexpr static u32 DefaultTimeout = 2'000;
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
std::future<Response<nlohmann::json>> postJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
std::future<Response<std::string>> uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
std::future<Response<void>> downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
[[nodiscard]] std::string encode(const std::string &input);
[[nodiscard]] std::string decode(const std::string &input);
[[nodiscard]] float getProgress() const { return this->m_progress; }
void cancel() { this->m_shouldCancel = true; }
static void setProxy(const std::string &url);
static void setCACert(const std::string &content);
private:
void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
std::optional<i32> execute();
friend int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
friend CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData);
private:
CURL *m_ctx;
mbedtls_x509_crt m_caCert;
curl_slist *m_headers = nullptr;
std::mutex m_transmissionActive;
float m_progress = 0.0F;
bool m_shouldCancel = false;
static std::string s_proxyUrl;
static std::string s_caCert;
};
}

View File

@@ -0,0 +1,216 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/concepts.hpp>
#include <cmath>
#include <map>
#include <span>
#include <string>
#include <imgui_impl_opengl3_loader.h>
namespace hex::gl {
namespace {
template<typename T>
GLuint getType() {
if constexpr (std::is_same_v<T, float>)
return GL_FLOAT;
else if constexpr (std::is_same_v<T, u32>)
return GL_UNSIGNED_INT;
else
static_assert(hex::always_false<T>::value, "Unsupported type");
}
}
template<typename T, size_t Size>
class Vector {
public:
Vector() = default;
Vector(std::array<T, Size> data) : m_data(data) { }
T &operator[](size_t index) { return this->m_data[index]; }
const T &operator[](size_t index) const { return this->m_data[index]; }
T *data() { return this->m_data.data(); }
const T *data() const { return this->m_data.data(); }
[[nodiscard]] size_t size() const { return this->m_data.size(); }
auto operator+(const Vector<T, Size>& other) {
auto copy = *this;
for (size_t i = 0; i < Size; i++)
copy[i] += other[i];
return copy;
}
auto operator-(const Vector<T, Size>& other) {
auto copy = *this;
for (size_t i = 0; i < Size; i++)
copy[i] -= other[i];
return copy;
}
auto dot(const Vector<T, Size>& other) {
T result = 0;
for (size_t i = 0; i < Size; i++)
result += this->m_data[i] * other[i];
return result;
}
auto cross(const Vector<T, Size>& other) {
static_assert(Size == 3, "Cross product is only defined for 3D vectors");
return Vector<T, Size>({ this->m_data[1] * other[2] - this->m_data[2] * other[1], this->m_data[2] * other[0] - this->m_data[0] * other[2], this->m_data[0] * other[1] - this->m_data[1] * other[0] });
}
auto normalize() {
auto copy = *this;
auto length = std::sqrt(copy.dot(copy));
for (size_t i = 0; i < Size; i++)
copy[i] /= length;
return copy;
}
auto operator==(const Vector<T, Size>& other) {
for (size_t i = 0; i < Size; i++)
if (this->m_data[i] != other[i])
return false;
return true;
}
private:
std::array<T, Size> m_data;
};
class Shader {
public:
Shader() = default;
Shader(std::string_view vertexSource, std::string_view fragmentSource);
~Shader();
Shader(const Shader&) = delete;
Shader(Shader&& other) noexcept;
Shader& operator=(const Shader&) = delete;
Shader& operator=(Shader&& other) noexcept;
void bind() const;
void unbind() const;
void setUniform(std::string_view name, const float &value);
void setUniform(std::string_view name, const Vector<float, 3> &value);
private:
void compile(GLuint shader, std::string_view source);
GLint getUniformLocation(std::string_view name);
private:
GLuint m_program = 0;
std::map<std::string, GLint> m_uniforms;
};
enum class BufferType {
Vertex = GL_ARRAY_BUFFER,
Index = GL_ELEMENT_ARRAY_BUFFER
};
template<typename T>
class Buffer {
public:
Buffer() = default;
Buffer(BufferType type, std::span<T> data);
~Buffer();
Buffer(const Buffer&) = delete;
Buffer(Buffer&& other) noexcept;
Buffer& operator=(const Buffer&) = delete;
Buffer& operator=(Buffer&& other) noexcept;
void bind() const;
void unbind() const;
void draw() const;
size_t getSize() const;
private:
GLuint m_buffer = 0;
size_t m_size = 0;
GLuint m_type = 0;
};
extern template class Buffer<float>;
extern template class Buffer<u32>;
class VertexArray {
public:
VertexArray();
~VertexArray();
VertexArray(const VertexArray&) = delete;
VertexArray(VertexArray&& other) noexcept;
VertexArray& operator=(const VertexArray&) = delete;
VertexArray& operator=(VertexArray&& other) noexcept;
template<typename T>
void addBuffer(u32 index, const Buffer<T> &buffer) const {
glEnableVertexAttribArray(index);
buffer.bind();
glVertexAttribPointer(index, 3, getType<T>(), GL_FALSE, 3 * sizeof(T), nullptr);
buffer.unbind();
}
void bind() const;
void unbind() const;
private:
GLuint m_array;
};
class Texture {
public:
Texture(u32 width, u32 height);
~Texture();
Texture(const Texture&) = delete;
Texture(Texture&& other) noexcept;
Texture& operator=(const Texture&) = delete;
Texture& operator=(Texture&& other) noexcept;
void bind() const;
void unbind() const;
GLuint getTexture() const;
u32 getWidth() const;
u32 getHeight() const;
GLuint release();
private:
GLuint m_texture;
u32 m_width, m_height;
};
class FrameBuffer {
public:
FrameBuffer();
~FrameBuffer();
FrameBuffer(const FrameBuffer&) = delete;
FrameBuffer(FrameBuffer&& other) noexcept;
FrameBuffer& operator=(const FrameBuffer&) = delete;
FrameBuffer& operator=(FrameBuffer&& other) noexcept;
void bind() const;
void unbind() const;
void attachTexture(const Texture &texture) const;
private:
GLuint m_frameBuffer, m_renderBuffer;
};
}

View File

@@ -4,14 +4,23 @@
#include <map>
#include <vector>
#include <expected>
namespace hex {
using Patches = std::map<u64, u8>;
std::vector<u8> generateIPSPatch(const Patches &patches);
std::vector<u8> generateIPS32Patch(const Patches &patches);
enum class IPSError {
AddressOutOfRange,
PatchTooLarge,
InvalidPatchHeader,
InvalidPatchFormat,
MissingEOF
};
Patches loadIPSPatch(const std::vector<u8> &ipsPatch);
Patches loadIPS32Patch(const std::vector<u8> &ipsPatch);
std::expected<std::vector<u8>, IPSError> generateIPSPatch(const Patches &patches);
std::expected<std::vector<u8>, IPSError> generateIPS32Patch(const Patches &patches);
std::expected<Patches, IPSError> loadIPSPatch(const std::vector<u8> &ipsPatch);
std::expected<Patches, IPSError> loadIPS32Patch(const std::vector<u8> &ipsPatch);
}

View File

@@ -1,55 +0,0 @@
#pragma once
#include <hex.hpp>
#include <string>
#include <vector>
#if defined(OS_WINDOWS)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define SOCKET_NONE INVALID_SOCKET
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#define SOCKET_NONE -1
#endif
namespace hex {
class Socket {
public:
Socket() = default;
Socket(const Socket &) = delete;
Socket(Socket &&other) noexcept;
Socket(const std::string &address, u16 port);
~Socket();
void connect(const std::string &address, u16 port);
void disconnect();
[[nodiscard]] bool isConnected() const;
[[nodiscard]] std::string readString(size_t size = 0x1000) const;
[[nodiscard]] std::vector<u8> readBytes(size_t size = 0x1000) const;
void writeString(const std::string &string) const;
void writeBytes(const std::vector<u8> &bytes) const;
private:
bool m_connected = false;
#if defined(OS_WINDOWS)
SOCKET m_socket = SOCKET_NONE;
#else
int m_socket = SOCKET_NONE;
#endif
};
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <hex.hpp>
#include <string>
#include <vector>
namespace hex::stacktrace {
struct StackFrame {
std::string file;
std::string function;
u32 line;
};
void initialize();
std::vector<StackFrame> getStackTrace();
}

View File

@@ -26,11 +26,11 @@ namespace hex {
void close();
[[nodiscard]] std::vector<u8> read(const std::fs::path &path);
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path);
[[nodiscard]] std::string readString(const std::fs::path &path);
void write(const std::fs::path &path, const std::vector<u8> &data);
void write(const std::fs::path &path, const std::string &data);
void writeVector(const std::fs::path &path, const std::vector<u8> &data);
void writeString(const std::fs::path &path, const std::string &data);
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/");
[[nodiscard]] bool contains(const std::fs::path &path);
@@ -42,6 +42,7 @@ namespace hex {
private:
mtar_t m_ctx = { };
std::fs::path m_path;
bool m_valid = false;
};

View File

@@ -19,14 +19,24 @@
#include <variant>
#include <vector>
#define TOKEN_CONCAT_IMPL(x, y) x##y
#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y)
#define ANONYMOUS_VARIABLE(prefix) TOKEN_CONCAT(prefix, __COUNTER__)
struct ImVec2;
namespace hex {
template<typename T>
std::vector<T> sampleData(const std::vector<T> &data, size_t count) {
size_t stride = std::max(1.0, double(data.size()) / count);
std::vector<T> result;
result.reserve(count);
for (size_t i = 0; i < data.size(); i += stride) {
result.push_back(data[i]);
}
return result;
}
float operator""_scaled(long double value);
float operator""_scaled(unsigned long long value);
ImVec2 scaled(const ImVec2 &vector);
@@ -44,6 +54,7 @@ namespace hex {
std::string to_string(u128 value);
std::string to_string(i128 value);
std::optional<u8> parseBinaryString(const std::string &string);
std::string toByteString(u64 bytes);
std::string makePrintable(u8 c);
@@ -101,11 +112,6 @@ namespace hex {
return i;
}
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
template<size_t Size>
struct SizeTypeImpl { };
@@ -205,14 +211,6 @@ namespace hex {
std::string toEngineeringString(double value);
template<typename T>
std::vector<u8> toBytes(T value) {
std::vector<u8> bytes(sizeof(T));
std::memcpy(bytes.data(), &value, sizeof(T));
return bytes;
}
inline std::vector<u8> parseByteString(const std::string &string) {
auto byteString = std::string(string);
byteString.erase(std::remove(byteString.begin(), byteString.end(), ' '), byteString.end());
@@ -240,26 +238,6 @@ namespace hex {
return result;
}
template<typename T>
inline void trimLeft(std::basic_string<T> &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch) && ch >= 0x20;
}));
}
template<typename T>
inline void trimRight(std::basic_string<T> &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch) && ch >= 0x20;
}).base(), s.end());
}
template<typename T>
inline void trim(std::basic_string<T> &s) {
trimLeft(s);
trimRight(s);
}
float float16ToFloat32(u16 float16);
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
@@ -276,13 +254,6 @@ namespace hex {
return iter != a.end();
}
template<typename T> requires requires(T t) { t.u8string(); }
std::string toUTF8String(const T &value) {
auto result = value.u8string();
return { result.begin(), result.end() };
}
template<typename T, typename... VariantTypes>
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
const T *value = std::get_if<T>(&variant);
@@ -312,89 +283,6 @@ namespace hex {
return string.substr(0, maxLength - 3) + "...";
}
namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
#define ON_SCOPE_EXIT [[maybe_unused]] auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
template<class F>
class ScopeGuard {
private:
F m_func;
bool m_active;
public:
explicit constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
~ScopeGuard() {
if (this->m_active) { this->m_func(); }
}
void release() { this->m_active = false; }
ScopeGuard(ScopeGuard &&other) noexcept : m_func(std::move(other.m_func)), m_active(other.m_active) {
other.cancel();
}
ScopeGuard &operator=(ScopeGuard &&) = delete;
};
enum class ScopeGuardOnExit
{
};
template<typename F>
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F &&f) {
return ScopeGuard<F>(std::forward<F>(f));
}
}
namespace first_time_exec {
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
template<class F>
class FirstTimeExecute {
public:
explicit constexpr FirstTimeExecute(F func) { func(); }
FirstTimeExecute &operator=(FirstTimeExecute &&) = delete;
};
enum class FirstTimeExecutor
{
};
template<typename F>
constexpr FirstTimeExecute<F> operator+(FirstTimeExecutor, F &&f) {
return FirstTimeExecute<F>(std::forward<F>(f));
}
}
namespace final_cleanup {
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
template<class F>
class FinalCleanupExecute {
F m_func;
public:
explicit constexpr FinalCleanupExecute(F func) : m_func(func) { }
constexpr ~FinalCleanupExecute() { this->m_func(); }
FinalCleanupExecute &operator=(FinalCleanupExecute &&) = delete;
};
enum class FinalCleanupExecutor
{
};
template<typename F>
constexpr FinalCleanupExecute<F> operator+(FinalCleanupExecutor, F &&f) {
return FinalCleanupExecute<F>(std::forward<F>(f));
}
}
std::optional<std::fs::path> getInitialFilePath();
}

View File

@@ -2,9 +2,12 @@
#if defined(OS_MACOS)
#include <string>
extern "C" {
extern "C" void openWebpageMacos(const char *url);
extern "C" bool isMacosSystemDarkModeEnabled();
void openWebpageMacos(const char *url);
bool isMacosSystemDarkModeEnabled();
float getBackingScaleFactor();
}
#endif

View File

@@ -6,6 +6,10 @@
#include <hex.hpp>
/**
* This macro is used to define all the required entry points for a plugin.
* Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
*/
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \

View File

@@ -6,279 +6,24 @@
#include <hex/providers/provider.hpp>
#include <hex/helpers/literals.hpp>
#include <wolv/io/buffered_reader.hpp>
namespace hex::prv {
using namespace hex::literals;
class BufferedReader {
inline void providerReaderFunction(Provider *provider, void *buffer, u64 address, size_t size) {
provider->read(address, buffer, size);
}
class ProviderReader : public wolv::io::BufferedReader<prv::Provider, providerReaderFunction> {
public:
explicit BufferedReader(Provider *provider, size_t bufferSize = 16_MiB)
: m_provider(provider), m_bufferAddress(provider->getBaseAddress()), m_maxBufferSize(bufferSize),
m_startAddress(provider->getBaseAddress()), m_endAddress(provider->getBaseAddress() + provider->getActualSize() - 1),
m_buffer(bufferSize) {
using BufferedReader::BufferedReader;
ProviderReader(Provider *provider, size_t bufferSize = 0x100000) : BufferedReader(provider, provider->getActualSize(), bufferSize) {
this->setEndAddress(provider->getBaseAddress() + provider->getActualSize() - 1);
this->seek(provider->getBaseAddress());
}
void seek(u64 address) {
this->m_startAddress = address;
}
void setEndAddress(u64 address) {
if (address >= this->m_provider->getActualSize())
address = this->m_provider->getActualSize() - 1;
this->m_endAddress = address;
}
[[nodiscard]] std::vector<u8> read(u64 address, size_t size) {
if (size > this->m_buffer.size()) {
std::vector<u8> result;
result.resize(size);
this->m_provider->read(address, result.data(), result.size());
return result;
}
this->updateBuffer(address, size);
auto result = &this->m_buffer[address - this->m_bufferAddress];
return { result, result + std::min(size, this->m_buffer.size()) };
}
[[nodiscard]] std::vector<u8> readReverse(u64 address, size_t size) {
if (size > this->m_buffer.size()) {
std::vector<u8> result;
result.resize(size);
this->m_provider->read(address, result.data(), result.size());
return result;
}
this->updateBuffer(address - std::min<u64>(address, this->m_buffer.size()), size);
auto result = &this->m_buffer[address - this->m_bufferAddress];
return { result, result + std::min(size, this->m_buffer.size()) };
}
class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = u8;
using pointer = const value_type*;
using reference = const value_type&;
Iterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
Iterator& operator++() {
this->m_address++;
return *this;
}
Iterator operator++(int) {
auto copy = *this;
this->m_address++;
return copy;
}
Iterator& operator--() {
this->m_address--;
return *this;
}
Iterator operator--(int) {
auto copy = *this;
this->m_address--;
return copy;
}
Iterator& operator+=(i64 offset) {
this->m_address += offset;
return *this;
}
Iterator& operator-=(i64 offset) {
this->m_address -= offset;
return *this;
}
value_type operator*() const {
return (*this)[0];
}
[[nodiscard]] u64 getAddress() const {
return this->m_address;
}
void setAddress(u64 address) {
this->m_address = address;
}
difference_type operator-(const Iterator &other) const {
return this->m_address - other.m_address;
}
Iterator operator+(i64 offset) const {
return { this->m_reader, this->m_address + offset };
}
value_type operator[](i64 offset) const {
auto result = this->m_reader->read(this->m_address + offset, 1);
if (result.empty())
return 0x00;
return result[0];
}
friend bool operator== (const Iterator& left, const Iterator& right) { return left.m_address == right.m_address; };
friend bool operator!= (const Iterator& left, const Iterator& right) { return left.m_address != right.m_address; };
friend bool operator> (const Iterator& left, const Iterator& right) { return left.m_address > right.m_address; };
friend bool operator< (const Iterator& left, const Iterator& right) { return left.m_address < right.m_address; };
friend bool operator>= (const Iterator& left, const Iterator& right) { return left.m_address >= right.m_address; };
friend bool operator<= (const Iterator& left, const Iterator& right) { return left.m_address <= right.m_address; };
private:
BufferedReader *m_reader;
u64 m_address;
};
class ReverseIterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = u8;
using pointer = const value_type*;
using reference = const value_type&;
ReverseIterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
ReverseIterator& operator++() {
this->m_address--;
return *this;
}
ReverseIterator operator++(int) {
auto copy = *this;
this->m_address--;
return copy;
}
ReverseIterator& operator--() {
this->m_address++;
return *this;
}
ReverseIterator operator--(int) {
auto copy = *this;
this->m_address++;
return copy;
}
ReverseIterator& operator+=(i64 offset) {
this->m_address -= offset;
return *this;
}
ReverseIterator& operator-=(i64 offset) {
this->m_address += offset;
return *this;
}
value_type operator*() const {
return (*this)[0];
}
[[nodiscard]] u64 getAddress() const {
return this->m_address;
}
void setAddress(u64 address) {
this->m_address = address;
}
difference_type operator-(const ReverseIterator &other) const {
return other.m_address - this->m_address;
}
ReverseIterator operator+(i64 offset) const {
return { this->m_reader, this->m_address - offset };
}
value_type operator[](i64 offset) const {
auto result = this->m_reader->readReverse(this->m_address - offset, 1);
if (result.empty())
return 0x00;
return result[0];
}
friend bool operator== (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address == right.m_address; };
friend bool operator!= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address != right.m_address; };
friend bool operator> (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address > right.m_address; };
friend bool operator< (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address < right.m_address; };
friend bool operator>= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address >= right.m_address; };
friend bool operator<= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address <= right.m_address; };
private:
BufferedReader *m_reader;
u64 m_address = 0x00;
};
Iterator begin() {
return { this, this->m_startAddress };
}
Iterator end() {
return { this, this->m_endAddress + 1 };
}
ReverseIterator rbegin() {
return { this, this->m_startAddress };
}
ReverseIterator rend() {
return { this, 0 };
}
private:
void updateBuffer(u64 address, size_t size) {
if (!this->m_bufferValid || address < this->m_bufferAddress || address + size > (this->m_bufferAddress + this->m_buffer.size())) {
const auto remainingBytes = (this->m_endAddress - address) + 1;
if (remainingBytes < this->m_maxBufferSize)
this->m_buffer.resize(remainingBytes);
else
this->m_buffer.resize(this->m_maxBufferSize);
this->m_provider->read(address, this->m_buffer.data(), this->m_buffer.size());
this->m_bufferAddress = address;
this->m_bufferValid = true;
}
}
private:
Provider *m_provider;
u64 m_bufferAddress = 0x00;
size_t m_maxBufferSize;
bool m_bufferValid = false;
u64 m_startAddress = 0x00, m_endAddress;
std::vector<u8> m_buffer;
};
}

View File

@@ -16,6 +16,9 @@
namespace hex::prv {
/**
* @brief Represent the data source for a tab in the UI
*/
class Provider {
public:
constexpr static size_t PageSize = 0x1000'0000;
@@ -29,7 +32,21 @@ namespace hex::prv {
[[nodiscard]] virtual bool isResizable() const = 0;
[[nodiscard]] virtual bool isSavable() const = 0;
/**
* @brief Read data from this provider, applying overlays and patches
* @param offset offset to start reading the data
* @param buffer buffer to write read data
* @param size number of bytes to read
* @param overlays apply overlays and patches is true. Same as readRaw() if false
*/
virtual void read(u64 offset, void *buffer, size_t size, bool overlays = true);
/**
* @brief Write data to the patches of this provider. Will not directly modify provider.
* @param offset offset to start writing the data
* @param buffer buffer to take data to write from
* @param size number of bytes to write
*/
virtual void write(u64 offset, const void *buffer, size_t size);
virtual void resize(size_t newSize);
@@ -39,7 +56,19 @@ namespace hex::prv {
virtual void save();
virtual void saveAs(const std::fs::path &path);
/**
* @brief Read data from this provider, without applying overlays and patches
* @param offset offset to start reading the data
* @param buffer buffer to write read data
* @param size number of bytes to read
*/
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
/**
* @brief Write data directly to this provider
* @param offset offset to start writing the data
* @param buffer buffer to take data to write from
* @param size number of bytes to write
*/
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
[[nodiscard]] virtual size_t getActualSize() const = 0;
@@ -64,8 +93,16 @@ namespace hex::prv {
[[nodiscard]] virtual std::optional<u32> getPageOfAddress(u64 address) const;
[[nodiscard]] virtual std::string getName() const = 0;
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() const = 0;
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataDescription() const = 0;
[[nodiscard]] virtual std::variant<std::string, i128> queryInformation(const std::string &category, const std::string &argument);
/**
* @brief Opens this provider
* the return value of this function allows to ensure the provider is available,
* so calling Provider::isAvailable() just after a call to open() that returned true is dedundant.
* @note This is not related to the EventProviderOpened event
* @return true if the provider was opened sucessfully, else false
*/
[[nodiscard]] virtual bool open() = 0;
virtual void close() = 0;
@@ -83,7 +120,7 @@ namespace hex::prv {
[[nodiscard]] virtual bool hasLoadInterface() const;
[[nodiscard]] virtual bool hasInterface() const;
virtual void drawLoadInterface();
virtual bool drawLoadInterface();
virtual void drawInterface();
[[nodiscard]] u32 getID() const;
@@ -102,19 +139,36 @@ namespace hex::prv {
void skipLoadInterface() { this->m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
void setErrorMessage(const std::string &errorMessage) { this->m_errorMessage = errorMessage; }
[[nodiscard]] const std::string& getErrorMessage() const { return this->m_errorMessage; }
protected:
u32 m_currPage = 0;
u64 m_baseAddress = 0;
u32 m_patchTreeOffset = 0;
std::list<std::map<u64, u8>> m_patches;
decltype(m_patches)::iterator m_currPatches;
std::list<Overlay *> m_overlays;
u32 m_id;
/**
* @brief true if there is any data that needs to be saved
*/
bool m_dirty = false;
/**
* @brief Control whetever to skip provider initialization
* initialization may be asking the user for information related to the provider,
* e.g. a process ID for the process memory provider
* this is used mainly when restoring a provider with already known initialization information
* for example when loading a project or loading a provider from the "recent" lsit
*
*/
bool m_skipLoadInterface = false;
std::string m_errorMessage;
private:
static u32 s_idCounter;
};

View File

@@ -0,0 +1,78 @@
#pragma once
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
#include <concepts>
#include <map>
#include <utility>
namespace hex {
template<typename T>
class PerProvider {
public:
PerProvider() { this->onCreate(); }
PerProvider(const PerProvider&) = delete;
PerProvider(PerProvider&&) = delete;
PerProvider& operator=(const PerProvider&) = delete;
PerProvider& operator=(PerProvider&&) = delete;
PerProvider(T data) : m_data({ { ImHexApi::Provider::get(), std::move(data) } }) { this->onCreate(); }
~PerProvider() = default;
T* operator->() {
return &this->get();
}
const T* operator->() const {
return &this->get();
}
T& get(prv::Provider *provider = ImHexApi::Provider::get()) {
return this->m_data[provider];
}
const T& get(prv::Provider *provider = ImHexApi::Provider::get()) const {
return this->m_data[provider];
}
T& operator*() {
return this->get();
}
const T& operator*() const {
return this->get();
}
PerProvider& operator=(T data) {
this->m_data = std::move(data);
return *this;
}
operator T&() {
return this->get();
}
private:
void onCreate() {
(void)EventManager::subscribe<EventProviderOpened>([this](prv::Provider *provider) {
this->m_data.emplace(provider, T());
});
(void)EventManager::subscribe<EventProviderDeleted>([this](prv::Provider *provider){
this->m_data.erase(provider);
});
EventManager::subscribe<EventImHexClosing>([this] {
this->m_data.clear();
});
}
private:
std::map<prv::Provider *, T> m_data;
};
}

View File

@@ -26,6 +26,10 @@ enum ImGuiCustomCol {
ImGuiCustomCol_Highlight,
ImGuiCustomCol_IEEEToolSign,
ImGuiCustomCol_IEEEToolExp,
ImGuiCustomCol_IEEEToolMantissa,
ImGuiCustomCol_COUNT
};
@@ -36,6 +40,7 @@ namespace ImGui {
Texture() = default;
Texture(const ImU8 *buffer, int size, int width = 0, int height = 0);
explicit Texture(const char *path);
Texture(unsigned int texture, int width, int height);
Texture(const Texture&) = delete;
Texture(Texture&& other) noexcept;
@@ -48,7 +53,7 @@ namespace ImGui {
return this->m_textureId != nullptr;
}
[[nodiscard]] constexpr operator ImTextureID() {
[[nodiscard]] constexpr operator ImTextureID() const noexcept {
return this->m_textureId;
}
@@ -74,6 +79,8 @@ namespace ImGui {
bool BulletHyperlink(const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
void HelpHover(const char *text);
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
void TextSpinner(const char *label);
@@ -87,7 +94,7 @@ namespace ImGui {
bool ToolBarButton(const char *symbol, ImVec4 color);
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, const char *format, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
@@ -150,4 +157,7 @@ namespace ImGui {
bool BitCheckbox(const char* label, bool* v);
bool DimmedButton(const char* label);
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
}

View File

@@ -0,0 +1,92 @@
#pragma once
#include <hex.hpp>
#include <memory>
#include <string>
#include <vector>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/helpers/utils.hpp>
#include <hex/api/task.hpp>
namespace hex {
namespace impl {
class PopupBase {
public:
explicit PopupBase(std::string unlocalizedName, bool closeButton, bool modal)
: m_unlocalizedName(std::move(unlocalizedName)), m_closeButton(closeButton), m_modal(modal) { }
virtual ~PopupBase() = default;
virtual void drawContent() = 0;
[[nodiscard]] virtual ImGuiWindowFlags getFlags() const { return ImGuiWindowFlags_None; }
[[nodiscard]] virtual ImVec2 getMinSize() const {
return { 0, 0 };
}
[[nodiscard]] virtual ImVec2 getMaxSize() const {
return { 0, 0 };
}
[[nodiscard]] static std::vector<std::unique_ptr<PopupBase>> &getOpenPopups() {
return s_openPopups;
}
[[nodiscard]] const std::string &getUnlocalizedName() const {
return this->m_unlocalizedName;
}
[[nodiscard]] bool hasCloseButton() const {
return this->m_closeButton;
}
[[nodiscard]] bool isModal() const {
return this->m_modal;
}
void close() {
this->m_close = true;
}
[[nodiscard]] bool shouldClose() const {
return this->m_close;
}
protected:
static std::vector<std::unique_ptr<PopupBase>> s_openPopups;
private:
std::string m_unlocalizedName;
bool m_closeButton, m_modal;
std::atomic<bool> m_close = false;
};
}
template<typename T>
class Popup : public impl::PopupBase {
protected:
explicit Popup(std::string unlocalizedName, bool closeButton = true, bool modal = true) : PopupBase(std::move(unlocalizedName), closeButton, modal) { }
public:
template<typename ...Args>
static void open(Args && ... args) {
static std::mutex mutex;
std::lock_guard lock(mutex);
auto popup = std::make_unique<T>(std::forward<Args>(args)...);
s_openPopups.emplace_back(std::move(popup));
}
};
}

View File

@@ -13,6 +13,7 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
#include <hex/providers/provider_data.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/api/localization.hpp>
@@ -34,13 +35,6 @@ namespace hex {
[[nodiscard]] virtual bool isAvailable() const;
[[nodiscard]] virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
static void showInfoPopup(const std::string &message);
static void showErrorPopup(const std::string &message);
static void showFatalPopup(const std::string &message);
static void showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback);
static void showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback);
[[nodiscard]] virtual bool hasViewMenuItemEntry() const;
[[nodiscard]] virtual ImVec2 getMinSize() const;
[[nodiscard]] virtual ImVec2 getMaxSize() const;

View File

@@ -0,0 +1,62 @@
#pragma once
#include <hex.hpp>
#include <vector>
#include <string>
#include <atomic>
#include <hex/api/task.hpp>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::ui {
template<typename T>
class SearchableWidget {
public:
SearchableWidget(const std::function<bool(const std::string&, const T&)> &comparator) : m_comparator(comparator) {
}
const std::vector<const T*> &draw(const auto &entries) {
if (this->m_filteredEntries.empty() && this->m_searchBuffer.empty()) {
for (auto &entry : entries)
this->m_filteredEntries.push_back(&entry);
}
if (ImGui::InputText("##search", this->m_searchBuffer)) {
this->m_pendingUpdate = true;
}
if (this->m_pendingUpdate && !this->m_updateTask.isRunning()) {
this->m_pendingUpdate = false;
this->m_filteredEntries.clear();
this->m_filteredEntries.reserve(entries.size());
this->m_updateTask = TaskManager::createBackgroundTask("Searching", [this, &entries, searchBuffer = this->m_searchBuffer](Task&) {
for (auto &entry : entries) {
if (searchBuffer.empty() || this->m_comparator(searchBuffer, entry))
this->m_filteredEntries.push_back(&entry);
}
});
}
return this->m_filteredEntries;
}
void reset() {
this->m_filteredEntries.clear();
}
private:
std::atomic<bool> m_pendingUpdate = false;
TaskHolder m_updateTask;
std::string m_searchBuffer;
std::vector<const T*> m_filteredEntries;
std::function<bool(const std::string&, const T&)> m_comparator;
};
}

View File

@@ -1,17 +1,17 @@
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/ui/view.hpp>
#include <hex/data_processor/node.hpp>
#include <filesystem>
#include <fstream>
#include <thread>
#include <nlohmann/json.hpp>
#include <hex/data_processor/node.hpp>
#include <wolv/io/file.hpp>
namespace hex {
@@ -19,58 +19,89 @@ namespace hex {
constexpr auto SettingsFile = "settings.json";
void load() {
bool loaded = false;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
fs::File file(dir / SettingsFile, fs::File::Mode::Read);
namespace impl {
if (file.isValid()) {
getSettingsData() = nlohmann::json::parse(file.readString());
loaded = true;
break;
std::map<Category, std::vector<Entry>> &getEntries() {
static std::map<Category, std::vector<Entry>> entries;
return entries;
}
std::map<std::string, std::string> &getCategoryDescriptions() {
static std::map<std::string, std::string> descriptions;
return descriptions;
}
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
auto &settings = getSettingsData();
if (!settings.contains(unlocalizedCategory)) return {};
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
return settings[unlocalizedCategory][unlocalizedName];
}
nlohmann::json &getSettingsData() {
static nlohmann::json settings;
return settings;
}
void load() {
bool loaded = false;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
if (file.isValid()) {
getSettingsData() = nlohmann::json::parse(file.readString());
loaded = true;
break;
}
}
if (!loaded)
store();
}
void store() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
if (file.isValid()) {
file.writeString(getSettingsData().dump(4));
break;
}
}
}
if (!loaded)
store();
}
void store() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
fs::File file(dir / SettingsFile, fs::File::Mode::Create);
if (file.isValid()) {
file.write(getSettingsData().dump(4));
break;
void clear() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::fs::remove(dir / SettingsFile);
}
}
}
void clear() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
hex::fs::remove(dir / SettingsFile);
}
}
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
auto &entries = getEntries();
const size_t curSlot = entries.size();
auto found = entries.find(Category { unlocalizedCategory });
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
auto &entries = getEntries();
const size_t curSlot = entries.size();
auto found = entries.find(Category { unlocalizedCategory });
if (found == entries.end()) {
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
return iter;
}
if (found == entries.end()) {
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
return iter;
return found;
}
return found;
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart) {
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart) {
log::debug("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -78,12 +109,12 @@ namespace hex {
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart) {
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart) {
log::debug("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -91,12 +122,12 @@ namespace hex {
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart) {
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart) {
log::debug("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -105,11 +136,11 @@ namespace hex {
}
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
impl::getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
}
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -118,7 +149,7 @@ namespace hex {
}
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -127,7 +158,7 @@ namespace hex {
}
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -137,7 +168,7 @@ namespace hex {
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
return defaultValue;
@@ -151,7 +182,7 @@ namespace hex {
}
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
return defaultValue;
@@ -165,7 +196,7 @@ namespace hex {
}
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
return defaultValue;
@@ -181,49 +212,37 @@ namespace hex {
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
}
std::map<Category, std::vector<Entry>> &getEntries() {
static std::map<Category, std::vector<Entry>> entries;
return entries;
}
std::map<std::string, std::string> &getCategoryDescriptions() {
static std::map<std::string, std::string> descriptions;
return descriptions;
}
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
auto &settings = getSettingsData();
if (!settings.contains(unlocalizedCategory)) return {};
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
return settings[unlocalizedCategory][unlocalizedName];
}
nlohmann::json &getSettingsData() {
static nlohmann::json settings;
return settings;
}
}
namespace ContentRegistry::CommandPaletteCommands {
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const DisplayCallback &displayCallback, const ExecuteCallback &executeCallback) {
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
log::debug("Registered new command palette command: {}", command);
getEntries().push_back(ContentRegistry::CommandPaletteCommands::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
impl::getEntries().push_back(ContentRegistry::CommandPaletteCommands::impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
}
std::vector<Entry> &getEntries() {
static std::vector<Entry> commands;
void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) {
log::debug("Registered new command palette command handler: {}", command);
impl::getHandlers().push_back(ContentRegistry::CommandPaletteCommands::impl::Handler { type, command, queryCallback, displayCallback });
}
namespace impl {
std::vector<Entry> &getEntries() {
static std::vector<Entry> commands;
return commands;
}
std::vector<Handler> &getHandlers() {
static std::vector<Handler> commands;
return commands;
}
return commands;
}
}
@@ -241,6 +260,18 @@ namespace hex {
return functionName;
}
pl::PatternLanguage& getRuntime() {
static PerProvider<pl::PatternLanguage> runtime;
return *runtime;
}
std::mutex& getRuntimeLock() {
static std::mutex runtimeLock;
return runtimeLock;
}
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
runtime.reset();
@@ -258,14 +289,14 @@ namespace hex {
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
for (const auto &func : getFunctions()) {
for (const auto &func : impl::getFunctions()) {
if (func.dangerous)
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
else
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
}
for (const auto &[name, callback] : getPragmas()) {
for (const auto &[name, callback] : impl::getPragmas()) {
runtime.addPragma(name, callback);
}
@@ -276,13 +307,13 @@ namespace hex {
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
log::debug("Registered new pattern language pragma: {}", name);
getPragmas()[name] = handler;
impl::getPragmas()[name] = handler;
}
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::debug("Registered new pattern language function: {}", getFunctionName(ns, name));
getFunctions().push_back({
impl::getFunctions().push_back({
ns, name,
parameterCount, func,
false
@@ -292,47 +323,69 @@ namespace hex {
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
getFunctions().push_back({
impl::getFunctions().push_back({
ns, name,
parameterCount, func,
true
});
}
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
static std::map<std::string, pl::api::PragmaHandler> pragmas;
return pragmas;
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
log::debug("Registered new pattern visualizer function: {}", name);
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
}
std::vector<impl::FunctionDefinition> &getFunctions() {
static std::vector<impl::FunctionDefinition> functions;
return functions;
namespace impl {
std::map<std::string, impl::Visualizer> &getVisualizers() {
static std::map<std::string, impl::Visualizer> visualizers;
return visualizers;
}
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
static std::map<std::string, pl::api::PragmaHandler> pragmas;
return pragmas;
}
std::vector<impl::FunctionDefinition> &getFunctions() {
static std::vector<impl::FunctionDefinition> functions;
return functions;
}
}
}
namespace ContentRegistry::Views {
void impl::add(View *view) {
namespace impl {
std::map<std::string, std::unique_ptr<View>> &getEntries() {
static std::map<std::string, std::unique_ptr<View>> views;
return views;
}
}
void impl::add(std::unique_ptr<View> &&view) {
log::debug("Registered new view: {}", view->getUnlocalizedName());
getEntries().insert({ view->getUnlocalizedName(), view });
impl::getEntries().insert({ view->getUnlocalizedName(), std::move(view) });
}
std::map<std::string, View *> &getEntries() {
static std::map<std::string, View *> views;
return views;
}
View *getViewByName(const std::string &unlocalizedName) {
auto &views = getEntries();
View* getViewByName(const std::string &unlocalizedName) {
auto &views = impl::getEntries();
if (views.contains(unlocalizedName))
return views[unlocalizedName];
return views[unlocalizedName].get();
else
return nullptr;
}
@@ -344,13 +397,17 @@ namespace hex {
void add(const std::string &unlocalizedName, const impl::Callback &function) {
log::debug("Registered new tool: {}", unlocalizedName);
getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
impl::getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<Entry> &getEntries() {
static std::vector<Entry> tools;
return tools;
}
return entries;
}
}
@@ -360,21 +417,26 @@ namespace hex {
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
impl::getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
impl::getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
return entries;
}
return entries;
}
}
namespace ContentRegistry::DataProcessorNode {
@@ -386,13 +448,17 @@ namespace hex {
}
void addSeparator() {
getEntries().push_back({ "", "", [] { return nullptr; } });
impl::getEntries().push_back({ "", "", [] { return nullptr; } });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> nodes;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> nodes;
return nodes;
}
return nodes;
}
}
@@ -400,6 +466,9 @@ namespace hex {
namespace ContentRegistry::Language {
void addLocalization(const nlohmann::json &data) {
if (!data.is_object())
return;
if (!data.contains("code") || !data.contains("country") || !data.contains("language") || !data.contains("translations")) {
log::error("Localization data is missing required fields!");
return;
@@ -422,7 +491,7 @@ namespace hex {
LangEntry::setFallbackLanguage(code.get<std::string>());
}
getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
impl::getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
std::map<std::string, std::string> translationDefinitions;
for (auto &[key, value] : translations.items()) {
@@ -434,20 +503,25 @@ namespace hex {
translationDefinitions[key] = value.get<std::string>();
}
getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
impl::getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
}
std::map<std::string, std::string> &getLanguages() {
static std::map<std::string, std::string> languages;
namespace impl {
std::map<std::string, std::string> &getLanguages() {
static std::map<std::string, std::string> languages;
return languages;
}
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
return definitions;
}
return languages;
}
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
return definitions;
}
}
@@ -456,85 +530,97 @@ namespace hex {
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) {
log::debug("Registered new main menu item: {}", unlocalizedName);
getMainMenuItems().insert({ priority, { unlocalizedName } });
impl::getMainMenuItems().insert({ priority, { unlocalizedName } });
}
void addMenuItem(const std::string &unlocalizedMainMenuName, u32 priority, const impl::DrawCallback &function) {
log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuName, priority);
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
log::debug("Added new menu item to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
getMenuItems().insert({
priority, {unlocalizedMainMenuName, function}
impl::getMenuItems().insert({
priority, { unlocalizedMainMenuNames, shortcut, function, enabledCallback }
});
if (shortcut.isLocal() && view != nullptr)
ShortcutManager::addShortcut(view, shortcut, function);
else
ShortcutManager::addGlobalShortcut(shortcut, function);
}
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
log::debug("Added new menu item sub menu to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
impl::getMenuItems().insert({
priority, { unlocalizedMainMenuNames, {}, function, enabledCallback }
});
}
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority) {
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
impl::getMenuItems().insert({
priority, { unlocalizedMainMenuNames, {}, []{}, []{ return true; } }
});
}
void addWelcomeScreenEntry(const impl::DrawCallback &function) {
getWelcomeScreenEntries().push_back(function);
impl::getWelcomeScreenEntries().push_back(function);
}
void addFooterItem(const impl::DrawCallback &function) {
getFooterItems().push_back(function);
impl::getFooterItems().push_back(function);
}
void addToolbarItem(const impl::DrawCallback &function) {
getToolbarItems().push_back(function);
impl::getToolbarItems().push_back(function);
}
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function) {
getSidebarItems().push_back({ icon, function });
impl::getSidebarItems().push_back({ icon, function });
}
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) {
getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
impl::getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
}
void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function) {
log::debug("Added new layout: {}", unlocalizedName);
namespace impl {
getLayouts().push_back({ unlocalizedName, function });
}
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
static std::multimap<u32, impl::MainMenuItem> items;
return items;
}
std::multimap<u32, impl::MenuItem> &getMenuItems() {
static std::multimap<u32, impl::MenuItem> items;
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
static std::multimap<u32, impl::MainMenuItem> items;
return items;
}
return items;
}
std::multimap<u32, impl::MenuItem> &getMenuItems() {
static std::multimap<u32, impl::MenuItem> items;
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
static std::vector<impl::DrawCallback> entries;
return items;
}
return entries;
}
std::vector<impl::DrawCallback> &getFooterItems() {
static std::vector<impl::DrawCallback> items;
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
static std::vector<impl::DrawCallback> entries;
return items;
}
std::vector<impl::DrawCallback> &getToolbarItems() {
static std::vector<impl::DrawCallback> items;
return entries;
}
std::vector<impl::DrawCallback> &getFooterItems() {
static std::vector<impl::DrawCallback> items;
return items;
}
std::vector<impl::SidebarItem> &getSidebarItems() {
static std::vector<impl::SidebarItem> items;
return items;
}
std::vector<impl::DrawCallback> &getToolbarItems() {
static std::vector<impl::DrawCallback> items;
return items;
}
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
static std::vector<impl::TitleBarButton> buttons;
return items;
}
std::vector<impl::SidebarItem> &getSidebarItems() {
static std::vector<impl::SidebarItem> items;
return buttons;
}
return items;
}
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
static std::vector<impl::TitleBarButton> buttons;
return buttons;
}
std::vector<impl::Layout> &getLayouts() {
static std::vector<impl::Layout> layouts;
return layouts;
}
}
@@ -547,12 +633,18 @@ namespace hex {
getEntries().push_back(unlocalizedName);
}
std::vector<std::string> &getEntries() {
static std::vector<std::string> providerNames;
return providerNames;
namespace impl {
std::vector<std::string> &getEntries() {
static std::vector<std::string> providerNames;
return providerNames;
}
}
}
namespace ContentRegistry::DataFormatter {
@@ -560,13 +652,17 @@ namespace hex {
void add(const std::string &unlocalizedName, const impl::Callback &callback) {
log::debug("Registered new data formatter: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, callback });
impl::getEntries().push_back({ unlocalizedName, callback });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
return entries;
}
return entries;
}
}
@@ -577,13 +673,17 @@ namespace hex {
for (const auto &extension : extensions)
log::debug("Registered new data handler for extensions: {}", extension);
getEntries().push_back({ extensions, callback });
impl::getEntries().push_back({ extensions, callback });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
return entries;
}
return entries;
}
}
@@ -592,7 +692,7 @@ namespace hex {
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
bool DataVisualizer::drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
struct UserData {
u8 *data;
i32 maxChars;
@@ -621,29 +721,127 @@ namespace hex {
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
}
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
getVisualizers().insert({ unlocalizedName, visualizer });
bool DataVisualizer::drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const {
struct UserData {
std::string *data;
i32 maxChars;
bool editingDone;
};
UserData userData = {
.data = &data,
.maxChars = this->getMaxCharsPerCell(),
.editingDone = false
};
ImGui::PushID(reinterpret_cast<void*>(address));
ImGui::InputText("##editing_input", data.data(), data.size() + 1, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
userData.data->resize(data->BufSize);
if (data->BufTextLen >= userData.maxChars)
userData.editingDone = true;
return 0;
}, &userData);
ImGui::PopID();
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
}
namespace impl {
void addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
getVisualizers().insert({ unlocalizedName, visualizer });
}
std::map<std::string, DataVisualizer*> &getVisualizers() {
static std::map<std::string, DataVisualizer*> visualizers;
return visualizers;
}
}
std::map<std::string, DataVisualizer*> &impl::getVisualizers() {
static std::map<std::string, DataVisualizer*> visualizers;
return visualizers;
}
}
namespace ContentRegistry::Hashes {
std::vector<Hash *> &impl::getHashes() {
static std::vector<Hash *> hashes;
namespace impl {
std::vector<Hash *> &getHashes() {
static std::vector<Hash *> hashes;
return hashes;
}
void add(Hash *hash) {
getHashes().push_back(hash);
}
return hashes;
}
void impl::add(Hash *hash) {
getHashes().push_back(hash);
}
namespace ContentRegistry::BackgroundServices {
namespace impl {
std::vector<Service> &getServices() {
static std::vector<Service> services;
return services;
}
void stopServices() {
for (auto &service : getServices()) {
service.thread.request_stop();
}
for (auto &service : getServices()) {
service.thread.detach();
}
}
}
void registerService(const std::string &unlocalizedName, const impl::Callback &callback) {
log::debug("Registered new background service: {}", unlocalizedName);
impl::getServices().push_back(impl::Service {
unlocalizedName,
std::jthread([callback](const std::stop_token &stopToken){
while (!stopToken.stop_requested()) {
callback();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
})
});
}
}
namespace ContentRegistry::CommunicationInterface {
namespace impl {
std::map<std::string, NetworkCallback> &getNetworkEndpoints() {
static std::map<std::string, NetworkCallback> endpoints;
return endpoints;
}
}
void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback) {
log::debug("Registered new network endpoint: {}", endpoint);
impl::getNetworkEndpoints().insert({ endpoint, callback });
}
}

View File

@@ -2,6 +2,7 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/event.hpp>
#include <hex/api/task.hpp>
#include <hex/providers/provider.hpp>
#include <utility>
@@ -19,19 +20,6 @@
namespace hex {
namespace ImHexApi::Common {
void closeImHex(bool noQuestions) {
EventManager::post<RequestCloseImHex>(noQuestions);
}
void restartImHex() {
EventManager::post<RequestRestartImHex>();
EventManager::post<RequestCloseImHex>(false);
}
}
namespace ImHexApi::HexEditor {
@@ -190,6 +178,10 @@ namespace hex {
return impl::s_currentSelection;
}
void clearSelection() {
impl::s_currentSelection.reset();
}
void setSelection(const Region &region, prv::Provider *provider) {
setSelection(ProviderRegion { region, provider == nullptr ? Provider::get() : provider });
}
@@ -310,8 +302,6 @@ namespace hex {
if (it == s_providers.end())
return;
EventManager::post<EventProviderDeleted>(provider);
if (!s_providers.empty() && it - s_providers.begin() == s_currentProvider)
setCurrentProvider(0);
@@ -323,6 +313,7 @@ namespace hex {
EventManager::post<EventProviderClosed>(provider);
TaskManager::runWhenTasksFinished([provider] {
EventManager::post<EventProviderDeleted>(provider);
delete provider;
});
}
@@ -408,6 +399,18 @@ namespace hex {
}
void closeImHex(bool noQuestions) {
EventManager::post<RequestCloseImHex>(noQuestions);
}
void restartImHex() {
EventManager::post<RequestRestartImHex>();
EventManager::post<RequestCloseImHex>(false);
}
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress) {
EventManager::post<EventSetTaskBarIconState>(u32(state), u32(type), progress);
}
const ProgramArguments &getProgramArguments() {
return impl::s_programArguments;
@@ -429,7 +432,7 @@ namespace hex {
}
static float s_targetFPS = 60.0F;
static float s_targetFPS = 14.0F;
float getTargetFPS() {
return s_targetFPS;

View File

@@ -15,7 +15,7 @@ namespace hex {
view->m_shortcuts.insert({ shortcut, callback });
}
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
Shortcut pressedShortcut;
if (ctrl)
@@ -26,21 +26,23 @@ namespace hex {
pressedShortcut += SHIFT;
if (super)
pressedShortcut += SUPER;
if (focused)
pressedShortcut += CurrentView;
pressedShortcut += static_cast<Keys>(keyCode);
return pressedShortcut;
}
void ShortcutManager::process(View *currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, keyCode);
void ShortcutManager::process(const std::unique_ptr<View> &currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, focused, keyCode);
if (focused && currentView->m_shortcuts.contains(pressedShortcut))
if (currentView->m_shortcuts.contains(pressedShortcut))
currentView->m_shortcuts[pressedShortcut]();
}
void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, keyCode);
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode);
if (ShortcutManager::s_globalShortcuts.contains(pressedShortcut))
ShortcutManager::s_globalShortcuts[pressedShortcut]();

View File

@@ -0,0 +1,83 @@
#include <hex/api/layout_manager.hpp>
#include <hex/helpers/fs.hpp>
#include <wolv/utils/string.hpp>
#include <imgui.h>
#include <fmt/format.h>
namespace hex {
std::optional<std::fs::path> LayoutManager::s_layoutPathToLoad;
std::optional<std::string> LayoutManager::s_layoutStringToLoad;
std::vector<LayoutManager::Layout> LayoutManager::s_layouts;
void LayoutManager::load(const std::fs::path &path) {
s_layoutPathToLoad = path;
}
void LayoutManager::loadString(const std::string &content) {
s_layoutStringToLoad = content;
}
void LayoutManager::save(const std::string &name) {
auto fileName = name;
fileName = wolv::util::replaceStrings(fileName, " ", "_");
std::transform(fileName.begin(), fileName.end(), fileName.begin(), tolower);
fileName += ".hexlyt";
const auto path = hex::fs::getDefaultPaths(fs::ImHexPath::Layouts).front() / fileName;
ImGui::SaveIniSettingsToDisk(wolv::util::toUTF8String(path).c_str());
LayoutManager::reload();
}
std::vector<LayoutManager::Layout> LayoutManager::getLayouts() {
return s_layouts;
}
void LayoutManager::process() {
if (s_layoutPathToLoad.has_value()) {
ImGui::LoadIniSettingsFromDisk(wolv::util::toUTF8String(*s_layoutPathToLoad).c_str());
s_layoutPathToLoad = std::nullopt;
}
if (s_layoutStringToLoad.has_value()) {
ImGui::LoadIniSettingsFromMemory(s_layoutStringToLoad->c_str());
s_layoutStringToLoad = std::nullopt;
}
}
void LayoutManager::reload() {
s_layouts.clear();
for (const auto &directory : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
for (const auto &entry : std::fs::directory_iterator(directory)) {
const auto &path = entry.path();
if (path.extension() != ".hexlyt")
continue;
auto name = path.stem().string();
name = wolv::util::replaceStrings(name, "_", " ");
for (size_t i = 0; i < name.size(); i++) {
if (i == 0 || name[i - 1] == '_')
name[i] = char(std::toupper(name[i]));
}
s_layouts.push_back({
name,
path
});
}
}
}
void LayoutManager::reset() {
s_layoutPathToLoad.reset();
s_layoutStringToLoad.reset();
s_layouts.clear();
}
}

View File

@@ -9,7 +9,7 @@ namespace hex {
LanguageDefinition::LanguageDefinition(std::map<std::string, std::string> &&entries) {
for (const auto &[key, value] : entries) {
if (value == "***** MISSING TRANSLATION *****")
if (value.empty())
continue;
this->m_entries.insert({ key, value });
@@ -76,7 +76,7 @@ namespace hex {
void LangEntry::loadLanguage(const std::string &language) {
LangEntry::s_currStrings.clear();
auto &definitions = ContentRegistry::Language::getLanguageDefinitions();
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
if (!definitions.contains(language))
return;
@@ -92,7 +92,7 @@ namespace hex {
}
const std::map<std::string, std::string> &LangEntry::getSupportedLanguages() {
return ContentRegistry::Language::getLanguages();
return ContentRegistry::Language::impl::getLanguages();
}
void LangEntry::setFallbackLanguage(const std::string &language) {

View File

@@ -3,6 +3,8 @@
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
#include <wolv/utils/string.hpp>
#include <filesystem>
#include <system_error>
@@ -17,7 +19,7 @@ namespace hex {
return;
}
#else
this->m_handle = dlopen(hex::toUTF8String(path).c_str(), RTLD_LAZY);
this->m_handle = dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY);
if (this->m_handle == nullptr) {
log::error("dlopen failed: {}!", dlerror());
@@ -69,7 +71,7 @@ namespace hex {
bool Plugin::initializePlugin() const {
const auto requestedVersion = getCompatibleVersion();
if (requestedVersion != IMHEX_VERSION) {
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", hex::toUTF8String(this->m_path.filename()), requestedVersion);
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", wolv::util::toUTF8String(this->m_path.filename()), requestedVersion);
return false;
}
@@ -145,7 +147,7 @@ namespace hex {
std::vector<Plugin> PluginManager::s_plugins;
bool PluginManager::load(const std::fs::path &pluginFolder) {
if (!fs::exists(pluginFolder))
if (!wolv::io::fs::exists(pluginFolder))
return false;
PluginManager::s_pluginFolder = pluginFolder;

View File

@@ -6,6 +6,9 @@
#include <hex/providers/provider.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/io/fs.hpp>
namespace hex {
constexpr static auto MetadataHeaderMagic = "HEX";
@@ -17,7 +20,14 @@ namespace hex {
std::fs::path ProjectFile::s_currProjectPath;
bool ProjectFile::load(const std::fs::path &filePath) {
if (!fs::exists(filePath) || !fs::isRegularFile(filePath))
auto originalPath = ProjectFile::s_currProjectPath;
ProjectFile::s_currProjectPath = filePath;
auto resetPath = SCOPE_GUARD {
ProjectFile::s_currProjectPath = originalPath;
};
if (!wolv::io::fs::exists(filePath) || !wolv::io::fs::isRegularFile(filePath))
return false;
if (filePath.extension() != ".hexproj")
return false;
@@ -30,23 +40,26 @@ namespace hex {
return false;
{
const auto metadataContent = tar.read(MetadataPath);
const auto metadataContent = tar.readVector(MetadataPath);
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
return false;
}
for (const auto &provider : ImHexApi::Provider::getProviders()) {
auto providers = auto(ImHexApi::Provider::getProviders());
for (const auto &provider : providers) {
ImHexApi::Provider::remove(provider);
}
bool result = true;
for (const auto &handler : ProjectFile::getHandlers()) {
try {
if (!handler.load(handler.basePath, tar))
if (!handler.load(handler.basePath, tar)) {
log::warn("Project file handler for {} failed to load {}", filePath.string(), handler.basePath.string());
result = false;
}
} catch (std::exception &e) {
log::info("{}", e.what());
log::warn("Project file handler for {} failed to load {}: {}", filePath.string(), handler.basePath.string(), e.what());
result = false;
}
@@ -72,15 +85,23 @@ namespace hex {
}
}
ProjectFile::s_currProjectPath = filePath;
resetPath.release();
EventManager::post<RequestUpdateWindowTitle>();
return true;
}
bool ProjectFile::store(std::optional<std::fs::path> filePath) {
auto originalPath = ProjectFile::s_currProjectPath;
if (!filePath.has_value())
filePath = ProjectFile::s_currProjectPath;
ProjectFile::s_currProjectPath = filePath.value();
auto resetPath = SCOPE_GUARD {
ProjectFile::s_currProjectPath = originalPath;
};
Tar tar(*filePath, Tar::Mode::Create);
if (!tar.isValid())
return false;
@@ -88,34 +109,37 @@ namespace hex {
bool result = true;
for (const auto &handler : ProjectFile::getHandlers()) {
try {
if (!handler.store(handler.basePath, tar))
if (!handler.store(handler.basePath, tar) && handler.required)
result = false;
} catch (std::exception &e) {
log::info("{}", e.what());
result = false;
if (handler.required)
result = false;
}
}
for (const auto &provider : ImHexApi::Provider::getProviders()) {
const auto basePath = std::fs::path(std::to_string(provider->getID()));
for (const auto &handler: ProjectFile::getProviderHandlers()) {
try {
if (!handler.store(provider, basePath / handler.basePath, tar))
if (!handler.store(provider, basePath / handler.basePath, tar) && handler.required)
result = false;
} catch (std::exception &e) {
log::info("{}", e.what());
result = false;
if (handler.required)
result = false;
}
}
}
{
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
tar.write(MetadataPath, metadataContent);
tar.writeString(MetadataPath, metadataContent);
}
ProjectFile::s_currProjectPath = filePath.value();
ImHexApi::Provider::resetDirty();
resetPath.release();
return result;
}
@@ -124,4 +148,16 @@ namespace hex {
return !ProjectFile::s_currProjectPath.empty();
}
void ProjectFile::clearPath() {
ProjectFile::s_currProjectPath.clear();
}
std::fs::path ProjectFile::getPath() {
return ProjectFile::s_currProjectPath;
}
void ProjectFile::setPath(const std::fs::path &path) {
ProjectFile::s_currProjectPath = path;
}
}

View File

@@ -47,7 +47,7 @@ namespace hex {
void Task::update(u64 value) {
this->m_currValue = value;
if (this->m_shouldInterrupt)
if (this->m_shouldInterrupt) [[unlikely]]
throw TaskInterruptor();
}
@@ -165,6 +165,14 @@ namespace hex {
task->interrupt();
}
u32 TaskHolder::getProgress() const {
if (this->m_task.expired())
return 0;
auto task = this->m_task.lock();
return (u32)((task->getValue() * 100) / task->getMaxValue());
}
void TaskManager::init() {
for (u32 i = 0; i < std::thread::hardware_concurrency(); i++)
@@ -184,7 +192,6 @@ namespace hex {
}
void TaskManager::runner(const std::stop_token &stopToken) {
std::mutex mutex;
while (true) {
std::shared_ptr<Task> task;
{
@@ -239,12 +246,13 @@ namespace hex {
}
void TaskManager::collectGarbage() {
std::unique_lock lock1(s_queueMutex);
std::unique_lock lock2(s_deferredCallsMutex);
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
{
std::unique_lock lock1(s_queueMutex);
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
}
if (s_tasks.empty()) {
std::unique_lock lock2(s_deferredCallsMutex);
for (auto &call : s_tasksFinishedCallbacks)
call();
s_tasksFinishedCallbacks.clear();
@@ -293,4 +301,4 @@ namespace hex {
s_tasksFinishedCallbacks.push_back(function);
}
}
}

View File

@@ -1,22 +1,25 @@
#include <hex/api/theme_manager.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
#include <nlohmann/json.hpp>
namespace hex::api {
namespace hex {
std::map<std::string, nlohmann::json> ThemeManager::s_themes;
std::map<std::string, std::function<void(std::string, std::string)>> ThemeManager::s_themeHandlers, ThemeManager::s_styleHandlers;
std::map<std::string, ThemeManager::ThemeHandler> ThemeManager::s_themeHandlers;
std::map<std::string, ThemeManager::StyleHandler> ThemeManager::s_styleHandlers;
std::string ThemeManager::s_imagePostfix;
std::string ThemeManager::s_currTheme;
void ThemeManager::addThemeHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler) {
s_themeHandlers[name] = handler;
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
s_themeHandlers[name] = { colorMap, getFunction, setFunction };
}
void ThemeManager::addStyleHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler) {
s_styleHandlers[name] = handler;
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
s_styleHandlers[name] = { styleMap };
}
void ThemeManager::addTheme(const std::string &content) {
@@ -29,6 +32,9 @@ namespace hex::api {
}
std::optional<ImColor> ThemeManager::parseColorString(const std::string &colorString) {
if (colorString == "auto")
return ImVec4(0, 0, 0, -1);
if (colorString.length() != 9 || colorString[0] != '#')
return std::nullopt;
@@ -46,13 +52,51 @@ namespace hex::api {
return std::nullopt;
}
if (color == 0x00000000)
return ImVec4(0, 0, 0, -1);
return ImColor(hex::changeEndianess(color, std::endian::big));
}
nlohmann::json ThemeManager::exportCurrentTheme(const std::string &name) {
nlohmann::json theme = {
{ "name", name },
{ "image_postfix", s_imagePostfix },
{ "colors", {} },
{ "styles", {} },
{ "base", s_currTheme }
};
for (const auto &[type, handler] : s_themeHandlers) {
theme["colors"][type] = {};
for (const auto &[key, value] : handler.colorMap) {
auto color = handler.getFunction(value);
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianess(u32(color), std::endian::big));
}
}
for (const auto &[type, handler] : s_styleHandlers) {
theme["styles"][type] = {};
for (const auto &[key, style] : handler.styleMap) {
if (std::holds_alternative<float*>(style.value))
theme["styles"][type][key] = *std::get<float*>(style.value);
else if (std::holds_alternative<ImVec2*>(style.value)) {
theme["styles"][type][key] = {
std::get<ImVec2*>(style.value)->x,
std::get<ImVec2*>(style.value)->y
};
}
}
}
return theme;
}
void ThemeManager::changeTheme(std::string name) {
if (!s_themes.contains(name)) {
if (s_themes.empty()) {
hex::log::error("Theme '{}' does not exist and no other themes are available!", name);
return;
} else {
const std::string &defaultTheme = s_themes.begin()->first;
@@ -65,7 +109,8 @@ namespace hex::api {
if (theme.contains("base")) {
if (theme["base"].is_string()) {
changeTheme(theme["base"].get<std::string>());
if (theme["base"] != name)
changeTheme(theme["base"].get<std::string>());
} else {
hex::log::error("Theme '{}' has invalid base theme!", name);
}
@@ -78,19 +123,53 @@ namespace hex::api {
continue;
}
for (const auto &[key, value] : content.items())
s_themeHandlers[type](key, value.get<std::string>());
const auto &handler = s_themeHandlers[type];
for (const auto &[key, value] : content.items()) {
if (!handler.colorMap.contains(key)) {
log::warn("No color found for '{}.{}'", type, key);
continue;
}
auto color = parseColorString(value.get<std::string>());
if (!color.has_value()) {
log::warn("Invalid color '{}' for '{}.{}'", value.get<std::string>(), type, key);
continue;
}
s_themeHandlers[type].setFunction(s_themeHandlers[type].colorMap.at(key), color.value());
}
}
}
if (theme.contains("styles")) {
for (const auto&[key, value] : theme["styles"].items()) {
if (!s_styleHandlers.contains(key)) {
log::warn("No style handler found for '{}'", key);
for (const auto&[type, content] : theme["styles"].items()) {
if (!s_styleHandlers.contains(type)) {
log::warn("No style handler found for '{}'", type);
continue;
}
s_styleHandlers[key](name, value.get<std::string>());
auto &handler = s_styleHandlers[type];
for (const auto &[key, value] : content.items()) {
if (!handler.styleMap.contains(key))
continue;
auto &style = handler.styleMap.at(key);
const float scale = style.needsScaling ? 1_scaled : 1.0F;
if (value.is_number_float()) {
if (auto newValue = std::get_if<float*>(&style.value); newValue != nullptr)
**newValue = value.get<float>() * scale;
else
log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name);
} else if (value.is_array() && value.size() == 2 && value[0].is_number_float() && value[1].is_number_float()) {
if (auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr)
**newValue = ImVec2(value[0].get<float>() * scale, value[1].get<float>() * scale);
else
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
} else {
hex::log::error("Theme '{}' has invalid style value for '{}.{}'!", name, type, key);
}
}
}
}
@@ -101,6 +180,8 @@ namespace hex::api {
hex::log::error("Theme '{}' has invalid image postfix!", name);
}
}
s_currTheme = name;
}
const std::string &ThemeManager::getThemeImagePostfix() {
@@ -115,4 +196,12 @@ namespace hex::api {
return themeNames;
}
void ThemeManager::reset() {
ThemeManager::s_themes.clear();
ThemeManager::s_styleHandlers.clear();
ThemeManager::s_themeHandlers.clear();
ThemeManager::s_imagePostfix.clear();
ThemeManager::s_currTheme.clear();
}
}

View File

@@ -14,7 +14,7 @@ namespace hex::dp {
attr.setParentNode(this);
}
std::vector<u8> Node::getBufferOnInput(u32 index) {
const std::vector<u8>& Node::getBufferOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index);
if (attribute == nullptr)
@@ -28,61 +28,65 @@ namespace hex::dp {
auto &outputData = attribute->getOutputData();
if (!outputData.has_value())
if (outputData.empty())
throwNodeError("No data available at connected attribute");
return outputData.value();
return outputData;
}
i128 Node::getIntegerOnInput(u32 index) {
const i128& Node::getIntegerOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index);
if (attribute == nullptr)
throwNodeError(hex::format("Nothing connected to input '{0}'", LangEntry(this->m_attributes[index].getUnlocalizedName())));
auto &outputData = [&] -> std::vector<u8>& {
if (attribute != nullptr) {
if (attribute->getType() != Attribute::Type::Integer)
throwNodeError("Tried to read integer from non-integer attribute");
if (attribute->getType() != Attribute::Type::Integer)
throwNodeError("Tried to read integer from non-integer attribute");
markInputProcessed(index);
attribute->getParentNode()->process();
markInputProcessed(index);
attribute->getParentNode()->process();
return attribute->getOutputData();
} else {
return this->getAttribute(index).getOutputData();
}
}();
auto &outputData = attribute->getOutputData();
if (!outputData.has_value())
if (outputData.empty())
throwNodeError("No data available at connected attribute");
if (outputData->size() < sizeof(u64))
if (outputData.size() < sizeof(i128))
throwNodeError("Not enough data provided for integer");
return *reinterpret_cast<i64 *>(outputData->data());
return *reinterpret_cast<i128 *>(outputData.data());
}
long double Node::getFloatOnInput(u32 index) {
const long double& Node::getFloatOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index);
if (attribute == nullptr)
throwNodeError(hex::format("Nothing connected to input '{0}'", LangEntry(this->m_attributes[index].getUnlocalizedName())));
auto &outputData = [&] -> std::vector<u8>& {
if (attribute != nullptr) {
if (attribute->getType() != Attribute::Type::Float)
throwNodeError("Tried to read integer from non-float attribute");
if (attribute->getType() != Attribute::Type::Float)
throwNodeError("Tried to read float from non-float attribute");
markInputProcessed(index);
attribute->getParentNode()->process();
markInputProcessed(index);
attribute->getParentNode()->process();
return attribute->getOutputData();
} else {
return this->getAttribute(index).getOutputData();
}
}();
auto &outputData = attribute->getOutputData();
if (!outputData.has_value())
if (outputData.empty())
throwNodeError("No data available at connected attribute");
if (outputData->size() < sizeof(long double))
if (outputData.size() < sizeof(long double))
throwNodeError("Not enough data provided for float");
long double result = 0;
std::memcpy(&result, outputData->data(), sizeof(long double));
return result;
return *reinterpret_cast<long double *>(outputData.data());
}
void Node::setBufferOnOutput(u32 index, const std::vector<u8> &data) {
void Node::setBufferOnOutput(u32 index, std::span<const u8> data) {
if (index >= this->getAttributes().size())
throwNodeError("Attribute index out of bounds!");
@@ -91,7 +95,7 @@ namespace hex::dp {
if (attribute.getIOType() != Attribute::IOType::Out)
throwNodeError("Tried to set output data of an input attribute!");
attribute.getOutputData() = data;
attribute.getOutputData() = { data.begin(), data.end() };
}
void Node::setIntegerOnOutput(u32 index, i128 integer) {

View File

@@ -1,8 +1,8 @@
#include <hex/helpers/crypto.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/concepts.hpp>
#include <wolv/utils/guards.hpp>
#include <mbedtls/version.h>
#include <mbedtls/base64.h>
@@ -11,13 +11,10 @@
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>
#include <mbedtls/aes.h>
#include <mbedtls/cipher.h>
#include <array>
#include <span>
#include <functional>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <bit>
@@ -157,7 +154,7 @@ namespace hex::crypt {
return crc.checksum();
}
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
u8 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
return calcCrc<8>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
}

View File

@@ -2,13 +2,16 @@
#include <hex/helpers/utils.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/string.hpp>
namespace hex {
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
auto file = fs::File(path, fs::File::Mode::Read);
auto file = wolv::io::File(path, wolv::io::File::Mode::Read);
switch (type) {
case Type::Thingy:
parseThingyFile(file);
parse(file.readString());
break;
default:
return;
@@ -17,13 +20,25 @@ namespace hex {
this->m_valid = true;
}
std::pair<std::string_view, size_t> EncodingFile::getEncodingFor(const std::vector<u8> &buffer) const {
EncodingFile::EncodingFile(Type type, const std::string &content) {
switch (type) {
case Type::Thingy:
parse(content);
break;
default:
return;
}
this->m_valid = true;
}
std::pair<std::string_view, size_t> EncodingFile::getEncodingFor(std::span<u8> buffer) const {
for (auto riter = this->m_mapping.crbegin(); riter != this->m_mapping.crend(); ++riter) {
const auto &[size, mapping] = *riter;
if (size > buffer.size()) continue;
auto key = std::vector<u8>(buffer.begin(), buffer.begin() + size);
std::vector<u8> key(buffer.begin(), buffer.begin() + size);
if (mapping.contains(key))
return { mapping.at(key), size };
}
@@ -31,8 +46,23 @@ namespace hex {
return { ".", 1 };
}
void EncodingFile::parseThingyFile(fs::File &file) {
for (const auto &line : splitString(file.readString(), "\n")) {
size_t EncodingFile::getEncodingLengthFor(std::span<u8> buffer) const {
for (auto riter = this->m_mapping.crbegin(); riter != this->m_mapping.crend(); ++riter) {
const auto &[size, mapping] = *riter;
if (size > buffer.size()) continue;
std::vector<u8> key(buffer.begin(), buffer.begin() + size);
if (mapping.contains(key))
return size;
}
return 1;
}
void EncodingFile::parse(const std::string &content) {
this->m_tableContent = content;
for (const auto &line : splitString(this->m_tableContent, "\n")) {
std::string from, to;
{
@@ -51,15 +81,17 @@ namespace hex {
if (fromBytes.empty()) continue;
if (to.length() > 1)
hex::trim(to);
to = wolv::util::trim(to);
if (to.empty())
to = " ";
if (!this->m_mapping.contains(fromBytes.size()))
this->m_mapping.insert({ fromBytes.size(), {} });
this->m_mapping[fromBytes.size()].insert({ fromBytes, to });
this->m_longestSequence = std::max(this->m_longestSequence, fromBytes.size());
auto keySize = fromBytes.size();
this->m_mapping[keySize].insert({ std::move(fromBytes), to });
this->m_longestSequence = std::max(this->m_longestSequence, keySize);
}
}

View File

@@ -1,171 +0,0 @@
#include <hex/helpers/file.hpp>
#include <hex/helpers/utils.hpp>
#include <unistd.h>
namespace hex::fs {
File::File(const std::fs::path &path, Mode mode) noexcept : m_path(path) {
#if defined(OS_WINDOWS)
if (mode == File::Mode::Read)
this->m_file = _wfopen(path.c_str(), L"rb");
else if (mode == File::Mode::Write)
this->m_file = _wfopen(path.c_str(), L"r+b");
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
this->m_file = _wfopen(path.c_str(), L"w+b");
#else
if (mode == File::Mode::Read)
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "rb");
else if (mode == File::Mode::Write)
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "r+b");
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "w+b");
#endif
}
File::File() noexcept {
this->m_file = nullptr;
}
File::File(File &&other) noexcept {
this->m_file = other.m_file;
other.m_file = nullptr;
}
File::~File() {
this->close();
}
File &File::operator=(File &&other) noexcept {
this->m_file = other.m_file;
other.m_file = nullptr;
this->m_path = std::move(other.m_path);
return *this;
}
void File::seek(u64 offset) {
fseeko64(this->m_file, offset, SEEK_SET);
}
void File::close() {
if (isValid()) {
std::fclose(this->m_file);
this->m_file = nullptr;
}
}
size_t File::readBuffer(u8 *buffer, size_t size) {
if (!isValid()) return 0;
return fread(buffer, size, 1, this->m_file);
}
std::vector<u8> File::readBytes(size_t numBytes) {
if (!isValid()) return {};
auto size = numBytes == 0 ? getSize() : numBytes;
if (size == 0) return {};
std::vector<u8> bytes(size);
auto bytesRead = fread(bytes.data(), 1, bytes.size(), this->m_file);
bytes.resize(bytesRead);
return bytes;
}
std::string File::readString(size_t numBytes) {
if (!isValid()) return {};
if (getSize() == 0) return {};
auto bytes = readBytes(numBytes);
if (bytes.empty())
return "";
auto cString = reinterpret_cast<const char *>(bytes.data());
return { cString, hex::strnlen(cString, bytes.size()) };
}
std::u8string File::readU8String(size_t numBytes) {
if (!isValid()) return {};
if (getSize() == 0) return {};
auto bytes = readBytes(numBytes);
if (bytes.empty())
return u8"";
auto cString = reinterpret_cast<const char8_t *>(bytes.data());
return { cString, hex::strnlen(reinterpret_cast<const char*>(bytes.data()), bytes.size()) };
}
void File::write(const u8 *buffer, size_t size) {
if (!isValid()) return;
std::fwrite(buffer, size, 1, this->m_file);
}
void File::write(const std::vector<u8> &bytes) {
if (!isValid()) return;
std::fwrite(bytes.data(), 1, bytes.size(), this->m_file);
}
void File::write(const std::string &string) {
if (!isValid()) return;
std::fwrite(string.data(), string.size(), 1, this->m_file);
}
void File::write(const std::u8string &string) {
if (!isValid()) return;
std::fwrite(string.data(), string.size(), 1, this->m_file);
}
size_t File::getSize() const {
if (!isValid()) return 0;
auto startPos = ftello64(this->m_file);
fseeko64(this->m_file, 0, SEEK_END);
auto size = ftello64(this->m_file);
fseeko64(this->m_file, startPos, SEEK_SET);
if (size < 0)
return 0;
return size;
}
void File::setSize(u64 size) {
if (!isValid()) return;
auto result = ftruncate64(fileno(this->m_file), size);
hex::unused(result);
}
void File::flush() {
std::fflush(this->m_file);
}
bool File::remove() {
this->close();
return std::remove(hex::toUTF8String(this->m_path).c_str()) == 0;
}
void File::disableBuffering() {
if (!isValid()) return;
std::setvbuf(this->m_file, nullptr, _IONBF, 0);
}
}

Some files were not shown because too many files have changed in this diff Show More