Compare commits

..

486 Commits

Author SHA1 Message Date
Nik
811214ddb7 build: Bump version to v1.35.4 2024-07-09 08:09:55 +02:00
WerWolv
cb406ea357 build: Fix lzma support and simplify zstd building 2024-07-09 07:29:06 +02:00
WerWolv
edb1a8876b fix: Multiple definitions errors with plugin features 2024-07-09 07:21:45 +02:00
WerWolv
2757075a10 impr: Make highlight hovering more efficient 2024-07-09 07:21:39 +02:00
WerWolv
8a4599feea impr: Disable pattern debug mode after evaluation has finished 2024-07-09 07:21:33 +02:00
WerWolv
f8f47012c4 build: Streamline definition on plugin features 2024-07-09 07:21:25 +02:00
WerWolv
32e2ccbca0 git: Update Mesa3D link for Windows NoGPU version 2024-07-09 07:20:48 +02:00
WerWolv
4d1e29d747 fix: Build issue due to uncaptured this pointer 2024-07-09 07:20:18 +02:00
WerWolv
22dc3c6589 fix: Crash on macOS when dirtying or undirtying a provider from a thread
Fixes #1799
2024-07-09 07:20:06 +02:00
WerWolv
1c2bb0c049 fix: Hex editor popups getting transparent when hovering over combo box popup 2024-07-09 07:19:59 +02:00
WerWolv
5d53417683 web: Trigger right click when long touching area 2024-07-09 07:19:50 +02:00
WerWolv
c79321b550 web: Fix canvas to the top left of the screen 2024-07-09 07:19:43 +02:00
WerWolv
0785270dfa fix: Remove unnecessary touch padding 2024-07-09 07:19:33 +02:00
WerWolv
84999d5c06 web: Improve logo size on mobile 2024-07-09 07:19:27 +02:00
WerWolv
a0ca0e8596 fix: Make sure welcome screen always stays in the background 2024-07-09 07:19:16 +02:00
WerWolv
1d99f8534d web: Fix touch input 2024-07-09 07:19:11 +02:00
WerWolv
cfbc6e085a fix: Wrong start/end offset and size for static array entries in pattern data view 2024-07-09 07:18:49 +02:00
WerWolv
a45d30edca impr: Added tooltips to toolbar buttons 2024-07-09 07:18:20 +02:00
Bernard Teo
5a053aa146 build: Update nativefiledialog and keep dialogs on top (#1771)
This PR updates the nativefiledialog submodule and uses its new feature
to set the ImHex main window as the parent of the dialog window. This
ensures that the dialog stays on top of the main window. This is
currently supported by NFDe on Windows, macOS, and Linux/X11.
Linux/Wayland behaves as it did previously due to limitations in NFDe.

Note that macOS file dialogs have already been parented properly as NFDe
previously used the key window (the window currently receiving keyboard
events) on macOS. However, it's probably better to do the correct thing
and pass the main window to NFDe even on macOS.

### Problem description
The file dialog go behind the main window if the main window is clicked
while the file dialog is open.

### Implementation description
Update nativefiledialog and pass the `GLFWwindow*` of the main window to
the library function.

### Screenshots
Before:


https://github.com/WerWolv/ImHex/assets/6948096/589c3401-702a-4b0a-99ed-02d3e4d9080e

After:


https://github.com/WerWolv/ImHex/assets/6948096/8fef4900-eedc-48d5-8a4e-7bd81e37e3c0

### Additional things
I have tested this on Windows and Linux/X11, but did not test this on
macOS. It would be ideal if someone can help with this. (But as far as
NFDe is concerned, macOS `NSWindow*` handles have been tested (with
SDL2) and works.)

Co-authored-by: Nik <werwolv98@gmail.com>
2024-07-09 07:17:59 +02:00
WerWolv
d5a69d9201 fix: Remove interactive help debug code 2024-07-09 07:17:50 +02:00
WerWolv
dd0204f31d impr: Added nicer console warning when .NET runtime isn't installed 2024-07-09 07:17:37 +02:00
WerWolv
3b799388c2 web: Improved canvas webgl creation logic 2024-07-09 07:17:33 +02:00
WerWolv
c7c4ecad6d impr: Improved size display in pattern data view 2024-07-09 07:17:28 +02:00
WerWolv
6784678ff0 impr: Disable tab overlines 2024-07-09 07:17:21 +02:00
WerWolv
dd8e7025d0 fix: Potential race condition with sorting in the pattern drawer 2024-07-09 07:17:17 +02:00
WerWolv
c2f661f021 patterns: Updated pattern language 2024-07-09 07:17:12 +02:00
WerWolv
c6fc26e2e7 impr: Added Boost.Regex to about page 2024-07-09 07:17:01 +02:00
WerWolv
3a99d53ba5 build: Updated ImGui, libfmt and libyara 2024-07-09 07:16:49 +02:00
WerWolv
5fced6bb63 impr: Completely eradicate Window resize flickering on Windows 2024-07-09 07:16:44 +02:00
WerWolv
67930cf65d web: Fix ImHex logo and progress bar default fill 2024-07-09 07:16:26 +02:00
WerWolv
b305adb286 impr: Prevent canvas flickering in web build 2024-07-09 07:16:19 +02:00
WerWolv
cbcf7b78e9 build: Properly look for boost and libimhex library in sdk again 2024-07-09 07:15:40 +02:00
WerWolv
c922d9ceec fix: Updater executable not being launched correctly when path had spaces in it
Fixes #1780
2024-07-09 07:12:25 +02:00
WerWolv
ad235fad25 impr: Further try to improve window resize flickering on Windows 2024-06-29 23:17:59 +02:00
WerWolv
dffb7e95e3 build: Bumped version to 1.35.3 2024-06-29 21:33:34 +02:00
WerWolv
916c1b7d4b fix: ImHex hanging at startup in certain cases 2024-06-29 21:33:12 +02:00
WerWolv
2743b04f50 fix: Don't delete font atlas after passing it to ImGui 2024-06-29 21:33:07 +02:00
WerWolv
dbe8bfd75f fix: Standard magic file not getting bundled into executable correctly 2024-06-29 19:43:40 +02:00
WerWolv
c6c599c75b build: Bumped version to 1.35.2 2024-06-29 19:26:00 +02:00
WerWolv
c2b7b4a11e fix: Default folders still not being created correctly on Linux 2024-06-29 19:25:20 +02:00
WerWolv
495255484e build: Bumped version to 1.35.1 2024-06-29 18:50:10 +02:00
WerWolv
b92b0922d5 fix: Default folders not being created correctly anymore 2024-06-29 18:50:01 +02:00
WerWolv
ac1a28311c build: Bumped version to 1.35.0 2024-06-29 11:27:24 +02:00
WerWolv
01d1938fea git: Update macOS version requirement in readme
#1647
2024-06-29 10:34:41 +02:00
WerWolv
802694ec68 build: Silence macOS CI build warnings 2024-06-28 22:29:38 +02:00
WerWolv
2aef5e4eef build: Lock install path in rpath behind an option 2024-06-28 22:21:10 +02:00
WerWolv
9a0a4d47dc build: Disable source_date_epoch_from_changelog 2024-06-28 21:53:34 +02:00
WerWolv
96b7366d53 build: Try fixing fedora build spec again 2024-06-28 21:29:49 +02:00
WerWolv
90ac96298a impr: Only re-render frame once during window resize or move operations 2024-06-28 21:27:35 +02:00
WerWolv
a6e5040e8f fix: Build issues on Fedora due to missing Changelog value 2024-06-28 18:29:24 +02:00
WerWolv
19e5aafc85 fix: String truncating being completely borken 2024-06-28 18:29:10 +02:00
WerWolv
77301fd018 impr: Swap some items between File and Edit menu to fit better 2024-06-28 11:13:03 +02:00
WerWolv
ed56b3dd12 impr: Limit string length by cutting out part of the middle instead 2024-06-28 11:12:41 +02:00
WerWolv
91f6aae9ef impr: Make Win32 API properly use unicode support 2024-06-28 11:12:17 +02:00
WerWolv
b642c493d7 fix: Opening files with unicode paths in external program/explorer not working 2024-06-27 23:12:20 +02:00
WerWolv
a950796306 fix: Recent file entry name encoding being broken 2024-06-27 22:40:19 +02:00
WerWolv
8672a2cfe0 fix: Content store downloads getting stuck sometimes 2024-06-27 19:54:45 +02:00
WerWolv
301e8c5a96 impr: Improve contrast of text in pattern data table when hovering 2024-06-27 19:45:49 +02:00
WerWolv
699a91c46b fix: Path in pattern tooltip wrapping too quickly 2024-06-27 19:27:54 +02:00
WerWolv
e43016735d fix: Open file in containing folder not working 2024-06-27 19:25:02 +02:00
WerWolv
d9cecbbb5f impr: Don't flash bang people when the ImHex main window appears 2024-06-27 17:11:28 +02:00
WerWolv
6e186e7d6a impr: Clean up .NET script loader error messages 2024-06-27 17:11:28 +02:00
WerWolv
af3680649c patterns: Updated pattern language 2024-06-27 17:10:48 +02:00
WerWolv
82f1d08dd7 fix: Race condition when loading projects while other providers are loaded already 2024-06-27 17:10:42 +02:00
WerWolv
b1b54a5fe7 impr: Drastically optimize event handler 2024-06-27 17:10:01 +02:00
WerWolv
ced3af3935 fix: Revert pattern include path back to the original paths 2024-06-27 17:09:48 +02:00
WerWolv
e5c782ebe9 impr: Further optimize ImGui text rendering 2024-06-27 17:09:20 +02:00
WerWolv
7d42742684 fix: Properly check return value of std::fgets 2024-06-26 22:46:01 +02:00
FireNX70
41820311cc fix: Off-by-one error in "Export selection to file" (#1774)
### Problem description
Export selection to file would never finish and wouldn't export the last
byte.

### Implementation description
It was just a simple off by one when using the selection's end address
to calculate the remaining data size. Add one to the remaining size
calculation.

### Additional things
Fixes https://github.com/WerWolv/ImHex/issues/1733,
https://github.com/WerWolv/ImHex/issues/1619 and
https://github.com/WerWolv/ImHex/issues/1597.
2024-06-26 22:44:10 +02:00
WerWolv
e132adad5d impr: Add short delay before a hover tooltip appears 2024-06-26 20:38:06 +02:00
WerWolv
2132e5adbf feat: Added tooltip to nightly icon on welcome screen 2024-06-26 20:37:39 +02:00
WerWolv
e2d55446fe impr: Get rid of more unnecessary ImGui::Text() calls 2024-06-26 19:41:06 +02:00
WerWolv
1dfce6a5c2 feat: Added --reset-settings command 2024-06-26 19:38:25 +02:00
WerWolv
a84db9821c impr: Optimize default hex cell visualizer 2024-06-26 19:15:49 +02:00
WerWolv
ec080ad69f fix: Indentation and wrapping of pattern hex editor tooltips 2024-06-26 19:14:43 +02:00
WerWolv
75cc9e4d84 fix: Pattern data filtering not applying correctly after rerunning pattern 2024-06-26 19:14:23 +02:00
WerWolv
d241a3ed5f impr: Make PageUp and PageDown not move the selection anymore 2024-06-26 19:14:01 +02:00
WerWolv
682aab8b23 feat: Allow faster hex editor scrolling by holding down CTRL or SHIFT + CTRL 2024-06-26 19:13:42 +02:00
WerWolv
474862b4af impr: Replace hardcoded pattern syntax highlighting colors style colors 2024-06-26 19:13:15 +02:00
WerWolv
dd02ec7a8e impr: Make the highlights minimap visualizer the default 2024-06-26 19:12:20 +02:00
WerWolv
1eadb77722 fix: Item tooltips being sized incorrectly 2024-06-26 19:11:59 +02:00
WerWolv
95f71bcb10 fix: Sub windows being used incorrectly 2024-06-26 19:11:31 +02:00
WerWolv
e1a4707569 impr: Make sure assertion handler doesn't get called too often 2024-06-26 19:10:43 +02:00
WerWolv
5a10613dd2 build: Add lib folder to all plugin's RPATH 2024-06-25 23:17:15 +02:00
WerWolv
c6a569ed88 impr: Don't reconstruct toolbar items list every frame 2024-06-25 23:14:05 +02:00
WerWolv
de24453fb9 impr: Open windowing menu on mouse down instead of on mouse up 2024-06-25 22:59:46 +02:00
WerWolv
d7c5c84110 build: Don't link plugins with plugin test library except in the test CI 2024-06-25 21:54:48 +02:00
WerWolv
95166ccfb8 impr: Further cleanup hex editor footer 2024-06-25 21:19:59 +02:00
WerWolv
c56667b0dd patterns: Updated pattern language 2024-06-25 20:57:45 +02:00
WerWolv
f754560bca patterns: Allow bitfield fields to be edited properly, improve type formatting 2024-06-25 16:14:28 +02:00
WerWolv
b54bb6cd56 patterns: Updated pattern language 2024-06-25 14:30:03 +02:00
WerWolv
b03b159907 impr: Better UI/UX for pattern drawer 2024-06-25 14:29:27 +02:00
WerWolv
bb7e6c9775 patterns: Updated pattern language 2024-06-25 13:54:55 +02:00
WerWolv
4bc724791d impr: Optimize frame times 2024-06-25 13:54:46 +02:00
WerWolv
ba7c10f4b1 feat: Fix sub menus, allow recent items to be collapsed 2024-06-25 13:54:29 +02:00
WerWolv
c1561c7b6a impr: Only allow scaling factors between 0.1x and 4.0x with slider
The old scaling values can still be entered by ctrl-clicking the slider and entering it manually
2024-06-24 23:04:20 +02:00
WerWolv
91a0be2d78 impr: Better UI/UX for interactive help 2024-06-24 23:01:46 +02:00
WerWolv
1f27530241 impr: Optimize event processing 2024-06-24 22:53:45 +02:00
WerWolv
e236872af3 feat: Added simple interactive help system 2024-06-24 22:53:25 +02:00
WerWolv
3d301c4202 fix: Don't automatically create directories in read-only locations
Fixes #1767
2024-06-24 21:51:37 +02:00
WerWolv
a5aaa60d29 fix: Build error due to uninitialized variable in web builds 2024-06-24 21:49:59 +02:00
WerWolv
d4a2de3b23 patterns: Updated pattern language 2024-06-24 14:27:32 +02:00
WerWolv
e85746ddba fix: Data paths being stored in config paths instead 2024-06-24 14:27:24 +02:00
WerWolv
a002eb1bc1 fix: Mixed path separators in default paths 2024-06-23 15:03:36 +02:00
WerWolv
7d4486f407 fix: Remove accidentally committed test code 2024-06-22 23:03:54 +02:00
WerWolv
a9915579a0 impr: Better detection of Intel GPUs with really bad driver bugs 2024-06-22 22:58:58 +02:00
iTrooz
65dfd4da0f feat: log stacktrace implementation used (#1769) 2024-06-22 21:33:52 +02:00
WerWolv
b93fd523aa fix: Remove last remaining getDefaultPaths 2024-06-22 12:57:13 +02:00
WerWolv
24621e6612 fix: Build issues on Linux due to unused parameter 2024-06-22 12:02:19 +02:00
WerWolv
1b383bdcf1 patterns: Updated pattern language 2024-06-22 11:56:17 +02:00
WerWolv
f47b357b23 impr: Reset unicode loading and scaling factor values if fonts fail to load 2024-06-22 11:25:32 +02:00
WerWolv
f9b778ecb8 impr: Use 1.0x scaling by default 2024-06-22 11:25:07 +02:00
WerWolv
f36d9831bb patterns: Updated pattern language 2024-06-22 10:45:03 +02:00
WerWolv
b60a262b58 fix: Replace old defaults path system with a new one
#1767
2024-06-22 10:44:55 +02:00
WerWolv
beef0fff33 impr: Better background opacity for the digital signal visualizer 2024-06-20 22:33:55 +02:00
WerWolv
24f535474a fix: Sidebar background and separator line overlapping footer 2024-06-20 22:33:42 +02:00
WerWolv
2e3f523f32 feat: Added digital signal pattern visualizer 2024-06-20 14:04:05 +02:00
WerWolv
c5f5973a9d feat: Added per-byte highlights to the hex editor minimap 2024-06-20 11:21:20 +02:00
WerWolv
5d59b8599d fix: Loading of file providers from UNC paths 2024-06-20 11:11:01 +02:00
WerWolv
3bfb0096e6 fix: Undefined behaviour when sending empty arguments to main instance 2024-06-20 11:09:57 +02:00
WerWolv
ca5763650b patterns: Updated pattern language 2024-06-19 13:59:58 +02:00
WerWolv
bf7beab0ab impr: Make auto backups not remove dirty status from project 2024-06-19 13:51:36 +02:00
SparkyTD
9b594d81bd feat: Added CSV, TSV and JSON as export options for Find results (#1673)
### Problem description
The default result export functionality of the Find tool is limited to
only exporting data in a nonstandard text format. This PR adds support
for exporting the results in CSV, TSV or JSON format. The PR also
removes the old format.

### Implementation description
I added the classes `ExportFormatter`, `ExportFormatterCsv`,
`ExportFormatterTsv` and `ExportFormatterJson`, with similar
implementations to the pattern data exporters.

~~I also moved the `ViewFind::Occurrence` class into
`hex/helpers/types.hh`, so the exporters can access it.~~

### Screenshots

![image](https://github.com/WerWolv/ImHex/assets/45818400/c7a1016b-6494-416d-a963-86484952837c)

### Additional things
Another small change I made is moving the "{} entries found" line on the
same line as the Search and Reset buttons. I think it looks cleaner this
way, but if anyone disagrees, I can revert it.

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
2024-06-18 20:57:55 +00:00
WerWolv
6a26c6002b git: Added ImHex pronunciation to readme 2024-06-18 22:12:01 +02:00
WerWolv
4fa64500af impr: Make sure footer items all start at the same height 2024-06-18 22:11:43 +02:00
WerWolv
085737af15 fix: Opening files on network drives (using UNC paths) crashing ImHex on startup 2024-06-18 22:11:26 +02:00
WerWolv
3e347fb6d4 impr: Improve icon scaling a bit 2024-06-18 22:10:02 +02:00
WerWolv
80cb126200 build: Cleanup configure step logging 2024-06-18 22:09:38 +02:00
WerWolv
f49715c7a0 impr: Better font loading logic 2024-06-16 22:41:16 +02:00
WerWolv
deee76e455 patterns: Updated pattern language 2024-06-16 15:42:04 +02:00
WerWolv
33885b863a fix: Disassembler always using little endian, no matter the setting
Fixes #1763
2024-06-16 15:06:30 +02:00
WerWolv
3ce9dbb278 fix: Alt and Ctrl being swapped in the text editor on macOS 2024-06-16 14:59:48 +02:00
WerWolv
bee4b906fb fix: Crash when closing providers 2024-06-16 14:48:31 +02:00
WerWolv
b3b79b3ee8 impr: Show document edited icon in close button on macOS 2024-06-12 19:51:12 +02:00
iTrooz
bd085dd495 git: Remove Fedora 38 and add Fedora 40 (#1755)
Fedora 38 is EOL
2024-06-12 09:21:35 +02:00
WerWolv
bf518b3590 fix: Pattern data view filter text box being too wide 2024-06-09 21:36:25 +02:00
WerWolv
32a8fcb84d fix: ImGui ID Push/Pop mismatch when disabling inspector rows 2024-06-09 21:18:29 +02:00
WerWolv
4fd65403c0 impr: Don't show separator in bookmark drag tooltip if no comment is present 2024-06-09 21:01:22 +02:00
WerWolv
ecf871a6f1 impr: Allow files to be switched between memory loaded and direct access 2024-06-09 20:59:06 +02:00
WerWolv
531c049bb0 impr: Improve bookmark drag-n-drop logic
Fixes #1745
2024-06-09 20:11:55 +02:00
WerWolv
99716eff1e impr: Make sure floating windows don't get reopened after restart 2024-06-09 20:11:21 +02:00
WerWolv
74205d5438 impr: Make sure icon input text boxes are the expected width 2024-06-09 14:56:56 +02:00
WerWolv
0136877978 fix: Bookmark "Open in View" tooltip not being displayed
Fixes #1749
2024-06-09 14:56:40 +02:00
Murmele
fb7d40ddbe fix: Allow bookmark region to be set to 1 Byte length (#1747)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
When entering for the end value the same value as the start it is not
recorgnized as valid region, because end must be strictly greater than
begin. Due to the +1 in the Region constructor this is not correct,
because the end is included in the range.

### Implementation description
<!-- Explain what you did to correct the problem -->

### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->
After:

![image](https://github.com/WerWolv/ImHex/assets/10099533/c45d2001-8790-430a-8f1a-4b65130f4d01)


### Additional things
<!-- Anything else you would like to say -->
2024-06-09 10:54:09 +02:00
WerWolv
c761054805 feat: Allow view providers to be renamed
Closes #1746
2024-06-09 10:51:59 +02:00
WerWolv
55e24b5e23 fix: Bookmarks not being correctly reorderable anymore
Fixes #1745
2024-06-09 10:28:58 +02:00
WerWolv
9cff5b8af4 fix: Release notes in about page not working in nightly builds 2024-06-08 14:07:52 +02:00
Justus Garbe
41b2523005 impr: Refactor various view drawing code (#1698)
Refactored:
- ViewDatainspector
- ViewAbout

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2024-06-08 13:56:48 +02:00
WerWolv
2ef256ee74 impr: Show full error message for custom data inspector row errors 2024-06-08 13:40:39 +02:00
WerWolv
e954d49c29 feat: Handle SIGINT 2024-06-08 00:57:56 +02:00
WerWolv
041bf47ff4 fix: Title bar height on non-macOS platforms 2024-06-08 00:56:52 +02:00
WerWolv
53ced98529 impr: Enable auto project backup by default 2024-06-08 00:52:27 +02:00
WerWolv
cb475c471d build: Updated libwolv 2024-06-08 00:39:12 +02:00
WerWolv
bf82690c80 fix: Build and drawing of title bar buttons on macOS 2024-06-08 00:28:17 +02:00
WerWolv
72a3a1acab build: Updated libwolv 2024-06-07 23:48:57 +02:00
WerWolv
18e2b0eaa2 fix: Regex crashes with too long input strings 2024-06-07 23:12:18 +02:00
WerWolv
b80a6152b3 fix: Unifont being blurry again 2024-06-07 22:50:47 +02:00
WerWolv
ffe3dae7b2 build: Updated ImGui to v1.90.8 2024-06-07 22:12:50 +02:00
WerWolv
d7845ec690 fix: Build issues 2024-06-07 21:57:39 +02:00
WerWolv
8531a67519 fix: Don't unload background .NET scripts 2024-06-07 21:27:01 +02:00
WerWolv
af59b9d2ca fix: Infinite loop when doing forwards/backwards searches in some cases
Fixes #1734
2024-06-07 21:00:55 +02:00
Tsukasa OI
08bb69c048 fix: Wrong query path when saving layouts (#1735)
### Problem description

At least on Windows (I have tested), it fails to save a layout on the
non-portable version of ImHex (unless we have an administrator
privilege).

The log (after an attempt to save a layout as "sample") will look like:

| Component | Message |
| --------- | ------- |
| `libimhex` | `Failed to save layout 'sample'. No writable path found`
|

But the underlying problem is platform-agnostic. It can be also a
problem on other platforms in other ways.

### Implementation description

The layout manager incorrectly queried whether the empty path
(effectively the current working directory) is writable before saving
the layout (not each "layouts" directories it queried earlier).

This is the snippet of the root cause.

```cxx
std::fs::path layoutPath;
for (const auto &path : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
    if (!hex::fs::isPathWritable(layoutPath))
        continue;

    layoutPath = path / fileName;
}
```

Look at the argument we are passing to `isPathWritable`. `layoutPath` is
a default (empty) `std::fs::path` object and will not be updated until
the directory describing itself is confirmed to be writable.

That caused a problem on non-portable version of Windows because:

1. The current working directory is usually the one of the executable
(`imhex-gui.exe`) and
2. That directory (`C:\Program Files\ImHex` by default) is usually not
writable unless ImHex is executed with an Administrator privilege.

The argument to `isPathWritable` should be `path` (containing one of the
`layouts` directories) and this PR fixes so that.

### Screenshots

### Additional things

This issue is hard to notice when developing because, to reproduce this
bug, the current working directory MUST NOT BE writable (usually
writable when we develop, even when we are working on the non-portable
Windows builds).
2024-06-07 20:33:43 +02:00
WerWolv
6fb32d20b3 fix: Don't try to compile process memory provider into Web build 2024-06-07 20:32:04 +02:00
WerWolv
ea09bfe8ea feat: Highlight patterns in pattern data view that are fully selected
Fixes #1741
2024-06-07 19:59:11 +02:00
WerWolv
c0dde570e4 feat: Highlight patterns in hex editor when hovering over pattern data row
Fixes #1742
2024-06-07 19:48:10 +02:00
WerWolv
6fd3fa77ed impr: Don't scroll hex editor view when jumping to a region that's on-screen already
Fixes #1743
2024-06-07 19:29:55 +02:00
WerWolv
ff20f81cfd impr: Added back selection size in hex to the footer 2024-06-07 19:21:38 +02:00
WerWolv
de8465a8f4 feat: Added limited support for the process memory provider to macOS 2024-06-07 19:17:14 +02:00
WerWolv
4540e1b561 impr: Select second to last provider when last one is selected and closed 2024-06-05 23:21:15 +02:00
WerWolv
789d469477 impr: Make providers close instantly 2024-06-05 23:02:38 +02:00
WerWolv
4797512207 fix: Variable naming style in splash window 2024-06-05 22:24:00 +02:00
WerWolv
348fe27a3c impr: Added small moon icon to the welcome screen of nightly builds 2024-06-05 22:23:43 +02:00
WerWolv
c217b1b100 build: Replace -WIP version suffix with .WIP 2024-06-05 20:59:48 +02:00
WerWolv
0e757e5fb1 build: Bumped version to 1.35.0-WIP 2024-06-03 23:06:28 +02:00
WerWolv
72d5707d33 build: Bumped version to 1.34.0 2024-06-03 22:22:33 +02:00
WerWolv
a491b85737 build: Added simple script to generate release notes 2024-06-03 22:14:08 +02:00
Alexander Wilms
d9d85cbfcc impr: Added keywords to .desktop file (#1732)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->
This adds a list of strings which may be used in addition to other
metadata to describe the application. This can be useful e.g. to
facilitate searching through entries.

Reference:
https://webcache.googleusercontent.com/search?q=cache:https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html

(The original site is currently down due to a Gitlab upgrade)

These keywords are used by
[Flathub](https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines/#launchable),
[KDE
Discover](https://discuss.kde.org/t/does-kde-discover-parse-the-desktop-file-for-categories-and-keywords/7041)
and [Gnome
Software](https://blogs.gnome.org/hughsie/2016/01/07/the-importance-of-keywords-for-the-software-center/).

### Implementation description
<!-- Explain what you did to correct the problem -->
Add a `Keywords` entry to the .desktop file.

### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->

Here's how the tags are displayed for TeXstudio on its Flathub page: 

![image](https://github.com/WerWolv/ImHex/assets/3226457/35e00272-433e-46cd-9a9e-c42913aefe3f)


### Additional things
<!-- Anything else you would like to say -->
2024-06-03 19:44:05 +02:00
iTrooz
283fe46230 git: Replace Ubuntu 23.04 with 24.04 LTS (#1731) 2024-06-03 17:25:50 +02:00
iTrooz
2c00aa5def fix: Do not use custom repo gcc 13 for Ubuntu because it doesn't run on vanilla Ubuntu (#1730) 2024-06-03 08:06:49 +00:00
iTrooz
984438e98d feat: show Linux distribution information on startup (#1729) 2024-06-03 10:02:29 +02:00
WerWolv
cf34c4bd95 fix: The font atlas does not own the custom font data 2024-06-01 13:55:06 +02:00
WerWolv
bab1d2e27e fix: Loading custom fonts from paths with unicode characters not working
Fixes #1727
2024-06-01 13:52:41 +02:00
WerWolv
d1b6a21e86 fix: Missing localization 2024-05-31 17:06:18 +02:00
WerWolv
3049590b68 feat: Added full pattern path to hex editor hover tooltip 2024-05-31 17:02:46 +02:00
WerWolv
8a289d2e4f impr: Make hex editor faster to render 2024-05-31 17:02:22 +02:00
WerWolv
7a81fa7ac5 fix: Mutliple potential nullptr derefes with shortcuts 2024-05-31 17:02:08 +02:00
WerWolv
fbf59b6f0b build: Updated ImGui 2024-05-31 16:59:52 +02:00
WerWolv
0ab200f77f fix: Hex editor popups closing when opening sub-popups 2024-05-30 22:01:18 +02:00
WerWolv
a91e40d731 lang: Fixed typo 2024-05-30 21:49:40 +02:00
WerWolv
e553fbc86c patterns: Updated pattern language 2024-05-30 21:49:08 +02:00
WerWolv
b4a810c374 fix: Build error on some platforms due to unused variables 2024-05-30 21:49:01 +02:00
WerWolv
0e97914d94 build: Updated libwolv 2024-05-30 16:57:57 +02:00
WerWolv
a5c250c811 fix: Byte type annotations not being reset correctly 2024-05-30 16:57:28 +02:00
WerWolv
08c2f3fc15 impr: Make window less prone to flickering during resizes on Windows 2024-05-30 16:57:07 +02:00
WerWolv
63f66662ce fix: Workspaces not being deletable correctly in all cases 2024-05-30 16:56:39 +02:00
iTrooz
89eee104ab chore: disable codecov PR comments (#1724) 2024-05-28 13:51:09 +02:00
iTrooz
92b1234ddb build: Reduce debug info produced (#1720) 2024-05-27 16:33:15 +02:00
iTrooz
0b0bf90e0b build: Compress debug info (#1719)
This PR compress the debug info in the ELF files built.

This has no impact on the packages (e.g. .deb files) because they themselves have compression, but once installed in the filesystem, they this compression will be beneficial

The compression is opportunistic, happens automatically when possible

For some reason, the web version doesn't work with this (most compiler tests after this seem to fail ?) so it is disabled there

More information: https://github.com/WerWolv/ImHex/issues/1714#issuecomment-2131373826
2024-05-26 20:48:14 +02:00
iTrooz
974c4ba040 git: remove unused name matrix parameter from Ubuntu builds (#1701) 2024-05-23 15:57:44 +02:00
iTrooz
4e2c1d20b4 git: change key used for web cache 2024-05-23 14:44:01 +02:00
iTrooz
e5b83d0ddf chore: add comment about IMHEX_COMMON_FLAGS 2024-05-23 14:44:01 +02:00
David Mentler
bdaf1e4151 build: Xcode accomodating CMake setup (#1688)
### Problem description
This PR implements some rudimentary Xcode support for building and
editing ImHex.

### Implementation description

#### Problem 1: Xcode is a multi-configuration buildsystem
The project is already rather CMake generator independent, thus it did
not need to change much to support Xcode's multi-configuration paradigm:

By default, CMake generates a `.xcodeproj` in which targets build their
artifacts into the specified `<>_OUTPUT_DIRECTORY`, postfixed by the
currently active configuration. To better fit the existing paradigm, I
instead opted ot introduce `IMHEX_MAIN_OUTPUT_DIRECTORY`. This variable
is equal to the previously used `RUNTIME_OUTPUT_DIRECTORY` when using
other generators, and is changed to include a configuration specific
_prefix_ when used with Xcode.

The result is different output directories when using Xcode, and no
changes when using any other generator.

#### Problem 2: ImHex does not support AppleClang
To allow building the codebase with Xcode, I have introduced
`IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER`. Specifying this option to
`ON` will force CMake to honor the user specified compiler settings,
even when using the Xcode generator.

In practice this can be used together with the new "xcode" CMakePreset
to build the project with mainline clang using `xcodebuild`, or Xcode
itself by generating a buildsystem like so:
```
cmake --preset xcode -DCMAKE_PREFIX_PATH=/opt/homebrew/opt/llvm@17
```

This solution is of course not without flaws. The inner workings are a
particularly ugly hack, and mainline clang does not implement the
necessary extensions to allow Xcode to index the code. Regardless this
option is useful to enable future work in terms of bundling/signing
macOS applications in the "intended" way using Xcode without additional
source modifications.

#### Problem 3: Vanilla CMake + Xcode = Bad developer UX 
By default, the CMake generated `.xcodeproj` is a mess. Tons of targets
are scattered about, and source files are not organized beyond grouping
them into a "Source Files" and "Header Files" group.

Even "Header Files" is missing, because the ImHex build system does not
regard private header files of libraries as sources of a target, and
Xcode does not try to guess this information.

The solution is twofold:
* Additional code has been added which organizes the targets into a neat
folder structure
* Additional code was added behind a configuration flag
`IMHEX_IDE_HELPERS_INTRUSIVE_IDE_TWEAKS` which automatically creates
source file trees in Xcode targets, and discovers the non-declared
header files via the folder convention.

### Screenshots
N/A

### Additional things

As a bonus: `IMHEX_OFFLINE_BUILD` assumes that ImHex-Patterns is cloned
into the source tree. I have added an additional fallback that tries to
locate it as a sibling folder of `${CMAKE_SOURCE_DIR}`, as this meshes
better with my filesystem setup.

The setup was tested with `CMake 3.29.2`, `Xcode 15.2`, and `llvm@17`
from homebrew.
2024-05-20 10:12:57 +00:00
David Mentler
751eff0edf impr: Restore native macOS title bar double click gesture in borderless mode (#1689)
### Problem description

#### Problem 1
In borderless mode ImHex disables the standard macOS titlebar rendering
and input processing. As a result double clicking the titlebar does not
trigger the native macOS behavior set in `System Settings -> Desktop &
Dock -> Double-click a window's title bar to [Zoom/Minimize/Do
nothing]`.

#### Problem 2
The ImHex window shows up as blank/transparent when de-minimizing it
from the dock.

#### Problem 3
Widgets experience ghost hover inputs from the past position of the
cursor during live resizing.

### Implementation description
ImGui elements consume input events in the order they are drawn. As a
result by "drawing" an `InvisibleButton` over the content area of the
titlebar we can catch unprocessed clicks in the titlebar area.
Connecting this button's double clicks to the native window is then a
trivial endeavour.

The blank windows was caused by the rendering stack clearing the GL
buffer, but proceeding to draw nothing in it. I have short circuited
this path.

Ghost hover inputs were squelched by consistently moving the ImGui
cursor to `0, 0` during a live resize. The OS will dispatch a cursor
positioning event once the resizing ends, restoring normal behavior.

### Screenshots
N/A

### Additional things
N/A

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2024-05-20 11:27:57 +02:00
WerWolv
666dc7dccb fix: Build when multisampling isn't available 2024-05-20 10:18:03 +02:00
WerWolv
a172e89620 fix: Don't restore toolbar items when they're empty 2024-05-20 10:16:14 +02:00
iTrooz
ecb9537c4e git: remove mock cache for Fedora because it seems to be duplicated with ccache 2024-05-20 01:35:12 +02:00
WerWolv
bba4cf9578 impr: Keep a safety backup of the last crash backup around 2024-05-19 23:13:46 +02:00
WerWolv
bfdb9b4019 impr: Allow views to opt out of having their open state saved 2024-05-19 21:51:55 +02:00
WerWolv
bad37d0940 fix: Crash when having path set in user folder settings page 2024-05-19 21:41:18 +02:00
WerWolv
62f5640678 patterns: Updated pattern language 2024-05-19 16:41:29 +02:00
WerWolv
71c1bcde0d feat: Added option to specify max file size to load into memory 2024-05-19 15:10:22 +02:00
SparkyTD
e9b492a287 lang: Added Hungarian translations (#1683)
### Problem description
ImHex didn't support Hungarian :(

### Implementation description
I translated ImHex to Hungarian :)

### Translation Coverage
| Plugin        | Percentage |
|---------------|------------|
| builtin       | 99%        |
| diffing       | 100%       |
| disassembler  | 100%       |
| hashes        | 95%        |
| script_loader | 100%       |
| ui            | 100%       |
| visualizers   | 100%       |
| windows       | 100%       |
| yara_rules    | 100%       |

### Additional Notes
There are four Hungarian "special" characters that fall outside the
default Unicode ranges loaded by ImHex, resulting in them being replaced
with the "�" character. These letters are Ő (U+0150), ő (U+0151), Ű
(U+0170) and ű (U+0171), all included in the Latin Extended-A Unicode
block.

The easy fix for this is to include the "Unicode Latin Extended-A" range
when loading the font glyphs in
[init_tasks.cpp:189](99abc4e78a/plugins/builtin/source/content/init_tasks.cpp (L189)).
This change would also unlock the full character range of Bosnian,
Croatian, Czech, Estonian, Latvian, Lithuanian, Maltese, Polish,
Romanian, Slovak, Slovene and Turkish. I can add the commit to this PR
if maintainers are okay with it. **EDIT:** Added a commit that loads
Latin Extended-A by default.

Also note that some words are longer than their English counterparts,
resulting in certain UI labels overflowing from their parent containers,
and being cut off. I might change some of the longer labels to be more
compact in the future, but the container size limitations will have to
be addressed eventually (e.g. with horizontal scrollbars).

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2024-05-19 14:33:33 +02:00
FireNX70
9b9b1aa6cc fix: Multisampling trying to use larger sample count than supported (#1670)
### Problem description
https://gitlab.freedesktop.org/mesa/mesa/-/issues/11135
It turns out LLVMpipe only supports 4x multisampling. Checking
GL_MAX_SAMPLES seems like the right thing to do.

### Implementation description
~~Right now, I only check GL_MAX_SAMPLES. Depending on the format, we
might need to check GL_MAX_INTEGER_SAMPLES. I don't know how likely it
is that you might want to use a different format in the future,
glGetInternalformativ might be a safer option to retrieve the max number
of samples we can use.~~

Ended up implementing it with glGetInternalformativ.

### Additional things
I guess I could merge the ```if```s at lines 95, 99 and 103 in
imgui_imhex_extensions.cpp while we're at it.

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2024-05-19 14:18:12 +02:00
David Mentler
2cb673fd81 impr: Stop rubber banding while resizing on macOS (#1690)
### Problem description
On macOS `glfwSetWindowSizeCallback` is invoked early during window
resizing, rendering a frame in that callback leads to wonky results as
the new framebuffer is swapped before the OS has the chance to actually
resize the window:


https://github.com/WerWolv/ImHex/assets/1068675/46336419-3fc2-4aa1-b16f-68b0c00e3584

### Implementation description
Window contents are redrawn only from `glfwSetWindowRefreshCallback`
during resizing, fixing the issue:


https://github.com/WerWolv/ImHex/assets/1068675/3acc5d4a-b2a5-42f0-9015-5e7172a027cf
2024-05-19 14:14:57 +02:00
WerWolv
d5eb6b5bbc impr: Added data size widget 2024-05-19 10:21:54 +02:00
WerWolv
1e48277566 impr: Removed [Project] prefix from recent project entries 2024-05-19 10:21:30 +02:00
WerWolv
ec748f4a64 impr: Allow full magic analysis, removed unidentified data from magic report 2024-05-19 10:21:02 +02:00
iTrooz
22f1713739 fix: actually generate coverage data when compiling/running program (#1686) 2024-05-18 20:35:49 +02:00
WerWolv
f0e135530a impr: Add warning about using fractional scaling with default font 2024-05-18 20:32:57 +02:00
WerWolv
125d6a3e2a fix: Settings not being written anymore after restart 2024-05-18 20:32:34 +02:00
WerWolv
d078f9d847 fix: Icon size being off when using fractional scaling with default font 2024-05-18 19:39:29 +02:00
WerWolv
6b6a6ae5f0 impr: Added support for returning results from scripts 2024-05-18 12:57:29 +02:00
WerWolv
1d6676f059 fix: Empty tooltip showing when hovering over search bar in welcome screen 2024-05-18 11:58:25 +02:00
WerWolv
1e91505e6e fix: .NET script loader not initializing correctly on macOS 2024-05-18 11:10:55 +02:00
WerWolv
9e2f228d9a fix: Providers not being closable 2024-05-17 23:51:34 +02:00
WerWolv
7a1d163450 fix: Insert mode cursor not being visible 2024-05-17 23:51:26 +02:00
WerWolv
22e717d778 fix: Don't capture the editor pointer by reference 2024-05-17 23:19:28 +02:00
WerWolv
2546c042dc fix: Crash when clicking on Advanced search in find popup 2024-05-17 23:16:49 +02:00
WerWolv
b54f46de30 fix: Crash when setting selection in a hex editor instance without provider 2024-05-17 22:43:35 +02:00
WerWolv
94bc279bd8 impr: Improved colors of toggle switches 2024-05-17 22:20:56 +02:00
WerWolv
2f7c2e79d2 impr: Remove ugly dark edges around light theme backdrop image 2024-05-17 22:18:44 +02:00
WerWolv
2ed5381f5a impr: Make menu bar items collapse less quickly 2024-05-17 22:14:15 +02:00
WerWolv
964d98dd7b impr: Remove frame borders in more cases 2024-05-17 22:05:32 +02:00
WerWolv
0571dae9b7 impr: Added frame borders in light theme 2024-05-17 21:58:16 +02:00
WerWolv
563bf78f03 impr: Allow providers to be closed quicker after being opened 2024-05-17 21:56:43 +02:00
WerWolv
cf480d95db build: Updated dependencies 2024-05-17 21:08:54 +02:00
iTrooz
44331506b2 test: Add code coverage support with CodeCov (#1681) 2024-05-17 19:08:22 +00:00
WerWolv
f6953fd829 impr: Merge in script loader structure improvements from python branch 2024-05-17 21:01:35 +02:00
WerWolv
663b99ed64 impr: Remove border from (?) hover button 2024-05-17 20:47:22 +02:00
WerWolv
0ef3be1851 fix: Look of some buttons and text fields with frame borders turned on 2024-05-17 20:38:30 +02:00
WerWolv
0453a23b12 impr: Cleanup .NET script library and API 2024-05-17 20:38:30 +02:00
WerWolv
7a14e3dac4 fix: Wayland error discarding build errors with older GLFW versions 2024-05-17 20:22:55 +02:00
WerWolv
275774a10a fix: C# OnLoad method not being run correctly 2024-05-17 09:27:00 +02:00
WerWolv
a6277533e8 impr: Better Intel GPU log warning 2024-05-17 09:26:41 +02:00
WerWolv
1426424899 fix: Window scaling defaulting to 1.0x instead of Native 2024-05-17 09:26:28 +02:00
WerWolv
85fa1b2122 fix: Log spam on Wayland 2024-05-17 09:26:13 +02:00
WerWolv
c28522b7ef fix: Settings sometimes being reset on shutdown 2024-05-16 19:00:31 +02:00
WerWolv
d90a04990b fix: Section button tooltips being visible even when not hovering buttons 2024-05-15 18:31:27 +02:00
WerWolv
027ff793ed fix: Icon text input boxes being wider than expected 2024-05-15 18:27:09 +02:00
WerWolv
c69d3bc7f4 fix: Visual glitches with highlights and selections in the hex editor view 2024-05-15 18:27:09 +02:00
WerWolv
ca17054a1e impr: Store settings and achievements immediately 2024-05-15 18:27:09 +02:00
WerWolv
6a9e07729f impr: Make pattern data filter behave more intuitively 2024-05-15 18:27:09 +02:00
iTrooz
ceeda6de3b doc: remove hex.builtin.provider.memory name (#1675) 2024-05-14 12:17:36 +00:00
iTrooz
17ab059b12 fix: fix Pattern::callUserFormatFunc() (previously Pattern::formatDisplayValue() with 3 args) sharing cache with Pattern::getFormattedValue() (#1674) 2024-05-14 09:26:34 +00:00
WerWolv
dedd99f30c patterns: Updated pattern language 2024-05-12 23:19:59 +02:00
WerWolv
add94c5926 fix: Loading of custom data processor nodes 2024-05-12 23:19:39 +02:00
WerWolv
a239edc759 fix: Locking layout not working correctly 2024-05-12 23:19:29 +02:00
iTrooz
ff569417fc test: Add plcli integration tests (#1671) 2024-05-12 00:19:20 +00:00
iTrooz
240bb299f0 fix: Fix CI failure with ImGui::SetTooltip() (#1672) 2024-05-11 21:52:33 +02:00
iTrooz
e2dd12416c git: run CI on tests/** branches 2024-05-11 21:42:27 +02:00
SparkyTD
2a726c7136 fix: TextEditor line numbers were still partially rendered despite mShowLineNumbers being set to false (#1669)
### Problem description
TextEditor line numbers were still partially rendered despite
mShowLineNumbers being set to false

### Implementation description
I wrapped the line no. rendering code in `if (mShowLineNumbers) { ...
}`.

### Screenshots
Before:

![image](https://github.com/WerWolv/ImHex/assets/45818400/58a2cfdd-1ee0-484b-ba05-6e886ad4fd65)

After:

![image](https://github.com/WerWolv/ImHex/assets/45818400/5d204e2b-12a5-4fc9-bcfc-da6b8e6359e1)
2024-05-11 18:11:14 +02:00
SparkyTD
62aea46c61 impr: Ensure that Text Editor's cursor blink state is never invisible after a keyboard event (#1664)
### Problem description
By default, the cursor's blinking cycle is independent from user
actions, which feels unconventional while editing pattern code. This
change ensures that the blinking cycle is reset, and the cursor is made
visible every time the editor receives a keyboard event like character
entry, or arrow navigation.


### Implementation description
I moved the hard-coded blink timing numbers to their dedicated static
constant fields since now they are referenced from multiple different
places.

I added the function `void ResetCursorBlinkTime()` to `TextEditor.cpp`
that will reset the blink cycle to `currentMillis() -
sCursorBlinkOnTime`, ensuring that the cursor is visible. This function
is called for every keyboard and mouse click event.

### Screenshots
Before:


https://github.com/WerWolv/ImHex/assets/45818400/668c6802-79a3-450b-80d3-d6abf2ce27be

After:


https://github.com/WerWolv/ImHex/assets/45818400/ee7f60e0-a75f-416d-b86d-8d12b5cdadf2

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2024-05-11 15:58:55 +02:00
SparkyTD
09bffb6745 impr: Add a link to the "Find" view in the search popup (#1665)
### Problem description
This PR adds a shortcut link on the Search (Ctrl+F) popup to the more
advanced "Find" view that is normally accessible at the `View > Find`
menu.

### Implementation description
I added a simple `ImGuiExt::IconHyperlink` link to the `draw()` function
of the `PopupFind` class to display the hyperlink. Clicking the link
will open the Find view, bring it into focus and close the current
popup.

### Screenshots
Before:

![image](https://github.com/WerWolv/ImHex/assets/45818400/0961f594-0548-426a-8622-20093d4a165e)

After:

![image](https://github.com/WerWolv/ImHex/assets/45818400/d40d78f4-1a5d-4bf6-97a4-ff7ab40d0cef)


### Additional things
- Localization keys were added to all .json files, but only `en_US` is
populated for now.
2024-05-11 10:15:17 +02:00
SparkyTD
3c91cb09e3 fix: Crash caused by missing ImGui::BeginDisabled() (#1667)
### Problem description
Merging my previous PRs, #1660 and #1658 has resulted in a conflict
causing an application crash due to a missing `ImGui::BeginDisabled();`
in the `PopupSelect` class. Specifically, none of the code related to
offset validation made it into the final merge. This PR fixes the crash
by reintroducing the deleted lines.

### Additional things
The nightly release build seems to be unaffected by the crash, most
likely because ImGui's `DisabledStack` assertions are only enforced in
Debug mode. The offset validation was still missing before this fix.
2024-05-11 00:52:43 +02:00
WerWolv
881a379fb4 fix: Compile error due to un-unpacked expected value 2024-05-10 23:02:39 +02:00
WerWolv
90a67af887 impr: Added better error messages to intel hex and motorola srec providers 2024-05-10 23:01:36 +02:00
WerWolv
d727100304 impr: Added tooltips for section view and export buttons 2024-05-10 22:54:55 +02:00
WerWolv
543fcf5447 impr: Make in variable values persistent between parser runs again 2024-05-10 22:51:53 +02:00
WerWolv
e9b140b75c impr: Make out variable values selectable and copyable in pattern editor 2024-05-10 22:41:12 +02:00
WerWolv
92a9843ef7 patterns: Updated pattern language 2024-05-10 22:40:53 +02:00
WerWolv
12528d6e6e fix: Edit -> Jump To -> Current Pattern not always resetting request correctly 2024-05-10 22:18:21 +02:00
WerWolv
8fae55487a fix: Closing providers not clearing selection correctly 2024-05-10 22:10:59 +02:00
SparkyTD
973af4650c impr: Convert all hex editor popups to floating, movable windows (#1658)
### Problem description
In previous versions of ImHex, all tool windows were implemented as
static popups fixed in the upper left position of the hex view. This PR
refactors all tool popups to use floating windows that can be dragged
around by the user, or closed with a dedicated close button on the title
bar. These popup also support a stylable transparency when the user is
not hovering their mouse over the window.

### Implementation description
I rewrote the logic in `ViewHexEditor::drawPopup()` to use a custom
`ImGuiExt::BeginHoveringPopup` function for rendering the popup windows.
This new function is an almost exact replica of the built-in
`ImGui::BeginPopupModal`, except it does also displays the default
window title bar with a close button.

A second custom function, `ImGuiExt::PopupTitleBarButton` was also added
for rendering small icon-based buttons into the title bar of the parent
popup window. This new function was used to implement an optional
"Pinning" feature that individual popup implementations can specify. If
a window is pinned, it won't close automatically when its main action is
executed. For example, the "Select" button on the Select dialog will
close the popup by default, unless the window is pinned.

### Screenshots
Popup dialogs before:

![image](https://github.com/WerWolv/ImHex/assets/45818400/7c253181-8284-4076-a066-089403554f0f)

Popup dialogs after:


https://github.com/WerWolv/ImHex/assets/45818400/99d1a628-8ac1-40ac-9146-9062091bb0db



### Additional things
- When the user stops hovering their mouse over a popup window, it
becomes semi-transparent, making it easier to see the content behind it
- This PR also introduces the `styles.imhex.popup-alpha` style, making
the transparency effect configurable, including the ability to disable
the effect completely by setting `popup-alpha` to `1.0`.
- Fixed a bug that caused some popup windows to ignore the Enter and the
KeypadEnter keys. With this PR, all tool windows will execute their main
action when the user presses either one of the two Enter keys, and will
also close automatically unless the window is pinned.

### Possible changes and improvements
- Should the transparency effect be disabled if a window is pinned?
- Should the transparency factor be modifiable on the Settings/Interface
page?
- A keyboard shortcut could be added for quickly pinning / unpinning the
current window.
- Can the pin icon stay on the left, or should it be moved next to the
close button, with a similar circular background?

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
2024-05-10 21:21:19 +02:00
SparkyTD
5f192d5dc7 impr: Don't move hex editor scroll position when jumping to address that's on-screen (#1660)
### Problem description
This PR offers two improvements:
1) When selecting / jumping to an offset that falls within the current
viewport of the scroll view, the scroll offset will no longer force the
selected byte to the top of the view. Instead, the scroll offset will
only be changed if the selected byte is outside the current view.

2) In case a wrong offset is entered into the Select or Goto dialog
(e.g. and offset beyond EoF), the dialog's button will be disabled.

### Implementation description
For the first change, I modified the logic that recalculates the
`m_scrollPosition ` based on the current byte offset.

For the second change, I added validation logic to both popups to ensure
that the entered offsets are valid (using `provider->getActualSize()`).
In case of the Select popup, I wrapped the button into an
`ImGui::Begin/EndDisabled` to enforce the validation check.
2024-05-10 21:20:10 +02:00
WerWolv
ec39546fed patterns: Updated pattern language 2024-05-10 11:14:53 +02:00
SparkyTD
ea0cafa229 fix: Not being able to close certain modal popups with the close button on the title bar (#1659)
### Problem description
When the close button is clicked, `ImGui::BeginPopupModal()` sets the
bool passed into the second parameter (p_open) to false. However, the
closing logic did not take this into account, making it difficult to
actually close modal popups.

For example, closing the "Export pattern File" modal took several clicks
on the "X" button, now it closes instantly.

### Implementation description
I added an additional check for the `open` variable being `false` in the
logic that checks the closing condition.
2024-05-09 17:49:31 +02:00
WerWolv
978fa17932 impr: Make accept pattern popup open faster and close correctly 2024-05-08 23:54:09 +02:00
WerWolv
6602e800ac fix: Make sure texture multisampling framebuffer is being unbinded in all cases
#1653
2024-05-08 23:08:53 +02:00
WerWolv
fdf9209605 build: Updated ImGui to v1.90.6 2024-05-08 22:56:20 +02:00
WerWolv
8a3739ee1c impr: Display background scripts in about page 2024-05-08 22:30:53 +02:00
WerWolv
89f360d1a7 fix: Texture multisampling being used on OpenGL < 3.2
#1653
2024-05-08 22:09:47 +02:00
WerWolv
d7ddf991a9 fix: Missing includes 2024-05-08 21:44:30 +02:00
WerWolv
19c02be673 impr: Only store paths with forward slashes in project files
Fixes #1657
2024-05-08 21:30:20 +02:00
SparkyTD
adbcc48de7 fix: Multiple file reload popups stacking on top of each other (#1654)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
This PR aims to address #1645 that caused the built in file provider's
change monitor to trigger the notification popup dialog multiple times
in a row after multiple external file changes.

### Implementation description
I added an additional boolean field
`m_changeEventAcknowledgementPending` that tracks whether there are any
pending or unacknowledged change notification dialogs to prevent further
dialogs from being opened. The flag is only reset to its initial value
once the user has acknowledged the first `PopupQuestion` dialog.

Since the file is reloaded only after the user clicks 'Yes', it is
unnecessary to ensure that only the latest popup is acknowledged.
2024-05-07 23:43:20 +02:00
WerWolv
a5eb031401 fix: Pattern data view rendering of bitfields within bitfields being broken 2024-05-07 23:32:51 +02:00
WerWolv
10351c5bdc fix: Text editor cursor not showing up anymore 2024-05-07 23:32:27 +02:00
WerWolv
5bc60d4b63 build: Updated dependencies 2024-05-07 23:32:12 +02:00
WerWolv
32a659a477 fix: Command palette losing focus when pressing Alt
Fixes #1651
2024-05-04 21:30:21 +02:00
WerWolv
40c4dbc20e impr: Make main menu bar not collapse completely when there's not enough space 2024-05-04 21:23:18 +02:00
WerWolv
f2b4e49ff3 fix: Crash when loading oobe screen 2024-05-04 19:54:57 +02:00
WerWolv
39dd67af78 patterns: Updated pattern language 2024-05-03 21:57:57 +02:00
WerWolv
337ec6bca6 impr: Better OpenGL texture load error messages 2024-05-03 21:41:02 +02:00
WerWolv
2994e69c08 impr: Refactor GLFW window hints into individual window files 2024-05-03 21:39:31 +02:00
WerWolv
49987b8793 impr: Indent license information in about page slightly 2024-05-03 21:38:35 +02:00
WerWolv
0f5e125992 impr: Added back multisampling with proper detection logic 2024-05-03 19:27:12 +02:00
WerWolv
57857559f5 fix: Disable texture multisampling for now as it causes issues on certain platforms 2024-05-03 14:02:43 +02:00
WerWolv
4eba620bee fix: Web version not starting due to unsupported texture multisampling 2024-05-02 09:40:39 +02:00
WerWolv
964a2e990e git: Fix broken .gitmodules 2024-05-01 20:51:44 +02:00
WerWolv
761bc941a8 impr: Make right click menus open faster 2024-05-01 20:50:35 +02:00
xtex
aa5a3ed080 lang: Refactored langtool, updated chinese translation (#1623)
- Better argument parsing
- Allow processing all language folders at the same time
- Allow an optional reference language when translating
- Save translations on KeyboardInterrupt
- Fixes a ooold input issues by importing readline
(https://github.com/kovidgoyal/kitty/issues/6560)
- Add untranslate mode to remove translations by a key regex

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2024-05-01 20:49:55 +02:00
daver32
6fbbf899b0 fix: Frame rate getting unlocked when inputs are being processed (#1632)
### Problem description
The framerate limiter doesn't work when inputs are being sent (eg mouse
cursor moving over the window), because `glfwWaitEventsTimeout` returns
early when it encounters an event.

### Implementation description
I made it sleep for the remaining time when that happens.
2024-05-01 20:48:41 +02:00
WerWolv
1df0eea6c6 impr: Added support for SVG loading, improved texture loading API 2024-05-01 20:36:10 +02:00
WerWolv
ef99e9d6f8 fix: Selectable text behaving weirdly when selecting 2024-04-29 21:20:54 +02:00
WerWolv
a685d2e97d impr: Make integer node accept math expressions 2024-04-29 21:20:38 +02:00
WerWolv
df04acc1b9 impr: Allow specifying buffer size in integer to buffer cast node 2024-04-29 21:20:22 +02:00
WerWolv
f510faa1da impr: Make integer, float and buffer visualizers selectable, added more radixes to integer node 2024-04-29 21:19:54 +02:00
WerWolv
3ad2c74519 impr: Make right click menu in data processor feel less sluggish 2024-04-29 20:43:25 +02:00
WerWolv
0e58204501 impr: Remove underline from hyperlinks if they're not hovered 2024-04-29 20:06:50 +02:00
WerWolv
f847807df5 fix: Buffer display data processor node being way too wide
#1644
2024-04-29 19:48:02 +02:00
WerWolv
81982aa821 impr: Make windows always fully opaque when they're not docked 2024-04-27 20:19:45 +02:00
WerWolv
08fc393451 build: Get rid of liblibimhex 2024-04-27 20:19:26 +02:00
Nora
a7033b68f7 feat: Support DWM immersive dark mode on Windows (#1636)
### Problem description
Implements support for DWM immersive dark mode.  
Closes #1635.

### Implementation description
Uses the DwmSetWindowAttribute API to enable this feature.

Documentation can be found
[here](https://learn.microsoft.com/en-us/windows/apps/desktop/modernize/apply-windows-themes#enable-a-dark-mode-title-bar-for-win32-applications).

### Screenshots
Before:

![image](https://github.com/WerWolv/ImHex/assets/51166756/a2be204f-aa2d-44d7-8628-643a903d6679)

After:

![image](https://github.com/WerWolv/ImHex/assets/51166756/f6c9ab41-c811-45f7-826f-401dd712674b)

### Additional things
Nothing.
2024-04-27 10:03:44 +02:00
WerWolv
3794aa425d feat: Display destination address in goto popup 2024-04-23 23:26:58 +02:00
WerWolv
a1ea8dfd84 fix: Build issue again when GLFW_WAYLAND_APP_ID isn't defined 2024-04-23 21:03:04 +02:00
WerWolv
79e1df1af2 fix: Exporting selection doesn't export last byte 2024-04-23 21:02:16 +02:00
WerWolv
fd61e757f0 impr: Make unsaved changes popup behave more like in other applications 2024-04-23 21:02:16 +02:00
WerWolv
7ec245925a fix: Lockup when changing themes in some cases 2024-04-23 21:02:16 +02:00
WerWolv
f913cd742f impr: Added new ImHex Banners 2024-04-23 21:02:16 +02:00
Nik
cc7a0db35c fix: Build issue when GLFW_WAYLAND_APP_ID isn't defined 2024-04-21 17:04:56 +02:00
Integral
6f11873d7e fix: Missing window icon under wayland (#1633)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
When running ImHex under Wayland, the window icon is missing.

### Implementation description
Setting
[```GLFW_WAYLAND_APP_ID```](https://www.glfw.org/docs/latest/group__window.html#gafbf1ce7a4362c75e602a4df9e1bdecd3)
to fix the issue.

### Screenshots
Before:

![Screenshot_20240420_162144](https://github.com/WerWolv/ImHex/assets/71180087/3318970f-6ed7-4161-b686-c2eaa28a0739)


After:

![Screenshot_20240420_161920](https://github.com/WerWolv/ImHex/assets/71180087/e9e35fb6-e3c1-44a8-b7a5-b145dfe225d9)


### Additional things
<!-- Anything else you would like to say -->
2024-04-21 12:24:20 +02:00
WerWolv
4b1b52caf0 fix: Cell highlighting in hex editor view overlapping at non-integer scale factors 2024-04-13 15:34:12 +02:00
WerWolv
e9ebfe36b0 build: Updated ImGui to v1.90.5 2024-04-12 22:56:10 +02:00
WerWolv
43149498cf fix: Main window being hard to resize when bytes are selected in the hex editor view 2024-04-12 22:55:54 +02:00
FireNX70
43070a1f5b fix: Diff table in diffing view displaying incorrect end address (#1627)
Trivial fix for #1617 .
2024-04-11 23:49:58 +02:00
WerWolv
f135bd86ac patterns: Updated pattern language 2024-04-11 22:59:09 +02:00
WerWolv
0bd8c5d115 fix: Color vector in 3D visualizer not getting assigned the correct size 2024-04-10 22:53:51 +02:00
WerWolv
9de10df90d fix: Store hanging when updating all entries in some cases 2024-04-10 22:52:21 +02:00
WerWolv
46ed6e2487 patterns: Updated pattern language 2024-04-10 22:52:06 +02:00
WerWolv
d81d409051 impr: Modernize ImHex logo 2024-04-10 21:05:38 +02:00
WerWolv
5f75c8684f impr: Better UI for the case when no plugins could be loaded 2024-04-10 21:04:57 +02:00
WerWolv
5d08499d20 impr: Use sidebar for settings categories instead of tabs 2024-04-10 19:55:37 +02:00
WerWolv
4115184952 patterns: Updated pattern language 2024-04-05 18:49:40 +02:00
WerWolv
e6a14977b9 fix: Highlight and tooltip flickering when hovering over highlighted patterns 2024-04-05 18:49:19 +02:00
WerWolv
a449f7a5e3 build: Updated libwolv 2024-03-30 13:36:02 +01:00
WerWolv
51302cfd88 build: Lock libmagic to latest release in M1 macOS docker file 2024-03-30 11:03:45 +01:00
WerWolv
696612385a fix: Use std::ranges::find instead of std::ranges::contains for now 2024-03-29 16:34:01 +01:00
WerWolv
edf047dde8 impr: Cleanup bookmark UI 2024-03-29 15:40:15 +01:00
WerWolv
166cd6c426 patterns: Updated pattern language 2024-03-29 15:38:13 +01:00
WerWolv
51010096bb feat: Added provider information to search bar hover tooltip 2024-03-29 15:38:03 +01:00
WerWolv
4e5a7ba483 fix: Closing providers still appearing in the provider list 2024-03-29 15:37:34 +01:00
WerWolv
92803c1536 feat: Added simple insert mode to hex editor 2024-03-29 13:22:28 +01:00
RoboSchmied
cc593fb6c4 fix: Misspelling of Endianness (#1609)
### Problem description
fix 40 typos

### Implementation description
`endianess` => `endianness`

Signed-off-by: RoboSchmied <github@roboschmie.de>
2024-03-28 22:25:28 +01:00
York Waugh
aeabc0c436 lang: Updated Simplified Chinese translation (#1610)
Thank you for an outstanding program! I have updated the Simplified
Chinese translation. Hope you can adopt it.
2024-03-28 22:24:51 +01:00
Kihau
32ad8ddb53 build: Added dependency download script for OpenSUSE Tumbleweed (#1612)
## Add dependency download script for OpenSUSE Tumbleweed.

### Testing
After installing the dependencies, I have managed to successfully
compile the project as described in the building instructions:
https://github.com/WerWolv/ImHex/blob/master/dist/compiling/linux.md

I have tested the script on a fresh installations of the OpenSUSE:
- Tumbleweed Server
- Tumbleweed Generic Desktop

### Note
Dependencies added in the script are based off of scripts for other
Linux distributions.
Because of that, some download dependencies might not be necessary (or
could be already included by other packages), so it is very much
possible that some of them could be removed.
2024-03-28 22:24:10 +01:00
WerWolv
f084bc4147 fix: View registers causing crashes when being deleted 2024-03-28 22:21:00 +01:00
WerWolv
cb1dcc2c9f impr: Disable achievement popups if tutorial is skipped 2024-03-28 22:15:48 +01:00
WerWolv
8030de7af2 fix: Icons not being fractionally scaled anymore 2024-03-28 22:15:30 +01:00
WerWolv
dd5ddbcc0f fix: Settings being overwritten sometimes on crash 2024-03-26 19:49:10 +01:00
WerWolv
f587710d1c fix: Multiple memory corruption issues 2024-03-26 19:49:10 +01:00
WerWolv
99142525b6 patterns: Updated pattern language 2024-03-26 19:47:45 +01:00
WerWolv
2d9ef1142d build: Updated dependencies 2024-03-26 19:47:39 +01:00
WerWolv
547169ea78 fix: Missing includes 2024-03-26 19:46:25 +01:00
WerWolv
8d08ab20ec fix: Added missing ImHex paths to about page 2024-03-26 19:18:34 +01:00
WerWolv
966a780432 impr: Updated contributors list 2024-03-25 21:02:55 +01:00
WerWolv
99abc4e78a fix: Unifont characters being scaled wrongly
Fixes #1616
2024-03-25 20:41:39 +01:00
WerWolv
ce1d581c3f fix: Settings values being uninitialized by default 2024-03-25 20:41:05 +01:00
WerWolv
b31ae6e690 impr: Optimize includes in logger 2024-03-25 20:37:19 +01:00
WerWolv
e984fde966 fix: Crash on some platforms due to empty main menu bar
#1600
2024-03-23 12:26:23 +01:00
WerWolv
5d0b474a7e build: Move renaming of the macOS bundle to the CI 2024-03-23 00:33:46 +01:00
WerWolv
d09f2c4f26 build: Fix creating the macOS bundle from within the M1 docker 2024-03-22 23:47:24 +01:00
WerWolv
dd20a16d3a git: Fix macOS bundle upload path 2024-03-22 22:35:44 +01:00
WerWolv
7d22b71e86 git: Fix bundle path for signing 2024-03-22 22:24:25 +01:00
WerWolv
567ccbfc3a build: Don't postprocess libimhex.dylib 2024-03-22 22:18:18 +01:00
WerWolv
ca40775678 git: Make sure CI bundles correct macOS bundle into dmg 2024-03-22 21:57:33 +01:00
WerWolv
4916e5542a fix: Splash screen being scaled incorrectly 2024-03-22 17:52:10 +01:00
WerWolv
ac8ec2b622 fix: Icons not being scaled correctly anymore 2024-03-22 17:52:00 +01:00
WerWolv
9b9f7e2a1d fix: Decompress functions not extracting full data
Thanks a lot to tocklime
2024-03-22 17:34:49 +01:00
WerWolv
28ea91e6c3 build: Move macOS rpath fixing to install step 2024-03-22 17:31:53 +01:00
WerWolv
0d58307e82 build: Fix bundling issues on macOS 2024-03-22 17:24:44 +01:00
WerWolv
c8ca84ede9 fix: Prevent view providers from pointing to themselves and being saved as recent provider
#1607
2024-03-22 00:16:28 +01:00
WerWolv
ed2939c39e impr: Better UI and UX for the hex editor footer 2024-03-21 23:50:34 +01:00
WerWolv
d36bd253e8 feat: Allow shift-selecting multiple find view occurrences 2024-03-21 23:50:13 +01:00
WerWolv
4615dce0a9 build: Try fixing packaging issues with macOS bundles 2024-03-21 21:56:27 +01:00
WerWolv
7ce8aa3638 impr: Added better error logging in script loader init 2024-03-21 21:39:29 +01:00
WerWolv
9236b92dc1 fix: Memory leak when closing ImHex 2024-03-21 21:39:29 +01:00
Nobutaka Mantani
05ffcab911 build: Added support patches for FreeBSD (#1584)
This pull request fixes build on FreeBSD. The changes are conditioned
with `#if defined(__FreeBSD__)` preprocessor macro and they should not
affect build for other operating systems.

---------

Co-authored-by: Nik <werwolv98@gmail.com>
Co-authored-by: iTrooz <hey@itrooz.fr>
2024-03-21 21:31:17 +01:00
WerWolv
61b9c0970b impr: Load unifont at correct size
Fixes #1604
2024-03-21 21:27:50 +01:00
paxcut
3b3701135f impr: Various fixes and an enhancement for the pattern editor (#1528)
Fixed console error messages using doc comment syntax highlights. Fixed
results of find not updating when march case was toggled. Fixed syntax
highlights of nested ifdefs. Fixed editor cursor blinks if OS focus goes
to another window. Fixed Highlights of "\\\"" was incorrectly handled.

---------

Co-authored-by: Nik <werwolv98@gmail.com>
2024-03-21 12:58:20 +00:00
iTrooz
f5987fde5a git: Fix MacOS packaging workflow in PRs (#1601)
Fix GeekyEggo/delete-artifact failing in PRs

https://github.com/GeekyEggo/delete-artifact/issues/25
2024-03-21 13:33:46 +01:00
iTrooz
e56b34f174 build: Mark tryDemangle as [[maybe_unused]] (#1606) 2024-03-21 13:33:23 +01:00
iTrooz
0fb43ccc2b fix: Use find_library() instead of find_file() to find system yara library (#1581)
Discord discussion:
https://discord.com/channels/789833418631675954/789840633414025246/1213564050848485427
2024-03-19 20:23:33 +01:00
WerWolv
48db4df028 build: Updated libromfs 2024-03-17 13:31:03 +01:00
WerWolv
86a0693081 fix: Crash when trying to open unopenable file 2024-03-17 13:20:02 +01:00
WerWolv
6295c1d0c3 feat: Added table pattern visualizer 2024-03-17 13:19:37 +01:00
WerWolv
35d29c8e30 patterns: Updated pattern language 2024-03-16 14:59:26 +01:00
WerWolv
ca78c4c2fc fix: Build errors when stacktrace headers are not present 2024-03-16 14:59:05 +01:00
WerWolv
f276409cde patterns: Updated pattern language 2024-03-16 10:03:23 +01:00
WerWolv
682f7bee72 patterns: Updated pattern language 2024-03-15 21:11:36 +01:00
WerWolv
43bec6a636 fix: Make sure pattern runtime is always properly configured 2024-03-15 21:08:03 +01:00
WerWolv
6eb9c750a7 fix: File open achievement not triggering when dropping a file onto ImHex 2024-03-15 21:07:45 +01:00
WerWolv
31c93c8c5c impr: Properly clear pattern editor when closing last provider 2024-03-15 21:07:21 +01:00
WerWolv
5aa1046541 fix: Potential crash when log file is unavailable 2024-03-15 21:06:47 +01:00
WerWolv
0f4504476a fix: File changed popup showing up when saving memory mapped file 2024-03-15 17:57:12 +01:00
WerWolv
3897245a7e fix: Control characters ending up in log files 2024-03-15 17:57:12 +01:00
WerWolv
373db3de95 fix: Potential crash on Linux when loading external libraries 2024-03-15 17:54:09 +01:00
WerWolv
a1437658af impr: Generate more useful stack traces on Linux 2024-03-15 17:53:12 +01:00
WerWolv
f4ec69021d impr: Manually implement VSync because GPU manufacturers are terrible at writing drivers 2024-03-14 21:18:57 +01:00
WerWolv
6012f20fb3 fix: Remove unused member variable in script loader provider wrapper 2024-03-14 20:56:08 +01:00
WerWolv
95da957f73 impr: Try to improve framerate limiting once more 2024-03-14 19:56:09 +01:00
WerWolv
642722bdb1 build: Enable cimgui on web builds again 2024-03-14 18:58:39 +01:00
WerWolv
cbc31f3c18 feat: Added short forms for commonly used commands 2024-03-14 18:24:31 +01:00
WerWolv
f2309ba079 impr: Make export selection task cancelable 2024-03-14 18:24:01 +01:00
WerWolv
246ed15d6d fix: Infinite loop when exporting selection to file 2024-03-14 17:52:44 +01:00
WerWolv
88756c83c7 fix: Right clicking reverse selected regions deselecting it 2024-03-14 17:49:46 +01:00
WerWolv
cf320266df fix: Linux build issues 2024-03-14 17:49:04 +01:00
WerWolv
47e7e80afe fix: Various issues with the virtual file system 2024-03-14 13:26:53 +01:00
WerWolv
0d880babfb fix: Advanced data information not showing up correctly 2024-03-13 22:39:21 +01:00
WerWolv
28ba34f1bf fix: Diffing option popup flickering when opening 2024-03-13 22:39:00 +01:00
WerWolv
e786cb8180 feat: Added option to create menu items from scripts 2024-03-13 19:50:05 +01:00
WerWolv
458584d778 feat: Added logger module to script loader 2024-03-13 19:49:48 +01:00
WerWolv
2c711ea206 feat: Load additional libraries from ImHex's /lib folder 2024-03-13 19:49:04 +01:00
WerWolv
7b25be51a5 fix: Base address issues with the data inspector and copy as array option
Fixes #1595
2024-03-13 16:38:44 +01:00
WerWolv
45b05a4846 fix: Denying server contact leaving crash upload option enabled
Fixes #1594
2024-03-13 09:41:04 +01:00
WerWolv
6972736abf fix: Remaining build issues 2024-03-13 09:40:37 +01:00
WerWolv
3798654f92 fix: Unix build issues with dladdr 2024-03-13 08:38:40 +01:00
WerWolv
fdf01dfb50 impr: Get rid of cimgui shared library by hooking pinvoke handler 2024-03-12 23:17:49 +01:00
WerWolv
876f091244 build: Make cimgui a shared library again 2024-03-12 19:44:21 +01:00
WerWolv
2988561f01 build: Try fix building issues with web build and Fedora 2024-03-12 19:09:01 +01:00
WerWolv
fbfc319ac1 build: Make dotnet script loader initialize properly with newer SDK version 2024-03-12 19:08:14 +01:00
WerWolv
9b1417f32d fix: ImHex using a ton of CPU power on Linux 2024-03-12 09:06:58 +01:00
WerWolv
c727762940 impr: Added AxCut to the about page 2024-03-11 21:26:03 +01:00
WerWolv
e3565d5bcb feat: Added support for creating views and drawing ImGui elemts from C# 2024-03-11 21:09:56 +01:00
WerWolv
a3f550c585 fix: Toasts not printing their message to the console correctly 2024-03-11 21:09:56 +01:00
WerWolv
c610d804b1 build: Added cimgui 2024-03-11 21:09:56 +01:00
WerWolv
3d592dbc79 fix: Highlighting not updating correctly when changing bookmark region
Fixes #1591
2024-03-11 14:00:52 +01:00
WerWolv
0186f2f456 feat: Added support for adding custom providers through C# 2024-03-10 22:05:26 +01:00
WerWolv
d817a813b0 fix: Update all task progress not increasing correctly 2024-03-10 18:59:35 +01:00
WerWolv
1d219ba511 build: Updated libwolv 2024-03-10 17:32:46 +01:00
WerWolv
285afb6d4b build: Updated libwolv 2024-03-10 15:58:57 +01:00
WerWolv
ca3708df71 fix: std::bind_front not supporting member functions everywhere 2024-03-10 15:40:32 +01:00
WerWolv
c2aafb14c2 fix: View provider not saving top-level data to project file 2024-03-10 15:32:01 +01:00
WerWolv
d4d1acb555 feat: Added --verbose command line option to enable debug logs 2024-03-10 15:22:14 +01:00
WerWolv
d1a59f8c1b fix: View provider not correctly saving its state to a project file 2024-03-10 15:17:15 +01:00
WerWolv
2fd17f97b6 build: Updated libwolv 2024-03-10 14:38:28 +01:00
WerWolv
45a3bdffe0 impr: Load small files into memory, open larger files as read-only by default
#841, #1585
2024-03-10 14:31:39 +01:00
iTrooz
f050c69ccd fix: fix ui plugin linking to pl when libimhex already does it (#1583) 2024-03-03 15:31:40 +00:00
WerWolv
c31a2551f1 git: Update release actions 2024-03-02 17:42:19 +01:00
WerWolv
90e93492a7 fix: Updater not working correctly on Windows 2024-03-02 17:42:02 +01:00
WerWolv
54266bf63b fix: Remove debug popup function in release mode to avoid build errors 2024-03-02 14:23:52 +01:00
WerWolv
ba12f7aec9 impr: Added testers to About screen 2024-03-02 11:57:30 +01:00
WerWolv
deafb6fe08 build: Allow precompiled headers to be turned off 2024-03-02 11:51:33 +01:00
WerWolv
091be1440a build: Added option to disable precompiled headers 2024-03-02 11:28:24 +01:00
WerWolv
030aee17f5 build: Disable precompiled headers in plugins again 2024-03-02 10:57:51 +01:00
WerWolv
bbbf836374 fix: Race condition when downloading multiple elements from the content store 2024-03-02 10:57:37 +01:00
WerWolv
f1b91ef360 fix: MIME based auto loading not working correctly 2024-03-02 10:57:13 +01:00
WerWolv
f6c59b456f impr: Move selection information to the top of the hex editor footer 2024-03-02 09:52:40 +01:00
WerWolv
8f3f941600 impr: Prevent ImHex from getting stuck in an infinite crash loop 2024-03-02 09:52:09 +01:00
WerWolv
e561f49e80 impr: Make welcome screen background look more interesting 2024-03-01 20:57:07 +01:00
WerWolv
2ff884fd11 feat: Replaced debug button functions with full debug menu 2024-03-01 20:56:46 +01:00
WerWolv
296af748ee fix: Platform window not being updated when recovering from a crash 2024-03-01 20:55:03 +01:00
WerWolv
0cb10fcc34 fix: Endless loop when throwing exception in deferred tasks 2024-03-01 20:54:27 +01:00
WerWolv
4a67ea0b29 patterns: Updated pattern language 2024-03-01 18:38:11 +01:00
WerWolv
8e94acc98f fix: Compile error 2024-03-01 18:37:28 +01:00
WerWolv
39cda3764b patterns: Updated pattern language 2024-03-01 18:23:45 +01:00
iTrooz
97f5175c84 impr: Better recovery from exceptions thrown in main thread (#1577)
This PR improves many things which can be seen by the commit name, but
the most important thing is the addition of a popup telling the user
when an exception is thrown


![image](https://github.com/WerWolv/ImHex/assets/42669835/db796416-9cce-4aa5-ad60-c22f05b5fc73)
2024-03-01 18:21:15 +01:00
WerWolv
78f8e5055e impr: Show hint if advanced data information section doesn't yield any result 2024-03-01 16:51:02 +01:00
WerWolv
735d896260 git: Run workflows on release branches 2024-02-29 22:28:29 +01:00
WerWolv
cb7a6596ba patterns: Updated pattern language 2024-02-29 22:23:34 +01:00
WerWolv
fdaa56fd86 build: Disable unknown pragmas warning 2024-02-29 21:49:36 +01:00
WerWolv
667b940feb fix: Build with precompiled headers for WebAssembly 2024-02-29 21:29:26 +01:00
WerWolv
bb3de7d510 fix: Build with precompiled headers on Linux 2024-02-29 21:15:51 +01:00
WerWolv
7bdde15796 build: Don't add defines to libimhex after precompiling headers 2024-02-29 20:39:14 +01:00
WerWolv
c412ba66d8 git: Updated compile instructions 2024-02-29 20:16:03 +01:00
WerWolv
dd62bee264 build: Added precompiled headers 2024-02-29 19:57:20 +01:00
WerWolv
f886eac7b5 build: Updated libwolv 2024-02-28 23:52:39 +01:00
WerWolv
623079ca40 fix: Pressing buttons while window is unfocused not working 2024-02-28 23:52:07 +01:00
WerWolv
ce9bd796d6 fix: Inserting bytes and resizing files not working correctly 2024-02-28 22:21:14 +01:00
WerWolv
d5f323a2cd feat: Allow workspaces to be deleted the same way as layouts
Fixed #1576
2024-02-28 22:10:48 +01:00
WerWolv
40592a93ac fix: MIME-based pattern loading not working correctly
Fixes #1574
2024-02-28 20:54:51 +01:00
WerWolv
dc1a5a860c fix: Buggy window detachment 2024-02-28 20:36:22 +01:00
WerWolv
f7b431902d fix: Make sure glfw waits properly on Wayland 2024-02-28 20:16:15 +01:00
WerWolv
686d47a59e fix: Frame limiting not working correctly on Linux 2024-02-28 18:48:01 +01:00
WerWolv
eaa4688182 fix: Crash when using CRC hashes 2024-02-27 22:39:18 +01:00
WerWolv
72645aa800 fix: Read-only file toast showing up for all providers 2024-02-27 20:20:28 +01:00
WerWolv
7044fc8004 fix: Import menu being disabled with read-only providers
Fixes #1573
2024-02-27 19:41:33 +01:00
Justus Garbe
9e8c780d66 fix: Use explicit string argument according to -Wformat-security on clang (#1572) 2024-02-27 19:07:44 +01:00
WerWolv
e1795d687f impr: Implement a better algorithm to determine if the frame content has changed 2024-02-27 18:55:18 +01:00
WerWolv
607f7cba8d fix: Yara rules not being read correctly in data information section 2024-02-27 18:01:30 +01:00
WerWolv
2572e23928 impr: Add better error handling when loading projects 2024-02-26 21:48:56 +01:00
WerWolv
60921031bd fix: Opening project files through the command line opening them as regular files 2024-02-26 21:43:28 +01:00
WerWolv
77550d902c feat: Added option to disable annotations in byte type graph 2024-02-26 21:41:43 +01:00
WerWolv
41935781fb fix: Build error due to use of localized strings 2024-02-26 21:13:57 +01:00
iTrooz
47362559ef tests: Add infrastructure for testing plugins (#1538)
This PR adds a test architecture to be able to test plugins

Main infrastructure done by @WerWolv

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
2024-02-26 20:51:08 +01:00
WerWolv
032ef0722d patterns: Updated pattern language 2024-02-26 20:49:42 +01:00
WerWolv
6e32f03a6b feat: Added plain text and similar bytes regions to byte types diagram 2024-02-26 20:49:35 +01:00
WerWolv
5731dcf135 impr: Make hex editor minimap rows stay a fixed height 2024-02-26 20:49:15 +01:00
445 changed files with 74041 additions and 6309 deletions

5
.github/codecov.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
comment: false
ignore:
- "lib/third_party" # Third party libraries should be ignored
- "lib/external" # Our own libraries should be checked in their own repositories
- "tests" # https://about.codecov.io/blog/should-i-include-test-files-in-code-coverage-calculations/

View File

@@ -2,7 +2,10 @@ name: Build
on:
push:
branches: ["*"]
branches:
- 'master'
- 'releases/**'
- 'tests/**'
pull_request:
workflow_dispatch:
@@ -73,7 +76,7 @@ jobs:
-DIMHEX_REPLACE_DWARF_WITH_PDB=ON \
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
..
- name: 🛠️ Build
run: |
cd build
@@ -104,7 +107,7 @@ jobs:
run: |
set -x
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
curl https://werwolv.net/downloads/mesa/MesaForWindows-x64-latest.7z -L -o mesa.7z
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
7z e mesa.7z
mv opengl32.dll build/install
@@ -150,15 +153,14 @@ jobs:
- name: ⬇️ Install dependencies
run: |
set -x
brew reinstall python || brew link --overwrite python
brew reinstall python || brew link --overwrite python || true
brew bundle --no-lock --file dist/Brewfile
rm -rf /usr/local/Cellar/capstone
- name: ⬇️ Install classic glfw
if: ${{! matrix.custom_glfw}}
run: |
brew install glfw
brew install glfw || true
- name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4
@@ -171,7 +173,7 @@ jobs:
with:
repository: glfw/glfw
path: glfw
# GLFW custom build (to allow software rendering)
- name: ⬇️ Patch and install custom glfw
if: ${{matrix.custom_glfw}}
@@ -211,21 +213,45 @@ jobs:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_INSTALL_PREFIX="./install" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
..
- name: 🛠️ Build
run: cd build && ninja package
run: cd build && ninja install
- name: ✒️ Fix Signature
run: |
set -x
cd build/install
mv imhex.app ImHex.app
codesign --remove-signature ImHex.app
codesign --force --deep --sign - ImHex.app
- name: 📁 Fix permissions
run: |
set -x
cd build/install
chmod -R 755 ImHex.app/
- name: 📦 Create DMG
run: |
set -x
mkdir bundle
mv build/install/ImHex.app bundle
cd bundle
ln -s /Applications Applications
cd ..
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64.dmg
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: macOS DMG${{matrix.suffix}} x86_64
path: build/*.dmg
path: ./*.dmg
macos-arm64-build:
runs-on: ubuntu-22.04
@@ -237,7 +263,7 @@ jobs:
uses: actions/checkout@v4
with:
submodules: recursive
- name: 📁 Restore docker /cache
uses: actions/cache@v4
with:
@@ -285,15 +311,15 @@ jobs:
path: out
- name: 🗑️ Delete artifact
uses: geekyeggo/delete-artifact@v4
uses: geekyeggo/delete-artifact@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: macos_arm64_intermediate
- name: ✒️ Fix Signature
run: |
set -x
cd out
mv imhex.app ImHex.app
codesign --remove-signature ImHex.app
codesign --force --deep --sign - ImHex.app
@@ -319,17 +345,15 @@ jobs:
if-no-files-found: error
name: macOS DMG arm64
path: ./*.dmg
# Ubuntu build
ubuntu:
strategy:
fail-fast: false
matrix:
include:
- name: Ubuntu
release_num: 22.04
- name: Ubuntu
release_num: 23.04
- release_num: 22.04
- release_num: 24.04
name: 🐧 Ubuntu ${{ matrix.release_num }}
runs-on: ubuntu-latest
@@ -384,9 +408,9 @@ jobs:
-DIMHEX_USE_GTK_FILE_PICKER=ON \
-DDOTNET_EXECUTABLE="dotnet" \
..
- name: 🛠️ Build
run: cd build && DESTDIR=DebDir ninja install
run: cd build && DESTDIR=DebDir ninja install
- name: 📜 Set version variable
run: |
@@ -421,7 +445,7 @@ jobs:
path: cache
key: appimage-ccache-${{ github.run_id }}
restore-keys: appimage-cache
- name: 🐳 Inject /cache into docker
uses: reproducible-containers/buildkit-cache-dance@v2
with:
@@ -507,9 +531,9 @@ jobs:
-DIMHEX_ENABLE_LTO=ON \
-DIMHEX_USE_GTK_FILE_PICKER=ON \
..
- name: 🛠️ Build
run: cd build && DESTDIR=installDir ninja install
run: cd build && DESTDIR=installDir ninja install
- name: 📜 Set version variable
run: |
@@ -557,14 +581,14 @@ jobs:
mock_release: rawhide
release_num: rawhide
mock_config: fedora-rawhide
- name: Fedora
mock_release: f40
release_num: 40
mock_config: fedora-40
- name: Fedora
mock_release: f39
release_num: 39
mock_config: fedora-39
- name: Fedora
mock_release: f38
release_num: 38
mock_config: fedora-38
- name: RHEL-AlmaLinux
mock_release: epel9
release_num: 9
@@ -625,11 +649,11 @@ jobs:
- name: ✒️ Modify spec file
run: |
sed -i \
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
-e '/%files/a %{_datadir}/%{name}/' \
-e 's/Version: VERSION$/Version: ${{env.IMHEX_VERSION}}/g' \
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
-e '/%files/a %{_datadir}/%{name}/' \
$GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
- name: 📜 Fix ccache on EL9
@@ -649,14 +673,6 @@ jobs:
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
EOT
- name: 📜 Setup Mock Cache
uses: actions/cache@v4
with:
path: /var/cache/mock
key: ${{ matrix.mock_release }}-mock-${{ github.run_id }}
restore-keys: |
${{ matrix.mock_release }}-mock
# Fedora cmake build (in imhex.spec)
- name: 📦 Build RPM
run: |

View File

@@ -2,7 +2,10 @@ name: Build for the web
on:
push:
branches: ["*"]
branches:
- 'master'
- 'releases/**'
- 'tests/**'
pull_request:
workflow_dispatch:
@@ -29,7 +32,7 @@ jobs:
uses: actions/cache@v4
with:
path: cache
key: web-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
key: web-cache-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🐳 Inject /cache into docker
uses: reproducible-containers/buildkit-cache-dance@v2

View File

@@ -90,7 +90,7 @@ jobs:
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
- name: ⬇️ Download artifacts from latest workflow
uses: dawidd6/action-download-artifact@v2
uses: dawidd6/action-download-artifact@v3
with:
github_token: ${{secrets.GITHUB_TOKEN}}
workflow: build.yml
@@ -119,7 +119,7 @@ jobs:
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip
- name: ⬆️ Upload everything to release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
with:
files: '*'

View File

@@ -2,9 +2,14 @@ name: "Unit Tests"
on:
push:
branches: [ master ]
branches:
- 'master'
- 'releases/**'
- 'tests/**'
pull_request:
branches: [ master ]
branches:
- 'master'
- 'releases/**'
workflow_dispatch:
jobs:
@@ -29,39 +34,51 @@ jobs:
restore-keys: ${{ runner.os }}-tests-build
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v4
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-tests-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update
sudo bash dist/get_deps_debian.sh
sudo apt install gcovr -y
- name: 🛠️ Build
run: |
set -x
mkdir -p build
cd build
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
-DIMHEX_OFFLINE_BUILD=ON \
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DIMHEX_ENABLE_UNIT_TESTS=ON \
-DIMHEX_ENABLE_PLUGIN_TESTS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \
-DIMHEX_OFFLINE_BUILD=ON \
..
make -j4 unit_tests
- name: 🧪 Perform plcli Integration Tests
run: |
cd lib/external/pattern_language
python tests/integration/integration.py ../../../build/imhex --pl
- name: 🧪 Perform Unit Tests
run: |
cd build
ctest --output-on-failure
# Generate report from all gcov .gcda files
- name: 🧪 Generate coverage report
run: |
gcovr --gcov-executable /usr/bin/gcov-12 -r . build --xml coverage_report.xml --verbose
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }}
file: coverage_report.xml
langs:
name: 🧪 Langs
runs-on: ubuntu-22.04

6
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.vscode/
.idea/
.kdev4/
cmake-build-*/
build*/
@@ -7,7 +8,8 @@ local/
venv/
*.mgc
*.kdev4
imgui.ini
.DS_Store
./CMakeUserPresets.json
Brewfile.lock.json
CMakeUserPresets.json
Brewfile.lock.json

13
.gitmodules vendored
View File

@@ -22,6 +22,14 @@
path = lib/third_party/jthread/jthread
url = https://github.com/josuttis/jthread
ignore = dirty
[submodule "lib/third_party/edlib"]
path = lib/third_party/edlib
url = https://github.com/Martinsos/edlib
ignore = dirty
[submodule "lib/third_party/lunasvg"]
path = lib/third_party/lunasvg
url = https://github.com/sammycage/lunasvg
ignore = dirty
[submodule "lib/external/libromfs"]
path = lib/external/libromfs
@@ -35,7 +43,4 @@
[submodule "lib/third_party/HashLibPlus"]
path = lib/third_party/HashLibPlus
url = https://github.com/WerWolv/HashLibPlus
[submodule "lib/third_party/edlib"]
path = lib/third_party/edlib
url = https://github.com/Martinsos/edlib
url = https://github.com/WerWolv/HashLibPlus

View File

@@ -19,24 +19,36 @@ option(IMHEX_ENABLE_UNITY_BUILD "Enables building ImHex as a unity build
option(IMHEX_GENERATE_PDBS "Enable generating PDB files in non-debug builds (Windows only)" OFF)
option(IMHEX_REPLACE_DWARF_WITH_PDB "Remove DWARF information from binaries when generating PDBS (Windows only)" OFF)
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF)
option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" OFF)
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
# Optional IDE support
include("${IMHEX_BASE_FOLDER}/cmake/ide_helpers.cmake")
# Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
# Setup project
loadVersion(IMHEX_VERSION)
loadVersion(IMHEX_VERSION IMHEX_VERSION_PLAIN)
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
configureCMake()
project(imhex
LANGUAGES C CXX
VERSION ${IMHEX_VERSION}
VERSION ${IMHEX_VERSION_PLAIN}
DESCRIPTION "The ImHex Hex Editor"
HOMEPAGE_URL "https://imhex.werwolv.net"
)
configureProject()
# Add ImHex sources
add_custom_target(imhex_all ALL)
# Make sure project is configured correctly
setDefaultBuiltTypeIfUnset()
@@ -54,17 +66,22 @@ configurePackingResources()
setUninstallTarget()
addBundledLibraries()
# Add ImHex sources
add_custom_target(imhex_all ALL)
add_subdirectory(lib/libimhex)
add_subdirectory(main)
addPluginDirectories()
# Add unit tests
enable_testing()
add_subdirectory(tests EXCLUDE_FROM_ALL)
if (IMHEX_ENABLE_UNIT_TESTS)
enable_testing()
add_subdirectory(tests EXCLUDE_FROM_ALL)
endif ()
# Configure more resources that will be added to the install package
createPackage()
generatePDBs()
generateSDKDirectory()
generateSDKDirectory()
# Handle package generation
createPackage()
# Accomodate IDEs with FOLDER support
tweakTargetsForIDESupport()

View File

@@ -28,6 +28,23 @@
"displayName": "x86_64 Build",
"description": "x86_64 build",
"inherits": [ "base" ]
},
{
"name": "xcode",
"inherits": [ "base" ],
"displayName": "Xcode",
"description": "Xcode with external compiler override",
"generator": "Xcode",
"cacheVariables": {
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_CXX_FLAGS": "-fexperimental-library -Wno-shorten-64-to-32 -Wno-deprecated-declarations",
"IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER": "ON"
}
}
],
"buildPresets": [

View File

@@ -1,14 +1,16 @@
<a href="https://imhex.werwolv.net">
<h1 align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./resources/projects/logo_text_light.svg">
<img height="100px" src="./resources/projects/logo_text_dark.svg">
<img height="300px" style="margin: 0; padding: 0" src="./resources/dist/common/logo/ImHexLogoSVGBG.svg">
</picture>
</h1>
</a>
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
<p align="center">
A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.
<br>
<a href="https://itinerarium.github.io/phoneme-synthesis/?w=/'ˈɪmhɛks/"><strong>/ˈɪmhɛks/</strong></a>
</p>
<p align="center">
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master"></a>
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge"></a>
@@ -109,7 +111,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
<details>
<summary><strong>Data Inspector</strong></summary>
- Interpreting data as many different types with endianess, decimal, hexadecimal and octal support and bit inversion
- Interpreting data as many different types with endianness, decimal, hexadecimal and octal support and bit inversion
- Unsigned and signed integers (8, 16, 24, 32, 48, 64 bit)
- Floats (16, 32, 64 bit)
- Signed and Unsigned LEB128
@@ -158,7 +160,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
- Numeric Value search
- Search for signed/unsigned integers and floats
- Search for ranges of values
- Option to specify size and endianess
- Option to specify size and endianness
- Option to ignore unaligned values
</details>
<details>
@@ -316,7 +318,8 @@ To use ImHex, the following minimal system requirements need to be met.
- **OS**:
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
- **macOS**: macOS 11 (Big Sur) or higher,
- **macOS**: macOS 12.1 (Monterey) or higher,
- Lower versions are supported, but you'll need to compile ImHex yourself
- **Linux**: "Modern" Linux. The following distributions have official releases available. Other distros are supported through the AppImage and Flatpak releases.
- Ubuntu 22.04/23.04
- Fedora 36/37
@@ -358,24 +361,29 @@ To develop plugins for ImHex, use the following template project to get started.
### Contributors
- [iTrooz](https://github.com/iTrooz) for getting ImHex onto the Web as well as hundreds of contributions in every part of the project
- [jumanji144](https://github.com/jumanji144) for huge contributions to the Pattern Language and ImHex's infrastructure
- [Mary](https://github.com/marysaka) for her immense help porting ImHex to MacOS and help during development
- [Roblabla](https://github.com/Roblabla) for adding MSI Installer support to ImHex
- [jam1garner](https://github.com/jam1garner) and [raytwo](https://github.com/raytwo) for their help with adding Rust support to plugins
- [Mailaender](https://github.com/Mailaender) for getting ImHex onto Flathub
- [iTrooz](https://github.com/iTrooz) for many improvements and new features to Imhex
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
### Dependencies
- Thanks a lot to ocornut for their amazing [Dear ImGui](https://github.com/ocornut/imgui) which is used for building the entire interface
- Thanks to ocornut as well for their hex editor view used as base for this project.
- Thanks to BalazsJako for their incredible [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for project files
- Thanks to aquynh for [capstone](https://github.com/aquynh/capstone) which is the base of the disassembly window
- Thanks to epezent for [ImPlot](https://github.com/epezent/implot) used to plot data in various places
- Thanks to Nelarius for [ImNodes](https://github.com/Nelarius/imnodes) used as base for the data processor
- Thanks to BalazsJako for [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for configuration files
- Thanks to vitaut for their [libfmt](https://github.com/fmtlib/fmt) library which makes formatting and logging so much better
- Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended) and their great support, used for handling file dialogs on all platforms
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp) used to handle folder paths on Linux
- Thanks to aquynh for [capstone](https://github.com/aquynh/capstone) which is the base of the disassembly window
- Thanks to rxi for [microtar](https://github.com/rxi/microtar) used for extracting downloaded store assets
- Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended)
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp)
- Thanks to VirusTotal for [Yara](https://github.com/VirusTotal/yara) used by the Yara plugin
- Thanks to Martinsos for [edlib](https://github.com/Martinsos/edlib) used for sequence searching in the diffing view
- Thanks to ron4fun for [HashLibPlus](https://github.com/ron4fun/HashLibPlus) which implements every hashing algorithm under the sun
- Thanks to mackron for [miniaudio](https://github.com/mackron/miniaudio) used to play audio files
- Thanks to all other groups and organizations whose libraries are used in ImHex
### License

View File

@@ -1 +1 @@
1.33.0
1.35.4

View File

@@ -46,6 +46,9 @@ function(addDefineToSource SOURCE DEFINE)
APPEND
PROPERTY COMPILE_DEFINITIONS "${DEFINE}"
)
# Disable precompiled headers for this file
set_source_files_properties(${SOURCE} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
endfunction()
# Detect current OS / System
@@ -56,6 +59,7 @@ macro(detectOS)
set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins")
add_compile_definitions(WIN32_LEAN_AND_MEAN)
add_compile_definitions(UNICODE)
elseif (APPLE)
add_compile_definitions(OS_MACOS)
set(CMAKE_INSTALL_BINDIR ".")
@@ -67,6 +71,9 @@ macro(detectOS)
add_compile_definitions(OS_WEB)
elseif (UNIX AND NOT APPLE)
add_compile_definitions(OS_LINUX)
if (BSD AND BSD STREQUAL "FreeBSD")
add_compile_definitions(OS_FREEBSD)
endif()
include(GNUInstallDirs)
if(IMHEX_PLUGINS_IN_SHARE)
@@ -86,6 +93,8 @@ macro(detectOS)
endmacro()
macro(configurePackingResources)
set(LIBRARY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
if (WIN32)
if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
set(APPLICATION_TYPE WIN32)
@@ -139,21 +148,17 @@ macro(configurePackingResources)
endif()
endmacro()
macro(createPackage)
set(LIBRARY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
macro(addPluginDirectories)
file(MAKE_DIRECTORY "plugins")
foreach (plugin IN LISTS PLUGINS)
add_subdirectory("plugins/${plugin}")
if (TARGET ${plugin})
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
if (APPLE)
if (IMHEX_GENERATE_PACKAGE)
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_INSTALL_LOCATION})
else ()
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
endif ()
else ()
if (WIN32)
@@ -172,9 +177,9 @@ macro(createPackage)
add_dependencies(imhex_all ${plugin})
endif ()
endforeach()
endmacro()
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
macro(createPackage)
if (WIN32)
# Install binaries directly in the prefix, usually C:\Program Files\ImHex.
set(CMAKE_INSTALL_BINDIR ".")
@@ -211,7 +216,6 @@ macro(createPackage)
endforeach()
]])
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
downloadImHexPatternsFiles("./")
elseif(UNIX AND NOT APPLE)
@@ -222,7 +226,6 @@ macro(createPackage)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
downloadImHexPatternsFiles("./share/imhex")
# install AppStream file
@@ -243,17 +246,15 @@ macro(createPackage)
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
# Fix rpath
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main> || true)
install(CODE "execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"@executable_path/../Frameworks/\" $<TARGET_FILE:main>)")
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/Resources")
downloadImHexPatternsFiles("${IMHEX_BUNDLE_PATH}/Contents/MacOS")
downloadImHexPatternsFiles("${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/MacOS")
install(FILES ${IMHEX_ICON} DESTINATION "${IMHEX_BUNDLE_PATH}/Contents/Resources")
install(FILES ${IMHEX_ICON} DESTINATION "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/Resources")
install(TARGETS main BUNDLE DESTINATION ".")
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
install(FILES $<TARGET_FILE:updater> DESTINATION "${IMHEX_BUNDLE_PATH}")
# Update library references to make the bundle portable
postprocess_bundle(imhex_all main)
@@ -262,15 +263,19 @@ macro(createPackage)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns")
set(CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}/Contents/Info.plist")
set(CPACK_BUNDLE_PLIST "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/Info.plist")
if (IMHEX_RESIGN_BUNDLE)
message(STATUS "Resigning bundle...")
find_program(CODESIGN_PATH codesign)
if (CODESIGN_PATH)
add_custom_command(TARGET imhex_all POST_BUILD COMMAND "codesign" ARGS "--force" "--deep" "--sign" "-" "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}")
install(CODE "message(STATUS \"Signing bundle '${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}'...\")")
install(CODE "execute_process(COMMAND ${CODESIGN_PATH} --force --deep --entitlements ${CMAKE_SOURCE_DIR}/resources/macos/Entitlements.plist --sign - ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME} COMMAND_ERROR_IS_FATAL ANY)")
endif()
endif()
install(CODE [[ message(STATUS "MacOS Bundle finalized. DO NOT TOUCH IT ANYMORE! ANY MODIFICATIONS WILL BREAK IT FROM NOW ON!") ]])
else()
downloadImHexPatternsFiles("${IMHEX_MAIN_OUTPUT_DIRECTORY}")
endif()
else()
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
@@ -338,8 +343,11 @@ macro(configureCMake)
if (LD_LLD_PATH)
set(CMAKE_LINKER ${LD_LLD_PATH})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
if (NOT XCODE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
endif()
else ()
message(WARNING "lld not found, using default linker!")
endif ()
@@ -374,6 +382,15 @@ macro(configureCMake)
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
endmacro()
function(configureProject)
if (XCODE)
# Support Xcode's multi configuration paradigm by placing built artifacts into separate directories
set(IMHEX_MAIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Configs/$<CONFIG>" PARENT_SCOPE)
else()
set(IMHEX_MAIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" PARENT_SCOPE)
endif()
endfunction()
macro(setDefaultBuiltTypeIfUnset)
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Using RelWithDebInfo build type as it was left unset" FORCE)
@@ -381,12 +398,14 @@ macro(setDefaultBuiltTypeIfUnset)
endif()
endmacro()
function(loadVersion version)
function(loadVersion version plain_version)
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
file(READ "${VERSION_FILE}" read_version)
string(STRIP ${read_version} read_version)
string(REPLACE ".WIP" "" read_version_plain ${read_version})
set(${version} ${read_version} PARENT_SCOPE)
set(${plain_version} ${read_version_plain} PARENT_SCOPE)
endfunction()
function(detectBadClone)
@@ -476,20 +495,71 @@ function(downloadImHexPatternsFiles dest)
message(STATUS "Finished downloading ImHex-Patterns")
else ()
set(imhex_patterns_SOURCE_DIR "")
# Maybe patterns are cloned to a subdirectory
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
endif()
# Or a sibling directory
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../ImHex-Patterns")
endif()
endif ()
if (EXISTS ${imhex_patterns_SOURCE_DIR})
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
message(WARNING "Failed to locate ImHex-Patterns repository, some resources will be missing during install!")
elseif(XCODE)
# The Xcode build has multiple configurations, which each need a copy of these files
file(GLOB_RECURSE sourceFilePaths LIST_DIRECTORIES NO CONFIGURE_DEPENDS RELATIVE "${imhex_patterns_SOURCE_DIR}"
"${imhex_patterns_SOURCE_DIR}/constants/*"
"${imhex_patterns_SOURCE_DIR}/encodings/*"
"${imhex_patterns_SOURCE_DIR}/includes/*"
"${imhex_patterns_SOURCE_DIR}/patterns/*"
"${imhex_patterns_SOURCE_DIR}/magic/*"
"${imhex_patterns_SOURCE_DIR}/nodes/*"
)
list(FILTER sourceFilePaths EXCLUDE REGEX "_schema.json$")
foreach(relativePath IN LISTS sourceFilePaths)
file(GENERATE OUTPUT "${dest}/${relativePath}" INPUT "${imhex_patterns_SOURCE_DIR}/${relativePath}")
endforeach()
else()
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic nodes)
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest} PATTERN "**/_schema.json" EXCLUDE)
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION "${dest}" PATTERN "**/_schema.json" EXCLUDE)
endforeach ()
endif ()
endfunction()
# Compress debug info. See https://github.com/WerWolv/ImHex/issues/1714 for relevant problem
macro(setupDebugCompressionFlag)
include(CheckCXXCompilerFlag)
include(CheckLinkerFlag)
check_cxx_compiler_flag(-gz=zstd ZSTD_AVAILABLE_COMPILER)
check_linker_flag(CXX -gz=zstd ZSTD_AVAILABLE_LINKER)
check_cxx_compiler_flag(-gz COMPRESS_AVAILABLE_COMPILER)
check_linker_flag(CXX -gz COMPRESS_AVAILABLE_LINKER)
if (NOT DEBUG_COMPRESSION_FLAG) # Cache variable
if (ZSTD_AVAILABLE_COMPILER AND ZSTD_AVAILABLE_LINKER)
message("Using Zstd compression for debug info because both compiler and linker support it")
set(DEBUG_COMPRESSION_FLAG "-gz=zstd" CACHE STRING "Cache to use for debug info compression")
elseif (COMPRESS_AVAILABLE_COMPILER AND COMPRESS_AVAILABLE_LINKER)
message("Using default compression for debug info because both compiler and linker support it")
set(DEBUG_COMPRESSION_FLAG "-gz" CACHE STRING "Cache to use for debug info compression")
endif()
endif()
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} ${DEBUG_COMPRESSION_FLAG}")
endmacro()
macro(setupCompilerFlags target)
# IMHEX_COMMON_FLAGS: flags common for C, C++, Objective C, etc.. compilers
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
# Define strict compilation flags
if (IMHEX_STRICT_WARNINGS)
@@ -503,7 +573,7 @@ macro(setupCompilerFlags target)
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
# Disable some warnings
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations")
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations -Wno-unknown-pragmas")
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -522,11 +592,24 @@ macro(setupCompilerFlags target)
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -pthread -Wno-dollar-in-identifier-extension -Wno-pthreads-mem-growth")
endif ()
if (IMHEX_COMPRESS_DEBUG_INFO)
setupDebugCompressionFlag()
endif()
# Set actual CMake flags
set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS} ${IMHEX_CXX_FLAGS}")
set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} ${IMHEX_COMMON_FLAGS}")
# Only generate minimal debug information for stacktraces in RelWithDebInfo builds
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -g1")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g1")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# Add flags for debug info in inline functions
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -gstatement-frontiers -ginline-points")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -gstatement-frontiers -ginline-points")
endif()
endmacro()
# uninstall target
@@ -592,6 +675,14 @@ macro(addBundledLibraries)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
endif()
if (NOT USE_SYSTEM_LUNASVG)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/lunasvg EXCLUDE_FROM_ALL)
set(LUNASVG_LIBRARIES lunasvg)
else()
find_package(LunaSVG REQUIRED)
set(LUNASVG_LIBRARIES lunasvg)
endif()
if (NOT USE_SYSTEM_LLVM)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
else()
@@ -610,7 +701,16 @@ macro(addBundledLibraries)
set(JTHREAD_LIBRARIES jthread)
endif()
if (USE_SYSTEM_BOOST)
find_package(boost REQUIRED)
set(BOOST_LIBRARIES boost::regex)
else()
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/boost ${CMAKE_CURRENT_BINARY_DIR}/boost EXCLUDE_FROM_ALL)
set(BOOST_LIBRARIES boost::regex)
endif()
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF CACHE BOOL "" FORCE)
set(LIBPL_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE)
if (WIN32)
set(LIBPL_SHARED_LIBRARY ON CACHE BOOL "" FORCE)
@@ -653,20 +753,20 @@ macro(addBundledLibraries)
if (${Backtrace_FOUND})
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
if (Backtrace_HEADER STREQUAL "execinfo.h")
if (Backtrace_HEADER STREQUAL "backtrace.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(HEX_HAS_EXECINFO)
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(BACKTRACE_HEADER=<${Backtrace_HEADER}>)
add_compile_definitions(HEX_HAS_BACKTRACE)
endif ()
elseif (Backtrace_HEADER STREQUAL "execinfo.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=<${Backtrace_HEADER}>)
add_compile_definitions(HEX_HAS_EXECINFO)
endif()
endif()
endif ()
endif ()
endif()
endif()
endmacro()
function(enableUnityBuild TARGET)
@@ -732,7 +832,7 @@ function(generateSDKDirectory)
if (WIN32)
set(SDK_PATH "./sdk")
elseif (APPLE)
set(SDK_PATH "${BUNDLE_NAME}/Contents/Resources/sdk")
set(SDK_PATH "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/Resources/sdk")
else()
set(SDK_PATH "share/imhex/sdk")
endif()
@@ -748,6 +848,9 @@ function(generateSDKDirectory)
if (NOT USE_SYSTEM_NLOHMANN_JSON)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
endif()
if (NOT USE_SYSTEM_NLOHMANN_JSON)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/boost DESTINATION "${SDK_PATH}/lib/third_party")
endif()
install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/modules DESTINATION "${SDK_PATH}/cmake")
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")
@@ -758,4 +861,19 @@ endfunction()
function(addIncludesFromLibrary target library)
get_target_property(library_include_dirs ${library} INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(${target} PRIVATE ${library_include_dirs})
endfunction()
function(precompileHeaders target includeFolder)
if (NOT IMHEX_ENABLE_PRECOMPILED_HEADERS)
return()
endif()
file(GLOB_RECURSE TARGET_INCLUDES "${includeFolder}/**/*.hpp")
set(SYSTEM_INCLUDES "<algorithm>;<array>;<atomic>;<chrono>;<cmath>;<cstddef>;<cstdint>;<cstdio>;<cstdlib>;<cstring>;<exception>;<filesystem>;<functional>;<iterator>;<limits>;<list>;<map>;<memory>;<optional>;<ranges>;<set>;<stdexcept>;<string>;<string_view>;<thread>;<tuple>;<type_traits>;<unordered_map>;<unordered_set>;<utility>;<variant>;<vector>")
set(INCLUDES "${SYSTEM_INCLUDES};${TARGET_INCLUDES}")
string(REPLACE ">" "$<ANGLE-R>" INCLUDES "${INCLUDES}")
target_precompile_headers(${target}
PUBLIC
"$<$<COMPILE_LANGUAGE:CXX>:${INCLUDES}>"
)
endfunction()

149
cmake/ide_helpers.cmake Normal file
View File

@@ -0,0 +1,149 @@
option(IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER "Enable choice of compiler for Xcode builds, despite CMake's best efforts" OFF)
option(IMHEX_IDE_HELPERS_INTRUSIVE_IDE_TWEAKS "Enable intrusive CMake tweaks to better support IDEs with folder support" OFF)
# The CMake infrastructure silently ignores the CMAKE_<>_COMPILER settings when
# using the `Xcode` generator.
#
# A particularly nasty (and potentially only) way of getting around this is to
# temporarily lie about the generator being used, while CMake determines and
# locks in the compiler to use.
#
# Needless to say, this is hacky and fragile. Use at your own risk!
if (IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER AND CMAKE_GENERATOR STREQUAL "Xcode")
set(CMAKE_GENERATOR "Unknown")
enable_language(C CXX)
set(CMAKE_GENERATOR "Xcode")
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_C_COMPILER}")
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_CXX_COMPILER}")
if (CLANG)
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_C_COMPILER}")
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_CXX_COMPILER}")
endif()
# By default Xcode passes a `-index-store-path=<...>` parameter to the compiler
# during builds to build code completion indexes. This is not supported by
# anything other than AppleClang
set(CMAKE_XCODE_ATTRIBUTE_COMPILER_INDEX_STORE_ENABLE "NO")
endif()
# Generate a launch/build scheme for all targets
set(CMAKE_XCODE_GENERATE_SCHEME YES)
# Utility function that helps avoid messing with non-standard targets
macro(returnIfTargetIsNonTweakable target)
get_target_property(targetIsAliased ${target} ALIASED_TARGET)
get_target_property(targetIsImported ${target} IMPORTED)
if (targetIsAliased OR targetIsImported)
return()
endif()
get_target_property(targetType ${target} TYPE)
if (targetType MATCHES "INTERFACE_LIBRARY|UNKNOWN_LIBRARY")
return()
endif()
endmacro()
# Targets usually don't specify their private headers, nor group their source files
# which results in very spotty coverage by IDEs with folders support
#
# Unfortunately, CMake does not have a `target_source_group` like construct yet, therefore
# we have to play by the limitations of `source_group`.
#
# A particularly problematic part is that the function must be called within the directoryies
# scope for the grouping to take effect.
#
# See: https://discourse.cmake.org/t/topic/7388
function(tweakTargetForIDESupport target)
returnIfTargetIsNonTweakable(${target})
# Don't assume directory structure of third parties
get_target_property(targetSourceDir ${target} SOURCE_DIR)
if (targetSourceDir MATCHES "third_party")
return()
endif()
# Add headers to target
get_target_property(targetSourceDir ${target} SOURCE_DIR)
if (targetSourceDir)
file(GLOB_RECURSE targetPrivateHeaders CONFIGURE_DEPENDS "${targetSourceDir}/include/*.hpp")
target_sources(${target} PRIVATE "${targetPrivateHeaders}")
endif()
# Organize target sources into directory tree
get_target_property(sources ${target} SOURCES)
foreach(file IN LISTS sources)
get_filename_component(path "${file}" ABSOLUTE)
if (NOT path MATCHES "^${targetSourceDir}")
continue()
endif()
source_group(TREE "${targetSourceDir}" PREFIX "Source Tree" FILES "${file}")
endforeach()
endfunction()
if (IMHEX_IDE_HELPERS_INTRUSIVE_IDE_TWEAKS)
# See tweakTargetForIDESupport for rationale
function(add_library target)
_add_library(${target} ${ARGN})
tweakTargetForIDESupport(${target})
endfunction()
function(add_executable target)
_add_executable(${target} ${ARGN})
tweakTargetForIDESupport(${target})
endfunction()
endif()
# Adjust target's FOLDER property, which is an IDE only preference
function(_tweakTarget target path)
get_target_property(targetType ${target} TYPE)
if (TARGET generator-${target})
set_target_properties(generator-${target} PROPERTIES FOLDER "romfs/${target}")
endif()
if (TARGET romfs_file_packer-${target})
set_target_properties(romfs_file_packer-${target} PROPERTIES FOLDER "romfs/${target}")
endif()
if (TARGET libromfs-${target})
set_target_properties(libromfs-${target} PROPERTIES FOLDER "romfs/${target}")
endif()
if (${targetType} MATCHES "EXECUTABLE|LIBRARY")
set_target_properties(${target} PROPERTIES FOLDER "${path}")
endif()
endfunction()
macro(_tweakTargetsRecursive dir)
get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
foreach(subdir IN LISTS subdirectories)
_tweakTargetsRecursive("${subdir}")
endforeach()
if(${dir} STREQUAL ${CMAKE_SOURCE_DIR})
return()
endif()
get_property(targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
file(RELATIVE_PATH rdir ${CMAKE_SOURCE_DIR} "${dir}/..")
foreach(target ${targets})
_tweakTarget(${target} "${rdir}")
endforeach()
endmacro()
# Tweak all targets this CMake build is aware about
function(tweakTargetsForIDESupport)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
_tweakTargetsRecursive("${CMAKE_SOURCE_DIR}")
endfunction()

View File

@@ -11,6 +11,14 @@ if (UNIX)
set(CORECLR_SUBARCH "arm64")
endif()
endif()
if (APPLE)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
set(CORECLR_ARCH "osx-arm64")
set(CORECLR_SUBARCH "arm64")
else()
set(CORECLR_ARCH "osx-x64")
endif()
endif()
if (NOT DOTNET_EXECUTABLE)
set(DOTNET_EXECUTABLE dotnet)
@@ -81,4 +89,5 @@ if (CoreClrEmbed_INCLUDE_DIR AND CoreClrEmbed_LIBRARY)
set(CoreClrEmbed_LIBRARIES "${CoreClrEmbed_LIBRARY}" CACHE STRING "CoreClrEmbed libraries" FORCE)
set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}" CACHE STRING "CoreClrEmbed shared libraries" FORCE)
set(CoreClrEmbed_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}" CACHE STRING "CoreClrEmbed include directories" FORCE)
set(CoreClrEmbed_VERSION "${CORECLR_RUNTIME_VERSION_FULL}" CACHE STRING "CoreClrEmbed version" FORCE)
endif()

View File

@@ -1,4 +1,4 @@
find_file(libyara.a YARA_LIBRARIES)
find_library(YARA_LIBRARIES NAMES yara)
find_file(yara.h YARA_INCLUDE_DIRS)
mark_as_advanced(YARA_LIBRARIES YARA_INCLUDE_DIRS)

View File

@@ -38,4 +38,8 @@ if (ZSTD_FOUND)
message(STATUS "Found Zstd: ${ZSTD_LIBRARY}")
endif()
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
add_library(ZSTD::zstd INTERFACE IMPORTED)
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ZSTD_INCLUDE_DIR})
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_LINK_LIBRARIES ${ZSTD_LIBRARY})

View File

@@ -36,8 +36,12 @@ macro(add_imhex_plugin)
# Add include directories and link libraries
target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES})
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${IMHEX_PLUGIN_LIBRARIES} ${FMT_LIBRARIES} imgui_all_includes libwolv)
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_LIBRARIES})
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} imgui_all_includes libwolv)
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl)
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl-gen)
precompileHeaders(${IMHEX_PLUGIN_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/include")
# Add IMHEX_PROJECT_NAME and IMHEX_VERSION define
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}")
@@ -51,7 +55,7 @@ macro(add_imhex_plugin)
# Configure build properties
set_target_properties(${IMHEX_PLUGIN_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
RUNTIME_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins"
CXX_STANDARD 23
PREFIX ""
SUFFIX ${IMHEX_PLUGIN_SUFFIX}
@@ -68,10 +72,23 @@ macro(add_imhex_plugin)
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
foreach(feature ${IMHEX_PLUGIN_FEATURES})
string(TOUPPER ${feature} feature)
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
endforeach()
set(FEATURE_DEFINE_CONTENT)
if (IMHEX_PLUGIN_FEATURES)
list(LENGTH IMHEX_PLUGIN_FEATURES IMHEX_FEATURE_COUNT)
math(EXPR IMHEX_FEATURE_COUNT "${IMHEX_FEATURE_COUNT} - 1" OUTPUT_FORMAT DECIMAL)
foreach(index RANGE 0 ${IMHEX_FEATURE_COUNT} 2)
list(SUBLIST IMHEX_PLUGIN_FEATURES ${index} 2 IMHEX_PLUGIN_FEATURE)
list(GET IMHEX_PLUGIN_FEATURE 0 feature_define)
list(GET IMHEX_PLUGIN_FEATURE 1 feature_description)
string(TOUPPER ${feature_define} feature_define)
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature_define}=0)
set(FEATURE_DEFINE_CONTENT "${FEATURE_DEFINE_CONTENT}{ \"${feature_description}\", IMHEX_FEATURE_ENABLED(${feature_define}) },")
endforeach()
endif()
target_compile_options(${IMHEX_PLUGIN_NAME} PRIVATE -DIMHEX_PLUGIN_FEATURES_CONTENT=${FEATURE_DEFINE_CONTENT})
# Add the new plugin to the main dependency list so it gets built by default
if (TARGET imhex_all)
@@ -84,13 +101,39 @@ macro(add_imhex_plugin)
# Fix rpath
if (APPLE)
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins")
set_target_properties(
${IMHEX_PLUGIN_NAME}
PROPERTIES
INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins"
)
elseif (UNIX)
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH_USE_ORIGIN ON INSTALL_RPATH "$ORIGIN/")
set(PLUGIN_RPATH "")
list(APPEND PLUGIN_RPATH "$ORIGIN")
if (IMHEX_PLUGIN_ADD_INSTALL_PREFIX_TO_RPATH)
list(APPEND PLUGIN_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
endif()
set_target_properties(
${IMHEX_PLUGIN_NAME}
PROPERTIES
INSTALL_RPATH_USE_ORIGIN ON
INSTALL_RPATH "${PLUGIN_RPATH}"
)
endif()
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt AND IMHEX_ENABLE_UNIT_TESTS AND IMHEX_ENABLE_PLUGIN_TESTS)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_NAME}_tests)
target_compile_definitions(${IMHEX_PLUGIN_NAME}_tests PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}-tests")
endif()
endmacro()
macro(add_romfs_resource input output)
if (NOT EXISTS ${input})
message(WARNING "Resource file ${input} does not exist")
endif()
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)

View File

@@ -14,12 +14,11 @@ if(CMAKE_GENERATOR)
# Being called as include(PostprocessBundle), so define a helper function.
set(_POSTPROCESS_BUNDLE_MODULE_LOCATION "${CMAKE_CURRENT_LIST_FILE}")
function(postprocess_bundle out_target in_target)
add_custom_command(TARGET ${out_target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -DBUNDLE_PATH="$<TARGET_FILE_DIR:${in_target}>/../.."
-DCODE_SIGN_CERTIFICATE_ID="${CODE_SIGN_CERTIFICATE_ID}"
-DEXTRA_BUNDLE_LIBRARY_PATHS="${EXTRA_BUNDLE_LIBRARY_PATHS}"
-P "${_POSTPROCESS_BUNDLE_MODULE_LOCATION}"
)
install(CODE "set(BUNDLE_PATH ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME})")
install(CODE "set(CODE_SIGN_CERTIFICATE_ID ${CODE_SIGN_CERTIFICATE_ID})")
install(CODE "set(EXTRA_BUNDLE_LIBRARY_PATHS ${EXTRA_BUNDLE_LIBRARY_PATHS})")
install(SCRIPT ${_POSTPROCESS_BUNDLE_MODULE_LOCATION})
endfunction()
return()
endif()
@@ -42,7 +41,7 @@ file(GLOB_RECURSE plugins "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug")
# makes it sometimes break on libraries that do weird things with @rpath. Specify
# equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625
# is fixed and in our minimum CMake version.
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS} "${BUNDLE_PATH}/Contents/MacOS/plugins")
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS} "${BUNDLE_PATH}/Contents/MacOS/plugins" "${BUNDLE_PATH}/Contents/Frameworks")
message(STATUS "Fixing up application bundle: ${extra_dirs}")
# BundleUtilities is overly verbose, so disable most of its messages

View File

@@ -29,6 +29,10 @@ add_subdirectory_if_exists(lib/third_party/nlohmann_json)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json PARENT_SCOPE)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
add_subdirectory_if_exists(lib/third_party/boost)
set(BOOST_LIBRARIES boost::regex PARENT_SCOPE)
set(BOOST_LIBRARIES boost::regex)
add_subdirectory(lib/external/libwolv EXCLUDE_FROM_ALL)
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)

View File

@@ -18,11 +18,11 @@ docker buildx build . -f <DOCKERFILE_PATH> --progress plain --build-arg 'JOBS=4'
where `<DOCKERFILE_PATH>` should be replaced by the wanted Dockerfile base d on the build you want to do:
| Wanted build | Dockerfile path |
|--------------|-----------------------------|
| MacOS M1 | dist/macOS/arm64.Dockerfile |
| AppImage | dist/appimage/Dockerfile |
| Web version | dist/web/Dockerfile |
| Wanted build | Dockerfile path | Target |
|--------------|-----------------------------|--------|
| MacOS M1 | dist/macOS/arm64.Dockerfile | - |
| AppImage | dist/appimage/Dockerfile | - |
| Web version | dist/web/Dockerfile | raw |
We'll explain this command in the next section
@@ -43,6 +43,7 @@ In the command saw earlier:
- `.` is the base folder that the Dockerfile will be allowed to see
- `-f <path>` is to specify the Dockerfile path
- `--progress plain` is to allow you to see the output of instructions
- `--build-arg <key>=<value>` is to allow to to specify arguments to the build (like -DKEY=VALUE in CMake)
- `--build-arg <key>=<value>` is to allow to specify arguments to the build (like -DKEY=VALUE in CMake)
- `--build-context key=<folder>` is to specify folders other than the base folder that the Dockerfile is allowed to see
- `--output <path>` is the path to write the output package to. If not specified, Docker will create an image as the output (probably not what you want)
- `--target <target>` specifies which docker target to build

View File

@@ -13,14 +13,8 @@ CC=gcc-12 CXX=g++-12 \
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
..
make -j 4 install
ninja install
```
All paths follow the XDG Base Directories standard, and can thus be modified

View File

@@ -15,7 +15,7 @@ OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=./install \
-DCMAKE_INSTALL_PREFIX="./install" \
-DIMHEX_GENERATE_PACKAGE=ON \
..
ninja install

View File

@@ -14,7 +14,7 @@ mkdir build
cd build
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCMAKE_INSTALL_PREFIX="./install" \
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
..
ninja install

48
dist/gen_release_notes.py vendored Normal file
View File

@@ -0,0 +1,48 @@
import subprocess
import sys
def get_commits(branch: str, start_tag: str, end_tag: str) -> list[str]:
try:
commits_raw = subprocess.check_output([ "git", "--no-pager", "log", branch, "--no-color", "--pretty=oneline", "--abbrev-commit", f"{start_tag}..{end_tag}"], stderr=subprocess.DEVNULL).decode("UTF-8").split("\n")
except:
return []
commits = []
for line in commits_raw:
commits.append(line[9:])
return commits
def main(args: list) -> int:
if len(args) != 2:
print(f"Usage: {args[0]} prev_minor")
return 1
last_minor_version = f"v1.{args[1]}"
master_commits = get_commits("master", f"{last_minor_version}.0", "master")
for i in range(1, 100):
branch_commits = get_commits(f"releases/{last_minor_version}.X", f"{last_minor_version}.0", f"{last_minor_version}.{i}")
if len(branch_commits) == 0:
break
master_commits = [commit for commit in master_commits if commit not in branch_commits]
sorted_commits = {}
for commit in master_commits:
category, commit_name = commit.split(":", 1)
if category not in sorted_commits:
sorted_commits[category] = []
sorted_commits[category].append(commit_name)
for category in sorted_commits:
print(f"## {category}\n")
for commit in sorted_commits[category]:
print(f"- {commit}")
print(f"\n")
if __name__ == "__main__":
exit(main(sys.argv))

19
dist/get_deps_tumbleweed.sh vendored Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env sh
zypper install \
cmake \
ninja \
gcc12 \
gcc12-c++ \
freetype2-devel \
libcurl-devel \
dbus-1-devel \
file-devel \
Mesa-libGL-devel \
libglfw-devel \
mbedtls-devel \
gtk3-devel \
libzstd-devel \
zlib-devel \
bzip3-devel \
xz-devel

1
dist/imhex.desktop vendored
View File

@@ -8,3 +8,4 @@ Type=Application
StartupNotify=true
Categories=Development;IDE;
StartupWMClass=imhex
Keywords=static-analysis;reverse-engineering;disassembler;disassembly;hacking;forensics;hex-editor;cybersecurity;security;binary-analysis;

238
dist/langtool.py vendored Normal file → Executable file
View File

@@ -1,104 +1,208 @@
#!/usr/bin/env python3
from pathlib import Path
import sys
import argparse
import json
# This fixes a CJK full-width character input issue
# which makes left halves of deleted characters displayed on screen
# pylint: disable=unused-import
import re
import readline
DEFAULT_LANG = "en_US"
DEFAULT_LANG_PATH = "plugins/*/romfs/lang/"
INVALID_TRANSLATION = ""
def handle_missing_key(command, lang_data, key, value):
if command == "check":
print(f"Error: Translation {lang_data['code']} is missing translation for key '{key}'")
exit(2)
elif command == "translate" or command == "create":
print(f"Key \033[1m'{key}': '{value}'\033[0m is missing in translation '{lang_data['code']}'")
new_value = input("Enter translation: ")
lang_data["translations"][key] = new_value
elif command == "update":
lang_data["translations"][key] = INVALID_TRANSLATION
def main():
if len(sys.argv) < 3:
print(f"Usage: {Path(sys.argv[0]).name} <check|translate|update|create> <lang folder path> <language>")
parser = argparse.ArgumentParser(
prog="langtool",
description="ImHex translate tool",
)
parser.add_argument(
"command",
choices=[
"check",
"translate",
"update",
"create",
"retranslate",
"untranslate",
"fmtzh",
],
)
parser.add_argument(
"-c", "--langdir", default=DEFAULT_LANG_PATH, help="Language folder glob"
)
parser.add_argument("-l", "--lang", default="", help="Language to translate")
parser.add_argument(
"-r", "--reflang", default="", help="Language for reference when translating"
)
parser.add_argument(
"-k", "--keys", help="Keys to re-translate (only in re/untranslate mode)"
)
args = parser.parse_args()
command = args.command
lang = args.lang
print(f"Running in {command} mode")
lang_files_glob = f"{lang}.json" if lang != "" else "*.json"
lang_folders = set(Path(".").glob(args.langdir))
if len(lang_folders) == 0:
print(f"Error: {args.langdir} matches nothing")
return 1
command = sys.argv[1]
if command not in ["check", "translate", "update", "create"]:
print(f"Unknown command: {command}")
return 1
for lang_folder in lang_folders:
if not lang_folder.is_dir():
print(f"Error: {lang_folder} is not a folder")
return 1
print(f"Using langtool in {command} mode")
default_lang_data = {}
default_lang_path = lang_folder / Path(DEFAULT_LANG + ".json")
if not default_lang_path.exists():
print(
f"Error: Default language file {default_lang_path} does not exist in {lang_folder}"
)
return 1
with default_lang_path.open("r", encoding="utf-8") as file:
default_lang_data = json.load(file)
lang_folder_path = Path(sys.argv[2])
if not lang_folder_path.exists():
print(f"Error: {lang_folder_path} does not exist")
return 1
if not lang_folder_path.is_dir():
print(f"Error: {lang_folder_path} is not a folder")
return 1
lang = sys.argv[3] if len(sys.argv) > 3 else ""
print(f"Processing language files in {lang_folder_path}...")
default_lang_file_path = lang_folder_path / Path(DEFAULT_LANG + ".json")
if not default_lang_file_path.exists():
print(f"Error: Default language file {default_lang_file_path} does not exist")
return 1
print(f"Using file '{default_lang_file_path.name}' as template language file")
with default_lang_file_path.open("r", encoding="utf-8") as default_lang_file:
default_lang_data = json.load(default_lang_file)
reference_lang_data = None
reference_lang_path = lang_folder / Path(args.reflang + ".json")
if reference_lang_path.exists():
with reference_lang_path.open("r", encoding="utf-8") as file:
reference_lang_data = json.load(file)
if command == "create" and lang != "":
lang_file_path = lang_folder_path / Path(lang + ".json")
lang_file_path = lang_folder / Path(lang + ".json")
if lang_file_path.exists():
print(f"Error: Language file {lang_file_path} already exists")
return 1
continue
print(f"Creating new language file '{lang_file_path.name}'")
exist_lang_data = None
for lang_folder1 in lang_folders:
lang_file_path1 = lang_folder1 / Path(lang + ".json")
if lang_file_path1.exists():
with lang_file_path1.open("r", encoding="utf-8") as file:
exist_lang_data = json.load(file)
break
print(f"Creating new language file '{lang_file_path}'")
with lang_file_path.open("w", encoding="utf-8") as new_lang_file:
new_lang_data = {
"code": lang,
"language": input("Enter language: "),
"country": input("Enter country: "),
"translations": {}
"language": (
exist_lang_data["language"]
if exist_lang_data
else input("Enter language name: ")
),
"country": (
exist_lang_data["country"]
if exist_lang_data
else input("Enter country name: ")
),
"translations": {},
}
json.dump(new_lang_data, new_lang_file, indent=4, ensure_ascii=False)
for additional_lang_file_path in lang_folder_path.glob("*.json"):
if not lang == "" and not additional_lang_file_path.stem == lang:
lang_files = set(lang_folder.glob(lang_files_glob))
if len(lang_files) == 0:
print(f"Warn: Language file for '{lang}' does not exist in '{lang_folder}'")
for lang_file_path in lang_files:
if (
lang_file_path.stem == f"{DEFAULT_LANG}.json"
or lang_file_path.stem == f"{args.reflang}.json"
):
continue
if additional_lang_file_path.name.startswith(DEFAULT_LANG):
continue
print(f"\nProcessing '{lang_file_path}'")
if not (command == "update" or command == "create"):
print("\n----------------------------\n")
print(f"\nProcessing file '{additional_lang_file_path.name}'\n----------------------------\n")
with additional_lang_file_path.open("r+", encoding="utf-8") as additional_lang_file:
additional_lang_data = json.load(additional_lang_file)
with lang_file_path.open("r+", encoding="utf-8") as target_lang_file:
lang_data = json.load(target_lang_file)
for key, value in default_lang_data["translations"].items():
if key not in additional_lang_data["translations"] or additional_lang_data["translations"][key] == INVALID_TRANSLATION:
handle_missing_key(command, additional_lang_data, key, value)
has_translation = (
key in lang_data["translations"]
and lang_data["translations"][key] != INVALID_TRANSLATION
)
if not has_translation and not (
(command == "retranslate" or command == "untranslate")
and re.compile(args.keys).fullmatch(key)
):
continue
if command == "check":
print(
f"Error: Translation {lang_data['code']} is missing translation for key '{key}'"
)
exit(2)
elif (
command == "translate"
or command == "retranslate"
or command == "untranslate"
):
if command == "untranslate" and not has_translation:
continue
reference_tranlsation = (
" '%s'" % reference_lang_data["translations"][key]
if reference_lang_data
else ""
)
print(
f"\033[1m'{key}' '{value}'{reference_tranlsation}\033[0m => {lang_data['language']}",
end="",
)
if has_translation:
translation = lang_data["translations"][key]
print(f" <= \033[1m'{translation}'\033[0m")
print() # for a new line
if command == "untranslate":
lang_data["translations"][key] = INVALID_TRANSLATION
continue
try:
new_value = input("=> ")
lang_data["translations"][key] = new_value
except KeyboardInterrupt:
break
elif command == "update" or command == "create":
lang_data["translations"][key] = INVALID_TRANSLATION
elif command == "fmtzh":
if has_translation:
lang_data["translations"][key] = fmtzh(
lang_data["translations"][key]
)
keys_to_remove = []
for key, value in additional_lang_data["translations"].items():
for key, value in lang_data["translations"].items():
if key not in default_lang_data["translations"]:
keys_to_remove.append(key)
for key in keys_to_remove:
additional_lang_data["translations"].pop(key)
print(f"Removed unused key '{key}' from translation '{additional_lang_data['code']}'")
lang_data["translations"].pop(key)
print(
f"Removed unused key '{key}' from translation '{lang_data['code']}'"
)
additional_lang_file.seek(0)
additional_lang_file.truncate()
json.dump(additional_lang_data, additional_lang_file, indent=4, sort_keys=True, ensure_ascii=False)
target_lang_file.seek(0)
target_lang_file.truncate()
json.dump(
lang_data,
target_lang_file,
indent=4,
sort_keys=True,
ensure_ascii=False,
)
if __name__ == '__main__':
def fmtzh(text: str) -> str:
text = re.sub(r"(\.{3}|\.{6})", "……", text)
text = text.replace("!", "")
text = re.sub(r"([^\.\na-zA-Z\d])\.$", "\1", text, flags=re.M)
text = text.replace("?", "")
return text
if __name__ == "__main__":
exit(main())

View File

@@ -35,9 +35,9 @@ EOF
## Download libmagic
### Clone libmagic
RUN git clone https://github.com/file/file /mnt/file
RUN git clone --depth 1 --branch FILE5_45 https://github.com/file/file /mnt/file
### Download libmagic dependencies
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt install -y libtool autoconf
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt update && apt install -y libtool autoconf
# -- DOWNLOADING + BUILDING STUFF
@@ -170,4 +170,4 @@ EOF
FROM scratch
COPY --from=build /mnt/ImHex/build/install/imhex.app ImHex.app
COPY --from=build /mnt/ImHex/build/install/imhex.app imhex.app

13
dist/rpm/imhex.spec vendored
View File

@@ -1,5 +1,7 @@
%define source_date_epoch_from_changelog 0
Name: imhex
Version: 1.26.2
Version: VERSION
Release: 0%{?dist}
Summary: A hex editor for reverse engineers and programmers
@@ -95,10 +97,6 @@ CXXFLAGS+=" -std=gnu++2b"
%set_build_flags
CXXFLAGS+=" -std=gnu++2b"
%endif
# build binaries required for tests
%cmake_build --target unit_tests
%ctest --exclude-regex '(Helpers/StoreAPI|Helpers/TipsAPI|Helpers/ContentAPI)'
# Helpers/*API exclude tests that require network access
%install
@@ -128,7 +126,4 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
%{_datadir}/applications/%{name}.desktop
%{_libdir}/libimhex.so*
%{_libdir}/%{name}/
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
%changelog
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml

1
dist/web/Dockerfile vendored
View File

@@ -59,6 +59,7 @@ cmake /imhex
-DIMHEX_OFFLINE_BUILD=ON \
-DIMHEX_STATIC_LINK_PLUGINS=ON \
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
-DIMHEX_COMPRESS_DEBUG_INFO=OFF \
-DNATIVE_CMAKE_C_COMPILER=gcc \
-DNATIVE_CMAKE_CXX_COMPILER=g++ \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \

View File

@@ -62,7 +62,7 @@
</head>
<body>
<div id="loading" class="centered">
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.png" id="logo" alt="ImHex Logo">
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.svg" id="logo" alt="ImHex Logo">
<h1>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</h1>
<h2>Available both natively and on the web</h2>
<h5>ImHex runs directly in your web browser with the help of Emscripten and WebAssembly.</h5>

View File

@@ -137,7 +137,7 @@ a:hover {
:root {
--progress: 25%;
--progress: 0%;
}
.progress-bar-container {
@@ -174,4 +174,15 @@ a:hover {
.progress-moved .progress-bar {
width: var(--progress);
background-color: #3864cb;
}
#logo {
height: 25%;
margin-top: 50px;
}
.canvas-fixed {
position: absolute;
top: 0;
left: 0;
}

View File

@@ -100,7 +100,77 @@ var notWorkingTimer = setTimeout(() => {
var Module = {
preRun: [],
postRun: [],
postRun: function() {
// Patch the emscripten GLFW module to send mouse and touch events in the right order
// For ImGui interactions to correctly work with touch input, MousePos events need
// to be processed first and then MouseButton events in the next frame. By default,
// GLFW does the exact opposite, which causes buttons to require two taps to register
// and windows get "stuck" to the cursor when dragged or resized
GLFW.onMousemove = event => {
if (event.type === "touchmove") {
event.preventDefault();
let primaryChanged = false;
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
Browser.setMouseCoords(i.pageX, i.pageY);
primaryChanged = true;
break;
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
}
};
GLFW.onMouseButtonChanged = (event, status) => {
if (!GLFW.active) return;
if (event.target != Module["canvas"]) return;
const isTouchType = event.type === "touchstart" || event.type === "touchend" || event.type === "touchcancel";
let eventButton = 0;
if (isTouchType) {
event.preventDefault();
let primaryChanged = false;
if (GLFW.primaryTouchId === null && event.type === "touchstart" && event.targetTouches.length > 0) {
const chosenTouch = event.targetTouches[0];
GLFW.primaryTouchId = chosenTouch.identifier;
Browser.setMouseCoords(chosenTouch.pageX, chosenTouch.pageY);
primaryChanged = true;
} else if (event.type === "touchend" || event.type === "touchcancel") {
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
GLFW.primaryTouchId = null;
primaryChanged = true;
break;
}
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
eventButton = GLFW.DOMToGLFWMouseButton(event);
}
if (status == 1) {
GLFW.active.buttons |= (1 << eventButton);
try {
event.target.setCapture();
} catch (e) {}
} else {
GLFW.active.buttons &= ~(1 << eventButton);
}
if (GLFW.active.cursorPosFunc) {
getWasmTableEntry(GLFW.active.cursorPosFunc)(GLFW.active.id, Browser.mouseX, Browser.mouseY);
}
if (GLFW.active.mouseButtonFunc) {
getWasmTableEntry(GLFW.active.mouseButtonFunc)(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active));
}
};
},
onRuntimeInitialized: function() {
// Triggered when the wasm module is loaded and ready to use.
document.getElementById("loading").style.display = "none"
@@ -111,13 +181,55 @@ var Module = {
print: (function() { })(),
printErr: function(text) { },
canvas: (function() {
let canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
const canvas = document.getElementById('canvas');
canvas.addEventListener("webglcontextlost", function(e) {
alert('WebGL context lost, please reload the page');
e.preventDefault();
}, false);
return canvas;
// Turn long touches into right-clicks
let timer = null;
canvas.addEventListener('touchstart', event => {
timer = setTimeout(() => {
let eventArgs = {
bubbles: true,
cancelable: true,
view: window,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY,
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY,
button: 2,
buttons: 2,
relatedTarget: event.target,
region: event.region
}
canvas.dispatchEvent(new MouseEvent('mousedown', eventArgs));
canvas.dispatchEvent(new MouseEvent('mouseup', eventArgs));
}, 400);
});
canvas.addEventListener('touchend', event => {
if (timer) {
clearTimeout(timer);
timer = null;
}
});
if (typeof WebGL2RenderingContext !== 'undefined') {
let gl = canvas.getContext('webgl2', { stencil: true });
if (!gl) {
console.error('WebGL 2 not available, falling back to WebGL');
gl = canvas.getContext('webgl', { stencil: true });
}
if (!gl) {
alert('WebGL not available with stencil buffer');
}
return canvas;
} else {
alert('WebGL 2 not supported by this browser');
}
})(),
setStatus: function(text) { },
totalDependencies: 0,
@@ -144,14 +256,9 @@ if (urlParams.has("lang")) {
window.addEventListener('resize', js_resizeCanvas, false);
function js_resizeCanvas() {
let canvas = document.getElementById('canvas');
canvas.top = document.documentElement.clientTop;
canvas.left = document.documentElement.clientLeft;
canvas.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
canvas.classList.add("canvas_full_screen")
if (GLFW.active && GLFW.active.windowPosFunc) {
getWasmTableEntry(GLFW.active.windowPosFunc)(GLFW.active.id, GLFW.active.x, GLFW.active.y);
}
GLFW.onWindowSizeChanged();
}

View File

@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.16)
project(libimhex)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_SHARED_LIBRARY_PREFIX "")
set(LIBIMHEX_SOURCES
source/api/imhex_api.cpp
@@ -37,6 +36,10 @@ set(LIBIMHEX_SOURCES
source/helpers/logger.cpp
source/helpers/tar.cpp
source/helpers/debugging.cpp
source/helpers/default_paths.cpp
source/helpers/imgui_hooks.cpp
source/test/tests.cpp
source/providers/provider.cpp
source/providers/memory_provider.cpp
@@ -77,37 +80,6 @@ else()
target_compile_definitions(libimhex PRIVATE IMHEX_PROJECT_NAME="${PROJECT_NAME}")
endif()
enableUnityBuild(libimhex)
setupCompilerFlags(libimhex)
include(GenerateExportHeader)
generate_export_header(libimhex)
target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR} ${MAGIC_LIBRARY_DIRS})
if (NOT EMSCRIPTEN)
# curl is only used in non-emscripten builds
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${CURL_LIBRARIES})
endif()
if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
if (WIN32)
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
elseif (APPLE)
find_library(FOUNDATION NAMES Foundation)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl ${JTHREAD_LIBRARIES})
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES})
endif()
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES})
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_BRANCH)
set(GIT_COMMIT_HASH_LONG "${IMHEX_COMMIT_HASH_LONG}")
@@ -142,4 +114,42 @@ endif ()
addDefineToSource(source/api/imhex_api.cpp "IMHEX_VERSION=\"${IMHEX_VERSION_STRING}\"")
add_dependencies(imhex_all libimhex)
enableUnityBuild(libimhex)
setupCompilerFlags(libimhex)
include(GenerateExportHeader)
generate_export_header(libimhex)
target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR} ${MAGIC_LIBRARY_DIRS})
if (NOT EMSCRIPTEN)
# curl is only used in non-emscripten builds
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} CURL::libcurl)
endif()
if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
if (WIN32)
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
elseif (APPLE)
find_library(FOUNDATION NAMES Foundation)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl ${JTHREAD_LIBRARIES})
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES})
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
endif()
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${LUNASVG_LIBRARIES} ${BOOST_LIBRARIES})
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
add_dependencies(imhex_all libimhex)
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set_target_properties(libimhex PROPERTIES PREFIX "")

View File

@@ -151,7 +151,7 @@ namespace hex {
if (m_icon.isValid())
return m_icon;
m_icon = ImGuiExt::Texture(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
m_icon = ImGuiExt::Texture::fromImage(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
return m_icon;
}

View File

@@ -6,6 +6,7 @@
#include <functional>
#include <map>
#include <mutex>
#include <span>
#include <string>
#include <utility>
@@ -98,7 +99,7 @@ namespace hex {
bool m_requiresRestart = false;
std::function<bool()> m_enabledCallback;
std::function<void(Widget&)> m_changedCallback;
std::optional<std::string> m_tooltip;
std::optional<UnlocalizedString> m_tooltip;
};
[[nodiscard]]
@@ -112,7 +113,7 @@ namespace hex {
}
[[nodiscard]]
const std::optional<std::string>& getTooltip() const {
const std::optional<UnlocalizedString>& getTooltip() const {
return m_interface.m_tooltip;
}
@@ -175,6 +176,21 @@ namespace hex {
float m_min, m_max;
};
class SliderDataSize : public Widget {
public:
SliderDataSize(u64 defaultValue, u64 min, u64 max) : m_value(defaultValue), m_min(min), m_max(max) { }
bool draw(const std::string &name) override;
void load(const nlohmann::json &data) override;
nlohmann::json store() override;
[[nodiscard]] i32 getValue() const { return m_value; }
protected:
u64 m_value;
u64 m_min, m_max;
};
class ColorPicker : public Widget {
public:
explicit ColorPicker(ImColor defaultColor);
@@ -340,6 +356,8 @@ namespace hex {
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &value) {
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
impl::runOnChangeHandlers(unlocalizedCategory, unlocalizedName, value);
impl::store();
}
using OnChangeCallback = std::function<void(const SettingsValue &)>;
@@ -756,6 +774,7 @@ namespace hex {
const std::multimap<u32, MainMenuItem>& getMainMenuItems();
const std::multimap<u32, MenuItem>& getMenuItems();
const std::vector<MenuItem*>& getToolbarMenuItems();
std::multimap<u32, MenuItem>& getMenuItemsMutable();
const std::vector<DrawCallback>& getWelcomeScreenEntries();
@@ -898,6 +917,11 @@ namespace hex {
*/
void addMenuItemToToolbar(const UnlocalizedString &unlocalizedName, ImGuiCustomCol color);
/**
* @brief Reconstructs the toolbar items list after they have been modified
*/
void updateToolbarItems();
/**
* @brief Adds a new sidebar item
* @param icon The icon to use for the item
@@ -931,7 +955,7 @@ namespace hex {
void addProviderName(const UnlocalizedString &unlocalizedName);
using ProviderCreationFunction = std::unique_ptr<prv::Provider>(*)();
using ProviderCreationFunction = std::function<std::unique_ptr<prv::Provider>()>;
void add(const std::string &typeName, ProviderCreationFunction creationFunction);
const std::vector<std::string>& getEntries();
@@ -963,12 +987,34 @@ namespace hex {
namespace impl {
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
struct Entry {
struct ExportMenuEntry {
UnlocalizedString unlocalizedName;
Callback callback;
};
const std::vector<Entry>& getEntries();
struct FindOccurrence {
Region region;
enum class DecodeType { ASCII, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
std::endian endian = std::endian::native;
bool selected;
};
using FindExporterCallback = std::function<std::vector<u8>(const std::vector<FindOccurrence>&, std::function<std::string(FindOccurrence)>)>;
struct FindExporterEntry {
UnlocalizedString unlocalizedName;
std::string fileExtension;
FindExporterCallback callback;
};
/**
* @brief Retrieves a list of all registered data formatters used by the 'File -> Export' menu
*/
const std::vector<ExportMenuEntry>& getExportMenuEntries();
/**
* @brief Retrieves a list of all registered data formatters used in the Results section of the 'Find' view
*/
const std::vector<FindExporterEntry>& getFindExporterEntries();
}
@@ -978,7 +1024,14 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the formatter
* @param callback The function to call to format the data
*/
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
void addExportMenuEntry(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
/**
* @brief Adds a new data exporter for Find results
* @param unlocalizedName The unlocalized name of the formatter
* @param callback The function to call to format the data
*/
void addFindExportFormatter(const UnlocalizedString &unlocalizedName, const std::string fileExtension, const impl::FindExporterCallback &callback);
}
@@ -1039,7 +1092,7 @@ namespace hex {
};
struct MiniMapVisualizer {
using Callback = std::function<ImColor(const std::vector<u8>&)>;
using Callback = std::function<void(u64, std::span<const u8>, std::vector<ImColor>&)>;
UnlocalizedString unlocalizedName;
Callback callback;

View File

@@ -2,28 +2,30 @@
#include <hex.hpp>
#include <algorithm>
#include <functional>
#include <list>
#include <mutex>
#include <map>
#include <string_view>
#include <functional>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/logger.hpp>
#include <wolv/types/type_name.hpp>
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
constexpr static auto ShouldLog = (should_log); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
\
static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(function); } \
static void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, function); } \
static void unsubscribe(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \
static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(token); } \
static void post(auto &&...args) noexcept { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \
};
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
constexpr static auto ShouldLog = (should_log); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
\
static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(std::move(function)); } \
static void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, std::move(function)); } \
static void unsubscribe(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \
static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(token); } \
static void post(auto &&...args) { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \
}
#define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, true, __VA_ARGS__)
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
@@ -56,6 +58,10 @@ namespace hex {
return m_hash == other.m_hash;
}
constexpr auto operator<=>(const EventId &other) const {
return m_hash <=> other.m_hash;
}
private:
u32 m_hash;
};
@@ -71,11 +77,13 @@ namespace hex {
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
void operator()(Params... params) const noexcept {
template<typename E>
void call(Params... params) const {
try {
m_func(params...);
} catch (const std::exception &e) {
log::error("An exception occurred while handling event: {}", e.what());
log::error("An exception occurred while handling event {}: {}", wolv::type::getTypeName<E>(), e.what());
throw;
}
}
@@ -95,7 +103,7 @@ namespace hex {
*/
class EventManager {
public:
using EventList = std::list<std::pair<impl::EventId, std::unique_ptr<impl::EventBase>>>;
using EventList = std::multimap<impl::EventId, std::unique_ptr<impl::EventBase>>;
/**
* @brief Subscribes to an event
@@ -108,7 +116,7 @@ namespace hex {
std::scoped_lock lock(getEventMutex());
auto &events = getEvents();
return events.insert(events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
return events.insert({ E::Id, std::make_unique<E>(function) });
}
/**
@@ -160,7 +168,7 @@ namespace hex {
});
if (iter != tokenStore.end()) {
getEvents().remove(*iter->second);
getEvents().erase(iter->second);
tokenStore.erase(iter);
}
@@ -172,17 +180,17 @@ namespace hex {
* @param args Arguments to pass to the event
*/
template<impl::EventType E>
static void post(auto &&...args) noexcept {
static void post(auto && ...args) {
std::scoped_lock lock(getEventMutex());
for (const auto &[id, event] : getEvents()) {
if (id == E::Id) {
(*static_cast<E *const>(event.get()))(std::forward<decltype(args)>(args)...);
}
auto [begin, end] = getEvents().equal_range(E::Id);
for (auto it = begin; it != end; ++it) {
const auto &[id, event] = *it;
(*static_cast<E *const>(event.get())).template call<E>(std::forward<decltype(args)>(args)...);
}
#if defined (DEBUG)
if (E::ShouldLog)
if constexpr (E::ShouldLog)
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
#endif
}
@@ -262,6 +270,7 @@ namespace hex {
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
EVENT_DEF(EventProviderDirtied, prv::Provider *);
/**
* @brief Called when a project has been loaded
@@ -271,6 +280,7 @@ namespace hex {
EVENT_DEF_NO_LOG(EventFrameBegin);
EVENT_DEF_NO_LOG(EventFrameEnd);
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
EVENT_DEF_NO_LOG(EventImGuiElementRendered, ImGuiID, const std::array<float, 4>&);
EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>);
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
@@ -308,4 +318,9 @@ namespace hex {
* The 'from' provider should not have any per provider data after this, and should be immediately deleted
*/
EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *);
/**
* Called when ImHex managed to catch an error in a general try/catch to prevent/recover from a crash
*/
EVENT_DEF(EventCrashRecovered, const std::exception &);
}

View File

@@ -3,11 +3,13 @@
#include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <functional>
#include <optional>
#include <span>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <wolv/io/fs.hpp>
@@ -73,7 +75,7 @@ namespace hex {
namespace impl {
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
using HoveringFunction = std::function<bool(const prv::Provider *, u64, const u8*, size_t)>;
using HoveringFunction = std::function<std::set<Region>(const prv::Provider *, u64, size_t)>;
const std::map<u32, Highlighting>& getBackgroundHighlights();
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions();
@@ -291,7 +293,7 @@ namespace hex {
namespace impl {
void resetClosingProvider();
const std::vector<prv::Provider*>& getClosingProviders();
std::set<prv::Provider*> getClosingProviders();
}
@@ -432,6 +434,7 @@ namespace hex {
void setInitialWindowProperties(InitialWindowProperties properties);
void setGPUVendor(const std::string &vendor);
void setGLRenderer(const std::string &renderer);
void addInitArgument(const std::string &key, const std::string &value = { });
@@ -571,6 +574,12 @@ namespace hex {
*/
const std::string& getGPUVendor();
/**
* @brief Gets the current GPU vendor
* @return The current GPU vendor
*/
const std::string& getGLRenderer();
/**
* @brief Checks if ImHex is running in portable mode
* @return Whether ImHex is running in portable mode
@@ -595,6 +604,16 @@ namespace hex {
*/
std::string getArchitecture();
struct LinuxDistro {
std::string name;
std::string version;
};
/**
* @brief Gets information related to the Linux distribution, if running on Linux
*/
std::optional<LinuxDistro> getLinuxDistro();
/**
* @brief Gets the current ImHex version
* @return ImHex version
@@ -620,6 +639,12 @@ namespace hex {
*/
bool isDebugBuild();
/**
* @brief Checks if this version of ImHex is a nightly build
* @return True if this version is a nightly, false if it's a release
*/
bool isNightlyBuild();
enum class UpdateType {
Stable,
Nightly
@@ -664,6 +689,12 @@ namespace hex {
*/
std::optional<InitialWindowProperties> getInitialWindowProperties();
/**
* @brief Gets the module handle of libimhex
* @return Module handle
*/
void* getLibImHexModuleHandle();
}
/**
@@ -698,6 +729,7 @@ namespace hex {
std::vector<GlyphRange> glyphRanges;
Offset offset;
u32 flags;
std::optional<u32> defaultSize;
};
namespace impl {
@@ -716,8 +748,8 @@ namespace hex {
GlyphRange range(const char *glyphBegin, const char *glyphEnd);
GlyphRange range(u32 codepointBegin, u32 codepointEnd);
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0);
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0);
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0, std::optional<u32> defaultSize = std::nullopt);
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0, std::optional<u32> defaultSize = std::nullopt);
constexpr static float DefaultFontSize = 13.0;

View File

@@ -46,7 +46,13 @@ namespace hex {
* @brief Get a list of all layouts
* @return List of all added layouts
*/
static std::vector<Layout> getLayouts();
static const std::vector<Layout> &getLayouts();
/**
* @brief Removes the layout with the given name
* @param name Name of the layout
*/
static void removeLayout(const std::string &name);
/**
* @brief Handles loading of layouts if needed

View File

@@ -102,12 +102,9 @@ namespace hex {
std::string m_unlocalizedString;
};
}
template<>
struct fmt::formatter<hex::Lang> : fmt::formatter<std::string_view> {
template<typename FormatContext>
auto format(const hex::Lang &entry, FormatContext &ctx) {
return fmt::formatter<std::string_view>::format(entry.get(), ctx);
// {fmt} formatter for hex::Lang
inline auto format_as(const hex::Lang &entry) {
return entry.get();
}
};
}

View File

@@ -15,8 +15,10 @@ struct ImGuiContext;
namespace hex {
struct SubCommand {
std::string commandKey;
std::string commandDesc;
std::string commandLong;
std::string commandShort;
std::string commandDescription;
std::function<void(const std::vector<std::string>&)> callback;
};
@@ -104,6 +106,10 @@ namespace hex {
static bool load();
static bool load(const std::fs::path &pluginFolder);
static bool loadLibraries();
static bool loadLibraries(const std::fs::path &libraryFolder);
static void unload();
static void reload();
static void initializeNewPlugins();
@@ -111,6 +117,7 @@ namespace hex {
static void addPlugin(const std::string &name, PluginFunctions functions);
static Plugin* getPlugin(const std::string &name);
static const std::list<Plugin>& getPlugins();
static const std::vector<std::fs::path>& getPluginPaths();
static const std::vector<std::fs::path>& getPluginLoadPaths();
@@ -121,6 +128,7 @@ namespace hex {
static std::list<Plugin>& getPluginsMutable();
static AutoReset<std::vector<std::fs::path>> s_pluginPaths, s_pluginLoadPaths;
static AutoReset<std::vector<uintptr_t>> s_loadedLibraries;
};
}

View File

@@ -119,6 +119,8 @@ namespace hex {
decltype(m_steps)::iterator m_currentStep, m_latestStep;
};
static void init();
/**
* @brief Gets a list of all tutorials
* @return List of all tutorials
@@ -145,6 +147,10 @@ namespace hex {
*/
static void startTutorial(const UnlocalizedString &unlocalizedName);
static void startHelpHover();
static void addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString unlocalizedString);
static void addInteractiveHelpLink(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, std::string link);
/**
* @brief Draws the tutorial

View File

@@ -13,18 +13,22 @@ namespace hex {
struct Workspace {
std::string layout;
std::fs::path path;
bool builtin;
};
static void createWorkspace(const std::string &name, const std::string &layout = "");
static void switchWorkspace(const std::string &name);
static void importFromFile(const std::fs::path &path);
static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {});
static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {}, bool builtin = false);
static void removeWorkspace(const std::string &name);
static const auto& getWorkspaces() { return *s_workspaces; }
static const auto& getCurrentWorkspace() { return s_currentWorkspace; }
static void reset();
static void reload();
static void process();
@@ -32,7 +36,7 @@ namespace hex {
WorkspaceManager() = default;
static AutoReset<std::map<std::string, Workspace>> s_workspaces;
static decltype(s_workspaces)::Type::iterator s_currentWorkspace, s_previousWorkspace;
static decltype(s_workspaces)::Type::iterator s_currentWorkspace, s_previousWorkspace, s_workspaceToRemove;
};
}

View File

@@ -50,14 +50,23 @@ namespace hex {
T& operator=(const T &value) {
m_value = value;
m_valid = true;
return m_value;
}
T& operator=(T &&value) noexcept {
m_value = std::move(value);
m_valid = true;
return m_value;
}
bool isValid() const {
return m_valid;
}
private:
friend void ImHexApi::System::impl::cleanup();
void reset() override {
if constexpr (requires { m_value.reset(); }) {
m_value.reset();
@@ -68,9 +77,12 @@ namespace hex {
} else {
m_value = { };
}
m_valid = false;
}
private:
bool m_valid = true;
T m_value;
};

View File

@@ -0,0 +1,111 @@
#pragma once
#include <hex/helpers/fs.hpp>
#include <vector>
namespace hex::paths {
namespace impl {
class DefaultPath {
protected:
constexpr DefaultPath() = default;
virtual ~DefaultPath() = default;
public:
DefaultPath(const DefaultPath&) = delete;
DefaultPath(DefaultPath&&) = delete;
DefaultPath& operator=(const DefaultPath&) = delete;
DefaultPath& operator=(DefaultPath&&) = delete;
virtual std::vector<std::fs::path> all() const = 0;
virtual std::vector<std::fs::path> read() const;
virtual std::vector<std::fs::path> write() const;
};
class ConfigPath : public DefaultPath {
public:
explicit ConfigPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
std::vector<std::fs::path> all() const override;
private:
std::fs::path m_postfix;
};
class DataPath : public DefaultPath {
public:
explicit DataPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
std::vector<std::fs::path> all() const override;
std::vector<std::fs::path> write() const override;
private:
std::fs::path m_postfix;
};
class PluginPath : public DefaultPath {
public:
explicit PluginPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
std::vector<std::fs::path> all() const override;
private:
std::fs::path m_postfix;
};
}
std::vector<std::fs::path> getDataPaths(bool includeSystemFolders);
std::vector<std::fs::path> getConfigPaths(bool includeSystemFolders);
const static inline impl::ConfigPath Config("config");
const static inline impl::ConfigPath Recent("recent");
const static inline impl::PluginPath Libraries("lib");
const static inline impl::PluginPath Plugins("plugins");
const static inline impl::DataPath Patterns("patterns");
const static inline impl::DataPath PatternsInclude("includes");
const static inline impl::DataPath Magic("magic");
const static inline impl::DataPath Yara("yara");
const static inline impl::DataPath YaraAdvancedAnalysis("yara/advanced_analysis");
const static inline impl::DataPath Backups("backups");
const static inline impl::DataPath Resources("resources");
const static inline impl::DataPath Constants("constants");
const static inline impl::DataPath Encodings("encodings");
const static inline impl::DataPath Logs("logs");
const static inline impl::DataPath Scripts("scripts");
const static inline impl::DataPath Inspectors("scripts/inspectors");
const static inline impl::DataPath Themes("themes");
const static inline impl::DataPath Nodes("scripts/nodes");
const static inline impl::DataPath Layouts("layouts");
const static inline impl::DataPath Workspaces("workspaces");
constexpr static inline std::array<const impl::DefaultPath*, 20> All = {
&Config,
&Recent,
&Libraries,
&Plugins,
&Patterns,
&PatternsInclude,
&Magic,
&Yara,
&YaraAdvancedAnalysis,
&Backups,
&Resources,
&Constants,
&Encodings,
&Logs,
&Scripts,
&Inspectors,
&Themes,
&Nodes,
&Layouts,
&Workspaces,
};
}

View File

@@ -2,6 +2,7 @@
#include <string_view>
#include <fmt/format.h>
#include <fmt/ranges.h>
namespace hex {

View File

@@ -1,7 +1,5 @@
#pragma once
#include <hex.hpp>
#include <string>
#include <vector>
#include <filesystem>
@@ -31,36 +29,7 @@ namespace hex::fs {
void openFolderExternal(const std::fs::path &dirPath);
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath);
enum class ImHexPath : u32 {
Patterns = 0,
PatternsInclude,
Magic,
Plugins,
Yara,
YaraAdvancedAnalysis,
Config,
Backups,
Resources,
Constants,
Encodings,
Logs,
Recent,
Scripts,
Inspectors,
Themes,
Libraries,
Nodes,
Layouts,
Workspaces,
END
};
bool isPathWritable(const std::fs::path &path);
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
// Temporarily expose these for the migration function
std::vector<std::fs::path> getDataPaths();
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder);
}

View File

@@ -1,72 +1,76 @@
#pragma once
#include <future>
#if defined(OS_WEB)
#include <emscripten/fetch.h>
#include <future>
namespace hex {
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
#include <emscripten/fetch.h>
// Execute the request
auto result = this->executeImpl<T>(response);
namespace hex {
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
// Write the result to the file
wolv::io::File file(path, wolv::io::File::Mode::Create);
file.writeBuffer(reinterpret_cast<const u8*>(result.getData().data()), result.getData().size());
// Execute the request
auto result = this->executeImpl<T>(response);
return result;
});
}
// Write the result to the file
wolv::io::File file(path, wolv::io::File::Mode::Create);
file.writeBuffer(reinterpret_cast<const u8*>(result.getData().data()), result.getData().size());
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
hex::unused(path, mimeName);
throw std::logic_error("Not implemented");
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
hex::unused(data, mimeName, fileName);
throw std::logic_error("Not implemented");
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
strcpy(m_attr.requestMethod, m_method.c_str());
m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
if (!m_body.empty()) {
m_attr.requestData = m_body.c_str();
m_attr.requestDataSize = m_body.size();
return result;
});
}
std::vector<const char*> headers;
for (auto it = m_headers.begin(); it != m_headers.end(); it++) {
headers.push_back(it->first.c_str());
headers.push_back(it->second.c_str());
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
hex::unused(path, mimeName);
throw std::logic_error("Not implemented");
}
headers.push_back(nullptr);
m_attr.requestHeaders = headers.data();
// Send request
emscripten_fetch_t* fetch = emscripten_fetch(&m_attr, m_url.c_str());
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
hex::unused(data, mimeName, fileName);
throw std::logic_error("Not implemented");
}
data.resize(fetch->numBytes);
std::copy(fetch->data, fetch->data + fetch->numBytes, data.begin());
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
strcpy(m_attr.requestMethod, m_method.c_str());
m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
if (!m_body.empty()) {
m_attr.requestData = m_body.c_str();
m_attr.requestDataSize = m_body.size();
}
std::vector<const char*> headers;
for (auto it = m_headers.begin(); it != m_headers.end(); it++) {
headers.push_back(it->first.c_str());
headers.push_back(it->second.c_str());
}
headers.push_back(nullptr);
m_attr.requestHeaders = headers.data();
// Send request
emscripten_fetch_t* fetch = emscripten_fetch(&m_attr, m_url.c_str());
data.resize(fetch->numBytes);
std::copy(fetch->data, fetch->data + fetch->numBytes, data.begin());
return Result<T>(fetch->status, { data.begin(), data.end() });
}
return Result<T>(fetch->status, { data.begin(), data.end() });
}
}
#endif

View File

@@ -1,145 +1,149 @@
#pragma once
#include <string>
#include <future>
#if !defined(OS_WEB)
#include <curl/curl.h>
#include <string>
#include <future>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/fmt.hpp>
#include <curl/curl.h>
#include <wolv/utils/string.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/fmt.hpp>
namespace hex {
#include <wolv/utils/string.hpp>
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
namespace hex {
wolv::io::File file(path, wolv::io::File::Mode::Create);
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &file);
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
return this->executeImpl<T>(response);
});
}
wolv::io::File file(path, wolv::io::File::Mode::Create);
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &file);
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
return std::async(std::launch::async, [this, path, mimeName]{
auto fileName = wolv::util::toUTF8String(path.filename());
curl_mime *mime = curl_mime_init(m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
wolv::io::File file(path, wolv::io::File::Mode::Read);
curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto handle = static_cast<FILE*>(arg);
return fread(buffer, size, nitems, handle);
},
[](void *arg, curl_off_t offset, int origin) -> int {
auto handle = static_cast<FILE*>(arg);
if (fseek(handle, offset, origin) != 0)
return CURL_SEEKFUNC_CANTSEEK;
else
return CURL_SEEKFUNC_OK;
},
[](void *arg) {
auto handle = static_cast<FILE*>(arg);
fclose(handle);
},
file.getHandle());
curl_mime_filename(part, fileName.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
curl_mime *mime = curl_mime_init(m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
auto fileNameStr = wolv::util::toUTF8String(fileName.filename());
curl_mime_filename(part, fileNameStr.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method.c_str());
setDefaultConfig();
if (!m_body.empty()) {
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str());
return this->executeImpl<T>(response);
});
}
curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Cache-Control: no-cache");
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
return std::async(std::launch::async, [this, path, mimeName]{
auto fileName = wolv::util::toUTF8String(path.filename());
for (auto &[key, value] : m_headers) {
std::string header = hex::format("{}: {}", key, value);
headers = curl_slist_append(headers, header.c_str());
curl_mime *mime = curl_mime_init(m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
wolv::io::File file(path, wolv::io::File::Mode::Read);
curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto handle = static_cast<FILE*>(arg);
return fread(buffer, size, nitems, handle);
},
[](void *arg, curl_off_t offset, int origin) -> int {
auto handle = static_cast<FILE*>(arg);
if (fseek(handle, offset, origin) != 0)
return CURL_SEEKFUNC_CANTSEEK;
else
return CURL_SEEKFUNC_OK;
},
[](void *arg) {
auto handle = static_cast<FILE*>(arg);
fclose(handle);
},
file.getHandle());
curl_mime_filename(part, fileName.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
{
std::scoped_lock lock(m_transmissionMutex);
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
curl_mime *mime = curl_mime_init(m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
auto result = curl_easy_perform(m_curl);
if (result != CURLE_OK){
char *url = nullptr;
curl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &url);
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", m_method, url, u32(result), curl_easy_strerror(result));
checkProxyErrors();
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
auto fileNameStr = wolv::util::toUTF8String(fileName.filename());
curl_mime_filename(part, fileNameStr.c_str());
curl_mime_name(part, mimeName.c_str());
return { };
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method.c_str());
setDefaultConfig();
if (!m_body.empty()) {
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str());
}
curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Cache-Control: no-cache");
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
for (auto &[key, value] : m_headers) {
std::string header = hex::format("{}: {}", key, value);
headers = curl_slist_append(headers, header.c_str());
}
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
{
std::scoped_lock lock(m_transmissionMutex);
auto result = curl_easy_perform(m_curl);
if (result != CURLE_OK){
char *url = nullptr;
curl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &url);
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", m_method, url, u32(result), curl_easy_strerror(result));
checkProxyErrors();
return { };
}
}
long statusCode = 0;
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
return Result<T>(statusCode, { data.begin(), data.end() });
}
long statusCode = 0;
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
return Result<T>(statusCode, { data.begin(), data.end() });
}
}
#endif

View File

@@ -2,12 +2,11 @@
#include <hex.hpp>
#include <mutex>
#include <fmt/core.h>
#include <fmt/color.h>
#include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp>
namespace hex::log {
@@ -19,8 +18,11 @@ namespace hex::log {
[[maybe_unused]] void redirectToFile();
[[maybe_unused]] void enableColorPrinting();
[[nodiscard]] std::recursive_mutex& getLoggerMutex();
[[nodiscard]] bool isLoggingSuspended();
[[nodiscard]] bool isDebugLoggingEnabled();
void lockLoggerMutex();
void unlockLoggerMutex();
struct LogEntry {
std::string project;
@@ -37,16 +39,19 @@ namespace hex::log {
if (isLoggingSuspended()) [[unlikely]]
return;
std::scoped_lock lock(getLoggerMutex());
lockLoggerMutex();
ON_SCOPE_EXIT { unlockLoggerMutex(); };
auto dest = getDestination();
printPrefix(dest, ts, level, IMHEX_PROJECT_NAME);
try {
printPrefix(dest, ts, level, IMHEX_PROJECT_NAME);
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}\n", message);
fflush(dest);
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}\n", message);
fflush(dest);
addLogEntry(IMHEX_PROJECT_NAME, level, std::move(message));
addLogEntry(IMHEX_PROJECT_NAME, level, std::move(message));
} catch (const std::exception&) { }
}
namespace color {
@@ -63,13 +68,14 @@ namespace hex::log {
void suspendLogging();
void resumeLogging();
void enableDebugLogging();
[[maybe_unused]] void debug(const std::string &fmt, auto && ... args) {
#if defined(DEBUG)
if (impl::isDebugLoggingEnabled()) [[unlikely]] {
hex::log::impl::print(fg(impl::color::debug()) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
#else
} else {
impl::addLogEntry(IMHEX_PROJECT_NAME, "[DEBUG]", fmt::format(fmt::runtime(fmt), args...));
#endif
}
}
[[maybe_unused]] void info(const std::string &fmt, auto && ... args) {
@@ -88,23 +94,28 @@ namespace hex::log {
hex::log::impl::print(fg(impl::color::fatal()) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
}
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
std::scoped_lock lock(impl::getLoggerMutex());
impl::lockLoggerMutex();
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
auto dest = impl::getDestination();
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}", message);
fflush(dest);
try {
auto dest = impl::getDestination();
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}", message);
fflush(dest);
} catch (const std::exception&) { }
}
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
std::scoped_lock lock(impl::getLoggerMutex());
impl::lockLoggerMutex();
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
auto dest = impl::getDestination();
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}\n", message);
fflush(dest);
try {
auto dest = impl::getDestination();
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}\n", message);
fflush(dest);
} catch (const std::exception&) { }
}
}
}

View File

@@ -61,6 +61,10 @@ namespace hex {
constexpr static Region Invalid() {
return { 0, 0 };
}
constexpr bool operator<(const Region &other) const {
return this->address < other.address;
}
};

View File

@@ -152,7 +152,7 @@ namespace hex {
using SizeType = typename SizeTypeImpl<Size>::Type;
template<typename T>
[[nodiscard]] constexpr T changeEndianess(const T &value, size_t size, std::endian endian) {
[[nodiscard]] constexpr T changeEndianness(const T &value, size_t size, std::endian endian) {
if (endian == std::endian::native)
return value;
@@ -172,8 +172,8 @@ namespace hex {
}
template<typename T>
[[nodiscard]] constexpr T changeEndianess(const T &value, std::endian endian) {
return changeEndianess(value, sizeof(value), endian);
[[nodiscard]] constexpr T changeEndianness(const T &value, std::endian endian) {
return changeEndianness(value, sizeof(value), endian);
}
[[nodiscard]] constexpr u128 bitmask(u8 bits) {
@@ -298,31 +298,7 @@ namespace hex {
[[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env);
[[nodiscard]] inline std::string limitStringLength(const std::string &string, size_t maxLength) {
// If the string is shorter than the max length, return it as is
if (string.size() < maxLength)
return string;
// If the string is longer than the max length, find the last space before the max length
auto it = string.begin() + maxLength;
while (it != string.begin() && !std::isspace(*it)) --it;
// If there's no space before the max length, just cut the string
if (it == string.begin()) {
it = string.begin() + maxLength;
// Try to find a UTF-8 character boundary
while (it != string.begin() && (*it & 0x80) != 0x00) --it;
++it;
}
// If we still didn't find a valid boundary, just return the string as is
if (it == string.begin())
return string;
// Append
return std::string(string.begin(), it) + "";
}
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength);
[[nodiscard]] std::optional<std::fs::path> getInitialFilePath();
@@ -331,4 +307,14 @@ namespace hex {
[[nodiscard]] std::string formatSystemError(i32 error);
/**
* Gets the shared library handle for a given pointer
* @param symbol Pointer to any function or variable in the shared library
* @return The module handle
* @warning Important! Calling this function on functions defined in other modules will return the handle of the current module!
* This is because you're not actually passing a pointer to the function in the other module but rather a pointer to a thunk
* that is defined in the current module.
*/
[[nodiscard]] void* getContainingModule(void* symbol);
}

View File

@@ -15,6 +15,10 @@
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode);
void enumerateFontsMacos();
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window);
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
}
#endif
#endif

View File

@@ -37,15 +37,34 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
return nullptr;
}
[[maybe_unused]] static auto& getFeaturesImpl() {
static std::vector<hex::Feature> features;
return features;
}
#if defined (IMHEX_STATIC_LINK_PLUGINS)
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static
#else
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
#endif
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
#define IMHEX_DEFINE_PLUGIN_FEATURES() IMHEX_DEFINE_PLUGIN_FEATURES_IMPL()
#define IMHEX_DEFINE_PLUGIN_FEATURES_IMPL() \
template<> \
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
static void* getFeatures(); \
}; \
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
return &getFeaturesImpl(); \
} \
static auto initFeatures = [] { getFeaturesImpl() = std::vector<hex::Feature>({ IMHEX_PLUGIN_FEATURES_CONTENT }); return 0; }()
#define IMHEX_PLUGIN_FEATURES ::getFeaturesImpl()
/**
* This macro is used to define all the required entry points for a plugin.
* Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
* Name, Author and Description will be displayed in the plugin list on the Welcome screen.
*/
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
@@ -85,6 +104,7 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
ImGui::SetCurrentContext(ctx); \
GImGui = ctx; \
} \
IMHEX_DEFINE_PLUGIN_FEATURES(); \
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
} \
@@ -129,16 +149,3 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
return &g_subCommands; \
} \
std::vector<hex::SubCommand> g_subCommands
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
#define IMHEX_PLUGIN_FEATURES() IMHEX_PLUGIN_FEATURES_IMPL()
#define IMHEX_PLUGIN_FEATURES_IMPL() \
extern std::vector<hex::Feature> g_features; \
template<> \
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
static void* getFeatures(); \
}; \
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
return &g_features; \
} \
std::vector<hex::Feature> g_features

View File

@@ -35,8 +35,6 @@ namespace hex::prv {
[[nodiscard]] u64 getActualSize() const override { return m_data.size(); }
void resizeRaw(u64 newSize) override;
void insertRaw(u64 offset, u64 size) override;
void removeRaw(u64 offset, u64 size) override;
[[nodiscard]] std::string getName() const override { return m_name; }

View File

@@ -148,7 +148,7 @@ namespace hex::prv {
* @brief Gets the type name of this provider
* @note This is mainly used to be stored in project files and recents to be able to later on
* recreate this exact provider type. This needs to be unique across all providers, this is usually something
* like "hex.builtin.provider.memory" or "hex.builtin.provider.file"
* like "hex.builtin.provider.mem_file" or "hex.builtin.provider.file"
* @return The provider's type name
*/
[[nodiscard]] virtual std::string getTypeName() const = 0;
@@ -161,13 +161,13 @@ namespace hex::prv {
*/
[[nodiscard]] virtual std::string getName() const = 0;
void resize(u64 newSize);
bool resize(u64 newSize);
void insert(u64 offset, u64 size);
void remove(u64 offset, u64 size);
virtual void resizeRaw(u64 newSize) { hex::unused(newSize); }
virtual void insertRaw(u64 offset, u64 size) { hex::unused(offset, size); }
virtual void removeRaw(u64 offset, u64 size) { hex::unused(offset, size); }
virtual void insertRaw(u64 offset, u64 size);
virtual void removeRaw(u64 offset, u64 size);
virtual void save();
virtual void saveAs(const std::fs::path &path);
@@ -258,7 +258,7 @@ namespace hex::prv {
*/
bool m_skipLoadInterface = false;
std::string m_errorMessage;
std::string m_errorMessage = "Unspecified error";
u64 m_pageSize = MaxPageSize;
};

View File

@@ -74,21 +74,30 @@ namespace hex {
return m_data | std::views::values;
}
void setOnCreateCallback(std::function<void(const prv::Provider *, T&)> callback) {
void setOnCreateCallback(std::function<void(prv::Provider *, T&)> callback) {
m_onCreateCallback = std::move(callback);
}
void setOnDestroyCallback(std::function<void(prv::Provider *, T&)> callback) {
m_onDestroyCallback = std::move(callback);
}
private:
void onCreate() {
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) {
auto [it, inserted] = m_data.emplace(provider, T());
auto &[key, value] = *it;
if (m_onCreateCallback)
m_onCreateCallback(key, value);
m_onCreateCallback(provider, value);
});
EventProviderDeleted::subscribe(this, [this](prv::Provider *provider){
m_data.erase(provider);
if (auto it = m_data.find(provider); it != m_data.end()) {
if (m_onDestroyCallback)
m_onDestroyCallback(provider, m_data.at(provider));
m_data.erase(it);
}
});
EventImHexClosing::subscribe(this, [this] {
@@ -113,6 +122,7 @@ namespace hex {
}
void onDestroy() {
EventProviderOpened::unsubscribe(this);
EventProviderDeleted::unsubscribe(this);
EventImHexClosing::unsubscribe(this);
@@ -121,7 +131,7 @@ namespace hex {
private:
std::map<const prv::Provider *, T> m_data;
std::function<void(const prv::Provider *, T&)> m_onCreateCallback;
std::function<void(prv::Provider *, T&)> m_onCreateCallback, m_onDestroyCallback;
};
}

View File

@@ -27,6 +27,7 @@ namespace hex::prv::undo {
void groupOperations(u32 count, const UnlocalizedString &unlocalizedName);
void apply(const Stack &otherStack);
void reapply();
[[nodiscard]] bool canUndo() const;
[[nodiscard]] bool canRedo() const;

View File

@@ -5,6 +5,7 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/api/plugin_manager.hpp>
#include <wolv/utils/preproc.hpp>
@@ -28,16 +29,20 @@
} \
} while (0)
#define INIT_PLUGIN(name) \
if (!hex::test::initPluginImpl(name)) TEST_FAIL();
namespace hex::test {
using Function = int(*)();
struct Test {
std::function<int()> function;
Function function;
bool shouldFail;
};
class Tests {
public:
static auto addTest(const std::string &name, const std::function<int()> &func, bool shouldFail) noexcept {
static auto addTest(const std::string &name, Function func, bool shouldFail) noexcept {
s_tests.insert({
name, {func, shouldFail}
});
@@ -50,7 +55,7 @@ namespace hex::test {
}
private:
static inline std::map<std::string, Test> s_tests;
static std::map<std::string, Test> s_tests;
};
template<class F>
@@ -86,4 +91,5 @@ namespace hex::test {
return TestSequence<F>(executor.getName(), std::forward<F>(f), executor.shouldFail());
}
bool initPluginImpl(std::string name);
}

View File

@@ -76,14 +76,21 @@ namespace ImGuiExt {
};
Texture() = default;
Texture(const ImU8 *buffer, int size, Filter filter = Filter::Nearest, int width = 0, int height = 0);
Texture(std::span<const std::byte> bytes, Filter filter = Filter::Nearest, int width = 0, int height = 0);
explicit Texture(const char *path, Filter filter = Filter::Nearest);
explicit Texture(const std::fs::path &path, Filter filter = Filter::Nearest);
Texture(unsigned int texture, int width, int height);
Texture(const Texture&) = delete;
Texture(Texture&& other) noexcept;
static Texture fromImage(const ImU8 *buffer, int size, Filter filter = Filter::Nearest);
static Texture fromImage(std::span<const std::byte> buffer, Filter filter = Filter::Nearest);
static Texture fromImage(const char *path, Filter filter = Filter::Nearest);
static Texture fromImage(const std::fs::path &path, Filter filter = Filter::Nearest);
static Texture fromGLTexture(unsigned int texture, int width, int height);
static Texture fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter = Filter::Nearest);
static Texture fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter = Filter::Nearest);
static Texture fromSVG(const char *path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
static Texture fromSVG(std::span<const std::byte> buffer, int width = 0, int height = 0, Filter filter = Filter::Nearest);
~Texture();
Texture& operator=(const Texture&) = delete;
@@ -116,6 +123,8 @@ namespace ImGuiExt {
int m_width = 0, m_height = 0;
};
float GetTextWrapPos();
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
@@ -124,7 +133,7 @@ namespace ImGuiExt {
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool DescriptionButtonProgress(const char *label, const char *description, float fraction, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
void HelpHover(const char *text);
void HelpHover(const char *text, const char *icon = "(?)", ImU32 iconColor = ImGui::GetColorU32(ImGuiCol_ButtonActive));
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
@@ -143,6 +152,8 @@ namespace ImGuiExt {
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, ImGuiSliderFlags flags = ImGuiSliderFlags_None);
inline bool HasSecondPassed() {
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
}
@@ -154,6 +165,7 @@ namespace ImGuiExt {
struct Styles {
float WindowBlur = 0.0F;
float PopupWindowAlpha = 0.0F; // Alpha used by Popup tool windows when the user is not hovering over them
} styles;
};
@@ -175,11 +187,16 @@ namespace ImGuiExt {
void SmallProgressBar(float fraction, float yOffset = 0.0F);
inline void TextFormatted(const std::string &fmt, auto &&...args) {
ImGui::TextUnformatted(hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
inline void TextFormatted(std::string_view fmt, auto &&...args) {
if constexpr (sizeof...(args) == 0) {
ImGui::TextUnformatted(fmt.data(), fmt.data() + fmt.size());
} else {
const auto string = hex::format(fmt, std::forward<decltype(args)>(args)...);
ImGui::TextUnformatted(string.c_str(), string.c_str() + string.size());
}
}
inline void TextFormattedSelectable(const std::string &fmt, auto &&...args) {
inline void TextFormattedSelectable(std::string_view fmt, auto &&...args) {
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
ImGui::PushID(text.c_str());
@@ -187,8 +204,8 @@ namespace ImGuiExt {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
ImGui::PushItemWidth(-FLT_MIN);
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly);
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll);
ImGui::PopItemWidth();
ImGui::PopStyleColor();
@@ -197,19 +214,28 @@ namespace ImGuiExt {
ImGui::PopID();
}
inline void TextFormattedColored(ImColor color, const std::string &fmt, auto &&...args) {
ImGui::TextColored(color, "%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
inline void TextFormattedColored(ImColor color, std::string_view fmt, auto &&...args) {
ImGui::PushStyleColor(ImGuiCol_Text, color.Value);
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
ImGui::PopStyleColor();
}
inline void TextFormattedDisabled(const std::string &fmt, auto &&...args) {
ImGui::TextDisabled("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
inline void TextFormattedDisabled(std::string_view fmt, auto &&...args) {
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
ImGui::PopStyleColor();
}
inline void TextFormattedWrapped(const std::string &fmt, auto &&...args) {
ImGui::TextWrapped("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
inline void TextFormattedWrapped(std::string_view fmt, auto &&...args) {
const bool need_backup = ImGuiExt::GetTextWrapPos() < 0.0F; // Keep existing wrap position if one is already set
if (need_backup)
ImGui::PushTextWrapPos(0.0F);
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
if (need_backup)
ImGui::PopTextWrapPos();
}
inline void TextFormattedWrappedSelectable(const std::string &fmt, auto &&...args) {
inline void TextFormattedWrappedSelectable(std::string_view fmt, auto &&...args) {
// Manually wrap text, using the letter M (generally the widest character in non-monospaced fonts) to calculate the character width to use.
auto text = wolv::util::wrapMonospacedString(
hex::format(fmt, std::forward<decltype(args)>(args)...),
@@ -222,7 +248,7 @@ namespace ImGuiExt {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
ImGui::PushItemWidth(-FLT_MIN);
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
ImGui::InputTextMultiline(
"##",
const_cast<char *>(text.c_str()),
@@ -239,13 +265,13 @@ namespace ImGuiExt {
}
void TextUnformattedCentered(const char *text);
inline void TextFormattedCentered(const std::string &fmt, auto &&...args) {
inline void TextFormattedCentered(std::string_view fmt, auto &&...args) {
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
TextUnformattedCentered(text.c_str());
}
inline void TextFormattedCenteredHorizontal(const std::string &fmt, auto &&...args) {
inline void TextFormattedCenteredHorizontal(std::string_view fmt, auto &&...args) {
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
auto availableSpace = ImGui::GetContentRegionAvail();
auto textSize = ImGui::CalcTextSize(text.c_str(), nullptr, false, availableSpace.x * 0.75F);
@@ -276,7 +302,7 @@ namespace ImGuiExt {
bool BeginBox();
void EndBox();
void BeginSubWindow(const char *label, ImVec2 size = ImVec2(0, 0), ImGuiChildFlags flags = ImGuiChildFlags_None);
bool BeginSubWindow(const char *label, bool *collapsed = nullptr, ImVec2 size = ImVec2(0, 0), ImGuiChildFlags flags = ImGuiChildFlags_None);
void EndSubWindow();
void ConfirmButtons(const char *textLeft, const char *textRight, const auto &leftButtonCallback, const auto &rightButtonCallback) {
@@ -297,6 +323,9 @@ namespace ImGuiExt {
bool ToggleSwitch(const char *label, bool *v);
bool ToggleSwitch(const char *label, bool v);
bool PopupTitleBarButton(const char* label, bool p_enabled);
void PopupTitleBarText(const char* text);
template<typename T>
constexpr ImGuiDataType getImGuiDataType() {
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;

View File

@@ -80,6 +80,8 @@ namespace hex {
*/
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
[[nodiscard]] virtual bool shouldStoreWindowState() const { return true; }
[[nodiscard]] const char *getIcon() const { return m_icon; }
[[nodiscard]] bool &getWindowOpenState();
@@ -156,6 +158,7 @@ namespace hex {
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {}
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
};
/**
@@ -178,12 +181,13 @@ namespace hex {
ImGui::EndPopup();
}
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
this->getWindowOpenState() = false;
}
}
virtual bool hasCloseButton() const { return true; }
[[nodiscard]] virtual bool hasCloseButton() const { return true; }
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
};
}

View File

@@ -2,6 +2,7 @@
#include <hex/api/event_manager.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <nlohmann/json.hpp>
@@ -197,7 +198,7 @@ namespace hex {
constexpr static auto AchievementsFile = "achievements.json";
void AchievementManager::loadProgress() {
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
for (const auto &directory : paths::Config.read()) {
auto path = directory / AchievementsFile;
if (!wolv::io::fs::exists(path)) {
@@ -246,7 +247,7 @@ namespace hex {
if (json.empty())
return;
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
for (const auto &directory : paths::Config.write()) {
auto path = directory / AchievementsFile;
wolv::io::File file(path, wolv::io::File::Mode::Create);

View File

@@ -4,6 +4,7 @@
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <hex/ui/view.hpp>
#include <hex/data_processor/node.hpp>
@@ -51,10 +52,14 @@ namespace hex {
if (!settings[unlocalizedCategory].contains(unlocalizedName))
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
if (settings[unlocalizedCategory][unlocalizedName].is_null())
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
return settings[unlocalizedCategory][unlocalizedName];
}
#if defined(OS_WEB)
void load() {
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
let data = localStorage.getItem("config");
@@ -70,7 +75,11 @@ namespace hex {
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
for (const auto &[name, callbacks] : rest) {
for (const auto &[id, callback] : callbacks) {
callback(getSetting(category, name, {}));
try {
callback(getSetting(category, name, {}));
} catch (const std::exception &e) {
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
}
}
}
}
@@ -93,7 +102,7 @@ namespace hex {
void load() {
bool loaded = false;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
for (const auto &dir : paths::Config.read()) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
if (file.isValid()) {
@@ -109,14 +118,21 @@ namespace hex {
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
for (const auto &[name, callbacks] : rest) {
for (const auto &[id, callback] : callbacks) {
callback(getSetting(category, name, {}));
try {
callback(getSetting(category, name, {}));
} catch (const std::exception &e) {
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
}
}
}
}
}
void store() {
const auto &settingsData = getSettingsData();
if (!s_settings.isValid())
return;
const auto &settingsData = *s_settings;
// During a crash settings can be empty, causing them to be overwritten.
if (settingsData.empty()) {
@@ -127,7 +143,7 @@ namespace hex {
if (result.empty()) {
return;
}
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
for (const auto &dir : paths::Config.write()) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
if (file.isValid()) {
@@ -138,7 +154,7 @@ namespace hex {
}
void clear() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
for (const auto &dir : paths::Config.write()) {
wolv::io::fs::remove(dir / SettingsFile);
}
}
@@ -297,6 +313,23 @@ namespace hex {
}
bool SliderDataSize::draw(const std::string &name) {
return ImGuiExt::SliderBytes(name.c_str(), &m_value, m_min, m_max);
}
void SliderDataSize::load(const nlohmann::json &data) {
if (data.is_number_integer()) {
m_value = data.get<u64>();
} else {
log::warn("Invalid data type loaded from settings for slider!");
}
}
nlohmann::json SliderDataSize::store() {
return m_value;
}
ColorPicker::ColorPicker(ImColor defaultColor) {
m_value = {
defaultColor.Value.x,
@@ -533,6 +566,11 @@ namespace hex {
pl::PatternLanguage& getRuntime() {
static PerProvider<pl::PatternLanguage> runtime;
AT_FIRST_TIME {
runtime.setOnCreateCallback([](prv::Provider *provider, pl::PatternLanguage &runtime) {
configureRuntime(runtime, provider);
});
};
return *runtime;
}
@@ -558,7 +596,7 @@ namespace hex {
);
}
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
runtime.setIncludePaths(paths::PatternsInclude.read() | paths::Patterns.read());
for (const auto &[ns, name, paramCount, callback, dangerous] : impl::getFunctions()) {
if (dangerous)
@@ -783,6 +821,12 @@ namespace hex {
return *s_menuItems;
}
static AutoReset<std::vector<MenuItem*>> s_toolbarMenuItems;
const std::vector<MenuItem*>& getToolbarMenuItems() {
return s_toolbarMenuItems;
}
std::multimap<u32, MenuItem>& getMenuItemsMutable() {
return *s_menuItems;
}
@@ -892,11 +936,35 @@ namespace hex {
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
menuItem.toolbarIndex = maxIndex + 1;
menuItem.icon.color = color;
updateToolbarItems();
break;
}
}
}
struct MenuItemSorter {
bool operator()(const auto *a, const auto *b) const {
return a->toolbarIndex < b->toolbarIndex;
}
};
void updateToolbarItems() {
std::set<ContentRegistry::Interface::impl::MenuItem*, MenuItemSorter> menuItems;
for (auto &[priority, menuItem] : impl::getMenuItemsMutable()) {
if (menuItem.toolbarIndex != -1) {
menuItems.insert(&menuItem);
}
}
impl::s_toolbarMenuItems->clear();
for (auto menuItem : menuItems) {
impl::s_toolbarMenuItems->push_back(menuItem);
}
}
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) {
impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
@@ -945,17 +1013,28 @@ namespace hex {
namespace impl {
static AutoReset<std::vector<Entry>> s_entries;
const std::vector<Entry>& getEntries() {
return *s_entries;
static AutoReset<std::vector<ExportMenuEntry>> s_exportMenuEntries;
const std::vector<ExportMenuEntry>& getExportMenuEntries() {
return *s_exportMenuEntries;
}
static AutoReset<std::vector<FindExporterEntry>> s_findExportEntries;
const std::vector<FindExporterEntry>& getFindExporterEntries() {
return *s_findExportEntries;
}
}
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
void addExportMenuEntry(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
log::debug("Registered new data formatter: {}", unlocalizedName.get());
impl::s_entries->push_back({ unlocalizedName, callback });
impl::s_exportMenuEntries->push_back({ unlocalizedName, callback });
}
void addFindExportFormatter(const UnlocalizedString &unlocalizedName, const std::string fileExtension, const impl::FindExporterCallback &callback) {
log::debug("Registered new export formatter: {}", unlocalizedName.get());
impl::s_findExportEntries->push_back({ unlocalizedName, fileExtension, callback });
}
}

View File

@@ -14,6 +14,8 @@
#include <imgui.h>
#include <imgui_internal.h>
#include <set>
#include <algorithm>
#include <GLFW/glfw3.h>
#if defined(OS_WINDOWS)
@@ -75,7 +77,11 @@ namespace hex {
static AutoReset<std::optional<ProviderRegion>> s_currentSelection;
void setCurrentSelection(const std::optional<ProviderRegion> &region) {
*s_currentSelection = region;
if (region == Region::Invalid()) {
clearSelection();
} else {
*s_currentSelection = region;
}
}
static PerProvider<std::optional<Region>> s_hoveredRegion;
@@ -178,24 +184,24 @@ namespace hex {
impl::s_hoveringFunctions->erase(id);
}
static u32 tooltipId = 0;
static u32 s_tooltipId = 0;
u32 addTooltip(Region region, std::string value, color_t color) {
tooltipId++;
impl::s_tooltips->insert({ tooltipId, { region, std::move(value), color } });
s_tooltipId++;
impl::s_tooltips->insert({ s_tooltipId, { region, std::move(value), color } });
return tooltipId;
return s_tooltipId;
}
void removeTooltip(u32 id) {
impl::s_tooltips->erase(id);
}
static u32 tooltipFunctionId;
static u32 s_tooltipFunctionId;
u32 addTooltipProvider(TooltipFunction function) {
tooltipFunctionId++;
impl::s_tooltipFunctions->insert({ tooltipFunctionId, std::move(function) });
s_tooltipFunctionId++;
impl::s_tooltipFunctions->insert({ s_tooltipFunctionId, std::move(function) });
return tooltipFunctionId;
return s_tooltipFunctionId;
}
void removeTooltipProvider(u32 id) {
@@ -212,7 +218,7 @@ namespace hex {
}
void clearSelection() {
impl::s_currentSelection.reset();
impl::s_currentSelection->reset();
}
void setSelection(const Region &region, prv::Provider *provider) {
@@ -262,18 +268,20 @@ namespace hex {
static i64 s_currentProvider = -1;
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers;
static AutoReset<std::list<std::unique_ptr<prv::Provider>>> s_providersToRemove;
namespace impl {
static std::vector<prv::Provider*> s_closingProviders;
static std::set<prv::Provider*> s_closingProviders;
void resetClosingProvider() {
s_closingProviders.clear();
}
const std::vector<prv::Provider*>& getClosingProviders() {
std::set<prv::Provider*> getClosingProviders() {
return s_closingProviders;
}
static std::recursive_mutex s_providerMutex;
}
prv::Provider *get() {
@@ -293,6 +301,8 @@ namespace hex {
}
void setCurrentProvider(i64 index) {
std::scoped_lock lock(impl::s_providerMutex);
if (TaskManager::getRunningTaskCount() > 0)
return;
@@ -306,6 +316,8 @@ namespace hex {
}
void setCurrentProvider(NonNull<prv::Provider*> provider) {
std::scoped_lock lock(impl::s_providerMutex);
if (TaskManager::getRunningTaskCount() > 0)
return;
@@ -326,6 +338,7 @@ namespace hex {
void markDirty() {
get()->markDirty();
EventProviderDirtied::post(get());
}
void resetDirty() {
@@ -340,6 +353,8 @@ namespace hex {
}
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
std::scoped_lock lock(impl::s_providerMutex);
if (TaskManager::getRunningTaskCount() > 0)
return;
@@ -354,6 +369,8 @@ namespace hex {
}
void remove(prv::Provider *provider, bool noQuestions) {
std::scoped_lock lock(impl::s_providerMutex);
if (provider == nullptr)
return;
@@ -361,7 +378,7 @@ namespace hex {
return;
if (!noQuestions) {
impl::s_closingProviders.push_back(provider);
impl::s_closingProviders.insert(provider);
bool shouldClose = true;
EventProviderClosing::post(provider, &shouldClose);
@@ -409,20 +426,37 @@ namespace hex {
}
}
provider->close();
EventProviderClosed::post(provider);
static std::mutex eraseMutex;
// Move provider over to a list of providers to delete
eraseMutex.lock();
auto removeIt = s_providersToRemove->emplace(s_providersToRemove->end(), std::move(*it));
eraseMutex.unlock();
// Remove left over references from the main provider list
s_providers->erase(it);
impl::s_closingProviders.erase(provider);
if (s_currentProvider >= i64(s_providers->size()) && !s_providers->empty())
setCurrentProvider(s_providers->size() - 1);
if (s_providers->empty())
EventProviderChanged::post(provider, nullptr);
EventProviderClosed::post(removeIt->get());
RequestUpdateWindowTitle::post();
TaskManager::runWhenTasksFinished([it, provider] {
EventProviderDeleted::post(provider);
std::erase(impl::s_closingProviders, provider);
// Do the destruction of the provider in the background once all tasks have finished
TaskManager::runWhenTasksFinished([removeIt] {
EventProviderDeleted::post(removeIt->get());
TaskManager::createBackgroundTask("Closing Provider", [removeIt](Task &) {
eraseMutex.lock();
auto provider = std::move(*removeIt);
s_providersToRemove->erase(removeIt);
eraseMutex.unlock();
s_providers->erase(it);
if (s_currentProvider >= i64(s_providers->size()))
setCurrentProvider(0);
if (s_providers->empty())
EventProviderChanged::post(provider, nullptr);
provider->close();
});
});
}
@@ -437,7 +471,6 @@ namespace hex {
namespace ImHexApi::System {
namespace impl {
// Default to true means we forward to ourselves by default
@@ -499,6 +532,11 @@ namespace hex {
s_gpuVendor = vendor;
}
static AutoReset<std::string> s_glRenderer;
void setGLRenderer(const std::string &renderer) {
s_glRenderer = renderer;
}
static AutoReset<std::map<std::string, std::string>> s_initArguments;
void addInitArgument(const std::string &key, const std::string &value) {
static std::mutex initArgumentsMutex;
@@ -599,6 +637,11 @@ namespace hex {
return impl::s_initialWindowProperties;
}
void* getLibImHexModuleHandle() {
return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle));
}
const std::map<std::string, std::string>& getInitArguments() {
return *impl::s_initArguments;
}
@@ -638,6 +681,10 @@ namespace hex {
return impl::s_gpuVendor;
}
const std::string &getGLRenderer() {
return impl::s_glRenderer;
}
bool isPortableVersion() {
static std::optional<bool> portable;
if (portable.has_value())
@@ -658,7 +705,11 @@ namespace hex {
#if defined(OS_WINDOWS)
return "Windows";
#elif defined(OS_LINUX)
return "Linux";
#if defined(OS_FREEBSD)
return "FreeBSD";
#else
return "Linux";
#endif
#elif defined(OS_MACOS)
return "macOS";
#elif defined(OS_WEB)
@@ -720,6 +771,25 @@ namespace hex {
#endif
}
std::optional<LinuxDistro> getLinuxDistro() {
wolv::io::File file("/etc/os-release", wolv::io::File::Mode::Read);
std::string name;
std::string version;
auto fileContent = file.readString();
for (const auto &line : wolv::util::splitString(fileContent, "\n")) {
if (line.find("PRETTY_NAME=") != std::string::npos) {
name = line.substr(line.find("=") + 1);
std::erase(name, '\"');
} else if (line.find("VERSION_ID=") != std::string::npos) {
version = line.substr(line.find("=") + 1);
std::erase(version, '\"');
}
}
return { { name, version } };
}
std::string getImHexVersion(bool withBuildType) {
#if defined IMHEX_VERSION
if (withBuildType) {
@@ -762,6 +832,10 @@ namespace hex {
#endif
}
bool isNightlyBuild() {
return getImHexVersion(false).ends_with("WIP");
}
bool updateImHex(UpdateType updateType) {
// Get the path of the updater executable
std::fs::path executablePath;
@@ -788,7 +862,7 @@ namespace hex {
EventImHexClosing::subscribe([executablePath, updateTypeString] {
hex::executeCommand(
hex::format("{} {}",
hex::format("\"{}\" \"{}\"",
wolv::util::toUTF8String(executablePath),
updateTypeString
)
@@ -867,9 +941,9 @@ namespace hex {
s_fontSize = size;
}
static AutoReset<std::unique_ptr<ImFontAtlas>> s_fontAtlas;
static AutoReset<ImFontAtlas*> s_fontAtlas;
void setFontAtlas(ImFontAtlas* fontAtlas) {
s_fontAtlas = std::unique_ptr<ImFontAtlas>(fontAtlas);
s_fontAtlas = fontAtlas;
}
static ImFont *s_boldFont = nullptr;
@@ -915,7 +989,7 @@ namespace hex {
};
}
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags) {
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags, std::optional<u32> defaultSize) {
wolv::io::File fontFile(path, wolv::io::File::Mode::Read);
if (!fontFile.isValid()) {
log::error("Failed to load font from file '{}'", wolv::util::toUTF8String(path));
@@ -927,17 +1001,19 @@ namespace hex {
fontFile.readVector(),
glyphRanges,
offset,
flags
flags,
defaultSize
});
}
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags) {
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags, std::optional<u32> defaultSize) {
impl::s_fonts->emplace_back(Font {
name,
{ data.begin(), data.end() },
glyphRanges,
offset,
flags
flags,
defaultSize
});
}
@@ -950,7 +1026,7 @@ namespace hex {
}
ImFontAtlas* getFontAtlas() {
return impl::s_fontAtlas->get();
return impl::s_fontAtlas;
}
ImFont* Bold() {

View File

@@ -1,13 +1,15 @@
#include <hex/api/layout_manager.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/utils/string.hpp>
#include <imgui.h>
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
namespace hex {
@@ -40,10 +42,7 @@ namespace hex {
fileName += ".hexlyt";
std::fs::path layoutPath;
for (const auto &path : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
if (!hex::fs::isPathWritable(layoutPath))
continue;
for (const auto &path : paths::Layouts.write()) {
layoutPath = path / fileName;
}
@@ -64,10 +63,25 @@ namespace hex {
}
std::vector<LayoutManager::Layout> LayoutManager::getLayouts() {
const std::vector<LayoutManager::Layout>& LayoutManager::getLayouts() {
return s_layouts;
}
void LayoutManager::removeLayout(const std::string& name) {
for (const auto &layout : *s_layouts) {
if (layout.name == name) {
if (wolv::io::fs::remove(layout.path)) {
log::info("Removed layout '{}'", name);
} else {
log::error("Failed to remove layout '{}'", name);
}
}
}
LayoutManager::reload();
}
void LayoutManager::closeAllViews() {
for (const auto &[name, view] : ContentRegistry::Views::impl::getEntries())
view->getWindowOpenState() = false;
@@ -75,28 +89,26 @@ namespace hex {
void LayoutManager::process() {
if (s_layoutPathToLoad->has_value()) {
const auto pathString = wolv::util::toUTF8String(**s_layoutPathToLoad);
LayoutManager::closeAllViews();
ImGui::LoadIniSettingsFromDisk(pathString.c_str());
s_layoutPathToLoad = std::nullopt;
log::info("Loaded layout from {}", pathString);
wolv::io::File file(**s_layoutPathToLoad, wolv::io::File::Mode::Read);
s_layoutStringToLoad = file.readString();
s_layoutPathToLoad->reset();
}
if (s_layoutStringToLoad->has_value()) {
LayoutManager::closeAllViews();
ImGui::LoadIniSettingsFromMemory((*s_layoutStringToLoad)->c_str());
s_layoutStringToLoad = std::nullopt;
log::info("Loaded layout from string");
s_layoutStringToLoad->reset();
log::info("Loaded new Layout");
}
}
void LayoutManager::reload() {
s_layouts->clear();
for (const auto &directory : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
for (const auto &directory : paths::Layouts.read()) {
for (const auto &entry : std::fs::directory_iterator(directory)) {
const auto &path = entry.path();
@@ -119,8 +131,8 @@ namespace hex {
}
void LayoutManager::reset() {
s_layoutPathToLoad.reset();
s_layoutStringToLoad.reset();
s_layoutPathToLoad->reset();
s_layoutStringToLoad->reset();
s_layouts->clear();
}

View File

@@ -5,6 +5,7 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/utils/string.hpp>
@@ -18,24 +19,50 @@
namespace hex {
static uintptr_t loadLibrary(const std::fs::path &path) {
#if defined(OS_WINDOWS)
auto handle = uintptr_t(LoadLibraryW(path.c_str()));
if (handle == uintptr_t(INVALID_HANDLE_VALUE) || handle == 0) {
log::error("Loading library '{}' failed: {} {}!", wolv::util::toUTF8String(path.filename()), ::GetLastError(), hex::formatSystemError(::GetLastError()));
return 0;
}
return handle;
#else
auto handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY));
if (handle == 0) {
log::error("Loading library '{}' failed: {}!", wolv::util::toUTF8String(path.filename()), dlerror());
return 0;
}
return handle;
#endif
}
static void unloadLibrary(uintptr_t handle, const std::fs::path &path) {
#if defined(OS_WINDOWS)
if (handle != 0) {
if (FreeLibrary(HMODULE(handle)) == FALSE) {
log::error("Error when unloading library '{}': {}!", wolv::util::toUTF8String(path.filename()), hex::formatSystemError(::GetLastError()));
}
}
#else
if (handle != 0) {
if (dlclose(reinterpret_cast<void*>(handle)) != 0) {
log::error("Error when unloading library '{}': {}!", path.filename().string(), dlerror());
}
}
#endif
}
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
log::info("Loading plugin '{}'", wolv::util::toUTF8String(path.filename()));
#if defined(OS_WINDOWS)
m_handle = uintptr_t(LoadLibraryW(path.c_str()));
if (m_handle == uintptr_t(INVALID_HANDLE_VALUE) || m_handle == 0) {
log::error("Loading plugin '{}' failed: {} {}!", wolv::util::toUTF8String(path.filename()), ::GetLastError(), hex::formatSystemError(::GetLastError()));
return;
}
#else
m_handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY));
if (m_handle == 0) {
log::error("Loading plugin '{}' failed: {}!", wolv::util::toUTF8String(path.filename()), dlerror());
return;
}
#endif
m_handle = loadLibrary(path);
if (m_handle == 0)
return;
const auto fileName = path.stem().string();
@@ -89,15 +116,7 @@ namespace hex {
log::info("Trying to unload plugin '{}'", getPluginName());
}
#if defined(OS_WINDOWS)
if (m_handle != 0)
if (FreeLibrary(HMODULE(m_handle)) == FALSE) {
log::error("Error when unloading plugin '{}': {}!", wolv::util::toUTF8String(m_path.filename()), hex::formatSystemError(::GetLastError()));
}
#else
if (m_handle != 0)
dlclose(reinterpret_cast<void*>(m_handle));
#endif
unloadLibrary(m_handle, m_path);
}
bool Plugin::initializePlugin() const {
@@ -284,6 +303,35 @@ namespace hex {
return true;
}
AutoReset<std::vector<uintptr_t>> PluginManager::s_loadedLibraries;
bool PluginManager::loadLibraries() {
bool success = true;
for (const auto &loadPath : paths::Libraries.read())
success = PluginManager::loadLibraries(loadPath) && success;
return success;
}
bool PluginManager::loadLibraries(const std::fs::path& libraryFolder) {
bool success = true;
for (const auto &entry : std::fs::directory_iterator(libraryFolder)) {
if (!(entry.path().extension() == ".dll" || entry.path().extension() == ".so" || entry.path().extension() == ".dylib"))
continue;
auto handle = loadLibrary(entry);
if (handle == 0) {
success = false;
}
PluginManager::s_loadedLibraries->push_back(handle);
}
return success;
}
void PluginManager::initializeNewPlugins() {
for (const auto &plugin : getPlugins()) {
if (!plugin.isLoaded())
@@ -304,6 +352,11 @@ namespace hex {
plugins.pop_back();
}
while (!s_loadedLibraries->empty()) {
unloadLibrary(s_loadedLibraries->back(), "");
s_loadedLibraries->pop_back();
}
getPluginsMutable() = std::move(savedPlugins);
}
@@ -321,6 +374,15 @@ namespace hex {
return plugins;
}
Plugin* PluginManager::getPlugin(const std::string &name) {
for (auto &plugin : getPluginsMutable()) {
if (plugin.getPluginName() == name)
return &plugin;
}
return nullptr;
}
const std::vector<std::fs::path>& PluginManager::getPluginPaths() {
return s_pluginPaths;
}
@@ -335,5 +397,4 @@ namespace hex {
});
}
}

View File

@@ -412,18 +412,24 @@ namespace hex {
void TaskManager::runDeferredCalls() {
std::scoped_lock lock(s_deferredCallsMutex);
for (const auto &call : s_deferredCalls)
call();
for (const auto &[location, call] : s_onceDeferredCalls)
call();
s_deferredCalls.clear();
s_onceDeferredCalls.clear();
while (!s_deferredCalls.empty()) {
auto callback = s_deferredCalls.front();
s_deferredCalls.pop_front();
callback();
}
while (!s_onceDeferredCalls.empty()) {
auto node = s_onceDeferredCalls.extract(s_onceDeferredCalls.begin());
node.mapped()();
}
}
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
std::scoped_lock lock(s_tasksFinishedMutex);
for (const auto &task : s_tasks) {
task->interrupt();
}
s_tasksFinishedCallbacks.push_back(function);
}
@@ -437,7 +443,7 @@ namespace hex {
static auto setThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>(
reinterpret_cast<uintptr_t>(
::GetProcAddress(
::GetModuleHandle("Kernel32.dll"),
::GetModuleHandleW(L"Kernel32.dll"),
"SetThreadDescription"
)
)

View File

@@ -17,18 +17,25 @@ namespace hex {
AutoReset<std::string> s_imageTheme;
AutoReset<std::string> s_currTheme;
std::recursive_mutex s_themeMutex;
}
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
std::unique_lock lock(s_themeMutex);
(*s_themeHandlers)[name] = { colorMap, getFunction, setFunction };
}
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
std::unique_lock lock(s_themeMutex);
(*s_styleHandlers)[name] = { styleMap };
}
void ThemeManager::addTheme(const std::string &content) {
std::unique_lock lock(s_themeMutex);
try {
auto theme = nlohmann::json::parse(content);
@@ -66,7 +73,7 @@ namespace hex {
if (color == 0x00000000)
return ImVec4(0, 0, 0, -1);
return ImColor(hex::changeEndianess(color, std::endian::big));
return ImColor(hex::changeEndianness(color, std::endian::big));
}
nlohmann::json ThemeManager::exportCurrentTheme(const std::string &name) {
@@ -83,7 +90,7 @@ namespace hex {
for (const auto &[key, value] : handler.colorMap) {
auto color = handler.getFunction(value);
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianess(u32(color), std::endian::big));
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianness(u32(color), std::endian::big));
}
}
@@ -106,6 +113,8 @@ namespace hex {
}
void ThemeManager::changeTheme(std::string name) {
std::unique_lock lock(s_themeMutex);
if (!s_themes->contains(name)) {
if (s_themes->empty()) {
return;
@@ -168,12 +177,12 @@ namespace hex {
const float scale = style.needsScaling ? 1_scaled : 1.0F;
if (value.is_number_float()) {
if (const auto newValue = std::get_if<float*>(&style.value); newValue != nullptr)
if (const auto newValue = std::get_if<float*>(&style.value); newValue != nullptr && *newValue != nullptr)
**newValue = value.get<float>() * scale;
else
log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name);
} else if (value.is_array() && value.size() == 2 && value[0].is_number_float() && value[1].is_number_float()) {
if (const auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr)
if (const auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr && *newValue != nullptr)
**newValue = ImVec2(value[0].get<float>() * scale, value[1].get<float>() * scale);
else
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
@@ -191,6 +200,8 @@ namespace hex {
hex::log::error("Theme '{}' has invalid image theme!", name);
s_imageTheme = "dark";
}
} else {
s_imageTheme = "dark";
}
s_currTheme = name;
@@ -211,6 +222,8 @@ namespace hex {
}
void ThemeManager::reset() {
std::unique_lock lock(s_themeMutex);
s_themes->clear();
s_styleHandlers->clear();
s_themeHandlers->clear();

View File

@@ -21,6 +21,11 @@ namespace hex {
AutoReset<std::map<ImGuiID, std::string>> s_highlights;
AutoReset<std::vector<std::pair<ImRect, std::string>>> s_highlightDisplays;
AutoReset<std::map<ImGuiID, std::function<void()>>> s_interactiveHelpItems;
ImRect s_hoveredRect;
ImGuiID s_hoveredId;
bool s_helpHoverActive = false;
class IDStack {
public:
@@ -56,8 +61,42 @@ namespace hex {
ImVector<ImGuiID> idStack;
};
ImGuiID calculateId(const auto &ids) {
IDStack idStack;
for (const auto &id : ids) {
std::visit(wolv::util::overloaded {
[&idStack](const Lang &id) {
idStack.add(id.get());
},
[&idStack](const auto &id) {
idStack.add(id);
}
}, id);
}
return idStack.get();
}
}
void TutorialManager::init() {
EventImGuiElementRendered::subscribe([](ImGuiID id, const std::array<float, 4> bb){
const auto boundingBox = ImRect(bb[0], bb[1], bb[2], bb[3]);
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(boundingBox, element->second);
}
if (id != 0 && boundingBox.Contains(ImGui::GetMousePos())) {
if ((s_hoveredRect.GetArea() == 0 || boundingBox.GetArea() < s_hoveredRect.GetArea()) && s_interactiveHelpItems->contains(id)) {
s_hoveredRect = boundingBox;
s_hoveredId = id;
}
}
});
}
const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() {
return s_tutorials;
@@ -72,6 +111,28 @@ namespace hex {
return s_tutorials->try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second;
}
void TutorialManager::startHelpHover() {
TaskManager::doLater([]{
s_helpHoverActive = true;
});
}
void TutorialManager::addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString text) {
auto id = calculateId(ids);
s_interactiveHelpItems->emplace(id, [text = std::move(text)]{
log::info("{}", Lang(text).get());
});
}
void TutorialManager::addInteractiveHelpLink(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, std::string link) {
auto id = calculateId(ids);
s_interactiveHelpItems->emplace(id, [link = std::move(link)]{
hex::openWebpage(link);
});
}
void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) {
s_currentTutorial = s_tutorials->find(unlocalizedName);
if (s_currentTutorial == s_tutorials->end())
@@ -81,6 +142,30 @@ namespace hex {
}
void TutorialManager::drawHighlights() {
if (s_helpHoverActive) {
const auto &drawList = ImGui::GetForegroundDrawList();
drawList->AddText(ImGui::GetMousePos() + scaled({ 10, -5, }), ImGui::GetColorU32(ImGuiCol_Text), "?");
const bool mouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
if (s_hoveredId != 0) {
drawList->AddRectFilled(s_hoveredRect.Min, s_hoveredRect.Max, 0x30FFFFFF);
if (mouseClicked) {
auto it = s_interactiveHelpItems->find(s_hoveredId);
if (it != s_interactiveHelpItems->end()) {
it->second();
}
}
s_hoveredId = 0;
s_hoveredRect = {};
}
if (mouseClicked || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
s_helpHoverActive = false;
}
}
for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) {
const auto drawList = ImGui::GetForegroundDrawList();
@@ -241,39 +326,13 @@ namespace hex {
m_onAppear();
for (const auto &[text, ids] : m_highlights) {
IDStack idStack;
for (const auto &id : ids) {
std::visit(wolv::util::overloaded {
[&idStack](const Lang &id) {
idStack.add(id.get());
},
[&idStack](const auto &id) {
idStack.add(id);
}
}, id);
}
s_highlights->emplace(idStack.get(), text);
s_highlights->emplace(calculateId(ids), text);
}
}
void TutorialManager::Tutorial::Step::removeHighlights() const {
for (const auto &[text, ids] : m_highlights) {
IDStack idStack;
for (const auto &id : ids) {
std::visit(wolv::util::overloaded {
[&idStack](const Lang &id) {
idStack.add(id.get());
},
[&idStack](const auto &id) {
idStack.add(id);
}
}, id);
}
s_highlights->erase(idStack.get());
s_highlights->erase(calculateId(ids));
}
}
@@ -368,15 +427,4 @@ namespace hex {
}
}
}
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(bb, element->second);
}
}
void ImGuiTestEngineHook_ItemInfo(ImGuiContext*, ImGuiID, const char*, ImGuiItemStatusFlags) {}
void ImGuiTestEngineHook_Log(ImGuiContext*, const char*, ...) {}
const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext*, ImGuiID) { return nullptr; }
}

View File

@@ -3,28 +3,35 @@
#include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/io/file.hpp>
#include <nlohmann/json.hpp>
#include <imgui.h>
#include <wolv/utils/string.hpp>
namespace hex {
AutoReset<std::map<std::string, WorkspaceManager::Workspace>> WorkspaceManager::s_workspaces;
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_currentWorkspace = s_workspaces->end();
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_previousWorkspace = s_workspaces->end();
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_workspaceToRemove = s_workspaces->end();
void WorkspaceManager::createWorkspace(const std::string& name, const std::string &layout) {
s_currentWorkspace = s_workspaces->insert_or_assign(name, Workspace {
.layout = layout.empty() ? LayoutManager::saveToString() : layout,
.path = {}
.layout = layout.empty() ? LayoutManager::saveToString() : layout,
.path = {},
.builtin = false
}).first;
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
if (exportToFile(path / (name + ".hexws")))
for (const auto &workspaceFolder : paths::Workspaces.write()) {
const auto workspacePath = workspaceFolder / (name + ".hexws");
if (exportToFile(workspacePath)) {
s_currentWorkspace->second.path = workspacePath;
break;
}
}
}
@@ -37,6 +44,10 @@ namespace hex {
}
void WorkspaceManager::importFromFile(const std::fs::path& path) {
if (std::ranges::any_of(*s_workspaces, [path](const auto &pair) { return pair.second.path == path; })) {
return;
}
wolv::io::File file(path, wolv::io::File::Mode::Read);
if (!file.isValid()) {
log::error("Failed to load workspace from file '{}'", path.string());
@@ -50,10 +61,12 @@ namespace hex {
const std::string name = json["name"];
std::string layout = json["layout"];
const bool builtin = json.value("builtin", false);
(*s_workspaces)[name] = Workspace {
.layout = std::move(layout),
.path = path
.path = path,
.builtin = builtin
};
} catch (nlohmann::json::exception &e) {
log::error("Failed to load workspace from file '{}': {}", path.string(), e.what());
@@ -61,41 +74,77 @@ namespace hex {
}
}
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName) {
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName, bool builtin) {
if (path.empty()) {
if (s_currentWorkspace == s_workspaces->end())
if (s_currentWorkspace == s_workspaces->end()) {
return false;
}
path = s_currentWorkspace->second.path;
}
if (workspaceName.empty())
if (workspaceName.empty()) {
workspaceName = s_currentWorkspace->first;
}
wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid())
if (!file.isValid()) {
return false;
}
nlohmann::json json;
json["name"] = workspaceName;
json["layout"] = LayoutManager::saveToString();
json["builtin"] = builtin;
file.writeString(json.dump(4));
return true;
}
void WorkspaceManager::removeWorkspace(const std::string& name) {
bool deletedCurrentWorkspace = false;
for (const auto &[workspaceName, workspace] : *s_workspaces) {
if (workspaceName == name) {
log::info("Removing workspace file '{}'", wolv::util::toUTF8String(workspace.path));
if (wolv::io::fs::remove(workspace.path)) {
log::info("Removed workspace '{}'", name);
if (workspaceName == s_currentWorkspace->first) {
deletedCurrentWorkspace = true;
}
} else {
log::error("Failed to remove workspace '{}'", name);
}
}
}
WorkspaceManager::reload();
if (deletedCurrentWorkspace && !s_workspaces->empty()) {
s_currentWorkspace = s_workspaces->begin();
}
}
void WorkspaceManager::process() {
if (s_previousWorkspace != s_currentWorkspace) {
if (s_previousWorkspace != s_workspaces->end())
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first);
log::info("Updating workspace");
if (s_previousWorkspace != s_workspaces->end()) {
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first, s_previousWorkspace->second.builtin);
}
LayoutManager::closeAllViews();
ImGui::LoadIniSettingsFromMemory(s_currentWorkspace->second.layout.c_str());
s_previousWorkspace = s_currentWorkspace;
if (s_workspaceToRemove != s_workspaces->end()) {
s_workspaces->erase(s_workspaceToRemove);
s_workspaceToRemove = s_workspaces->end();
}
}
}
@@ -106,6 +155,26 @@ namespace hex {
s_previousWorkspace = s_workspaces->end();
}
void WorkspaceManager::reload() {
WorkspaceManager::reset();
for (const auto &defaultPath : paths::Workspaces.read()) {
for (const auto &entry : std::fs::directory_iterator(defaultPath)) {
if (!entry.is_regular_file()) {
continue;
}
const auto &path = entry.path();
if (path.extension() != ".hexws") {
continue;
}
WorkspaceManager::importFromFile(path);
}
}
}
}

View File

@@ -0,0 +1,153 @@
#include <hex/helpers/default_paths.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/project_file_manager.hpp>
#if defined(OS_WINDOWS)
#include <windows.h>
#include <shlobj.h>
#elif defined(OS_LINUX) || defined(OS_WEB)
#include <xdg.hpp>
# endif
namespace hex::paths {
std::vector<std::fs::path> getDataPaths(bool includeSystemFolders) {
std::vector<std::fs::path> paths;
#if defined(OS_WINDOWS)
// In the portable Windows version, we just use the executable directory
// Prevent the use of the AppData folder here
if (!ImHexApi::System::isPortableVersion()) {
PWSTR wAppDataPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
paths.emplace_back(wAppDataPath);
CoTaskMemFree(wAppDataPath);
}
}
#elif defined(OS_MACOS)
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
#elif defined(OS_LINUX) || defined(OS_WEB)
paths.push_back(xdg::DataHomeDir());
auto dataDirs = xdg::DataDirs();
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
#endif
#if defined(OS_MACOS)
if (includeSystemFolders) {
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
paths.push_back(*executablePath);
}
}
#else
for (auto &path : paths)
path = path / "imhex";
if (ImHexApi::System::isPortableVersion() || includeSystemFolders) {
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(executablePath->parent_path());
}
#endif
// Add additional data directories to the path
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
std::ranges::copy(additionalDirs, std::back_inserter(paths));
// Add the project file directory to the path, if one is loaded
if (ProjectFile::hasPath()) {
paths.push_back(ProjectFile::getPath().parent_path());
}
return paths;
}
std::vector<std::fs::path> getConfigPaths(bool includeSystemFolders) {
#if defined(OS_WINDOWS)
return getDataPaths(includeSystemFolders);
#elif defined(OS_MACOS)
return getDataPaths(includeSystemFolders);
#elif defined(OS_LINUX) || defined(OS_WEB)
hex::unused(includeSystemFolders);
return {xdg::ConfigHomeDir() / "imhex"};
#endif
}
static std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, std::fs::path folder) {
folder.make_preferred();
for (auto &path : paths)
path = path / folder;
return paths;
}
static std::vector<std::fs::path> getPluginPaths() {
std::vector<std::fs::path> paths = getDataPaths(true);
// Add the system plugin directory to the path if one was provided at compile time
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
paths.push_back(SYSTEM_PLUGINS_LOCATION);
#endif
return paths;
}
namespace impl {
std::vector<std::fs::path> DefaultPath::read() const {
auto result = this->all();
std::erase_if(result, [](const auto &entryPath) {
return !wolv::io::fs::isDirectory(entryPath);
});
return result;
}
std::vector<std::fs::path> DefaultPath::write() const {
auto result = this->read();
std::erase_if(result, [](const auto &entryPath) {
return !hex::fs::isPathWritable(entryPath);
});
return result;
}
std::vector<std::fs::path> ConfigPath::all() const {
return appendPath(getConfigPaths(false), m_postfix);
}
std::vector<std::fs::path> DataPath::all() const {
return appendPath(getDataPaths(true), m_postfix);
}
std::vector<std::fs::path> DataPath::write() const {
auto result = appendPath(getDataPaths(false), m_postfix);
std::erase_if(result, [](const auto &entryPath) {
return !hex::fs::isPathWritable(entryPath);
});
return result;
}
std::vector<std::fs::path> PluginPath::all() const {
return appendPath(getPluginPaths(), m_postfix);
}
}
}

View File

@@ -13,13 +13,48 @@
#include <shellapi.h>
#elif defined(OS_LINUX) || defined(OS_WEB)
#include <xdg.hpp>
# if defined(OS_FREEBSD)
#include <sys/syslimits.h>
# else
#include <limits.h>
# endif
#endif
#if defined(OS_WEB)
#include <emscripten.h>
#else
#include <nfd.hpp>
#if defined(OS_WINDOWS)
#define GLFW_EXPOSE_NATIVE_WIN32
#endif
#if defined(OS_MACOS)
// macOS platform headers can't be compiled with gcc
#define GLFW_NATIVE_INCLUDE_NONE
typedef uint32_t CGDirectDisplayID;
typedef void *id;
typedef void NSWindow;
#define GLFW_EXPOSE_NATIVE_COCOA
#endif
#if defined(OS_LINUX)
#define GLFW_EXPOSE_NATIVE_X11
#endif
#if defined(OS_LINUX) && defined(GLFW_WAYLAND_APP_ID)
#define GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#include <nfd_glfw3.h>
#if defined(OS_LINUX) && defined(GLFW_WAYLAND_APP_ID)
#undef GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#if defined(OS_LINUX)
#undef GLFW_EXPOSE_NATIVE_X11
#endif
#if defined(OS_MACOS)
#undef GLFW_EXPOSE_NATIVE_COCOA
#undef GLFW_NATIVE_INCLUDE_NONE
#endif
#if defined(OS_WINDOWS)
#undef GLFW_EXPOSE_NATIVE_WIN32
#endif
#endif
#include <filesystem>
@@ -28,6 +63,9 @@
#include <wolv/io/fs.hpp>
#include <wolv/utils/string.hpp>
#include <fmt/format.h>
#include <fmt/xchar.h>
namespace hex::fs {
static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback;
@@ -44,7 +82,7 @@ namespace hex::fs {
#if defined(OS_WINDOWS)
hex::unused(
ShellExecute(nullptr, "open", wolv::util::toUTF8String(filePath).c_str(), nullptr, nullptr, SW_SHOWNORMAL)
ShellExecuteW(nullptr, L"open", filePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL)
);
#elif defined(OS_MACOS)
hex::unused(system(
@@ -62,9 +100,8 @@ namespace hex::fs {
}
#if defined(OS_WINDOWS)
hex::unused(system(
hex::format("explorer.exe {}", wolv::util::toUTF8String(dirPath)).c_str()
));
auto args = fmt::format(L"\"{}\"", dirPath.c_str());
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
#elif defined(OS_MACOS)
hex::unused(system(
hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str()
@@ -81,9 +118,8 @@ namespace hex::fs {
}
#if defined(OS_WINDOWS)
hex::unused(system(
hex::format(R"(explorer.exe /select,"{}")", wolv::util::toUTF8String(selectedFilePath)).c_str()
));
auto args = fmt::format(L"/select,\"{}\"", selectedFilePath.c_str());
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
#elif defined(OS_MACOS)
hex::unused(system(
hex::format(
@@ -228,20 +264,22 @@ namespace hex::fs {
NFD::UniquePathU8 outPath;
NFD::UniquePathSet outPaths;
nfdresult_t result = NFD_ERROR;
nfdwindowhandle_t nativeWindow{};
NFD_GetNativeWindowFromGLFWWindow(ImHexApi::System::getMainWindowHandle(), &nativeWindow);
// Open the correct file dialog based on the mode
switch (mode) {
case DialogMode::Open:
if (multiple)
result = NFD::OpenDialogMultiple(outPaths, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::OpenDialogMultiple(outPaths, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
else
result = NFD::OpenDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::OpenDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
break;
case DialogMode::Save:
result = NFD::SaveDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::SaveDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nullptr, nativeWindow);
break;
case DialogMode::Folder:
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str());
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
break;
}
@@ -282,170 +320,6 @@ namespace hex::fs {
#endif
std::vector<std::fs::path> getDataPaths() {
std::vector<std::fs::path> paths;
#if defined(OS_WINDOWS)
// In the portable Windows version, we just use the executable directory
// Prevent the use of the AppData folder here
if (!ImHexApi::System::isPortableVersion()) {
PWSTR wAppDataPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
paths.emplace_back(wAppDataPath);
CoTaskMemFree(wAppDataPath);
}
}
#elif defined(OS_MACOS)
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
#elif defined(OS_LINUX) || defined(OS_WEB)
paths.push_back(xdg::DataHomeDir());
auto dataDirs = xdg::DataDirs();
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
#endif
#if defined(OS_MACOS)
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(*executablePath);
#else
for (auto &path : paths)
path = path / "imhex";
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(executablePath->parent_path());
#endif
// Add additional data directories to the path
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
std::ranges::copy(additionalDirs, std::back_inserter(paths));
// Add the project file directory to the path, if one is loaded
if (ProjectFile::hasPath()) {
paths.push_back(ProjectFile::getPath().parent_path());
}
return paths;
}
static std::vector<std::fs::path> getConfigPaths() {
#if defined(OS_WINDOWS)
return getDataPaths();
#elif defined(OS_MACOS)
return getDataPaths();
#elif defined(OS_LINUX) || defined(OS_WEB)
return {xdg::ConfigHomeDir() / "imhex"};
#endif
}
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder) {
for (auto &path : paths)
path = path / folder;
return paths;
}
std::vector<std::fs::path> getPluginPaths() {
std::vector<std::fs::path> paths = getDataPaths();
// Add the system plugin directory to the path if one was provided at compile time
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
paths.push_back(SYSTEM_PLUGINS_LOCATION);
#endif
return paths;
}
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
std::vector<std::fs::path> result;
// Return the correct path based on the ImHexPath enum
switch (path) {
case ImHexPath::END:
return { };
case ImHexPath::Constants:
result = appendPath(getDataPaths(), "constants");
break;
case ImHexPath::Config:
result = appendPath(getConfigPaths(), "config");
break;
case ImHexPath::Backups:
result = appendPath(getDataPaths(), "backups");
break;
case ImHexPath::Encodings:
result = appendPath(getDataPaths(), "encodings");
break;
case ImHexPath::Logs:
result = appendPath(getDataPaths(), "logs");
break;
case ImHexPath::Plugins:
result = appendPath(getPluginPaths(), "plugins");
break;
case ImHexPath::Libraries:
result = appendPath(getPluginPaths(), "lib");
break;
case ImHexPath::Resources:
result = appendPath(getDataPaths(), "resources");
break;
case ImHexPath::Magic:
result = appendPath(getDataPaths(), "magic");
break;
case ImHexPath::Patterns:
result = appendPath(getDataPaths(), "patterns");
break;
case ImHexPath::PatternsInclude:
result = appendPath(getDataPaths(), "includes");
break;
case ImHexPath::Yara:
result = appendPath(getDataPaths(), "yara");
break;
case ImHexPath::YaraAdvancedAnalysis:
result = appendPath(getDefaultPaths(ImHexPath::Yara), "advanced_analysis");
break;
case ImHexPath::Recent:
result = appendPath(getConfigPaths(), "recent");
break;
case ImHexPath::Scripts:
result = appendPath(getDataPaths(), "scripts");
break;
case ImHexPath::Inspectors:
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
break;
case ImHexPath::Nodes:
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "nodes");
break;
case ImHexPath::Themes:
result = appendPath(getDataPaths(), "themes");
break;
case ImHexPath::Layouts:
result = appendPath(getDataPaths(), "layouts");
break;
case ImHexPath::Workspaces:
result = appendPath(getDataPaths(), "workspaces");
break;
}
// Remove all paths that don't exist if requested
if (!listNonExisting) {
std::erase_if(result, [](const auto &entryPath) {
return !wolv::io::fs::isDirectory(entryPath);
});
}
return result;
}
bool isPathWritable(const std::fs::path &path) {
constexpr static auto TestFileName = "__imhex__tmp__";

View File

@@ -0,0 +1,15 @@
#include <hex/api/event_manager.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#include <array>
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
std::array<float, 4> boundingBox = { bb.Min.x, bb.Min.y, bb.Max.x, bb.Max.y };
hex::EventImGuiElementRendered::post(id, boundingBox);
}
void ImGuiTestEngineHook_ItemInfo(ImGuiContext*, ImGuiID, const char*, ImGuiItemStatusFlags) {}
void ImGuiTestEngineHook_Log(ImGuiContext*, const char*, ...) {}
const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext*, ImGuiID) { return nullptr; }

View File

@@ -1,12 +1,17 @@
#include <hex/helpers/logger.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/io/file.hpp>
#include <mutex>
#include <chrono>
#include <fmt/chrono.h>
#include <hex/api/task_manager.hpp>
#if defined(OS_WINDOWS)
#include <Windows.h>
@@ -20,6 +25,7 @@ namespace hex::log {
bool s_colorOutputEnabled = false;
std::recursive_mutex s_loggerMutex;
bool s_loggingSuspended = false;
bool s_debugLoggingEnabled = false;
}
@@ -31,16 +37,33 @@ namespace hex::log {
s_loggingSuspended = false;
}
void enableDebugLogging() {
s_debugLoggingEnabled = true;
}
namespace impl {
std::recursive_mutex& getLoggerMutex() {
return s_loggerMutex;
void lockLoggerMutex() {
s_loggerMutex.lock();
}
void unlockLoggerMutex() {
s_loggerMutex.unlock();
}
bool isLoggingSuspended() {
return s_loggingSuspended;
}
bool isDebugLoggingEnabled() {
#if defined(DEBUG)
return true;
#else
return s_debugLoggingEnabled;
#endif
}
FILE *getDestination() {
if (s_loggerFile.isValid())
return s_loggerFile.getHandle();
@@ -59,13 +82,13 @@ namespace hex::log {
void redirectToFile() {
if (s_loggerFile.isValid()) return;
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
for (const auto &path : paths::Logs.all()) {
wolv::io::fs::createDirectories(path);
s_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))), wolv::io::File::Mode::Create);
s_loggerFile.disableBuffering();
if (s_loggerFile.isValid()) {
s_colorOutputEnabled = true;
s_colorOutputEnabled = false;
break;
}
}
@@ -121,14 +144,12 @@ namespace hex::log {
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
}
void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
if (!expr) {
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
void assertionHandler(const char* exprString, const char* file, int line) {
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
#if defined (DEBUG)
std::abort();
#endif
}
#if defined (DEBUG)
std::abort();
#endif
}
namespace color {

View File

@@ -3,6 +3,7 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/utils/string.hpp>
@@ -29,7 +30,7 @@ namespace hex::magic {
std::string magicFiles;
std::error_code error;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
for (const auto &dir : paths::Magic.read()) {
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
auto path = std::fs::absolute(entry.path());
@@ -64,12 +65,12 @@ namespace hex::magic {
if (magicFiles->empty())
return true;
std::array<char, 1024> cwd = { 0x00 };
std::array<char, 1024> cwd = { };
if (getcwd(cwd.data(), cwd.size()) == nullptr)
return false;
std::optional<std::fs::path> magicFolder;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
for (const auto &dir : paths::Magic.write()) {
if (std::fs::exists(dir) && fs::isPathWritable(dir)) {
magicFolder = dir;
break;
@@ -105,8 +106,13 @@ namespace hex::magic {
ON_SCOPE_EXIT { magic_close(ctx); };
if (magic_load(ctx, magicFiles->c_str()) == 0) {
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
return wolv::util::replaceStrings(result, "\\012-", "\n-");
if (auto description = magic_buffer(ctx, data.data(), data.size()); description != nullptr) {
auto result = wolv::util::replaceStrings(description, "\\012-", "\n-");
if (result.ends_with("- data"))
result = result.substr(0, result.size() - 6);
return result;
}
}
}
@@ -130,8 +136,13 @@ namespace hex::magic {
ON_SCOPE_EXIT { magic_close(ctx); };
if (magic_load(ctx, magicFiles->c_str()) == 0) {
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
return wolv::util::replaceStrings(result, "\\012-", "\n-");
if (auto mimeType = magic_buffer(ctx, data.data(), data.size()); mimeType != nullptr) {
auto result = wolv::util::replaceStrings(mimeType, "\\012-", "\n-");
if (result.ends_with("- application/octet-stream"))
result = result.substr(0, result.size() - 26);
return result;
}
}
}
@@ -162,8 +173,13 @@ namespace hex::magic {
ON_SCOPE_EXIT { magic_close(ctx); };
if (magic_load(ctx, magicFiles->c_str()) == 0) {
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
return wolv::util::replaceStrings(result, "\\012-", "\n-");
if (auto extension = magic_buffer(ctx, data.data(), data.size()); extension != nullptr) {
auto result = wolv::util::replaceStrings(extension, "\\012-", "\n-");
if (result.ends_with("- ???"))
result = result.substr(0, result.size() - 5);
return result;
}
}
}

View File

@@ -138,7 +138,7 @@ namespace hex {
result.push_back(addressBytes[2]);
result.push_back(addressBytes[1]);
result.push_back(addressBytes[0]);
pushBytesBack<u16>(result, changeEndianess<u16>(bytes.size(), std::endian::big));
pushBytesBack<u16>(result, changeEndianness<u16>(bytes.size(), std::endian::big));
for (auto byte : bytes)
result.push_back(byte);
@@ -189,7 +189,7 @@ namespace hex {
result.push_back(addressBytes[2]);
result.push_back(addressBytes[1]);
result.push_back(addressBytes[0]);
pushBytesBack<u16>(result, changeEndianess<u16>(bytes.size(), std::endian::big));
pushBytesBack<u16>(result, changeEndianness<u16>(bytes.size(), std::endian::big));
for (auto byte : bytes)
result.push_back(byte);

View File

@@ -90,11 +90,7 @@ namespace hex {
bool Tar::contains(const std::fs::path &path) const {
mtar_header_t header;
auto fixedPath = path.string();
#if defined(OS_WINDOWS)
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
#endif
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
return mtar_find(m_ctx.get(), fixedPath.c_str(), &header) == MTAR_ESUCCESS;
}
@@ -115,10 +111,7 @@ namespace hex {
std::vector<u8> Tar::readVector(const std::fs::path &path) const {
mtar_header_t header;
auto fixedPath = path.string();
#if defined(OS_WINDOWS)
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
#endif
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
int ret = mtar_find(m_ctx.get(), fixedPath.c_str(), &header);
if (ret != MTAR_ESUCCESS){
log::debug("Failed to read vector from path {} in tarred file {}: {}",
@@ -143,18 +136,12 @@ namespace hex {
for (const auto &part : path.parent_path()) {
pathPart /= part;
auto fixedPath = pathPart.string();
#if defined(OS_WINDOWS)
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
#endif
auto fixedPath = wolv::io::fs::toNormalizedPathString(pathPart);
mtar_write_dir_header(m_ctx.get(), fixedPath.c_str());
}
}
auto fixedPath = path.string();
#if defined(OS_WINDOWS)
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
#endif
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
mtar_write_file_header(m_ctx.get(), fixedPath.c_str(), data.size());
mtar_write_data(m_ctx.get(), data.data(), data.size());
}

View File

@@ -16,9 +16,11 @@
#include <wolv/utils/guards.hpp>
#elif defined(OS_LINUX)
#include <unistd.h>
#include <dlfcn.h>
#include <hex/helpers/utils_linux.hpp>
#elif defined(OS_MACOS)
#include <unistd.h>
#include <dlfcn.h>
#include <hex/helpers/utils_macos.hpp>
#elif defined(OS_WEB)
#include "emscripten.h"
@@ -353,7 +355,7 @@ namespace hex {
url = "https://" + url;
#if defined(OS_WINDOWS)
ShellExecute(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
ShellExecuteA(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
#elif defined(OS_MACOS)
openWebpageMacos(url.c_str());
#elif defined(OS_LINUX)
@@ -677,6 +679,44 @@ namespace hex {
return value;
}
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength) {
// If the string is shorter than the max length, return it as is
if (string.size() < maxLength)
return string;
// If the string is longer than the max length, find the last space before the max length
auto it = string.begin() + maxLength / 2;
while (it != string.begin() && !std::isspace(*it)) --it;
// If there's no space before the max length, just cut the string
if (it == string.begin()) {
it = string.begin() + maxLength / 2;
// Try to find a UTF-8 character boundary
while (it != string.begin() && (*it & 0xC0) == 0x80) --it;
}
// If we still didn't find a valid boundary, just return the string as is
if (it == string.begin())
return string;
auto result = std::string(string.begin(), it) + "";
// If the string is longer than the max length, find the last space before the max length
it = string.end() - 1 - maxLength / 2;
while (it != string.end() && !std::isspace(*it)) ++it;
// If there's no space before the max length, just cut the string
if (it == string.end()) {
it = string.end() - 1 - maxLength / 2;
// Try to find a UTF-8 character boundary
while (it != string.end() && (*it & 0xC0) == 0x80) ++it;
}
return result + std::string(it, string.end());
}
static std::optional<std::fs::path> s_fileToOpen;
extern "C" void openFile(const char *path) {
log::info("Opening file: {0}", path);
@@ -784,4 +824,24 @@ namespace hex {
#endif
}
void* getContainingModule(void* symbol) {
#if defined(OS_WINDOWS)
MEMORY_BASIC_INFORMATION mbi;
if (VirtualQuery(symbol, &mbi, sizeof(mbi)))
return mbi.AllocationBase;
return nullptr;
#elif !defined(OS_WEB)
Dl_info info = {};
if (dladdr(symbol, &info) == 0)
return nullptr;
return dlopen(info.dli_fname, RTLD_LAZY);
#else
hex::unused(symbol);
return nullptr;
#endif
}
}

View File

@@ -88,6 +88,42 @@
CFRelease(fontDescriptors);
}
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
// Consult user preferences: "System Settings -> Desktop & Dock -> Double-click a window's title bar to"
NSString* action = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleActionOnDoubleClick"];
if (action == nil || [action isEqualToString:@"None"]) {
// Nothing to do
} else if ([action isEqualToString:@"Minimize"]) {
if ([cocoaWindow isMiniaturizable]) {
[cocoaWindow miniaturize:nil];
}
} else if ([action isEqualToString:@"Maximize"]) {
// `[NSWindow zoom:_ sender]` takes over pumping the main runloop for the duration of the resize,
// and would interfere with our renderer's frame logic. Schedule it for the next frame
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
if ([cocoaWindow isZoomable]) {
[cocoaWindow zoom:nil];
}
});
}
}
bool macosIsWindowBeingResizedByUser(GLFWwindow *window) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
return cocoaWindow.inLiveResize;
}
void macosMarkContentEdited(GLFWwindow *window, bool edited) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
[cocoaWindow setDocumentEdited:edited];
}
@interface HexDocument : NSDocument
@end

View File

@@ -31,41 +31,4 @@ namespace hex::prv {
m_data.resize(newSize);
}
void MemoryProvider::insertRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
this->resizeRaw(oldSize + size);
std::vector<u8> buffer(0x1000);
const std::vector<u8> zeroBuffer(0x1000);
auto position = oldSize;
while (position > offset) {
const auto readSize = std::min<size_t>(position - offset, buffer.size());
position -= readSize;
this->readRaw(position, buffer.data(), readSize);
this->writeRaw(position, zeroBuffer.data(), readSize);
this->writeRaw(position + size, buffer.data(), readSize);
}
}
void MemoryProvider::removeRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
std::vector<u8> buffer(0x1000);
const auto newSize = oldSize - size;
auto position = offset;
while (position < newSize) {
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
this->readRaw(position + size, buffer.data(), readSize);
this->writeRaw(position, buffer.data(), readSize);
position += readSize;
}
this->resizeRaw(oldSize - size);
}
}

View File

@@ -74,7 +74,11 @@ namespace hex::prv {
}
}
void Provider::resize(u64 newSize) {
bool Provider::resize(u64 newSize) {
if (newSize >> 63) {
log::error("new provider size is very large ({}). Is it a negative number ?", newSize);
return false;
}
i64 difference = newSize - this->getActualSize();
if (difference > 0)
@@ -83,6 +87,7 @@ namespace hex::prv {
EventProviderDataRemoved::post(this, this->getActualSize() + difference, -difference);
this->markDirty();
return true;
}
void Provider::insert(u64 offset, u64 size) {
@@ -97,6 +102,52 @@ namespace hex::prv {
this->markDirty();
}
void Provider::insertRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize();
this->resizeRaw(oldSize + size);
std::vector<u8> buffer(0x1000);
const std::vector<u8> zeroBuffer(0x1000);
auto position = oldSize;
while (position > offset) {
const auto readSize = std::min<size_t>(position - offset, buffer.size());
position -= readSize;
this->readRaw(position, buffer.data(), readSize);
this->writeRaw(position, zeroBuffer.data(), readSize);
this->writeRaw(position + size, buffer.data(), readSize);
}
}
void Provider::removeRaw(u64 offset, u64 size) {
if (offset > this->getActualSize() || size == 0)
return;
if ((offset + size) > this->getActualSize())
size = this->getActualSize() - offset;
auto oldSize = this->getActualSize();
std::vector<u8> buffer(0x1000);
const auto newSize = oldSize - size;
auto position = offset;
while (position < newSize) {
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
this->readRaw(position + size, buffer.data(), readSize);
this->writeRaw(position, buffer.data(), readSize);
position += readSize;
}
this->resizeRaw(newSize);
}
void Provider::applyOverlays(u64 offset, void *buffer, size_t size) const {
for (auto &overlay : m_overlays) {
auto overlayOffset = overlay->getAddress();

View File

@@ -79,6 +79,7 @@ namespace hex::prv::undo {
for (u32 i = 0; i < count; i += 1) {
i64 index = startIndex + i;
m_undoStack[index]->undo(m_provider);
operation->addOperation(std::move(m_undoStack[index]));
}
@@ -93,6 +94,13 @@ namespace hex::prv::undo {
}
}
void Stack::reapply() {
for (const auto &operation : m_undoStack) {
operation->redo(m_provider);
}
}
bool Stack::add(std::unique_ptr<Operation> &&operation) {

View File

@@ -15,11 +15,12 @@ namespace hex::subcommands {
std::optional<SubCommand> findSubCommand(const std::string &arg) {
for (auto &plugin : PluginManager::getPlugins()) {
for (auto &subCommand : plugin.getSubCommands()) {
if (hex::format("--{}", subCommand.commandKey) == arg) {
if (hex::format("--{}", subCommand.commandLong) == arg || hex::format("-{}", subCommand.commandShort) == arg) {
return subCommand;
}
}
}
return std::nullopt;
}
@@ -27,7 +28,8 @@ namespace hex::subcommands {
// If no arguments, do not even try to process arguments
// (important because this function will exit ImHex if an instance is already opened,
// and we don't want that if no arguments were provided)
if (args.empty()) return;
if (args.empty())
return;
std::vector<std::pair<SubCommand, std::vector<std::string>>> subCommands;
@@ -76,18 +78,18 @@ namespace hex::subcommands {
}
// Save last command to run
if (currentSubCommand) {
if (currentSubCommand.has_value()) {
subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs);
}
// Run the subcommands
for (auto& subCommandPair : subCommands) {
subCommandPair.first.callback(subCommandPair.second);
for (auto &[subcommand, args] : subCommands) {
subcommand.callback(args);
}
// Exit the process if its not the main instance (the commands have been forwarded to another instance)
// Exit the process if it's not the main instance (the commands have been forwarded to another instance)
if (!ImHexApi::System::isMainInstance()) {
exit(0);
std::exit(0);
}
}
@@ -95,12 +97,15 @@ namespace hex::subcommands {
log::debug("Forwarding subcommand {} (maybe to us)", cmdName);
std::vector<u8> data;
for (const auto &arg: args) {
data.insert(data.end(), arg.begin(), arg.end());
data.push_back('\0');
if (!args.empty()) {
for (const auto &arg: args) {
data.insert(data.end(), arg.begin(), arg.end());
data.push_back('\0');
}
data.pop_back();
}
data.erase(data.end()-1);
SendMessageToMainInstance::post(hex::format("command/{}", cmdName), data);
}
@@ -112,8 +117,8 @@ namespace hex::subcommands {
std::vector<std::string> args;
for (const auto &arg_view : std::views::split(string, char(0x00))) {
std::string arg(arg_view.data(), arg_view.size());
for (const auto &argument : std::views::split(string, char(0x00))) {
std::string arg(argument.data(), argument.size());
args.push_back(arg);
}

View File

@@ -0,0 +1,23 @@
#include <hex/test/tests.hpp>
namespace hex::test {
std::map<std::string, Test> Tests::s_tests;
bool initPluginImpl(std::string name) {
if (name != "Built-in") {
if(!initPluginImpl("Built-in")) return false;
}
hex::Plugin *plugin = hex::PluginManager::getPlugin(name);
if (plugin == nullptr) {
hex::log::fatal("Plugin '{}' was not found !", name);
return false;
}else if (!plugin->initializePlugin()) {
hex::log::fatal("Failed to initialize plugin '{}' !", name);
return false;
}
hex::log::info("Initialized plugin '{}' successfully", name);
return true;
}
}

View File

@@ -4,6 +4,7 @@
#include <imgui_internal.h>
#include <implot.h>
#include <implot_internal.h>
#include <cimgui.h>
#include <opengl_support.h>
#undef IMGUI_DEFINE_MATH_OPERATORS
@@ -11,14 +12,17 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <lunasvg.h>
#include <set>
#include <string>
#include <algorithm>
#include <hex/api/imhex_api.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/helpers/logger.hpp>
namespace ImGuiExt {
@@ -27,6 +31,32 @@ namespace ImGuiExt {
namespace {
bool isOpenGLExtensionSupported(const char *name) {
static std::set<std::string> extensions;
if (extensions.empty()) {
GLint extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
for (GLint i = 0; i < extensionCount; i++) {
std::string extension = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
extensions.emplace(std::move(extension));
}
}
return extensions.contains(name);
}
bool isOpenGLVersionAtLeast(u8 major, u8 minor) {
static GLint actualMajor = 0, actualMinor = 0;
if (actualMajor == 0 || actualMinor == 0) {
glGetIntegerv(GL_MAJOR_VERSION, &actualMajor);
glGetIntegerv(GL_MINOR_VERSION, &actualMinor);
}
return actualMajor > major || (actualMajor == major && actualMinor >= minor);
}
constexpr auto getGLFilter(Texture::Filter filter) {
switch (filter) {
using enum Texture::Filter;
@@ -39,74 +69,189 @@ namespace ImGuiExt {
return GL_NEAREST;
}
[[maybe_unused]] GLint getMaxSamples(GLenum target, GLenum format) {
GLint maxSamples;
glGetInternalformativ(target, format, GL_SAMPLES, 1, &maxSamples);
return maxSamples;
}
GLuint createTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
GLuint texture;
// Generate texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
// Allocate storage for the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return texture;
}
GLuint createMultisampleTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
// Create a regular texture from the RGBA8 array
GLuint texture = createTextureFromRGBA8Array(buffer, width, height, filter);
if (filter == Texture::Filter::Nearest) {
return texture;
}
if (!isOpenGLVersionAtLeast(3,2)) {
return texture;
}
if (!isOpenGLExtensionSupported("GL_ARB_texture_multisample")) {
return texture;
}
#if defined(GL_TEXTURE_2D_MULTISAMPLE)
static const auto sampleCount = std::min(static_cast<GLint>(8), getMaxSamples(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8));
// Generate renderbuffer
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH24_STENCIL8, width, height);
// Generate framebuffer
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Unbind framebuffer on exit
ON_SCOPE_EXIT {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
};
// Attach texture to color attachment 0
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture, 0);
// Attach renderbuffer to depth-stencil attachment
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
// Check framebuffer status
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
hex::log::error("Driver claims to support texture multisampling but it's not working");
return texture;
}
#endif
return texture;
}
}
Texture::Texture(const ImU8 *buffer, int size, Filter filter, int width, int height) {
Texture Texture::fromImage(const ImU8 *buffer, int size, Filter filter) {
if (size == 0)
return;
return {};
unsigned char *imageData = nullptr;
if (width == 0 || height == 0)
imageData = stbi_load_from_memory(buffer, size, &m_width, &m_height, nullptr, 4);
if (imageData == nullptr) {
if (width * height * 4 > size)
return;
imageData = static_cast<unsigned char *>(STBI_MALLOC(size));
std::memcpy(imageData, buffer, size);
m_width = width;
m_height = height;
}
Texture result;
imageData = stbi_load_from_memory(buffer, size, &result.m_width, &result.m_height, nullptr, 4);
if (imageData == nullptr)
return;
return {};
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
STBI_FREE(imageData);
m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture::Texture(std::span<const std::byte> bytes, Filter filter, int width, int height) : Texture(reinterpret_cast<const ImU8*>(bytes.data()), bytes.size(), filter, width, height) { }
Texture Texture::fromImage(std::span<const std::byte> buffer, Filter filter) {
return Texture::fromImage(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), filter);
}
Texture::Texture(const std::fs::path &path, Filter filter) : Texture(reinterpret_cast<const char *>(path.u8string().c_str()), filter) { }
Texture::Texture(const char *path, Filter filter) {
unsigned char *imageData = stbi_load(path, &m_width, &m_height, nullptr, 4);
Texture Texture::fromImage(const std::fs::path &path, Filter filter) {
return Texture::fromImage(wolv::util::toUTF8String(path).c_str(), filter);
}
Texture Texture::fromImage(const char *path, Filter filter) {
Texture result;
unsigned char *imageData = stbi_load(path, &result.m_width, &result.m_height, nullptr, 4);
if (imageData == nullptr)
return;
return {};
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
STBI_FREE(imageData);
m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture::Texture(unsigned int texture, int width, int height) : m_textureId(reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture))), m_width(width), m_height(height) {
Texture Texture::fromGLTexture(unsigned int glTexture, int width, int height) {
Texture texture;
texture.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(glTexture));
texture.m_width = width;
texture.m_height = height;
return texture;
}
Texture Texture::fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter) {
return Texture::fromBitmap(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), width, height, filter);
}
Texture Texture::fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter) {
if (width * height * 4 > size)
return {};
GLuint texture = createMultisampleTextureFromRGBA8Array(buffer, width, height, filter);
Texture result;
result.m_width = width;
result.m_height = height;
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture Texture::fromSVG(const char *path, int width, int height, Filter filter) {
auto document = lunasvg::Document::loadFromFile(path);
auto bitmap = document->renderToBitmap(width, height);
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
Texture result;
result.m_width = bitmap.width();
result.m_height = bitmap.height();
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture Texture::fromSVG(const std::fs::path &path, int width, int height, Filter filter) {
return Texture::fromSVG(wolv::util::toUTF8String(path).c_str(), width, height, filter);
}
Texture Texture::fromSVG(std::span<const std::byte> buffer, int width, int height, Filter filter) {
auto document = lunasvg::Document::loadFromData(reinterpret_cast<const char*>(buffer.data()), buffer.size());
auto bitmap = document->renderToBitmap(width, height);
bitmap.convertToRGBA();
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
Texture result;
result.m_width = bitmap.width();
result.m_height = bitmap.height();
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture::Texture(Texture&& other) noexcept {
@@ -137,8 +282,11 @@ namespace ImGuiExt {
if (m_textureId == nullptr)
return;
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(m_textureId));
glDeleteTextures(1, &glTextureId);
glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId));
}
float GetTextWrapPos() {
return GImGui->CurrentWindow->DC.TextWrapPos;
}
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
@@ -179,7 +327,10 @@ namespace ImGuiExt {
PushStyleColor(ImGuiCol_Text, ImU32(col));
Text("%s %s", icon, label);
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
if (hovered)
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
PopStyleColor();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
@@ -208,7 +359,10 @@ namespace ImGuiExt {
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
PushStyleColor(ImGuiCol_Text, ImU32(col));
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
if (hovered)
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
PopStyleColor();
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
@@ -360,26 +514,25 @@ namespace ImGuiExt {
return pressed;
}
void HelpHover(const char *text) {
const auto iconColor = GetStyleColorVec4(ImGuiCol_ButtonActive);
void HelpHover(const char *text, const char *icon, ImU32 iconColor) {
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, GetStyle().FramePadding.y));
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0F);
PushStyleColor(ImGuiCol_Text, iconColor);
Button("(?)");
Button(icon);
PopStyleColor();
if (IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
SetNextWindowSizeConstraints(ImVec2(GetTextLineHeight() * 25, 0), ImVec2(GetTextLineHeight() * 25, FLT_MAX));
SetNextWindowSizeConstraints(ImVec2(GetTextLineHeight() * 25, 0), ImVec2(GetTextLineHeight() * 35, FLT_MAX));
BeginTooltip();
TextFormattedWrapped("{}", text);
EndTooltip();
}
PopStyleVar();
PopStyleVar(2);
PopStyleColor(3);
}
@@ -422,14 +575,30 @@ namespace ImGuiExt {
ImGuiID hoveredID = GetHoveredID();
bool result = false;
if (IsItemHovered() && (currTime - lastMoveTime) >= 0.5 && hoveredID == lastHoveredID) {
if (IsItemHovered(ImGuiHoveredFlags_DelayNormal) && (currTime - lastMoveTime) >= 0.5 && hoveredID == lastHoveredID) {
if (!std::string_view(text).empty()) {
BeginTooltip();
if (isSeparator)
SeparatorText(text);
const auto textWidth = CalcTextSize(text).x;
const auto maxWidth = 300 * hex::ImHexApi::System::getGlobalScale();
const bool wrapping = textWidth > maxWidth;
if (wrapping)
ImGui::SetNextWindowSizeConstraints(ImVec2(maxWidth, 0), ImVec2(maxWidth, FLT_MAX));
else
TextUnformatted(text);
EndTooltip();
ImGui::SetNextWindowSize(ImVec2(textWidth + GetStyle().WindowPadding.x * 2, 0));
if (BeginTooltip()) {
if (isSeparator)
SeparatorText(text);
else {
if (wrapping)
TextFormattedWrapped("{}", text);
else
TextFormatted("{}", text);
}
EndTooltip();
}
}
result = true;
@@ -574,7 +743,7 @@ namespace ImGuiExt {
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb);
// Automatically close popups
@@ -599,7 +768,9 @@ namespace ImGuiExt {
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(ImVec2(1, 1) * GetCurrentWindow()->MenuBarHeight(), label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
ImVec2 size = CalcItemSize(ImVec2(1, 1) * GetCurrentWindow()->MenuBarHeight, label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
ImVec2 padding = (size - label_size) / 2;
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
@@ -616,7 +787,7 @@ namespace ImGuiExt {
: ImGuiCol_MenuBarBg);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + padding, bb.Max - padding, symbol, nullptr, &size, style.ButtonTextAlign, &bb);
PopStyleColor();
@@ -679,20 +850,13 @@ namespace ImGuiExt {
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), CalcTextSize(prefix).x, label_size.y + style.FramePadding.y * 2.0F);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(CalcItemWidth(), frame_size.y));
SetCursorPosX(GetCursorPosX() + frame_size.x);
char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, format);
bool value_changed = false;
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0F), flags))
value_changed = DataTypeApplyFromText(buf, type, value, format);
if (value_changed)
MarkItemEdited(GImGui->LastItemData.ID);
RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
@@ -700,6 +864,19 @@ namespace ImGuiExt {
RenderText(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y), prefix);
PopStyleVar();
bool value_changed = false;
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0);
PushStyleColor(ImGuiCol_FrameBg, 0x00000000);
PushStyleColor(ImGuiCol_FrameBgHovered, 0x00000000);
PushStyleColor(ImGuiCol_FrameBgActive, 0x00000000);
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0F), flags))
value_changed = DataTypeApplyFromText(buf, type, value, format);
PopStyleColor(3);
PopStyleVar();
if (value_changed)
MarkItemEdited(GImGui->LastItemData.ID);
return value_changed;
}
@@ -711,6 +888,21 @@ namespace ImGuiExt {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, "%llX", flags | ImGuiInputTextFlags_CharsHexadecimal);
}
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, ImGuiSliderFlags flags) {
std::string format;
if (*value < 1024) {
format = hex::format("{} Bytes", *value);
} else if (*value < 1024 * 1024) {
format = hex::format("{:.2f} KB", *value / 1024.0);
} else if (*value < 1024 * 1024 * 1024) {
format = hex::format("{:.2f} MB", *value / (1024.0 * 1024.0));
} else {
format = hex::format("{:.2f} GB", *value / (1024.0 * 1024.0 * 1024.0));
}
return ImGui::SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format.c_str(), flags | ImGuiSliderFlags_Logarithmic);
}
void SmallProgressBar(float fraction, float yOffset) {
ImGuiWindow *window = GetCurrentWindow();
if (window->SkipItems)
@@ -982,17 +1174,37 @@ namespace ImGuiExt {
PopStyleVar();
}
void BeginSubWindow(const char *label, ImVec2 size, ImGuiChildFlags flags) {
bool BeginSubWindow(const char *label, bool *collapsed, ImVec2 size, ImGuiChildFlags flags) {
const bool hasMenuBar = !std::string_view(label).empty();
bool result = false;
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0F);
if (ImGui::BeginChild(hex::format("{}##SubWindow", label).c_str(), size, ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY | flags, hasMenuBar ? ImGuiWindowFlags_MenuBar : ImGuiWindowFlags_None)) {
result = true;
if (hasMenuBar && ImGui::BeginMenuBar()) {
ImGui::TextUnformatted(label);
if (collapsed == nullptr)
ImGui::TextUnformatted(label);
else {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, ImGui::GetStyle().FramePadding.y));
ImGui::PushStyleColor(ImGuiCol_Button, 0x00);
if (ImGui::Button(label))
*collapsed = !*collapsed;
ImGui::PopStyleColor();
ImGui::PopStyleVar();
}
ImGui::EndMenuBar();
}
if (collapsed != nullptr && *collapsed) {
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - (ImGui::GetStyle().FramePadding.y * 2));
ImGuiExt::TextFormattedDisabled("...");
result = false;
}
}
ImGui::PopStyleVar();
return result;
}
void EndSubWindow() {
@@ -1073,9 +1285,9 @@ namespace ImGuiExt {
window->DrawList->AddRectFilled(knob_bb.Min, knob_bb.Max, GetColorU32(held ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : *v ? ImGuiCol_ButtonActive : ImGuiCol_Button), size.y / 2);
if (*v)
window->DrawList->AddCircleFilled(knob_bb.Max - ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_Text), 16);
window->DrawList->AddCircleFilled(knob_bb.Max - ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_ScrollbarGrabActive), 16);
else
window->DrawList->AddCircleFilled(knob_bb.Min + ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_Text), 16);
window->DrawList->AddCircleFilled(knob_bb.Min + ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_ScrollbarGrabActive), 16);
ImVec2 label_pos = ImVec2(knob_bb.Max.x + style.ItemInnerSpacing.x, knob_bb.Min.y + style.FramePadding.y);
if (g.LogEnabled)
@@ -1091,6 +1303,59 @@ namespace ImGuiExt {
return ToggleSwitch(label, &v);
}
bool PopupTitleBarButton(const char* label, bool p_enabled)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const ImGuiID id = window->GetID(label);
const ImRect title_rect = window->TitleBarRect();
const ImVec2 size(g.FontSize, g.FontSize); // Button size matches font size for aesthetic consistency.
const ImVec2 pos = window->DC.CursorPos;
const ImVec2 max_pos = pos + size;
const ImRect bb(pos.x, title_rect.Min.y, max_pos.x, title_rect.Max.y);
ImGui::PushClipRect(title_rect.Min, title_rect.Max, false);
// Check for item addition (similar to how clipping is handled in the original button functions).
bool is_clipped = !ItemAdd(bb, id);
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
if (is_clipped)
{
ImGui::PopClipRect();
return pressed;
}
// const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
// window->DrawList->AddCircleFilled(bb.GetCenter(), ImMax(2.0f, g.FontSize * 0.5f + 1.0f), bg_col);
// Draw the label in the center
ImU32 text_col = GetColorU32(p_enabled || hovered ? ImGuiCol_Text : ImGuiCol_TextDisabled);
window->DrawList->AddText(bb.GetCenter() - ImVec2(g.FontSize * 0.45F, g.FontSize * 0.5F), text_col, label);
// Return the button press state
ImGui::PopClipRect();
return pressed;
}
void PopupTitleBarText(const char* text) {
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
const ImRect title_rect = window->TitleBarRect();
const ImVec2 size(g.FontSize, g.FontSize); // Button size matches font size for aesthetic consistency.
const ImVec2 pos = window->DC.CursorPos;
const ImVec2 max_pos = pos + size;
const ImRect bb(pos.x, title_rect.Min.y, max_pos.x, title_rect.Max.y);
ImGui::PushClipRect(title_rect.Min, title_rect.Max, false);
// Draw the label in the center
ImU32 text_col = GetColorU32(ImGuiCol_Text);
window->DrawList->AddText(bb.GetCenter() - ImVec2(g.FontSize * 0.45F, g.FontSize * 0.5F), text_col, text);
// Return the button press state
ImGui::PopClipRect();
}
}
namespace ImGui {
@@ -1111,4 +1376,4 @@ namespace ImGui {
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGuiExt::UpdateStringSizeCallback, &buffer);
}
}
}

View File

@@ -71,7 +71,7 @@ namespace hex {
}
std::string View::toWindowName(const UnlocalizedString &unlocalizedName) {
return Lang(unlocalizedName) + "###" + unlocalizedName.get();
return fmt::format("{}###{}", Lang(unlocalizedName), unlocalizedName.get());
}
}

3
lib/third_party/boost/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,3 @@
project(boost)
add_subdirectory(regex)

View File

@@ -0,0 +1,10 @@
project(boost-regex)
add_library(boost-regex INTERFACE)
target_include_directories(boost-regex INTERFACE
include
)
target_compile_definitions(boost-regex INTERFACE BOOST_REGEX_STANDALONE)
add_library(boost::regex ALIAS boost-regex)

View File

@@ -0,0 +1,43 @@
/*
*
* Copyright (c) 1998-2002
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org/libs/regex for most recent version.
* FILE cregex.cpp
* VERSION see <boost/version.hpp>
* DESCRIPTION: Declares POSIX API functions
* + boost::RegEx high level wrapper.
*/
#ifndef BOOST_RE_CREGEX_HPP
#define BOOST_RE_CREGEX_HPP
#ifndef BOOST_REGEX_CONFIG_HPP
#include <boost/regex/config.hpp>
#endif
#ifdef BOOST_REGEX_CXX03
#include <boost/regex/v4/cregex.hpp>
#else
#include <boost/regex/v5/cregex.hpp>
#endif
#endif /* include guard */

View File

@@ -0,0 +1,100 @@
/*
*
* Copyright (c) 1998-2000
* Dr John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org/libs/regex for documentation.
* FILE regex.h
* VERSION 3.12
* DESCRIPTION: Declares POSIX API functions
*/
#ifndef BOOST_RE_REGEX_H
#define BOOST_RE_REGEX_H
#include <boost/cregex.hpp>
/*
* add using declarations to bring POSIX API functions into
* global scope, only if this is C++ (and not C).
*/
#ifdef __cplusplus
using boost::regoff_t;
using boost::regex_tA;
using boost::regmatch_t;
using boost::REG_BASIC;
using boost::REG_EXTENDED;
using boost::REG_ICASE;
using boost::REG_NOSUB;
using boost::REG_NEWLINE;
using boost::REG_NOSPEC;
using boost::REG_PEND;
using boost::REG_DUMP;
using boost::REG_NOCOLLATE;
using boost::REG_ESCAPE_IN_LISTS;
using boost::REG_NEWLINE_ALT;
using boost::REG_PERL;
using boost::REG_AWK;
using boost::REG_GREP;
using boost::REG_EGREP;
using boost::REG_ASSERT;
using boost::REG_INVARG;
using boost::REG_ATOI;
using boost::REG_ITOA;
using boost::REG_NOTBOL;
using boost::REG_NOTEOL;
using boost::REG_STARTEND;
using boost::reg_comp_flags;
using boost::reg_exec_flags;
using boost::regcompA;
using boost::regerrorA;
using boost::regexecA;
using boost::regfreeA;
#ifndef BOOST_NO_WREGEX
using boost::regcompW;
using boost::regerrorW;
using boost::regexecW;
using boost::regfreeW;
using boost::regex_tW;
#endif
using boost::REG_NOERROR;
using boost::REG_NOMATCH;
using boost::REG_BADPAT;
using boost::REG_ECOLLATE;
using boost::REG_ECTYPE;
using boost::REG_EESCAPE;
using boost::REG_ESUBREG;
using boost::REG_EBRACK;
using boost::REG_EPAREN;
using boost::REG_EBRACE;
using boost::REG_BADBR;
using boost::REG_ERANGE;
using boost::REG_ESPACE;
using boost::REG_BADRPT;
using boost::REG_EEND;
using boost::REG_ESIZE;
using boost::REG_ERPAREN;
using boost::REG_EMPTY;
using boost::REG_E_MEMORY;
using boost::REG_E_UNKNOWN;
using boost::reg_errcode_t;
#endif /* __cplusplus */
#endif /* BOOST_RE_REGEX_H */

View File

@@ -0,0 +1,41 @@
/*
*
* Copyright (c) 1998-2002
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org/libs/regex for documentation.
* FILE regex.cpp
* VERSION see <boost/version.hpp>
* DESCRIPTION: Declares boost::basic_regex<> and associated
* functions and classes. This header is the main
* entry point for the template regex code.
*/
/* start with C compatibility API */
#ifndef BOOST_RE_REGEX_HPP
#define BOOST_RE_REGEX_HPP
#ifndef BOOST_REGEX_CONFIG_HPP
#include <boost/regex/config.hpp>
#endif
#ifdef BOOST_REGEX_CXX03
#include <boost/regex/v4/regex.hpp>
#else
#include <boost/regex/v5/regex.hpp>
#endif
#endif // include

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,480 @@
/*
*
* Copyright (c) 1998-2002
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org for most recent version.
* FILE config.hpp
* VERSION see <boost/version.hpp>
* DESCRIPTION: regex extended config setup.
*/
#ifndef BOOST_REGEX_CONFIG_HPP
#define BOOST_REGEX_CONFIG_HPP
#if !((__cplusplus >= 201103L) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(BOOST_REGEX_CXX03))
# define BOOST_REGEX_CXX03
#endif
#if defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_CXX03)
# define BOOST_REGEX_CXX03
#endif
#if defined(__has_include)
#if !defined(BOOST_REGEX_STANDALONE) && !__has_include(<boost/version.hpp>)
#define BOOST_REGEX_STANDALONE
#endif
#endif
/*
* Borland C++ Fix/error check
* this has to go *before* we include any std lib headers:
*/
#if defined(__BORLANDC__) && !defined(__clang__)
# include <boost/regex/config/borland.hpp>
#endif
#ifndef BOOST_REGEX_STANDALONE
#include <boost/version.hpp>
#endif
/*************************************************************************
*
* Asserts:
*
*************************************************************************/
#ifdef BOOST_REGEX_STANDALONE
#include <cassert>
# define BOOST_REGEX_ASSERT(x) assert(x)
#else
#include <boost/assert.hpp>
# define BOOST_REGEX_ASSERT(x) BOOST_ASSERT(x)
#endif
/*****************************************************************************
*
* Include all the headers we need here:
*
****************************************************************************/
#ifdef __cplusplus
# ifndef BOOST_REGEX_USER_CONFIG
# define BOOST_REGEX_USER_CONFIG <boost/regex/user.hpp>
# endif
# include BOOST_REGEX_USER_CONFIG
#ifndef BOOST_REGEX_STANDALONE
# include <boost/config.hpp>
# include <boost/predef.h>
#endif
#else
/*
* C build,
* don't include <boost/config.hpp> because that may
* do C++ specific things in future...
*/
# include <stdlib.h>
# include <stddef.h>
# ifdef _MSC_VER
# define BOOST_MSVC _MSC_VER
# endif
#endif
/****************************************************************************
*
* Legacy support:
*
*******************************************************************************/
#if defined(BOOST_NO_STD_LOCALE) || defined(BOOST_NO_CXX11_HDR_MUTEX) || defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) \
|| defined(BOOST_NO_CXX11_HDR_ATOMIC) || defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_CXX11_SMART_PTR) \
|| defined(BOOST_NO_CXX11_STATIC_ASSERT) || defined(BOOST_NO_NOEXCEPT)
#ifndef BOOST_REGEX_CXX03
# define BOOST_REGEX_CXX03
#endif
#endif
/*****************************************************************************
*
* Boilerplate regex config options:
*
****************************************************************************/
/* Obsolete macro, use BOOST_VERSION instead: */
#define BOOST_RE_VERSION 500
/* fix: */
#if defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#define BOOST_REGEX_JOIN(X, Y) BOOST_REGEX_DO_JOIN(X, Y)
#define BOOST_REGEX_DO_JOIN(X, Y) BOOST_REGEX_DO_JOIN2(X,Y)
#define BOOST_REGEX_DO_JOIN2(X, Y) X##Y
#ifdef BOOST_FALLTHROUGH
# define BOOST_REGEX_FALLTHROUGH BOOST_FALLTHROUGH
#else
#if defined(__clang__) && (__cplusplus >= 201103L) && defined(__has_warning)
# if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
# define BOOST_REGEX_FALLTHROUGH [[clang::fallthrough]]
# endif
#endif
#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1800) && (__cplusplus >= 201703)
# define BOOST_REGEX_FALLTHROUGH [[fallthrough]]
#endif
#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__GNUC__) && (__GNUC__ >= 7)
# define BOOST_REGEX_FALLTHROUGH __attribute__((fallthrough))
#endif
#if !defined(BOOST_REGEX_FALLTHROUGH)
# define BOOST_REGEX_FALLTHROUGH
#endif
#endif
#ifdef BOOST_NORETURN
# define BOOST_REGEX_NORETURN BOOST_NORETURN
#else
# define BOOST_REGEX_NORETURN
#endif
/*
* Define a macro for the namespace that details are placed in, this includes the Boost
* version number to avoid mismatched header and library versions:
*/
#define BOOST_REGEX_DETAIL_NS BOOST_REGEX_JOIN(re_detail_, BOOST_RE_VERSION)
/*
* Fix for gcc prior to 3.4: std::ctype<wchar_t> doesn't allow
* masks to be combined, for example:
* std::use_facet<std::ctype<wchar_t> >.is(std::ctype_base::lower|std::ctype_base::upper, L'a');
* returns *false*.
*/
#if defined(__GLIBCPP__) && defined(BOOST_REGEX_CXX03)
# define BOOST_REGEX_BUGGY_CTYPE_FACET
#endif
/*
* If there isn't good enough wide character support then there will
* be no wide character regular expressions:
*/
#if (defined(BOOST_NO_CWCHAR) || defined(BOOST_NO_CWCTYPE) || defined(BOOST_NO_STD_WSTRING))
# if !defined(BOOST_NO_WREGEX)
# define BOOST_NO_WREGEX
# endif
#else
# if defined(__sgi) && (defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION))
/* STLPort on IRIX is misconfigured: <cwctype> does not compile
* as a temporary fix include <wctype.h> instead and prevent inclusion
* of STLPort version of <cwctype> */
# include <wctype.h>
# define __STLPORT_CWCTYPE
# define _STLP_CWCTYPE
# endif
#if defined(__cplusplus) && defined(BOOST_REGEX_CXX03)
# include <boost/regex/config/cwchar.hpp>
#endif
#endif
/*
* If Win32 support has been disabled for boost in general, then
* it is for regex in particular:
*/
#if defined(BOOST_DISABLE_WIN32) && !defined(BOOST_REGEX_NO_W32)
# define BOOST_REGEX_NO_W32
#endif
/* disable our own file-iterators and mapfiles if we can't
* support them: */
#if defined(_WIN32)
# if defined(BOOST_REGEX_NO_W32) || BOOST_PLAT_WINDOWS_RUNTIME
# define BOOST_REGEX_NO_FILEITER
# endif
#else /* defined(_WIN32) */
# if !defined(BOOST_HAS_DIRENT_H)
# define BOOST_REGEX_NO_FILEITER
# endif
#endif
/* backwards compatibitity: */
#if defined(BOOST_RE_NO_LIB)
# define BOOST_REGEX_NO_LIB
#endif
#if defined(__GNUC__) && !defined(_MSC_VER) && (defined(_WIN32) || defined(__CYGWIN__))
/* gcc on win32 has problems if you include <windows.h>
(sporadically generates bad code). */
# define BOOST_REGEX_NO_W32
#endif
#if defined(__COMO__) && !defined(BOOST_REGEX_NO_W32) && !defined(_MSC_EXTENSIONS)
# define BOOST_REGEX_NO_W32
#endif
#ifdef BOOST_REGEX_STANDALONE
# if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
# define BOOST_REGEX_MSVC _MSC_VER
#endif
#elif defined(BOOST_MSVC)
# define BOOST_REGEX_MSVC BOOST_MSVC
#endif
/*****************************************************************************
*
* Set up dll import/export options:
*
****************************************************************************/
#if (defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_REGEX_STATIC_LINK) && defined(BOOST_SYMBOL_IMPORT)
# if defined(BOOST_REGEX_SOURCE)
# define BOOST_REGEX_BUILD_DLL
# define BOOST_REGEX_DECL BOOST_SYMBOL_EXPORT
# else
# define BOOST_REGEX_DECL BOOST_SYMBOL_IMPORT
# endif
#else
# define BOOST_REGEX_DECL
#endif
#ifdef BOOST_REGEX_CXX03
#if !defined(BOOST_REGEX_NO_LIB) && !defined(BOOST_REGEX_SOURCE) && !defined(BOOST_ALL_NO_LIB) && defined(__cplusplus)
# define BOOST_LIB_NAME boost_regex
# if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
# define BOOST_DYN_LINK
# endif
# ifdef BOOST_REGEX_DIAG
# define BOOST_LIB_DIAGNOSTIC
# endif
# include <boost/config/auto_link.hpp>
#endif
#endif
/*****************************************************************************
*
* Set up function call type:
*
****************************************************************************/
#if defined(_MSC_VER) && defined(_MSC_EXTENSIONS)
#if defined(_DEBUG) || defined(__MSVC_RUNTIME_CHECKS) || defined(_MANAGED) || defined(BOOST_REGEX_NO_FASTCALL)
# define BOOST_REGEX_CALL __cdecl
#else
# define BOOST_REGEX_CALL __fastcall
#endif
# define BOOST_REGEX_CCALL __cdecl
#endif
#if defined(__BORLANDC__) && !defined(BOOST_DISABLE_WIN32)
#if defined(__clang__)
# define BOOST_REGEX_CALL __cdecl
# define BOOST_REGEX_CCALL __cdecl
#else
# define BOOST_REGEX_CALL __fastcall
# define BOOST_REGEX_CCALL __stdcall
#endif
#endif
#ifndef BOOST_REGEX_CALL
# define BOOST_REGEX_CALL
#endif
#ifndef BOOST_REGEX_CCALL
#define BOOST_REGEX_CCALL
#endif
/*****************************************************************************
*
* Set up localisation model:
*
****************************************************************************/
/* backwards compatibility: */
#ifdef BOOST_RE_LOCALE_C
# define BOOST_REGEX_USE_C_LOCALE
#endif
#ifdef BOOST_RE_LOCALE_CPP
# define BOOST_REGEX_USE_CPP_LOCALE
#endif
#if defined(__CYGWIN__)
# define BOOST_REGEX_USE_C_LOCALE
#endif
/* use C++ locale when targeting windows store */
#if BOOST_PLAT_WINDOWS_RUNTIME
# define BOOST_REGEX_USE_CPP_LOCALE
# define BOOST_REGEX_NO_WIN32_LOCALE
#endif
/* Win32 defaults to native Win32 locale: */
#if defined(_WIN32) && \
!defined(BOOST_REGEX_USE_WIN32_LOCALE) && \
!defined(BOOST_REGEX_USE_C_LOCALE) && \
!defined(BOOST_REGEX_USE_CPP_LOCALE) && \
!defined(BOOST_REGEX_NO_W32) && \
!defined(BOOST_REGEX_NO_WIN32_LOCALE)
# define BOOST_REGEX_USE_WIN32_LOCALE
#endif
/* otherwise use C++ locale if supported: */
#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE) && !defined(BOOST_NO_STD_LOCALE)
# define BOOST_REGEX_USE_CPP_LOCALE
#endif
/* otherwise use C locale: */
#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE)
# define BOOST_REGEX_USE_C_LOCALE
#endif
#ifndef BOOST_REGEX_MAX_STATE_COUNT
# define BOOST_REGEX_MAX_STATE_COUNT 100000000
#endif
/*****************************************************************************
*
* Error Handling for exception free compilers:
*
****************************************************************************/
#ifdef BOOST_NO_EXCEPTIONS
/*
* If there are no exceptions then we must report critical-errors
* the only way we know how; by terminating.
*/
#include <stdexcept>
#include <string>
#include <boost/throw_exception.hpp>
# define BOOST_REGEX_NOEH_ASSERT(x)\
if(0 == (x))\
{\
std::string s("Error: critical regex++ failure in: ");\
s.append(#x);\
std::runtime_error e(s);\
boost::throw_exception(e);\
}
#else
/*
* With exceptions then error handling is taken care of and
* there is no need for these checks:
*/
# define BOOST_REGEX_NOEH_ASSERT(x)
#endif
/*****************************************************************************
*
* Stack protection under MS Windows:
*
****************************************************************************/
#if !defined(BOOST_REGEX_NO_W32) && !defined(BOOST_REGEX_V3)
# if(defined(_WIN32) || defined(_WIN64) || defined(_WINCE)) \
&& !(defined(__GNUC__) || defined(__BORLANDC__) && defined(__clang__)) \
&& !(defined(__BORLANDC__) && (__BORLANDC__ >= 0x600)) \
&& !(defined(__MWERKS__) && (__MWERKS__ <= 0x3003))
# define BOOST_REGEX_HAS_MS_STACK_GUARD
# endif
#elif defined(BOOST_REGEX_HAS_MS_STACK_GUARD)
# undef BOOST_REGEX_HAS_MS_STACK_GUARD
#endif
#if defined(__cplusplus) && defined(BOOST_REGEX_HAS_MS_STACK_GUARD)
namespace boost{
namespace BOOST_REGEX_DETAIL_NS{
BOOST_REGEX_DECL void BOOST_REGEX_CALL reset_stack_guard_page();
}
}
#endif
/*****************************************************************************
*
* Algorithm selection and configuration.
* These options are now obsolete for C++11 and later (regex v5).
*
****************************************************************************/
#if !defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_NON_RECURSIVE)
# if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && !defined(_STLP_DEBUG) && !defined(__STL_DEBUG) && !(defined(_MSC_VER) && (_MSC_VER >= 1400)) && defined(BOOST_REGEX_CXX03)
# define BOOST_REGEX_RECURSIVE
# else
# define BOOST_REGEX_NON_RECURSIVE
# endif
#endif
#ifdef BOOST_REGEX_NON_RECURSIVE
# ifdef BOOST_REGEX_RECURSIVE
# error "Can't set both BOOST_REGEX_RECURSIVE and BOOST_REGEX_NON_RECURSIVE"
# endif
# ifndef BOOST_REGEX_BLOCKSIZE
# define BOOST_REGEX_BLOCKSIZE 4096
# endif
# if BOOST_REGEX_BLOCKSIZE < 512
# error "BOOST_REGEX_BLOCKSIZE must be at least 512"
# endif
# ifndef BOOST_REGEX_MAX_BLOCKS
# define BOOST_REGEX_MAX_BLOCKS 1024
# endif
# ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
# undef BOOST_REGEX_HAS_MS_STACK_GUARD
# endif
# ifndef BOOST_REGEX_MAX_CACHE_BLOCKS
# define BOOST_REGEX_MAX_CACHE_BLOCKS 16
# endif
#endif
/*****************************************************************************
*
* Diagnostics:
*
****************************************************************************/
#ifdef BOOST_REGEX_CONFIG_INFO
BOOST_REGEX_DECL void BOOST_REGEX_CALL print_regex_library_info();
#endif
#if defined(BOOST_REGEX_DIAG)
# pragma message ("BOOST_REGEX_DECL" BOOST_STRINGIZE(=BOOST_REGEX_DECL))
# pragma message ("BOOST_REGEX_CALL" BOOST_STRINGIZE(=BOOST_REGEX_CALL))
# pragma message ("BOOST_REGEX_CCALL" BOOST_STRINGIZE(=BOOST_REGEX_CCALL))
#ifdef BOOST_REGEX_USE_C_LOCALE
# pragma message ("Using C locale in regex traits class")
#elif BOOST_REGEX_USE_CPP_LOCALE
# pragma message ("Using C++ locale in regex traits class")
#else
# pragma message ("Using Win32 locale in regex traits class")
#endif
#if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
# pragma message ("Dynamic linking enabled")
#endif
#if defined(BOOST_REGEX_NO_LIB) || defined(BOOST_ALL_NO_LIB)
# pragma message ("Auto-linking disabled")
#endif
#ifdef BOOST_REGEX_NO_EXTERNAL_TEMPLATES
# pragma message ("Extern templates disabled")
#endif
#endif
#endif

View File

@@ -0,0 +1,72 @@
/*
*
* Copyright (c) 1998-2002
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org for most recent version.
* FILE boost/regex/config/borland.hpp
* VERSION see <boost/version.hpp>
* DESCRIPTION: regex borland-specific config setup.
*/
#if defined(__BORLANDC__) && !defined(__clang__)
# if (__BORLANDC__ == 0x550) || (__BORLANDC__ == 0x551)
// problems with std::basic_string and dll RTL:
# if defined(_RTLDLL) && defined(_RWSTD_COMPILE_INSTANTIATE)
# ifdef BOOST_REGEX_BUILD_DLL
# error _RWSTD_COMPILE_INSTANTIATE must not be defined when building regex++ as a DLL
# else
# pragma message("Defining _RWSTD_COMPILE_INSTANTIATE when linking to the DLL version of the RTL may produce memory corruption problems in std::basic_string, as a result of separate versions of basic_string's static data in the RTL and you're exe/dll: be warned!!")
# endif
# endif
# ifndef _RTLDLL
// this is harmless for a staic link:
# define _RWSTD_COMPILE_INSTANTIATE
# endif
// external templates cause problems for some reason:
# define BOOST_REGEX_NO_EXTERNAL_TEMPLATES
# endif
# if (__BORLANDC__ <= 0x540) && !defined(BOOST_REGEX_NO_LIB) && !defined(_NO_VCL)
// C++ Builder 4 and earlier, we can't tell whether we should be using
// the VCL runtime or not, do a static link instead:
# define BOOST_REGEX_STATIC_LINK
# endif
//
// VCL support:
// if we're building a console app then there can't be any VCL (can there?)
# if !defined(__CONSOLE__) && !defined(_NO_VCL)
# define BOOST_REGEX_USE_VCL
# endif
//
// if this isn't Win32 then don't automatically select link
// libraries:
//
# ifndef _Windows
# ifndef BOOST_REGEX_NO_LIB
# define BOOST_REGEX_NO_LIB
# endif
# ifndef BOOST_REGEX_STATIC_LINK
# define BOOST_REGEX_STATIC_LINK
# endif
# endif
#if __BORLANDC__ < 0x600
//
// string workarounds:
//
#include <cstring>
#undef strcmp
#undef strcpy
#endif
#endif

View File

@@ -0,0 +1,207 @@
/*
*
* Copyright (c) 1998-2002
* John Maddock
*
* Use, modification and distribution are subject to the
* Boost Software License, Version 1.0. (See accompanying file
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*
*/
/*
* LOCATION: see http://www.boost.org for most recent version.
* FILE boost/regex/config/cwchar.hpp
* VERSION see <boost/version.hpp>
* DESCRIPTION: regex wide character string fixes.
*/
#ifndef BOOST_REGEX_CONFIG_CWCHAR_HPP
#define BOOST_REGEX_CONFIG_CWCHAR_HPP
#include <cwchar>
#include <cwctype>
#include <boost/config.hpp>
#if defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
// apparently this is required for the RW STL on Linux:
#undef iswalnum
#undef iswalpha
#undef iswblank
#undef iswcntrl
#undef iswdigit
#undef iswgraph
#undef iswlower
#undef iswprint
#undef iswprint
#undef iswpunct
#undef iswspace
#undef iswupper
#undef iswxdigit
#undef iswctype
#undef towlower
#undef towupper
#undef towctrans
#undef wctrans
#undef wctype
#endif
namespace std{
#ifndef BOOST_NO_STDC_NAMESPACE
extern "C"{
#endif
#ifdef iswalnum
inline int (iswalnum)(wint_t i)
{ return iswalnum(i); }
#undef iswalnum
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswalnum;
#endif
#ifdef iswalpha
inline int (iswalpha)(wint_t i)
{ return iswalpha(i); }
#undef iswalpha
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswalpha;
#endif
#ifdef iswcntrl
inline int (iswcntrl)(wint_t i)
{ return iswcntrl(i); }
#undef iswcntrl
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswcntrl;
#endif
#ifdef iswdigit
inline int (iswdigit)(wint_t i)
{ return iswdigit(i); }
#undef iswdigit
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswdigit;
#endif
#ifdef iswgraph
inline int (iswgraph)(wint_t i)
{ return iswgraph(i); }
#undef iswgraph
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswgraph;
#endif
#ifdef iswlower
inline int (iswlower)(wint_t i)
{ return iswlower(i); }
#undef iswlower
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswlower;
#endif
#ifdef iswprint
inline int (iswprint)(wint_t i)
{ return iswprint(i); }
#undef iswprint
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswprint;
#endif
#ifdef iswpunct
inline int (iswpunct)(wint_t i)
{ return iswpunct(i); }
#undef iswpunct
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswpunct;
#endif
#ifdef iswspace
inline int (iswspace)(wint_t i)
{ return iswspace(i); }
#undef iswspace
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswspace;
#endif
#ifdef iswupper
inline int (iswupper)(wint_t i)
{ return iswupper(i); }
#undef iswupper
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswupper;
#endif
#ifdef iswxdigit
inline int (iswxdigit)(wint_t i)
{ return iswxdigit(i); }
#undef iswxdigit
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::iswxdigit;
#endif
#ifdef towlower
inline wint_t (towlower)(wint_t i)
{ return towlower(i); }
#undef towlower
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::towlower;
#endif
#ifdef towupper
inline wint_t (towupper)(wint_t i)
{ return towupper(i); }
#undef towupper
#elif defined(BOOST_NO_STDC_NAMESPACE)
using :: towupper;
#endif
#ifdef wcscmp
inline int (wcscmp)(const wchar_t *p1, const wchar_t *p2)
{ return wcscmp(p1,p2); }
#undef wcscmp
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::wcscmp;
#endif
#ifdef wcscoll
inline int (wcscoll)(const wchar_t *p1, const wchar_t *p2)
{ return wcscoll(p1,p2); }
#undef wcscoll
#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(UNDER_CE)
using ::wcscoll;
#endif
#ifdef wcscpy
inline wchar_t *(wcscpy)(wchar_t *p1, const wchar_t *p2)
{ return wcscpy(p1,p2); }
#undef wcscpy
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::wcscpy;
#endif
#ifdef wcslen
inline size_t (wcslen)(const wchar_t *p)
{ return wcslen(p); }
#undef wcslen
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::wcslen;
#endif
#ifdef wcsxfrm
size_t wcsxfrm(wchar_t *p1, const wchar_t *p2, size_t s)
{ return wcsxfrm(p1,p2,s); }
#undef wcsxfrm
#elif defined(BOOST_NO_STDC_NAMESPACE)
using ::wcsxfrm;
#endif
#ifndef BOOST_NO_STDC_NAMESPACE
} // extern "C"
#endif
} // namespace std
#endif

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