Compare commits

...

264 Commits

Author SHA1 Message Date
WerWolv
f5b8021405 build: Bumped version to 1.31.0 2023-09-24 20:05:03 +02:00
WerWolv
89abc8557f feat: Added shortcuts for the pattern debugger 2023-09-24 18:26:42 +02:00
WerWolv
181a7c5b3d feat: Added evaluate pattern shortcut 2023-09-24 18:17:58 +02:00
WerWolv
f79e2df11a feat: Added shortcut to switch between providers 2023-09-24 18:11:17 +02:00
Paul Sorensen
be8c679d4a impr: Return early to remove nested code (#1253)
<!--
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 will simplify the codebase in the pattern drawer. It returns early
on conditional statements and reduces the amount of nested code making
it easier to read and track while developing.
2023-09-20 10:49:09 +02:00
paxcut
c577a42f62 impr: Refactoring of floating point tool to decrease code complexity. (#1275)
I noticed the bad score on code factor so I reorganized it to make it
more readable and maintainable. In order to break down the big function
into it much smaller parts I encapsulated all the variables that the
functions need to access in two classes, one for the imgui related
statics and the other for non-static variables.

When writing the smaller functions I was noticed that there was room to
simplify the existing algorithms by writing functions that could be
called by parts that previously shared no code. I tested the changes the
same way I tested the original and it seems to work the same way but
maybe a bit faster. Although it may be possible to further optimize the
present code code factor no longer flags the function at all.
2023-09-20 10:48:44 +02:00
Lennard Fonteijn
ad69ac84b1 feat: Added hex::group attribute and various fixes (#1302)
As discussed (many times) on Discord, does the same as the new favorite
tag, but instead allows you to add multiple groups.

Initially, this would cause some insane issues with draw/reset
(apparantly) fighting eachother in the pattern drawer. After a lot of
trial and error, I decided to rewrite the flow that is responsible for
calling reset. Now evaluating patterns is the one to decide when the
reset happens, not the core "game"-loop.

To make sure that draw and reset can never happen at the same time, the
mutex originally used for the favorites has been repurposed. Due to the
restructuring, the mutex in the favorite-task is no longer needed, as
that will only ever kick-off after reset is called and if there are
actually patterns, which can never line up to be accessed on different
threads at the same time.

Last but not least, I noticed that hard crashes could result in your
config file getting overridden. I added a check to prevent that.

Last I issue I can see is that if you use an excessive amount of
favorites/groups, a crash can still happen, but it only happens when you
close the program (occasionally, but unpredictable). Before, this would
happen if you ran the evaluation a second time. I boiled the cause of
the crash down to these lines of code in evaluator.cpp >
patternDestroyed:

```cpp
if (pattern->isPatternLocal()) {
    if (auto it = this->m_patternLocalStorage.find(pattern->getHeapAddress()); it != this->m_patternLocalStorage.end()) {
        auto &[key, data] = *it;

        data.referenceCount--;
        if (data.referenceCount == 0)
            this->m_patternLocalStorage.erase(it);
    } else if (!this->m_evaluated) {
        err::E0001.throwError(fmt::format("Double free of variable named '{}'.", pattern->getVariableName()));
    }
}
```

Specifically, trying to access the `*it` is the reason for the crash
(this was also the cause of the crashes before my fixes, but then during
evaluation).

I'm suspecting the root cause is somewhere in the `.clone` methods of
the patterns. I'd say that for now a crash when closing the program is
more acceptable than during evaluation (which can even happen if you use
favorites).
2023-09-16 13:09:59 +02:00
Imron jehleh
64a30a45d5 fix: Error popup now showing up immediately after click (#1272)
From #1265, Looks like Error Popup doesn't handle properly in some
circumstances.

---------

Co-authored-by: iTrooz <hey@itrooz.fr>
Co-authored-by: WerWolv <werwolv98@gmail.com>
2023-09-16 13:09:24 +02:00
PerikiyoXD
691df0fc83 fix: Implemented forwarder executable (#1308)
Fixes random .NET plugin crash caused by the console window being freed
on the same process.

### Problem description
Sometimes when launching from the explorer ImHex crashes

### Implementation description
We've implemented a launcher to avoid freeing the std streams, that
generated the bug.

### Screenshots
N/A

### Additional things
Blame windows console subsystem
2023-09-16 13:08:19 +02:00
WerWolv
1a2a926b77 fix: "About ... that much" achievement not triggering correctly 2023-09-12 22:24:12 +02:00
WerWolv
da18428f27 fix: Highlighting not being cleared correctly in some cases 2023-09-12 22:23:47 +02:00
iTrooz
5e86f62a98 fix: Handle exceptions thrown by providers on loadSettings() (#1307) 2023-09-12 12:00:00 +02:00
iTrooz
e65021c85e feat: Add more details to startup tasks (#1301) 2023-09-09 12:49:15 +02:00
WerWolv
83e26522b6 fix: Potential use-after-free with the .NET SDK 2023-09-08 22:00:15 +02:00
WerWolv
d011f37658 impr: Added better provider documentation 2023-09-08 21:59:27 +02:00
iTrooz
c07842d7ca refactor: separate loop and frame logic (#1300) 2023-09-07 20:33:49 +02:00
Nik
4e7c3817ed git: Updated windows build instructions 2023-09-05 13:43:29 +02:00
WerWolv
68b203eb75 patterns: Updated pattern language 2023-09-05 10:40:10 +02:00
WerWolv
1bb0a72bed fix: Issues with various float nodes 2023-09-04 19:59:09 +02:00
WerWolv
7685a22c5f fix: Crash when pressing delete twice when data processor nodes are selected 2023-09-04 19:58:55 +02:00
WerWolv
fc91c8e4b0 patterns: Updated pattern language 2023-09-04 19:58:31 +02:00
iTrooz
57084fd797 build: Update libfmt to 10.1.1 (#1286) 2023-09-03 22:49:47 +02:00
WerWolv
2b8a9db0f0 impr: Clean up default layout file 2023-09-03 22:45:03 +02:00
WerWolv
9badfc043b patterns: Updated pattern language 2023-09-03 22:37:58 +02:00
WerWolv
4ff25819c2 fix: Pasting not working correctly on non-zero pages
Fixes #1291
2023-09-03 16:25:51 +02:00
WerWolv
563ff5a774 fix: Future proof the previous fix 2023-09-03 16:18:29 +02:00
WerWolv
b042b8327a fix: Crash when re-opening a custom section window while having a selection in it 2023-09-03 16:09:06 +02:00
WerWolv
971c8739ca fix: Potential crash when preprocessing invalid pattern file when loading a file 2023-09-03 15:49:27 +02:00
WerWolv
26f4aa0d9f fix: Buffer to integer node not working correctly 2023-09-03 15:41:00 +02:00
WerWolv
dc5e5344c5 fix: ImHex not starting at all anymore when launched through the explorer 2023-09-03 14:07:47 +02:00
WerWolv
b2d1568abb fix: First overlay being assigned to all end nodes 2023-09-03 13:44:13 +02:00
WerWolv
632f388ece impr: Make --pl subcommand automatically register ImHex's include dirs 2023-09-03 12:25:00 +02:00
WerWolv
632ca944de impr: Align log output better 2023-09-03 11:45:20 +02:00
WerWolv
0bbd21f25a fix: Build issues with older standard libraries 2023-09-03 11:44:48 +02:00
WerWolv
367c4ec9c8 impr: More view comments and refactoring 2023-09-03 10:27:03 +02:00
WerWolv
5538307838 impr: Make achievement popups stay up for longer 2023-09-03 10:26:40 +02:00
WerWolv
eba8c82699 fix: Crash when using provider overlays 2023-09-03 10:26:25 +02:00
iTrooz
be3ac26306 fix: Remove remannts of #680 bugfix (#1282) 2023-09-02 22:59:09 +02:00
iTrooz
fc1ad592cb feat: Adapt content store view for new API contents (#1268) 2023-09-02 18:36:34 +02:00
Lennard Fonteijn
f725d763d1 feat: Remember bytes per row in Hex Editor (#1276) 2023-09-02 17:52:05 +02:00
iTrooz
c2fe9f0966 fix: verify that file names queried from the store do not allow path traversal (#1277) 2023-09-02 17:51:21 +02:00
iTrooz
235f4e39b4 git: build llvm ourselves in Fedora packages (#1280) 2023-09-02 16:41:20 +02:00
WerWolv
58cef2361b impr: Added hint when patterns are still loading 2023-08-30 10:04:06 +02:00
WerWolv
60649d1cba fix: Occasional crash when using favorites 2023-08-30 09:18:24 +02:00
WerWolv
ea9457c08c patterns: Added [[hex::favorite]] attribute 2023-08-29 21:46:08 +02:00
WerWolv
7bf9634e6e patterns: Updated pattern language 2023-08-29 12:14:34 +02:00
WerWolv
4288f876e2 impr: Added lots of comments and cleaned up many views 2023-08-29 12:14:12 +02:00
iTrooz
10ad239fb9 fix: add _lang suffix to "Load into memory" localization string (#1267) 2023-08-28 02:21:41 +02:00
WerWolv
550392c8d6 fix: Texture loading from romfs 2023-08-26 23:43:35 +02:00
WerWolv
32e05cc62f patterns: Updated pattern language 2023-08-26 23:31:25 +02:00
WerWolv
886c52b322 patterns: Updated pattern language 2023-08-26 12:55:09 +02:00
WerWolv
ba66005585 impr: Various code cleanup 2023-08-26 12:54:52 +02:00
Justus Garbe
bfc835fc54 fix: add new capstone options and fixed overextending name array 2023-08-26 12:21:44 +02:00
iTrooz
32d6ac2241 feat: move PerProvider data to new provider when saving memory provider into file provider (#1264) 2023-08-26 01:47:44 +02:00
WerWolv
758cdd91f3 impr: Make sure logs are always output immediately 2023-08-26 01:44:10 +02:00
WerWolv
6e81ce152e impr: Get rid of some manual memory management 2023-08-25 23:54:39 +02:00
WerWolv
e487fd7450 fix: Crash loop when segfault gets triggered 2023-08-25 23:51:51 +02:00
WerWolv
bd75b70d85 impr: More style and comment fixes in crash handler 2023-08-25 23:19:13 +02:00
WerWolv
6ef96c5533 fix: Missing typeinfo include 2023-08-25 23:11:05 +02:00
WerWolv
6fc62bac94 build: Remove unnecessary yara autoconf file configuring 2023-08-25 22:55:09 +02:00
WerWolv
baecf66716 feat: Added .gdbinit script to aid with debugging 2023-08-25 22:55:09 +02:00
WerWolv
7476ae230c fix: Make ImHex exit cleanly when crashing 2023-08-25 22:55:09 +02:00
iTrooz
175e66a60e feat: Do not save memory providers as recent entries (#1259) 2023-08-25 15:35:15 +02:00
Nik
a1dc979217 build: Fixed plugins not having their C++ version set correctly 2023-08-22 19:29:03 +02:00
iTrooz
fbdcd22117 git: Make CI faster (#1257) 2023-08-21 16:20:36 +02:00
WerWolv
d50fb8d17b fix: Crash when deleting items from file combiner in some cases 2023-08-19 19:18:57 +02:00
WerWolv
83e42ddfd9 fix: Don't show accept pattern popup if no patterns are available 2023-08-19 19:12:48 +02:00
WerWolv
6c8a90720f feat: Added window actions popup when clicking on icon 2023-08-19 19:12:15 +02:00
WerWolv
e70ec10b0e impr: Allow the file combiner tool to select multiple files at once 2023-08-19 19:11:38 +02:00
WerWolv
b4401b7df1 fix: Rest in peace, Anonfiles 2023-08-17 09:27:14 +02:00
WerWolv
f598421705 patterns: Updated pattern language 2023-08-17 08:24:38 +02:00
lorsanta
84ceb45129 impr: Update timestamp when saving a file in windows (#1248)
### Problem description
Ref #1210 

### Implementation description
Call
[`SetFileTime()`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfiletime)
everytime `FileProvider::save()` is called.

### Additional things
I moved the call to `File::close()` from `FileProvider::open()` to
`FileProvider::close()` because `SetFileTime()` requires a file handler
as input, so I need `File::m_file` to be valid.
2023-08-16 23:18:16 +02:00
WerWolv
fc93f8bd66 fix: CI being broken on Arch Linux 2023-08-16 23:07:16 +02:00
WerWolv
8a2afd1c05 fix: Crashes when having pattern auto evaluation enabled 2023-08-16 22:26:05 +02:00
Justus Garbe
33e9ad7775 fix: Draw title bar correctly when no title bar buttons exist 2023-08-13 23:54:22 +02:00
Justus Garbe
2059ad82c3 fix: Update title on project save 2023-08-13 23:36:50 +02:00
Lennard Fonteijn
c25aad552d feat: Selectable demangler (#1250)
Supersedes #1240 - depends on #1249 and
https://github.com/WerWolv/libwolv/pull/8 to work.
2023-08-13 21:51:05 +02:00
Lennard Fonteijn
896091b124 feat: Added toggle for human-readable units in hex editor footer (#1251)
Finalization of #1245 by adding a toggle to the hex editor itself, issue
can be closed afterwards.
2023-08-13 19:08:09 +02:00
Lennard Fonteijn
d2e6d8e4d9 Added ImGui extension to create single- and multiline formatted selec… (#1249)
(Partial) implementation of #1245 with additional functionality to
supersede PR #1240.
2023-08-13 17:08:17 +02:00
Justus Garbe
285b79f31e fix: Crypto buffered hexadecimal encoding 2023-08-13 15:27:01 +02:00
Justus Garbe
d468893bb0 build: Updated libwolv 2023-08-13 14:30:52 +02:00
Lennard Fonteijn
df24d1e1e9 fix: Revert the FPS limiter back to the one used in v1.30.1 (#1247)
As requested on Discord, a PR to revert the FPS limiter back to the one
that was used in v1.30.1.

The new FPS limiter seems to be flawed in that it runs at about half the
speed it is supposed to be.

See this illustration:

![FPS](https://github.com/WerWolv/ImHex/assets/869973/8a101b4c-23d8-4806-8d53-3be7aeb84fed)

Left is v1.30.1, right is the new version (without this fix). See how
long it takes to respectively reach 0xE90.

This is not a performance issue, because when you fully unlock the
framerate on the right, it's just as fluent as on the left.
2023-08-11 22:03:30 +02:00
WerWolv
65c56a887c feat: Added option to load files into memory 2023-08-09 20:04:12 +02:00
WerWolv
ef556d07ed fix: Init task text being offset on larger screen resolutions 2023-08-09 20:02:38 +02:00
WerWolv
882849e73c fix: Highlighting of found elements not being cleared correctly 2023-08-09 20:01:57 +02:00
WerWolv
49d3fe65a3 fix: Allow converting very long hex strings to bytes 2023-08-09 20:01:29 +02:00
WerWolv
a6aafa8cd6 feat: Allow memory files to be renamed 2023-08-08 19:04:00 +02:00
WerWolv
ba9227c1e0 feat: Properly save memory provider data 2023-08-06 21:48:08 +02:00
Nik
e77f138514 feat: Added Achievements (#1230)
This PR adds Achievements to ImHex that serve as both a guide and a fun
way to learn more about ImHex and reverse engineering
2023-08-06 21:33:15 +02:00
WerWolv
64a0c3f6e2 build: Updated json and miniaudio libraries 2023-08-06 11:10:42 +02:00
WerWolv
fae8f0a8d5 build: Fixed cmake not using default settings on Windows 2023-08-06 01:52:23 +02:00
WerWolv
f2cfc70eca fix: Highest / Lowest entropy block address being wrong 2023-08-06 01:51:01 +02:00
iTrooz
55e6761bf1 build: Fix LTO not being enabled correctly (#1217)
Currently, LTO isn't enabled (at least on Linux ?), because LTO doesn't
recognize any language as being enabled.

I fixed that by explicitly enabling C and CXX languages before enabling
LTO
2023-08-05 20:39:20 +02:00
WerWolv
1a765ee5ab build: Updated libromfs 2023-08-05 10:26:27 +02:00
WerWolv
e1ca84d89c patterns: Updated pattern language
Fixes #1228
2023-08-05 09:59:53 +02:00
WerWolv
2082781cf5 fix: Correct endianess of CRC hashes
Fixes #1225
2023-08-04 16:05:21 +02:00
WerWolv
d28d6d1a1b patterns: Updated pattern language
Fixes #958
2023-08-03 23:43:40 +02:00
WerWolv
a61c93e99c impr: Better tooltip for update all button in content store
#1222
2023-08-03 21:50:28 +02:00
WerWolv
e65497ec3b fix: /imhex being appended to Application Support folder paths on macOS
Fixes #1221
2023-08-03 21:49:41 +02:00
WerWolv
50dd6405e9 patterns: Updated pattern language 2023-08-02 20:41:56 +02:00
WerWolv
79eb53eb0d fix: --pl command line interface not working correctly 2023-08-02 20:30:13 +02:00
WerWolv
05ca498343 feat: Added Fill option to hex editor 2023-08-02 13:09:21 +02:00
WerWolv
fbd4bc337b fix: Crash when trying to format invalid timestamps 2023-08-02 12:52:10 +02:00
WerWolv
89115bcdde impr: Added better data processor workspace close button 2023-08-02 12:51:58 +02:00
WerWolv
954c0d5bda fix: Writing to hex cells in big endian mode writing the value as little endian
Fixes #1219
2023-08-02 12:51:33 +02:00
WerWolv
bf8924ae0c feat: Added support for string in/out variables 2023-08-02 12:51:02 +02:00
WerWolv
30b202cf0c patterns: Updated pattern language 2023-08-01 00:00:45 +02:00
WerWolv
84766d5f6e patterns: Updated pattern language 2023-07-31 23:19:23 +02:00
WerWolv
106e669512 feat: Added setting to remember and restore window position and size
Closes #1215
#944
2023-07-31 11:17:37 +02:00
iTrooz
4d6e6cf75a fix: Magic compile dumping files into cwd (#1212)
This PR fix libmagic dumping files in the imhex cwd when compiling them

This code was actually written by you (notice the source branch), this
PR is just a reminder that the fix works and you can merge it ^^

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
2023-07-30 21:36:48 +02:00
iTrooz
26e7e12f09 git: Update custom macOS GLFW build settings (#1214)
<!--
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 -->

There are unused ImHex-specific flags in the custom GLFW build on MacOS.
Also, it isn't built in release mode
2023-07-30 21:36:27 +02:00
WerWolv
b469e68ddb fix: Pattern console not updating correctly 2023-07-30 21:35:31 +02:00
WerWolv
2e5a51bb05 patterns: Updated pattern language 2023-07-30 00:44:09 +02:00
WerWolv
4ae55f69e1 build: Updated libwolv 2023-07-29 11:26:18 +02:00
WerWolv
d079b8c3bb impr: Hide column headers when hiding ASCII or custom encoding column 2023-07-28 10:31:44 +02:00
WerWolv
33f0d59545 fix: Bad formatting of project open error popup 2023-07-28 00:01:49 +02:00
Nik
42c36279d1 build: Properly bundle libcurl into AppImage 2023-07-27 23:36:50 +02:00
WerWolv
b55c6fa3e1 git: Remove updating of the plugin templates from release CI 2023-07-27 11:09:20 +02:00
WerWolv
3a39d3c532 git: Updated plugins list 2023-07-27 11:08:55 +02:00
WerWolv
f67e808d0b build: Add plugins to main dependency 2023-07-27 10:45:11 +02:00
WerWolv
e1d0a057ff build: Set plugin output directory correctly 2023-07-27 02:07:36 +02:00
WerWolv
e829c407e3 fix: Writing behaving weirdly when using a custom base address 2023-07-27 02:05:35 +02:00
WerWolv
94a02c4b6d build: Streamlined plugin creation process 2023-07-27 00:53:04 +02:00
WerWolv
4792a29fac fix: Crash when passing invalid parameters to sound visualizer
Fixes #1208
2023-07-26 22:13:39 +02:00
WerWolv
27c8e19c14 build: Remove all static variables from headers to hopefully fix plugins 2023-07-26 13:50:51 +02:00
WerWolv
866c87b2bf patterns: Updated pattern language 2023-07-26 13:05:47 +02:00
WerWolv
aa4ce01c73 build: Forcefully disable LTO for libimhex 2023-07-26 12:57:38 +02:00
WerWolv
d0a5c144e6 patterns: Updated pattern language 2023-07-26 00:23:09 +02:00
WerWolv
5feb4dce51 build: Try and make libimhex export all symbols 2023-07-25 11:25:59 +02:00
WerWolv
4d4f223357 impr: Improve frame rate when lots of bytes are highlighted 2023-07-24 23:24:31 +02:00
WerWolv
440e2d91fc impr: Better logging during font loading 2023-07-24 23:24:11 +02:00
WerWolv
bca73ef01e fix: Loading of custom fonts not working anymore 2023-07-24 17:25:36 +02:00
WerWolv
a032bfa0f5 feat: Added support for hashing arbitrary strings using the string view 2023-07-24 16:58:52 +02:00
WerWolv
ff8946b851 fix: Pattern array chunks being rendered wrongly 2023-07-24 16:55:35 +02:00
WerWolv
599b43db22 impr: Initialize script loaders during splash screen again 2023-07-24 15:36:57 +02:00
WerWolv
a4e4e01d2d fix: Crash when cleaning log files that are open in another program 2023-07-24 15:36:29 +02:00
WerWolv
8b3cd2d76d impr: Properly print asserts 2023-07-23 23:39:00 +02:00
WerWolv
ffdaf0d16e impr: Use better splash screen selection color generator 2023-07-23 23:38:13 +02:00
WerWolv
b8d5e1e9c5 feat: Added built-in logging console 2023-07-23 23:37:47 +02:00
WerWolv
aa66d4b9e7 impr: Insert short delay before opening popups so the animation finishes 2023-07-23 18:22:53 +02:00
WerWolv
fdd2e1fcde patterns: Added [[hex::spec_name]] 2023-07-23 09:14:00 +02:00
WerWolv
591435761b impr: Added "Close ImHex" button to all plugin-related fatal popups 2023-07-22 22:59:05 +02:00
WerWolv
4979c65566 fix: Missing <array> include in stacktrace helper 2023-07-22 22:47:35 +02:00
WerWolv
f5fda76414 impr: Cleanup main 2023-07-22 21:30:22 +02:00
WerWolv
4b0d980d54 impr: Don't use fmt::println if it's not supported 2023-07-22 20:22:25 +02:00
WerWolv
46ee3f0faa impr: Improve uncaught exception error handling to provide actual stack trace 2023-07-22 20:16:36 +02:00
WerWolv
564ae6dd8c fix: Crash when loading bad font 2023-07-22 19:35:58 +02:00
WerWolv
8aec382440 fix: Loading of plugins and localizations after restart 2023-07-22 18:38:14 +02:00
WerWolv
a99f8f78d0 fix: Crash when trying to paste invalid data 2023-07-22 18:21:58 +02:00
WerWolv
0faea9d7c7 impr: Make splash screen look much nicer 2023-07-22 18:21:47 +02:00
WerWolv
c294619102 impr: Make script loaders be initialized synchronously 2023-07-21 20:25:56 +02:00
WerWolv
f6bbfd7283 impr: Properly print new line characters in cli 2023-07-21 15:17:21 +02:00
WerWolvTranslationBot
d3f493b6c2 lang: Translations update from Weblate (#1200)
Translations update from [Weblate](https://weblate.werwolv.net) for
[ImHex/Built-in
Plugin](https://weblate.werwolv.net/projects/imhex/built-in-plugin/).


It also includes following components:

* [ImHex/Windows
Plugin](https://weblate.werwolv.net/projects/imhex/windows-plugin/)



Current translation status:

![Weblate translation
status](https://weblate.werwolv.net/widgets/imhex/-/built-in-plugin/horizontal-auto.svg)

Co-authored-by: Justus Garbe <gihihoh@gmail.com>
2023-07-21 14:30:27 +02:00
WerWolv
bd8868d2c8 impr: Added better help output for cli 2023-07-21 14:28:15 +02:00
WerWolv
ee41a5a046 fix: Selection changes not being handled correctly 2023-07-21 14:22:53 +02:00
WerWolv
0033d9f4eb patterns: Updated pattern language 2023-07-21 14:20:57 +02:00
WerWolv
e5a793e8de fix: Subcommands not working at all on Linux 2023-07-21 14:12:08 +02:00
WerWolv
3149183450 patterns: Updated pattern language 2023-07-21 11:53:37 +02:00
WerWolv
7c321a79c3 impr: Print message if no stacktrace can be collected 2023-07-20 21:41:22 +02:00
WerWolv
7c203e0635 build: Updated libwolv
Fixes #1201
2023-07-20 21:38:37 +02:00
WerWolv
ffd3efe5fa git: Disable .NET scripts in AppImage since it hangs on startup 2023-07-20 20:59:06 +02:00
WerWolv
18dd754b31 impr: Better handling of hex editor selections 2023-07-20 20:58:28 +02:00
WerWolv
3c97759aa7 fix: Crash when trying to load files with invalid paths 2023-07-19 22:35:55 +02:00
WerWolv
f930b6e17d fix: Various .NET and plugin loading fixes 2023-07-19 21:40:24 +02:00
WerWolv
2d4f971d10 impr: Disable endianess switch in hex editor when visualizer only uses one byte 2023-07-18 14:23:02 +02:00
WerWolv
90267ec356 impr: Allow hex editor view to be scrolled slightly past the end 2023-07-18 14:22:39 +02:00
WerWolvTranslationBot
7fc53bf861 lang: Translations update from Weblate (#1199)
Translations update from [Weblate](https://weblate.werwolv.net) for
[ImHex/Built-in
Plugin](https://weblate.werwolv.net/projects/imhex/built-in-plugin/).


It also includes following components:

* [ImHex/Windows
Plugin](https://weblate.werwolv.net/projects/imhex/windows-plugin/)



Current translation status:

![Weblate translation
status](https://weblate.werwolv.net/widgets/imhex/-/built-in-plugin/horizontal-auto.svg)

---------

Co-authored-by: Justus Garbe <gihihoh@gmail.com>
Co-authored-by: xtex <xtexchooser@duck.com>
2023-07-17 16:40:40 +02:00
WerWolv
b9c2955b88 fix: Use ANSI escape codes for --plugins 2023-07-17 11:59:21 +02:00
WerWolv
ed33dd0bb0 git: Make rpm builds a bit less verbose 2023-07-17 11:50:22 +02:00
WerWolv
6d7f217e2a patterns: Updated pattern language 2023-07-17 11:20:17 +02:00
WerWolv
a83ca3c228 feat: Added --pl and --magic command 2023-07-17 10:43:29 +02:00
WerWolv
b9ec1a150d fix: Wrong libfmt header being included 2023-07-17 09:12:22 +02:00
classabbyamp
d9a4906b3c impr: Clarify portal error message (#1197)
<!--
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 -->

see #723


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

`xdg-desktop-portal-wlr` is not relevant because it does not provide the
FileChooser interface.

`xdg-desktop-portal` needs the `WAYLAND_DISPLAY` env var on wayland and
the `DISPLAY` and `XAUTHORITY` env vars on xorg. If the dbus user
session bus is not run in a way that it already gets those variables,
they must be given via `dbus-update-activation-environment(1)`.

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

### Additional things
<!-- Anything else you would like to say -->

fixes #723
2023-07-17 09:11:40 +02:00
WerWolv
a83f87fbfa build: Updated nativefiledialogs-extended to latest version 2023-07-17 08:08:29 +02:00
WerWolv
e9450b490f feat: Added --plugin, --calc, --hash, --encode and --decode subcommands 2023-07-16 23:46:41 +02:00
WerWolv
1588365d4a build: Use the libcurl WinSSL version on Windows to make SSL work again 2023-07-16 21:38:54 +02:00
WerWolv
76e932ecc0 build: Switch to using the system capstone version on Windows 2023-07-16 21:38:29 +02:00
WerWolv
52c517d38d fix: Potential crash when loading incorrect data processor node files 2023-07-16 20:41:06 +02:00
WerWolv
aac9bf3896 fix: Crash when using "Open in new View" button in bookmarks 2023-07-16 20:35:10 +02:00
WerWolv
54891c6d8f impr: Added proper localization for new visualizer endianess toggle 2023-07-16 20:25:31 +02:00
WerWolv
d7238a5f80 impr: Move script library to its own library 2023-07-16 20:13:50 +02:00
WerWolv
0a6815da8f fix: Always use default CA Cert 2023-07-16 19:56:07 +02:00
WerWolv
7631778edb feat: Added support for big endian in data visualizers 2023-07-16 19:53:02 +02:00
Justus Garbe
1a3debd6c9 fix: Raw Disk Provider not working correctly on Linux and macOS (#1195)
<!--
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
- Fixed disk provider not working for linux

### Implementation description
- Used ioctl instead of fstat
- Fixed buffer issues

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
2023-07-16 18:18:41 +02:00
WerWolv
893b06c78b feat: Allow hex editor editing mode to be entered when pressing Enter 2023-07-16 18:14:48 +02:00
WerWolv
709f4b7e80 build: Remove dangerous linker options from script loader plugin 2023-07-15 23:20:38 +02:00
WerWolv
54fba5bf8b build: Always bundle CA Cert on Windows 2023-07-15 23:20:09 +02:00
WerWolv
d977f1f988 impr: Move all .NET scripts to their own subfolder 2023-07-15 14:50:39 +02:00
WerWolv
2fea1975c2 build: Don't set recommended properties if they were already set 2023-07-15 14:29:54 +02:00
Nik
5171bea0bf feat: Added cross-platform .NET scripts support (#1185)
This PR intends to add support for .NET scripts that can extend ImHex's
functionality in a portable and cross-platform way.

---------

Co-authored-by: Justus Garbe <55301990+Nowilltolife@users.noreply.github.com>
2023-07-15 14:29:14 +02:00
WerWolv
4e3b8111fd build: Make sure the arch linux package bundles the correct libraries 2023-07-15 10:33:58 +02:00
WerWolv
afcc01c3dc build: Set default settings only if they haven't been set already 2023-07-15 10:33:42 +02:00
WerWolv
3a775e982f build: Removed outdated and dangerous linker flags in plugins 2023-07-15 10:02:34 +02:00
WerWolv
0f54a3a1f3 build: Added option to disable strict warnings 2023-07-15 10:02:19 +02:00
WerWolv
8500e4cba2 build: Switch to GTK file picker on non-sandboxed Linux builds 2023-07-15 10:01:50 +02:00
WerWolv
c1cdab72ef fix: Weird behaviour when trying to open a non-existing file through the command line 2023-07-15 00:12:09 +02:00
WerWolv
f4ae1fda6d impr: Print welcome message as fast as possible 2023-07-15 00:11:48 +02:00
Nik
aae3004f1f build: Various build improvements (#1193) 2023-07-15 00:10:01 +02:00
WerWolv
1aed960a38 build: Switch build system to Ninja 2023-07-14 22:03:44 +02:00
WerWolv
6c4fdd146f build: Use llvm-ar and llvm-ranlib on Windows 2023-07-14 21:51:18 +02:00
WerWolv
04b56c3d4d patterns: Updated pattern language 2023-07-14 21:39:49 +02:00
iTrooz
1ed658bcdc feat: Added command line interface support (#1172)
System design has been discussed on discord

Should fix #948

---------

Co-authored-by: WerWolv <werwolv98@gmail.com>
2023-07-13 14:08:23 +02:00
WerWolv
8c0395bc7c fix: Prevent wayland from spamming the console with useless errors 2023-07-12 14:33:09 +02:00
WerWolv
cdc4f2db89 patterns: Updated pattern language 2023-07-11 09:21:13 +02:00
WerWolv
272b4b0cf8 feat: Added "Update All" button to content store 2023-07-11 09:19:52 +02:00
WerWolv
10756c65a6 patterns: Updated pattern language 2023-07-11 00:04:54 +02:00
WerWolv
8524e93445 impr: Display encoding types in header of hex editor
Closes #1186
2023-07-11 00:04:26 +02:00
WerWolv
511ef3ef2b build: Supress warning generated by libraries setting BUILD_SHARED_LIBS 2023-07-09 22:39:27 +02:00
WerWolv
32ade6136b build: Make sure ImHex Patterns repo gets cloned correctly 2023-07-09 22:18:53 +02:00
WerWolv
65d9509c38 build: Add checked option to enable LTO 2023-07-09 20:34:49 +02:00
WerWolv
ce9ce42c1c impr: Only reload localization when necessary 2023-07-09 20:24:56 +02:00
WerWolv
6343cb092b build: Fixed include issues 2023-07-09 12:53:31 +02:00
WerWolv
7cb26b1499 patterns: Updated pattern language 2023-07-09 12:40:51 +02:00
WerWolv
5d047a335d patterns: Updated pattern language 2023-07-09 12:30:48 +02:00
WerWolv
3e797eeea2 fix: Never create an imgui.ini file
#1166
2023-07-07 09:20:33 +02:00
WerWolv
14bb98a519 build: Updated libwolv 2023-07-07 09:02:31 +02:00
WerWolv
a78d3f9977 fix: Framerate limits not working correctly 2023-07-06 21:15:08 +02:00
WerWolv
2449b08f64 fix: Crash when trying to remove chunks larger than the whole file 2023-07-06 21:14:50 +02:00
WerWolv
33d3bea472 fix: Flickering cursor issues 2023-07-06 10:26:12 +02:00
WerWolv
c9c6f3aadb fix: New visualizers behaving weirdly with large font sizes 2023-07-06 10:08:47 +02:00
WerWolv
c9dbcbb3d3 build: Updated dependencies 2023-07-06 08:26:36 +02:00
WerWolv
924c816dbd fix: Chunk size setting in information view being reset the first time 2023-07-06 00:00:56 +02:00
WerWolv
695e11477e feat: Added single stepping feature to pattern debugger 2023-07-05 21:32:11 +02:00
iTrooz
ac2a609d0a impr: Use execvp() instead of system() on Linux (#1170)
This PR it just a hack to fix #1160 , it doesn't solve the underlying
problem.

It fixes the problem because by using execvp() directly, it avoids the
call to `sh` done with `system()`, which has a bug on Ubuntu 22.04 which
makes it i,compatibles with the glibc inside the AppImage.
It doesn't fix the underlying problem because the programs we call
themselves still link to the AppImage's libraries instead of the system
ones.
2023-07-05 20:50:46 +02:00
iTrooz
e3ae169833 impr: Separate the behaviour of being savable and being dumpable for provider (#1183)
### Problem description

Currently, the providers use the method `isSavable()` to determine both
if they can use "Save" or "Save as".
This behaviour is problematic because some providers may need to be
saveable but not saveable as: for example the view provider. The
original provider may not allow to be saved.

### Implementation description
I separate these two behaviour by creating another function:
`isDumpable()`, that return true by default but can be overridden by the
provider to return false, if the provider should not be dumped in any
way.

### Additional things

While I was at it, I also marked "export" operations as needing the
"dumpable" flag. That way, we can't accidentally export the whole
address space of a process as base64.

I also added documentation for these some functions in Provider
2023-07-05 20:49:57 +02:00
WerWolv
25d6380963 build: Upgraded capstone to full V5 release 2023-07-05 20:45:46 +02:00
WerWolv
f00b9f05ac build: Fixed Ubuntu build issues 2023-07-05 20:25:40 +02:00
WerWolv
b6881d2362 feat: Added timestamp visualizer 2023-07-05 19:54:18 +02:00
WerWolv
8e0349e2ac fix: Projects failing to be loaded when another project is being unloaded 2023-07-04 23:30:37 +02:00
WerWolv
86c4c8fa96 feat: Added new pattern inline visualizers 2023-07-04 22:18:06 +02:00
WerWolv
33566137c2 impr: Allow bitmap visualizers to be zoomed 2023-07-04 22:17:51 +02:00
WerWolv
f16bbfb469 feat: Added coordinates visualizer 2023-07-04 09:40:05 +02:00
WerWolv
b265d8e54a build: Restructure romfs assets 2023-07-04 08:42:33 +02:00
WerWolv
6a667d9493 impr: Allow image visualizer image to be scaled 2023-07-03 21:24:36 +02:00
WerWolv
ceed8c7420 pattern: Properly display Start/End/Size column again for zero sized types 2023-07-03 21:24:15 +02:00
WerWolv
d297b2d1cc impr: Hide sections with an empty name 2023-07-03 12:04:20 +02:00
WerWolv
39e74c627e impr: Handle unidentifiable data in the data information view better 2023-07-02 10:27:56 +02:00
WerWolv
28dea8e5bd fix: Menu Bar being scrollable sideways 2023-07-01 22:55:59 +02:00
WerWolv
a0c89858ed patterns: Don't re-evaluate format functions during highlighting 2023-07-01 14:06:15 +02:00
iTrooz
c6c3ca4d26 fix: Reset terminate handler directly when being called + some other crashes to crash handling (#1174)
This PR fixes some things about crash handling:
- when the terminate handler is called, immediately set it back to the
original one, so can't make a recursion if the crash-handling code fails
- Only save projects if the crash occured after Imhex finished startup
- do not update the project location when saving the crash backup file:
this will remove problems when `EventAbnormalTermination` is called
before `crashCallback()`

I also added a bit more documentation
2023-07-01 12:32:28 +02:00
WerWolv
301418c728 fix: Bookmarks not being loaded correctly when multiple providers are in project 2023-07-01 12:27:59 +02:00
Nik
730e67881b build: Added Ubuntu 23.04 builds (#1173) 2023-06-30 23:58:20 +02:00
iTrooz
aec38328d0 impr: Added "Hold SHIFT for more info" text to provider tooltip (#1171)
As discussed on discord
2023-06-30 22:28:37 +02:00
WerWolv
050a71913a impr: Improved construction of language settings dropdown 2023-06-30 14:00:10 +02:00
WerWolv
8cc6994dd0 fix: Properly apply UI scaling on launch 2023-06-30 13:40:39 +02:00
WerWolv
f9909dab98 fix: Properly clear all global registries 2023-06-30 13:40:16 +02:00
WerWolv
bc98556897 impr: Automatically scroll pattern console to the bottom when new lines are added 2023-06-30 00:11:48 +02:00
WerWolv
4f08ba3590 patterns: Fixed race condition when evaluating patterns 2023-06-30 00:11:26 +02:00
WerWolv
78cb0a2592 patterns: Updated pattern language 2023-06-28 18:15:29 +02:00
WerWolv
a5fac85727 fix: Commit hash/branch in statistics being in wrong order 2023-06-27 01:46:11 +02:00
WerWolv
8fdb60758b impr: Load plugins asynchronously to speed up startup times 2023-06-27 00:52:13 +02:00
WerWolv
7510fa091e patterns: Updated pattern language 2023-06-27 00:26:50 +02:00
WerWolv
b87c32a94b build: Fedora fix again 2023-06-26 14:52:00 +02:00
WerWolv
b13494a192 build: Try fixing Fedora build 2023-06-26 14:37:35 +02:00
WerWolv
d527675bda build: Make sure changing commit hash doesn't trigger a full rebuild
Closes #1137
2023-06-26 14:01:45 +02:00
WerWolv
15cd2b693c fix: Crash when using paste without a valid selection 2023-06-26 11:14:10 +02:00
WerWolv
cda883bb0f fix: Page count displaying wrongly in empty files 2023-06-26 11:13:12 +02:00
WerWolv
e03c91b888 impr: Better UI for all data information diagrams 2023-06-26 10:51:37 +02:00
WerWolv
9282f1fe75 fix: Multiwindow support not being disabled by default on Linux 2023-06-26 09:02:23 +02:00
WerWolv
af147b4f54 fix: Titlebar button localization keys still being inside the windows plugin 2023-06-26 08:54:30 +02:00
WerWolv
13b4201446 build: Clean up build logs 2023-06-26 08:45:33 +02:00
WerWolv
83bcbfebdd patterns: Updated pattern language 2023-06-25 12:45:34 +02:00
WerWolv
1a31b4aaff patterns: Updated pattern language 2023-06-25 00:29:21 +02:00
WerWolv
c280b16787 fix: Make disassembler view not clear selection when typing in region 2023-06-24 20:53:36 +02:00
275 changed files with 99708 additions and 94288 deletions

9
.gdbinit Normal file
View File

@@ -0,0 +1,9 @@
# Skip all std:: and __gnu_debug:: symbols
skip -rfu ^std::
skip -rfu ^__gnu_debug::
# Skip all ImGui:: symbols
skip -rfu ^ImGui::
# Trigger breakpoint when execution reaches triggerSafeShutdown()
break triggerSafeShutdown

View File

@@ -7,7 +7,7 @@ on:
workflow_dispatch:
env:
BUILD_TYPE: Release
BUILD_TYPE: RelWithDebInfo
jobs:
@@ -20,8 +20,6 @@ jobs:
shell: msys2 {0}
env:
CCACHE_DIR: "${{ github.workspace }}/.ccache"
CCACHE_MAXSIZE: "1000M"
CCACHE_COMPRESS: "true"
steps:
- name: 🧰 Checkout
uses: actions/checkout@v3
@@ -32,16 +30,16 @@ jobs:
uses: hendrikmuhs/ccache-action@v1.2
id: cache-ccache
with:
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-ccache
max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🟦 Install msys2
uses: msys2/setup-msys2@v2
@@ -51,7 +49,6 @@ jobs:
gcc:p
lld:p
cmake:p
make:p
ccache:p
glfw:p
file:p
@@ -59,6 +56,14 @@ jobs:
freetype:p
dlfcn:p
libbacktrace:p
ninja:p
curl-winssl:p
capstone:p
- name: ⬇️ Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
- name: 📜 Set version variable
run: |
@@ -70,20 +75,19 @@ jobs:
mkdir -p build
cd build
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DUSE_SYSTEM_CAPSTONE=ON \
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
..
mingw32-make -j4 install
ninja install
cpack
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
@@ -145,16 +149,16 @@ jobs:
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
key: ${{ runner.os }}${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-ccache
max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
@@ -166,13 +170,19 @@ jobs:
run: |
brew install glfw
- name: ⬇️ Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
- name: 🧰 Checkout glfw
if: ${{matrix.custom_glfw}}
uses: actions/checkout@v3
with:
repository: glfw/glfw
path: glfw
# GLFW custom build (to allow software rendering)
- name: ⬇️ Patch and install custom glfw
if: ${{matrix.custom_glfw}}
run: |
@@ -182,17 +192,15 @@ jobs:
mkdir build
cd build
cmake \
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
..
make -j 4 install
ninja install
# MacOS cmake build
- name: 🛠️ Build
@@ -204,9 +212,8 @@ jobs:
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.10" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
@@ -217,10 +224,9 @@ jobs:
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
..
make -j4 package
ninja package
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v3
@@ -230,9 +236,24 @@ jobs:
# Ubuntu build
ubuntu:
runs-on: ubuntu-22.04
name: 🐧 Ubuntu 22.04
strategy:
matrix:
include:
- name: Ubuntu
release_num: 22.04
- name: Ubuntu
release_num: 23.04
name: 🐧 Ubuntu ${{ matrix.release_num }}
runs-on: ubuntu-latest
container:
image: "ubuntu:${{ matrix.release_num }}"
options: --privileged
steps:
- name: ⬇️ Install setup dependencies
run: apt update && apt install -y git curl
- name: 🧰 Checkout
uses: actions/checkout@v3
@@ -242,39 +263,50 @@ jobs:
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
key: Ubuntu-${{matrix.release_num}}-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
restore-keys: Ubuntu-${{matrix.release_num}}-${{ secrets.CACHE_VERSION }}-ccache
max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
key: Ubuntu-${{matrix.release_num}}-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update
sudo bash dist/get_deps_debian.sh
apt update
bash dist/get_deps_debian.sh
- name: ⬇️ Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
# Ubuntu cmake build
- name: 🛠️ Build
run: |
git config --global --add safe.directory '*'
echo COMMIT_SHA_SHORT=$(git rev-parse --short HEAD) >> $GITHUB_ENV
echo COMMIT_SHA_LONG=$(git rev-parse HEAD) >> $GITHUB_ENV
echo COMMIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV
mkdir -p build
cd build
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${{ env.COMMIT_SHA_SHORT }}" \
-DIMHEX_COMMIT_HASH_LONG="${{ env.COMMIT_SHA_LONG}}" \
-DIMHEX_COMMIT_BRANCH="${{ env.COMMIT_BRANCH }}" \
-DIMHEX_ENABLE_LTO=ON \
-DIMHEX_USE_GTK_FILE_PICKER=ON \
-DDOTNET_EXECUTABLE="dotnet" \
..
make -j 4 install DESTDIR=DebDir
DESTDIR=DebDir ninja install
- name: 📜 Set version variable
run: |
@@ -284,12 +316,12 @@ jobs:
run: |
cp -r build/DEBIAN build/DebDir
dpkg-deb -Zgzip --build build/DebDir
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04-x86_64.deb
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
- name: ⬆️ Upload DEB
uses: actions/upload-artifact@v3
with:
name: Ubuntu 22.04 DEB x86_64
name: Ubuntu ${{ matrix.release_num }} DEB x86_64
path: '*.deb'
# AppImage build
@@ -306,23 +338,23 @@ jobs:
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
key: appimage-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
restore-keys: appimage-${{ secrets.CACHE_VERSION }}-ccache
max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build-appimage/CMakeCache.txt
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
key: appimage-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update
sudo bash dist/get_deps_debian.sh
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse ninja-build
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
sudo chmod +x /usr/local/bin/appimagetool
sudo pip3 install git+https://github.com/iTrooz/appimage-builder@dpkg-package-versions
@@ -336,8 +368,8 @@ jobs:
run: |
mkdir -p build-appimage
cd build-appimage
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
@@ -345,11 +377,10 @@ jobs:
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DIMHEX_ENABLE_LTO=ON \
-DIMHEX_PLUGINS_IN_SHARE=ON \
-DIMHEX_USE_BUNDLED_CA=ON \
..
make -j 4 install DESTDIR=AppDir
DESTDIR=AppDir ninja install
- name: 📦 Bundle AppImage
run: |
@@ -395,31 +426,35 @@ jobs:
run: |
dist/get_deps_archlinux.sh --noconfirm
- name: ⬇️ Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
key: archlinux-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-ccache
max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
key: archlinux-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
# ArchLinux cmake build
- name: 🛠️ Build
run: |
mkdir -p build
cd build
CC=gcc CXX=g++ cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
CC=gcc CXX=g++ cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SYSTEM_FMT=ON \
-DUSE_SYSTEM_YARA=ON \
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
@@ -428,9 +463,10 @@ jobs:
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DIMHEX_ENABLE_LTO=ON \
-DIMHEX_USE_GTK_FILE_PICKER=ON \
..
make -j 4 install DESTDIR=installDir
DESTDIR=installDir ninja install
- name: 📜 Set version variable
run: |
@@ -519,11 +555,16 @@ jobs:
fedpkg \
ccache
- name: ⬇️ Install .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2.5
with:
key: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-rpm-${{ github.run_id }}
restore-keys: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-rpm
max-size: 1G
- name: 📜 Set version variable
@@ -566,7 +607,7 @@ jobs:
path: /var/cache/mock
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
restore-keys: |
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock
# Fedora cmake build (in imhex.spec)
- name: 📦 Build RPM

View File

@@ -51,26 +51,6 @@ jobs:
repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }}
- name: ✉️ Update C++ Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Cpp-Plugin-Template
event-type: update_submodule
- name: ✉️ Update Rust Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Rust-Plugin-Template
event-type: update_submodule
release-upload-artifacts:
runs-on: ubuntu-latest
name: Release Upload Artifacts

6
.gitmodules vendored
View File

@@ -14,10 +14,6 @@
path = lib/external/fmt
url = https://github.com/fmtlib/fmt
ignore = dirty
[submodule "lib/external/curl"]
path = lib/external/curl
url = https://github.com/curl/curl
ignore = dirty
[submodule "lib/external/capstone"]
path = lib/external/capstone
url = https://github.com/capstone-engine/capstone
@@ -31,4 +27,4 @@
url = https://github.com/WerWolv/PatternLanguage
[submodule "lib/external/libwolv"]
path = lib/external/libwolv
url = https://github.com/WerWolv/libwolv
url = https://github.com/WerWolv/libwolv

View File

@@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.20)
# Options
option(IMHEX_USE_BUNDLED_CA "Use the CA bundle in romfs instead of the system one" OFF)
option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins" OFF)
option(IMHEX_STRIP_RELEASE "Strip the release builds" ON)
option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
@@ -10,6 +9,10 @@ option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of t
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON)
option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" OFF)
option(IMHEX_USE_DEFAULT_BUILD_SETTINGS "Use default build settings" OFF)
option(IMHEX_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON)
# Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23)
@@ -21,6 +24,7 @@ include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
# Setup project
loadVersion(IMHEX_VERSION)
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
configureCMake()
project(imhex
LANGUAGES C CXX VERSION ${IMHEX_VERSION}
DESCRIPTION "The ImHex Hex Editor"
@@ -36,6 +40,7 @@ verifyCompiler()
set(PLUGINS
builtin
windows
script_loader
)
# Add various defines

View File

@@ -17,13 +17,10 @@
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_COMPILER": "gcc",
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
"CMAKE_C_FLAGS": "-fuse-ld=lld",
"CMAKE_CXX_FLAGS": "-fuse-ld=lld",
"IMHEX_PATTERNS_PULL_MASTER": "ON",
"CMAKE_INSTALL_PREFIX": "./install",
"USE_SYSTEM_CURL": "ON"
"USE_SYSTEM_CAPSTONE": "ON",
"IMHEX_USE_DEFAULT_BUILD_SETTINGS": "ON"
}
},
{

View File

@@ -9,9 +9,9 @@ To install plugins, simply download the relevant `.hexplug` file and drop it in
(If you're developing a Plugin on your own, please feel free to add it to this list)
### Official Plugins
- [Malcore Plugin](https://github.com/WerWolv/ImHex-Malcore-Plugin)
- Direcly upload your files to https://malcore.io for advanced binary analysis.
- [Extra Hashes Plugin](https://github.com/WerWolv/ImHex-Hashes-Plugin)
- Adds support for a variety of new hashes to the Hashes view including Blake, Adler32, Murmur and Tiger
- [Discord RPC Plugin](https://github.com/WerWolv/ImHex-Plugin-DiscordRPC)
- Adds support for Discord Rich Presence
### Third-Party Plugins

View File

@@ -120,7 +120,6 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
- Hexadecimal Color picker
- Base converter
- UNIX Permissions calculator
- Anonfiles File upload tool
- Wikipedia term definition finder
- File utilities
- File splitter
@@ -145,7 +144,14 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
To use ImHex, the following minimal system requirements need to be met:
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora 36/37, RHEL/AlmaLinux 9, and Arch Linux have official packages, other and older distributions can use the AppImage)
- **OS**:
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
- **macOS**: macOS 11 (Big Sur) or higher,
- **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
- RHEL/AlmaLinux 9
- Arch Linux
- **CPU**: x86_64 (64 Bit)
- **GPU**: OpenGL 3.0 or higher
- Intel HD drivers are really buggy and often cause graphic artifacts

View File

@@ -1 +1 @@
1.30.1
1.31.0

View File

@@ -14,47 +14,6 @@ macro(addDefines)
message(FATAL_ERROR "IMHEX_VERSION is not defined")
endif ()
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_HASH_SHORT AND DEFINED IMHEX_COMMIT_BRANCH)
add_compile_definitions(
GIT_COMMIT_HASH_LONG="${IMHEX_COMMIT_HASH_LONG}"
GIT_COMMIT_HASH_SHORT="${IMHEX_COMMIT_HASH_SHORT}"
GIT_BRANCH="${IMHEX_COMMIT_BRANCH}"
)
else()
# Get the current working branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_BRANCH
)
# Get the latest abbreviated commit hash of the working branch
execute_process(
COMMAND git log -1 --format=%h --abbrev=7
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_SHORT
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_SHORT
)
execute_process(
COMMAND git log -1 --format=%H
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_LONG
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_LONG
)
if (RESULT_BRANCH EQUAL 0 AND RESULT_HASH_LONG EQUAL 0 AND RESULT_HASH_SHORT EQUAL 0)
add_compile_definitions(
GIT_COMMIT_HASH_SHORT="${GIT_COMMIT_HASH_SHORT}"
GIT_COMMIT_HASH_LONG="${GIT_COMMIT_HASH_LONG}"
GIT_BRANCH="${GIT_BRANCH}")
endif ()
endif ()
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
@@ -65,16 +24,22 @@ macro(addDefines)
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
add_compile_definitions(DEBUG _GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-RelWithDebInfo)
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
add_compile_definitions(NDEBUG)
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-MinSizeRel)
add_compile_definitions(NDEBUG)
endif ()
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
endmacro()
function(addDefineToSource SOURCE DEFINE)
set_property(
SOURCE ${SOURCE}
APPEND
PROPERTY COMPILE_DEFINITIONS "${DEFINE}"
)
endfunction()
# Detect current OS / System
macro(detectOS)
if (WIN32)
@@ -82,10 +47,6 @@ macro(detectOS)
set(CMAKE_INSTALL_BINDIR ".")
set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins")
if (NOT USE_SYSTEM_CURL)
SET(IMHEX_USE_BUNDLED_CA ON)
endif ()
elseif (APPLE)
add_compile_definitions(OS_MACOS)
set(CMAKE_INSTALL_BINDIR ".")
@@ -109,10 +70,6 @@ macro(detectOS)
message(FATAL_ERROR "Unknown / unsupported system!")
endif()
if(IMHEX_USE_BUNDLED_CA)
add_compile_definitions(IMHEX_USE_BUNDLED_CA)
endif()
endmacro()
# Detect 32 vs. 64 bit system
@@ -135,7 +92,6 @@ macro(configurePackingResources)
if (WIN32)
set(APPLICATION_TYPE)
set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/resource.rc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-subsystem,windows")
if (CREATE_PACKAGE)
set(CPACK_GENERATOR "WIX")
@@ -164,7 +120,7 @@ macro(configurePackingResources)
set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/dist/macos/Info.plist.in")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH_SHORT}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${IMHEX_COMMIT_HASH_SHORT}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
string(TIMESTAMP CURR_YEAR "%Y")
@@ -297,6 +253,9 @@ macro(createPackage)
set(CPACK_GENERATOR "DragNDrop")
else()
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if(WIN32) # Forwarder is only needed on Windows
install(TARGETS imhex-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
endif()
if (CREATE_PACKAGE)
@@ -318,6 +277,75 @@ function(JOIN OUTPUT GLUE)
set(${OUTPUT} "${_TMP_RESULT}" PARENT_SCOPE)
endfunction()
macro(configureCMake)
message(STATUS "Configuring ImHex v${IMHEX_VERSION}")
# Enable C and C++ languages
enable_language(C CXX)
# Configure use of recommended build tools
if (IMHEX_USE_DEFAULT_BUILD_SETTINGS)
message(STATUS "Configuring CMake to use recommended build tools...")
find_program(CCACHE_PATH ccache)
find_program(NINJA_PATH ninja)
find_program(LD_LLD_PATH ld.lld)
find_program(AR_LLVMLIBS_PATH llvm-ar)
find_program(RANLIB_LLVMLIBS_PATH llvm-ranlib)
if (CCACHE_PATH)
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_PATH})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_PATH})
else ()
message(WARNING "ccache not found!")
endif ()
if (AR_LLVMLIBS_PATH)
set(CMAKE_AR ${AR_LLVMLIBS_PATH})
else ()
message(WARNING "llvm-ar not found, using default ar!")
endif ()
if (RANLIB_LLVMLIBS_PATH)
set(CMAKE_RANLIB ${RANLIB_LLVMLIBS_PATH})
else ()
message(WARNING "llvm-ranlib not found, using default ranlib!")
endif ()
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")
else ()
message(WARNING "lld not found, using default linker!")
endif ()
if (NINJA_PATH)
set(CMAKE_GENERATOR Ninja)
else ()
message(WARNING "ninja not found, using default generator!")
endif ()
endif()
# Enable LTO if desired and supported
if (IMHEX_ENABLE_LTO)
include(CheckIPOSupported)
check_ipo_supported(RESULT result OUTPUT output_error)
if (result)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
message(STATUS "LTO enabled!")
else ()
message(WARNING "LTO is not supported: ${output_error}")
endif ()
endif ()
# Some libraries we use set the BUILD_SHARED_LIBS variable to ON, which causes CMake to
# display a warning about options being set using set() instead of option().
# Explicitly set the policy to NEW to suppress the warning.
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
endmacro()
macro(setDefaultBuiltTypeIfUnset)
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Using Release build type as it was left unset" FORCE)
@@ -355,8 +383,8 @@ function(verifyCompiler)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0.0")
message(FATAL_ERROR "ImHex requires GCC 12.0.0 or newer. Please use the latest GCC version.")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14.0.0")
message(FATAL_ERROR "ImHex requires Clang 14.0.0 or newer. Please use the latest Clang version.")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "17.0.0")
message(FATAL_ERROR "ImHex requires Clang 17.0.0 or newer. Please use the latest Clang version.")
elseif (NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
message(FATAL_ERROR "ImHex can only be compiled with GCC or Clang. ${CMAKE_CXX_COMPILER_ID} is not supported.")
endif()
@@ -383,7 +411,7 @@ function(downloadImHexPatternsFiles dest)
FetchContent_Declare(
imhex_patterns
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
GIT_TAG master
GIT_TAG origin/master
)
message(STATUS "Downloading ImHex-Patterns repo branch ${PATTERNS_BRANCH}...")
@@ -406,7 +434,10 @@ endfunction()
macro(setupCompilerFlags target)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
if (IMHEX_STRICT_WARNINGS)
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
endif()
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-array-bounds")
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -453,8 +484,6 @@ macro(addBundledLibraries)
set_property(TARGET libwolv-net PROPERTY POSITION_INDEPENDENT_CODE ON)
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
set(CURL_USE_MBEDTLS ON)
set(BUILD_CURL_EXE OFF)
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
if(NOT USE_SYSTEM_FMT)
@@ -489,15 +518,8 @@ macro(addBundledLibraries)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
endif()
if(NOT USE_SYSTEM_CURL)
add_subdirectory(${EXTERN_LIBS_FOLDER}/curl EXCLUDE_FROM_ALL)
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_compile_options(libcurl PRIVATE -Wno-deprecated-declarations)
set(LIBCURL_LIBRARIES libcurl)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.76.1)
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.60.0)
if (NOT USE_SYSTEM_LLVM)
add_subdirectory(${EXTERN_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
@@ -530,6 +552,7 @@ macro(addBundledLibraries)
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
add_subdirectory(${EXTERN_LIBS_FOLDER}/capstone EXCLUDE_FROM_ALL)
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_compile_options(capstone PRIVATE -Wno-unused-function)
set(CAPSTONE_LIBRARIES "capstone")
set(CAPSTONE_INCLUDE_DIRS ${EXTERN_LIBS_FOLDER}/capstone/include)
else()
@@ -537,10 +560,11 @@ macro(addBundledLibraries)
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
endif()
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF)
add_subdirectory(${EXTERN_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
find_package(mbedTLS 2.26.0 REQUIRED)
find_package(mbedTLS 3.4.0 REQUIRED)
pkg_search_module(MAGIC libmagic>=5.39)
if(NOT MAGIC_FOUND)
@@ -587,11 +611,13 @@ function(generatePDBs)
)
FetchContent_Populate(cv2pdb)
set(PDBS_TO_GENERATE main libimhex ${PLUGINS})
set(PDBS_TO_GENERATE main imhex-forwarder libimhex ${PLUGINS})
add_custom_target(pdbs)
foreach (PDB ${PDBS_TO_GENERATE})
if (PDB STREQUAL "main")
set(GENERATED_PDB imhex)
elseif (PDB STREQUAL "imhex-forwarder")
set(GENERATED_PDB imhex-gui)
elseif (PDB STREQUAL "libimhex")
set(GENERATED_PDB libimhex)
else ()

View File

@@ -0,0 +1,81 @@
set(CoreClrEmbed_FOUND FALSE)
set(CORECLR_ARCH "linux-x64")
set(CORECLR_SUBARCH "x64")
if (WIN32)
set(CORECLR_ARCH "win-x64")
endif()
if (UNIX)
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
set(CORECLR_ARCH "linux-arm64")
set(CORECLR_SUBARCH "arm64")
endif()
endif()
if (NOT DOTNET_EXECUTABLE)
set(DOTNET_EXECUTABLE dotnet)
endif ()
set(CORECLR_VERSION "7.0")
execute_process(COMMAND ${DOTNET_EXECUTABLE} "--list-runtimes" OUTPUT_VARIABLE CORECLR_LIST_RUNTIMES_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE)
if (CORECLR_LIST_RUNTIMES_OUTPUT STREQUAL "")
message(STATUS "Unable to find any .NET runtimes")
return()
endif ()
set(_ALL_RUNTIMES ${CORECLR_LIST_RUNTIMES_OUTPUT})
string(REPLACE "\n" ";" _ALL_RUNTIMES_LIST ${_ALL_RUNTIMES})
foreach(X ${_ALL_RUNTIMES_LIST})
string(REGEX MATCH "Microsoft\.NETCore\.App ([0-9]+)\.([0-9]+)\.([a-zA-Z0-9.-]+) [\[](.*)Microsoft\.NETCore\.App[\]]"
CORECLR_VERSION_REGEX_MATCH ${X})
set(_RUNTIME_VERSION ${CMAKE_MATCH_1}.${CMAKE_MATCH_2})
if (CMAKE_MATCH_1 AND CMAKE_MATCH_4)
if (${_RUNTIME_VERSION} STREQUAL ${CORECLR_VERSION})
set(CORECLR_RUNTIME_VERSION ${_RUNTIME_VERSION})
set(CORECLR_RUNTIME_VERSION_FULL ${CORECLR_VERSION}.${CMAKE_MATCH_3})
set(CORECLR_RUNTIME_ROOT_PATH ${CMAKE_MATCH_4})
message(STATUS "Found matching .NET runtime version '${CORECLR_RUNTIME_VERSION_FULL}' path='${CORECLR_RUNTIME_ROOT_PATH}'")
endif()
endif()
endforeach()
if (CORECLR_RUNTIME_ROOT_PATH)
get_filename_component(CORECLR_RUNTIME_ROOT_PATH ${CORECLR_RUNTIME_ROOT_PATH} DIRECTORY)
endif()
set(CoreClrEmbed_ROOT_PATH "${CORECLR_RUNTIME_ROOT_PATH}")
file(GLOB _CORECLR_HOST_ARCH_PATH "${CORECLR_RUNTIME_ROOT_PATH}/packs/Microsoft.NETCore.App.Host.*-${CORECLR_SUBARCH}")
if (_CORECLR_HOST_ARCH_PATH)
get_filename_component(_CORECLR_HOST_ARCH_FILENAME ${_CORECLR_HOST_ARCH_PATH} NAME)
string(REPLACE "Microsoft.NETCore.App.Host." "" _CORECLR_COMPUTED_ARCH "${_CORECLR_HOST_ARCH_FILENAME}")
if (_CORECLR_COMPUTED_ARCH)
set(CORECLR_ARCH "${_CORECLR_COMPUTED_ARCH}")
endif()
endif()
set(CORECLR_HOST_BASE_PATH "${CORECLR_RUNTIME_ROOT_PATH}/packs/Microsoft.NETCore.App.Host.${CORECLR_ARCH}/${CORECLR_RUNTIME_VERSION_FULL}")
file(GLOB _CORECLR_FOUND_PATH ${CORECLR_HOST_BASE_PATH})
if (_CORECLR_FOUND_PATH)
set(CORECLR_NETHOST_ROOT "${_CORECLR_FOUND_PATH}/runtimes/${CORECLR_ARCH}/native")
endif()
find_library(CoreClrEmbed_LIBRARY nethost PATHS
${CORECLR_NETHOST_ROOT}
)
find_path(CoreClrEmbed_INCLUDE_DIR nethost.h PATHS
${CORECLR_NETHOST_ROOT}
)
find_file(CoreClrEmbed_SHARED_LIBRARY nethost.dll nethost.so libnethost.so nethost.dylib libnethost.dylib PATHS
${CORECLR_NETHOST_ROOT})
if (CoreClrEmbed_INCLUDE_DIR AND CoreClrEmbed_LIBRARY)
set(CoreClrEmbed_FOUND TRUE)
set(CoreClrEmbed_LIBRARIES "${CoreClrEmbed_LIBRARY}")
set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}")
set(CoreClrEmbed_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}")
endif()

View File

@@ -0,0 +1,44 @@
macro(add_imhex_plugin)
# Parse arguments
set(options "")
set(oneValueArgs NAME)
set(multiValueArgs SOURCES INCLUDES LIBRARIES)
cmake_parse_arguments(IMHEX_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
# Define new project for plugin
project(${IMHEX_PLUGIN_NAME})
# Create a new shared library for the plugin source code
add_library(${IMHEX_PLUGIN_NAME} SHARED ${IMHEX_PLUGIN_SOURCES})
# Add include directories and link libraries
target_include_directories(${IMHEX_PLUGIN_NAME} PRIVATE ${IMHEX_PLUGIN_INCLUDES})
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} ${IMHEX_PLUGIN_LIBRARIES})
# Add IMHEX_PROJECT_NAME and IMHEX_VERSION define
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}")
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_VERSION="${IMHEX_VERSION_STRING}")
# Enable required compiler flags
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
setupCompilerFlags(${IMHEX_PLUGIN_NAME})
# Configure build properties
set_target_properties(${IMHEX_PLUGIN_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
CXX_STANDARD 23
PREFIX ""
SUFFIX ".hexplug"
)
# Setup a romfs for the plugin
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
set(LIBROMFS_PROJECT_NAME ${IMHEX_PLUGIN_NAME})
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
# Add the new plugin to the main dependency list so it gets built by default
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
endmacro()

View File

@@ -15,7 +15,9 @@ if(CMAKE_GENERATOR)
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}"
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}"
)
endfunction()
@@ -29,13 +31,13 @@ message(STATUS "Fixing up application bundle: ${BUNDLE_PATH}")
# Make sure to fix up any included ImHex plugin.
file(GLOB_RECURSE extra_libs "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug")
message(STATUS "Fixing up application bundle: ${extra_dirs}")
# BundleUtilities doesn't support DYLD_FALLBACK_LIBRARY_PATH behavior, which
# 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")
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS})
message(STATUS "Fixing up application bundle: ${extra_dirs}")
# BundleUtilities is overly verbose, so disable most of its messages
function(message)

View File

@@ -64,6 +64,7 @@ AppDir:
- /lib/x86_64-linux-gnu/libbsd.so.0
- /lib/x86_64-linux-gnu/libcairo-gobject.so.2
- /lib/x86_64-linux-gnu/libcairo.so.2
- /lib/x86_64-linux-gnu/libcurl-gnutls.so.4
- /lib/x86_64-linux-gnu/libdatrie.so.1
- /lib/x86_64-linux-gnu/libedit.so.2
- /lib/x86_64-linux-gnu/libelf.so.1

2
dist/Arch/PKGBUILD vendored
View File

@@ -8,7 +8,7 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
arch=("x86_64")
url="https://github.com/WerWolv/ImHex"
license=('GPL2')
depends=(glfw mbedtls freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
depends=(glfw mbedtls freetype2 libglvnd dbus gtk3 curl fmt yara nlohmann-json)
makedepends=(git)
provides=(imhex)
conflicts=(imhex)

2
dist/Brewfile vendored
View File

@@ -5,6 +5,8 @@ brew "ccache"
brew "freetype2"
brew "libmagic"
brew "pkg-config"
brew "curl"
brew "gcc@12"
brew "llvm"
brew "glfw"
brew "ninja"

1
dist/Dockerfile vendored
View File

@@ -14,6 +14,7 @@ RUN pacman -S --needed --noconfirm \
file \
mbedtls \
freetype2 \
curl \
dbus \
xdg-desktop-portal

View File

@@ -7,22 +7,19 @@ On Windows, ImHex is built through [msys2 / mingw](https://www.msys2.org/)'s gcc
3. Clone the repo using `git clone https://github.com/WerWolv/ImHex --recurse-submodules`
4. Install all the dependencies using `./ImHex/dist/get_deps_msys2.sh`
5. Build ImHex itself using the following commands:
```sh
cd ImHex
mkdir build
cd build
cmake -G "MinGW Makefiles" \
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-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 \
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
..
mingw32-make -j install
ninja install
```
ImHex will look for any extra resources either in various folders directly next to the executable or in `%localappdata%/imhex`
For low RAM-usage system, you can use `mingw32-make -j N install` instead, to reduce RAM usage at compile time. Where `N` is amount of jobs you are willling to run at once. Roughly ~1 GB of RAM usage per job.

View File

@@ -9,8 +9,9 @@ pacman -S $@ --needed \
mbedtls \
freetype2 \
dbus \
xdg-desktop-portal \
gtk3 \
curl \
fmt \
yara \
nlohmann-json
nlohmann-json \
ninja

View File

@@ -13,7 +13,6 @@ apt install -y \
lld \
${PKGCONF:-} \
cmake \
make \
ccache \
libglfw3-dev \
libglm-dev \
@@ -21,4 +20,6 @@ apt install -y \
libmbedtls-dev \
libfreetype-dev \
libdbus-1-dev \
xdg-desktop-portal
libcurl4-gnutls-dev \
libgtk-3-dev \
ninja-build

View File

@@ -5,9 +5,11 @@ dnf install -y \
dbus-devel \
file-devel \
freetype-devel \
libcurl-devel \
gcc-c++ \
git \
mesa-libGL-devel \
glfw-devel \
lld \
mbedtls-devel
mbedtls-devel \
gtk3-devel

View File

@@ -4,10 +4,12 @@ pacman -S --needed --noconfirm \
mingw-w64-x86_64-gcc \
mingw-w64-x86_64-lld \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-make \
mingw-w64-x86_64-ccache \
mingw-w64-x86_64-glfw \
mingw-w64-x86_64-file \
mingw-w64-x86_64-curl-winssl \
mingw-w64-x86_64-mbedtls \
mingw-w64-x86_64-freetype \
mingw-w64-x86_64-dlfcn
mingw-w64-x86_64-dlfcn \
mingw-w64-x86_64-ninja \
mingw-w64-x86_64-capstone

5
dist/rpm/imhex.spec vendored
View File

@@ -26,6 +26,7 @@ BuildRequires: llvm-devel
BuildRequires: mbedtls-devel
BuildRequires: yara-devel
BuildRequires: nativefiledialog-extended-devel
BuildRequires: dotnet-sdk-7.0
%if 0%{?rhel}
BuildRequires: gcc-toolset-12
%endif
@@ -74,10 +75,10 @@ CXXFLAGS+=" -std=gnu++2b"
-D IMHEX_OFFLINE_BUILD=ON \
-D USE_SYSTEM_NLOHMANN_JSON=ON \
-D USE_SYSTEM_FMT=ON \
-D USE_SYSTEM_CURL=ON \
-D USE_SYSTEM_LLVM=ON \
-D USE_SYSTEM_YARA=ON \
-D USE_SYSTEM_NFD=ON \
-D IMHEX_USE_GTK_FILE_PICKER=ON \
-D IMHEX_BUNDLE_DOTNET=OFF \
# when capstone >= 5.x is released we should be able to build against \
# system libs of it \
# -D USE_SYSTEM_CAPSTONE=ON

1
lib/external/curl vendored

Submodule lib/external/curl deleted from b16d1fa8ee

View File

@@ -14,10 +14,16 @@
#pragma once
#include <assert.h>
//---- Define assertion handler. Defaults to calling assert().
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
namespace hex::log::impl {
void assertionHandler(bool expr, const char* expr_str, const char* file, int line);
}
#define IM_ASSERT(_EXPR) hex::log::impl::assertionHandler(_EXPR, #_EXPR, __FILE__, __LINE__)
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.

View File

@@ -636,8 +636,10 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
{
ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
if (src_tmp.GlyphsCount == 0)
continue;
// IMHEX PATCH BEGIN
// if (src_tmp.GlyphsCount == 0)
// continue;
// IMHEX PATCH END
// When merging fonts with MergeMode=true:
// - We can have multiple input fonts writing into a same destination font.

View File

@@ -202,8 +202,6 @@ void TextEditor::DeleteRange(const Coordinates &aStart, const Coordinates &aEnd)
}
int TextEditor::InsertTextAt(Coordinates & /* inout */ aWhere, const char *aValue) {
assert(!mReadOnly);
int cindex = GetCharacterIndex(aWhere);
int totalLines = 0;
while (*aValue != '\0') {
@@ -541,8 +539,6 @@ void TextEditor::RemoveLine(int aIndex) {
}
TextEditor::Line &TextEditor::InsertLine(int aIndex) {
assert(!mReadOnly);
auto &result = *mLines.insert(mLines.begin() + aIndex, Line());
ErrorMarkers etmp;
@@ -990,7 +986,6 @@ void TextEditor::Render() {
if (mScrollToCursor) {
EnsureCursorVisible();
ImGui::SetWindowFocus();
mScrollToCursor = false;
}
}

View File

@@ -824,34 +824,7 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
// IMHEX PATCH BEGIN
#if defined(_WIN32)
switch (imgui_cursor) {
case ImGuiMouseCursor_Hand:
SetCursor(LoadCursor(nullptr, IDC_HAND));
break;
case ImGuiMouseCursor_ResizeEW:
SetCursor(LoadCursor(nullptr, IDC_SIZEWE));
break;
case ImGuiMouseCursor_ResizeNS:
SetCursor(LoadCursor(nullptr, IDC_SIZENS));
break;
case ImGuiMouseCursor_ResizeNWSE:
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
break;
case ImGuiMouseCursor_ResizeNESW:
SetCursor(LoadCursor(nullptr, IDC_SIZENESW));
break;
case ImGuiMouseCursor_ResizeAll:
SetCursor(LoadCursor(nullptr, IDC_SIZEALL));
break;
case ImGuiMouseCursor_NotAllowed:
SetCursor(LoadCursor(nullptr, IDC_NO));
break;
case ImGuiMouseCursor_TextInput:
SetCursor(LoadCursor(nullptr, IDC_IBEAM));
break;
}
#else
#if !defined(_WIN32)
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,11 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.2
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
@@ -7,13 +15,116 @@
#include <string> // string
#include <vector> // vector
// #include <nlohmann/detail/abi_macros.hpp>
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++
// | | |__ | | | | | | version 3.11.2
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
// This file contains all macro definitions affecting or depending on the ABI
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2
#warning "Already included a different version of the library!"
#endif
#endif
#endif
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum)
#ifndef JSON_DIAGNOSTICS
#define JSON_DIAGNOSTICS 0
#endif
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
#endif
#if JSON_DIAGNOSTICS
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
#else
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
#endif
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
#else
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
#endif
// Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
#define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
// Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
_v ## major ## _ ## minor ## _ ## patch
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_VERSION
#else
#define NLOHMANN_JSON_NAMESPACE_VERSION \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
NLOHMANN_JSON_VERSION_MINOR, \
NLOHMANN_JSON_VERSION_PATCH)
#endif
// Combine namespace components
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
#ifndef NLOHMANN_JSON_NAMESPACE
#define NLOHMANN_JSON_NAMESPACE \
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_NAMESPACE_VERSION)
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
namespace nlohmann \
{ \
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_NAMESPACE_VERSION) \
{
#endif
#ifndef NLOHMANN_JSON_NAMESPACE_END
#define NLOHMANN_JSON_NAMESPACE_END \
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
} // namespace nlohmann
#endif
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
@since version 1.0.0
*/
namespace nlohmann
{
NLOHMANN_JSON_NAMESPACE_BEGIN
/*!
@brief default JSONSerializer template argument
@@ -24,6 +135,8 @@ for serialization.
template<typename T = void, typename SFINAE = void>
struct adl_serializer;
/// a class to store JSON values
/// @sa https://json.nlohmann.me/api/basic_json/
template<template<typename U, typename V, typename... Args> class ObjectType =
std::map,
template<typename U, typename... Args> class ArrayType = std::vector,
@@ -37,42 +150,26 @@ template<template<typename U, typename V, typename... Args> class ObjectType =
class BinaryType = std::vector<std::uint8_t>>
class basic_json;
/*!
@brief JSON Pointer
A JSON pointer defines a string syntax for identifying a specific value
within a JSON document. It can be used with functions `at` and
`operator[]`. Furthermore, JSON pointers are the base for JSON patches.
@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
@since version 2.0.0
*/
template<typename BasicJsonType>
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
/// @sa https://json.nlohmann.me/api/json_pointer/
template<typename RefStringType>
class json_pointer;
/*!
@brief default JSON class
This type is the default specialization of the @ref basic_json class which
uses the standard template types.
@since version 1.0.0
@brief default specialization
@sa https://json.nlohmann.me/api/json/
*/
using json = basic_json<>;
/// @brief a minimal map-like container that preserves insertion order
/// @sa https://json.nlohmann.me/api/ordered_map/
template<class Key, class T, class IgnoredLess, class Allocator>
struct ordered_map;
/*!
@brief ordered JSON class
This type preserves the insertion order of object keys.
@since version 3.9.0
*/
/// @brief specialization that maintains the insertion order of object keys
/// @sa https://json.nlohmann.me/api/ordered_json/
using ordered_json = basic_json<nlohmann::ordered_map>;
} // namespace nlohmann
NLOHMANN_JSON_NAMESPACE_END
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_

View File

@@ -114,7 +114,9 @@ target_compile_definitions(libyara PRIVATE
HASH_MODULE DOTNET_MODULE MAGIC_MODULE MACHO_MODULE DEX_MODULE
)
target_compile_options(libyara PRIVATE -Wno-shift-count-overflow -Wno-stringop-overflow)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_compile_options(libyara PRIVATE -Wno-shift-count-overflow -Wno-stringop-overflow)
endif ()
target_include_directories(
libyara
@@ -131,6 +133,5 @@ else ()
endif ()
include(GNUInstallDirs)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc.in
${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc @ONLY)
set(CMAKE_STATIC_LIBRARY_PREFIX "")

View File

@@ -15,12 +15,14 @@ set(LIBIMHEX_SOURCES
source/api/project_file_manager.cpp
source/api/theme_manager.cpp
source/api/layout_manager.cpp
source/api/achievement_manager.cpp
source/data_processor/attribute.cpp
source/data_processor/link.cpp
source/data_processor/node.cpp
source/helpers/utils.cpp
source/helpers/utils_linux.cpp
source/helpers/fs.cpp
source/helpers/magic.cpp
source/helpers/crypto.cpp
@@ -37,6 +39,8 @@ set(LIBIMHEX_SOURCES
source/ui/imgui_imhex_extensions.cpp
source/ui/view.cpp
source/ui/popup.cpp
source/subcommands/subcommands.cpp
)
if (APPLE)
@@ -58,11 +62,14 @@ add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
setupCompilerFlags(libimhex)
include(GenerateExportHeader)
generate_export_header(libimhex)
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
if (WIN32)
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)
@@ -70,4 +77,46 @@ elseif (APPLE)
endif ()
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl libpl-gen ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers)
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} plcli libpl libpl-gen ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers)
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_HASH_SHORT AND DEFINED IMHEX_COMMIT_BRANCH)
set(GIT_COMMIT_HASH_LONG "${IMHEX_COMMIT_HASH_LONG}")
set(GIT_COMMIT_HASH_SHORT "${IMHEX_COMMIT_HASH_SHORT}")
set(GIT_BRANCH "${IMHEX_COMMIT_BRANCH}")
else()
# Get the current working branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_BRANCH
)
# Get the latest abbreviated commit hash of the working branch
execute_process(
COMMAND git log -1 --format=%h --abbrev=7
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_SHORT
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_SHORT
)
execute_process(
COMMAND git log -1 --format=%H
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_LONG
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_LONG
)
endif ()
if ((NOT GIT_COMMIT_HASH_SHORT STREQUAL "") AND (NOT GIT_COMMIT_HASH_LONG STREQUAL "") AND (NOT GIT_BRANCH STREQUAL ""))
addDefineToSource(source/api/imhex_api.cpp "GIT_COMMIT_HASH_SHORT=\"${GIT_COMMIT_HASH_SHORT}\"")
addDefineToSource(source/api/imhex_api.cpp "GIT_COMMIT_HASH_LONG=\"${GIT_COMMIT_HASH_LONG}\"")
addDefineToSource(source/api/imhex_api.cpp "GIT_BRANCH=\"${GIT_BRANCH}\"")
endif ()
addDefineToSource(source/api/imhex_api.cpp "IMHEX_VERSION=\"${IMHEX_VERSION_STRING}\"")

View File

@@ -0,0 +1,412 @@
#pragma once
#include <string>
#include <unordered_map>
#include <utility>
#include <memory>
#include <vector>
#include <set>
#include <span>
#include <hex/api/event.hpp>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex {
class AchievementManager;
class Achievement {
public:
explicit Achievement(std::string unlocalizedCategory, std::string unlocalizedName) : m_unlocalizedCategory(std::move(unlocalizedCategory)), m_unlocalizedName(std::move(unlocalizedName)) { }
/**
* @brief Returns the unlocalized name of the achievement
* @return Unlocalized name of the achievement
*/
[[nodiscard]] const std::string &getUnlocalizedName() const {
return this->m_unlocalizedName;
}
/**
* @brief Returns the unlocalized category of the achievement
* @return Unlocalized category of the achievement
*/
[[nodiscard]] const std::string &getUnlocalizedCategory() const {
return this->m_unlocalizedCategory;
}
/**
* @brief Returns whether the achievement is unlocked
* @return Whether the achievement is unlocked
*/
[[nodiscard]] bool isUnlocked() const {
return this->m_progress == this->m_maxProgress;
}
/**
* @brief Sets the description of the achievement
* @param description Description of the achievement
* @return Reference to the achievement
*/
Achievement& setDescription(std::string description) {
this->m_unlocalizedDescription = std::move(description);
return *this;
}
/**
* @brief Adds a requirement to the achievement. The achievement will only be unlockable if all requirements are unlocked.
* @param requirement Unlocalized name of the requirement
* @return Reference to the achievement
*/
Achievement& addRequirement(std::string requirement) {
this->m_requirements.emplace_back(std::move(requirement));
return *this;
}
/**
* @brief Adds a visibility requirement to the achievement. The achievement will only be visible if all requirements are unlocked.
* @param requirement Unlocalized name of the requirement
* @return Reference to the achievement
*/
Achievement& addVisibilityRequirement(std::string requirement) {
this->m_visibilityRequirements.emplace_back(std::move(requirement));
return *this;
}
/**
* @brief Marks the achievement as blacked. Blacked achievements are visible but their name and description are hidden.
* @return Reference to the achievement
*/
Achievement& setBlacked() {
this->m_blacked = true;
return *this;
}
/**
* @brief Marks the achievement as invisible. Invisible achievements are not visible at all.
* @return Reference to the achievement
*/
Achievement& setInvisible() {
this->m_invisible = true;
return *this;
}
/**
* @brief Returns whether the achievement is blacked
* @return Whether the achievement is blacked
*/
[[nodiscard]] bool isBlacked() const {
return this->m_blacked;
}
/**
* @brief Returns whether the achievement is invisible
* @return Whether the achievement is invisible
*/
[[nodiscard]] bool isInvisible() const {
return this->m_invisible;
}
/**
* @brief Returns the list of requirements of the achievement
* @return List of requirements of the achievement
*/
[[nodiscard]] const std::vector<std::string> &getRequirements() const {
return this->m_requirements;
}
/**
* @brief Returns the list of visibility requirements of the achievement
* @return List of visibility requirements of the achievement
*/
[[nodiscard]] const std::vector<std::string> &getVisibilityRequirements() const {
return this->m_visibilityRequirements;
}
/**
* @brief Returns the unlocalized description of the achievement
* @return Unlocalized description of the achievement
*/
[[nodiscard]] const std::string &getUnlocalizedDescription() const {
return this->m_unlocalizedDescription;
}
/**
* @brief Returns the icon of the achievement
* @return Icon of the achievement
*/
[[nodiscard]] const ImGui::Texture &getIcon() const {
if (this->m_iconData.empty())
return this->m_icon;
if (this->m_icon.isValid())
return m_icon;
this->m_icon = ImGui::Texture(reinterpret_cast<const u8*>(this->m_iconData.data()), this->m_iconData.size());
return this->m_icon;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::span<const std::byte> data) {
this->m_iconData.reserve(data.size());
for (auto &byte : data)
this->m_iconData.emplace_back(static_cast<u8>(byte));
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::span<const u8> data) {
this->m_iconData.assign(data.begin(), data.end());
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::vector<u8> data) {
this->m_iconData = std::move(data);
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(const std::vector<std::byte> &data) {
this->m_iconData.reserve(data.size());
for (auto &byte : data)
this->m_iconData.emplace_back(static_cast<u8>(byte));
return *this;
}
/**
* @brief Specifies the required progress to unlock the achievement. This is the number of times this achievement has to be triggered to unlock it. The default is 1.
* @param progress Required progress
* @return Reference to the achievement
*/
Achievement& setRequiredProgress(u32 progress) {
this->m_maxProgress = progress;
return *this;
}
/**
* @brief Returns the required progress to unlock the achievement
* @return Required progress to unlock the achievement
*/
[[nodiscard]] u32 getRequiredProgress() const {
return this->m_maxProgress;
}
/**
* @brief Returns the current progress of the achievement
* @return Current progress of the achievement
*/
[[nodiscard]] u32 getProgress() const {
return this->m_progress;
}
/**
* @brief Sets the callback to call when the achievement is clicked
* @param callback Callback to call when the achievement is clicked
*/
void setClickCallback(const std::function<void(Achievement &)> &callback) {
this->m_clickCallback = callback;
}
/**
* @brief Returns the callback to call when the achievement is clicked
* @return Callback to call when the achievement is clicked
*/
[[nodiscard]] const std::function<void(Achievement &)> &getClickCallback() const {
return this->m_clickCallback;
}
/**
* @brief Returns whether the achievement is temporary. Temporary achievements have been added by challenge projects for example and will be removed when the project is closed.
* @return Whether the achievement is temporary
*/
[[nodiscard]] bool isTemporary() const {
return this->m_temporary;
}
/**
* @brief Sets whether the achievement is unlocked
* @param unlocked Whether the achievement is unlocked
*/
void setUnlocked(bool unlocked) {
if (unlocked) {
if (this->m_progress < this->m_maxProgress)
this->m_progress++;
} else {
this->m_progress = 0;
}
}
protected:
void setProgress(u32 progress) {
this->m_progress = progress;
}
private:
std::string m_unlocalizedCategory, m_unlocalizedName;
std::string m_unlocalizedDescription;
bool m_blacked = false;
bool m_invisible = false;
std::vector<std::string> m_requirements, m_visibilityRequirements;
std::function<void(Achievement &)> m_clickCallback;
std::vector<u8> m_iconData;
mutable ImGui::Texture m_icon;
u32 m_progress = 0;
u32 m_maxProgress = 1;
bool m_temporary = false;
friend class AchievementManager;
};
class AchievementManager {
public:
AchievementManager() = delete;
struct AchievementNode {
Achievement *achievement;
std::vector<AchievementNode*> children, parents;
std::vector<AchievementNode*> visibilityParents;
ImVec2 position;
[[nodiscard]] bool hasParents() const {
return !this->parents.empty();
}
[[nodiscard]] bool isUnlockable() const {
return std::all_of(this->parents.begin(), this->parents.end(), [](auto &parent) { return parent->achievement->isUnlocked(); });
}
[[nodiscard]] bool isVisible() const {
return std::all_of(this->visibilityParents.begin(), this->visibilityParents.end(), [](auto &parent) { return parent->achievement->isUnlocked(); });
}
[[nodiscard]] bool isUnlocked() const {
return this->achievement->isUnlocked();
}
};
/**
* @brief Adds a new achievement
* @tparam T Type of the achievement
* @param args Arguments to pass to the constructor of the achievement
* @return Reference to the achievement
*/
template<std::derived_from<Achievement> T = Achievement>
static Achievement& addAchievement(auto && ... args) {
auto newAchievement = std::make_unique<T>(std::forward<decltype(args)>(args)...);
const auto &category = newAchievement->getUnlocalizedCategory();
const auto &name = newAchievement->getUnlocalizedName();
auto [categoryIter, categoryInserted] = getAchievements().insert({ category, std::unordered_map<std::string, std::unique_ptr<Achievement>>{} });
auto &[categoryKey, achievements] = *categoryIter;
auto [achievementIter, achievementInserted] = achievements.insert({ name, std::move(newAchievement) });
auto &[achievementKey, achievement] = *achievementIter;
achievementAdded();
return *achievement;
}
/**
* @brief Adds a new temporary achievement
* @tparam T Type of the achievement
* @param args Arguments to pass to the constructor of the achievement
* @return Reference to the achievement
*/
template<std::derived_from<Achievement> T = Achievement>
static Achievement& addTemporaryAchievement(auto && ... args) {
auto &achievement = addAchievement(std::forward<decltype(args)>(args)...);
achievement.m_temporary = true;
return achievement;
}
/**
* @brief Unlocks an achievement
* @param unlocalizedCategory Unlocalized category of the achievement
* @param unlocalizedName Unlocalized name of the achievement
*/
static void unlockAchievement(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
/**
* @brief Returns all registered achievements
* @return All achievements
*/
static std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>& getAchievements();
/**
* @brief Returns all achievement start nodes
* @note Start nodes are all nodes that don't have any parents
* @param rebuild Whether to rebuild the list of start nodes
* @return All achievement start nodes
*/
static std::unordered_map<std::string, std::vector<AchievementNode*>>& getAchievementStartNodes(bool rebuild = true);
/**
* @brief Returns all achievement nodes
* @param rebuild Whether to rebuild the list of nodes
* @return All achievement nodes
*/
static std::unordered_map<std::string, std::list<AchievementNode>>& getAchievementNodes(bool rebuild = true);
/**
* @brief Loads the progress of all achievements from the achievements save file
*/
static void loadProgress();
/**
* @brief Stores the progress of all achievements to the achievements save file
*/
static void storeProgress();
/**
* @brief Removes all registered achievements from the tree
*/
static void clear();
/**
* @brief Removes all temporary achievements from the tree
*/
static void clearTemporary();
private:
static void achievementAdded();
};
}

View File

@@ -258,6 +258,7 @@ namespace hex {
};
std::map<std::string, Visualizer> &getVisualizers();
std::map<std::string, Visualizer> &getInlineVisualizers();
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
std::vector<impl::FunctionDefinition> &getFunctions();
@@ -317,6 +318,15 @@ namespace hex {
*/
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &func, u32 parameterCount);
/**
* @brief Adds a new inline visualizer to the pattern language
* @note Inline visualizers are extensions to the [[hex::inline_visualize]] attribute, used to visualize data
* @param name The name of the visualizer
* @param func The function callback
* @param parameterCount The amount of parameters the function takes
*/
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &func, u32 parameterCount);
}
/* View Registry. Allows adding of new windows */

View File

@@ -23,7 +23,11 @@
#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__)
/* Forward declarations */
struct GLFWwindow;
namespace hex { class Achievement; }
namespace hex {
@@ -39,7 +43,9 @@ namespace hex {
}
}
constexpr bool operator==(const EventId &rhs) const = default;
constexpr bool operator==(const EventId &other) const {
return this->m_hash == other.m_hash;
}
private:
u32 m_hash;
@@ -63,6 +69,9 @@ namespace hex {
Callback m_func;
};
template<typename T>
concept EventType = std::derived_from<T, EventBase>;
}
@@ -80,9 +89,10 @@ namespace hex {
* @param function Function to call when the event is posted
* @return Token to unsubscribe from the event
*/
template<typename E>
template<impl::EventType E>
static EventList::iterator subscribe(typename E::Callback function) {
return s_events.insert(s_events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
auto &events = getEvents();
return events.insert(events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
}
/**
@@ -91,9 +101,9 @@ namespace hex {
* @param token Unique token to register the event to. Later required to unsubscribe again
* @param function Function to call when the event is posted
*/
template<typename E>
template<impl::EventType E>
static void subscribe(void *token, typename E::Callback function) {
s_tokenStore.insert(std::make_pair(token, subscribe<E>(function)));
getTokenStore().insert(std::make_pair(token, subscribe<E>(function)));
}
/**
@@ -101,7 +111,7 @@ namespace hex {
* @param token Token returned by subscribe
*/
static void unsubscribe(const EventList::iterator &token) noexcept {
s_events.erase(token);
getEvents().erase(token);
}
/**
@@ -109,15 +119,16 @@ namespace hex {
* @tparam E Event
* @param token Token passed to subscribe
*/
template<typename E>
template<impl::EventType E>
static void unsubscribe(void *token) noexcept {
auto iter = std::find_if(s_tokenStore.begin(), s_tokenStore.end(), [&](auto &item) {
auto &tokenStore = getTokenStore();
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
return item.first == token && item.second->first == E::Id;
});
if (iter != s_tokenStore.end()) {
s_events.remove(*iter->second);
s_tokenStore.erase(iter);
if (iter != tokenStore.end()) {
getEvents().remove(*iter->second);
tokenStore.erase(iter);
}
}
@@ -127,9 +138,9 @@ namespace hex {
* @tparam E Event
* @param args Arguments to pass to the event
*/
template<typename E>
template<impl::EventType E>
static void post(auto &&...args) noexcept {
for (const auto &[id, event] : s_events) {
for (const auto &[id, event] : getEvents()) {
if (id == E::Id) {
(*static_cast<E *const>(event.get()))(std::forward<decltype(args)>(args)...);
}
@@ -145,13 +156,13 @@ namespace hex {
* @brief Unsubscribe all subscribers from all events
*/
static void clear() noexcept {
s_events.clear();
s_tokenStore.clear();
getEvents().clear();
getTokenStore().clear();
}
private:
static std::map<void *, EventList::iterator> s_tokenStore;
static EventList s_events;
static std::map<void *, EventList::iterator>& getTokenStore();
static EventList& getEvents();
};
/* Default Events */
@@ -195,11 +206,13 @@ namespace hex {
EVENT_DEF(EventWindowInitialized);
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
EVENT_DEF(EventPatchCreated, u64, u8, u8);
EVENT_DEF(EventPatternEvaluating);
EVENT_DEF(EventPatternExecuted, const std::string&);
EVENT_DEF(EventPatternEditorChanged, const std::string&);
EVENT_DEF(EventStoreContentDownloaded, const std::fs::path&);
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
EVENT_DEF(EventImHexClosing);
EVENT_DEF(EventAchievementUnlocked, const Achievement&);
/**
* @brief Called when a project has been loaded
@@ -232,4 +245,16 @@ namespace hex {
EVENT_DEF(RequestOpenInfoPopup, const std::string);
EVENT_DEF(RequestOpenErrorPopup, const std::string);
EVENT_DEF(RequestOpenFatalPopup, const std::string);
/**
* @brief Send an event to the main Imhex instance
*/
EVENT_DEF(SendMessageToMainInstance, const std::string, const std::vector<u8>&);
/**
* Move the data from all PerProvider instances from one provider to another.
* The 'from' provider should not have any per provider data after this, and should be immediately deleted
*/
EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *);
}

View File

@@ -261,6 +261,12 @@ namespace hex {
*/
void setCurrentProvider(u32 index);
/**
* @brief Gets the index of the currently selected data provider
* @return Index of the selected provider
*/
i64 getCurrentProviderIndex();
/**
* @brief Checks whether the currently selected data provider is valid
* @return Whether the currently selected data provider is valid
@@ -322,7 +328,10 @@ namespace hex {
/* Functions to interact with various ImHex system settings */
namespace System {
bool isMainInstance();
namespace impl {
void setMainInstanceStatus(bool status);
void setMainWindowPosition(i32 x, i32 y);
void setMainWindowSize(u32 width, u32 height);
@@ -331,8 +340,6 @@ namespace hex {
void setGlobalScale(float scale);
void setNativeScale(float scale);
void setProgramArguments(int argc, char **argv, char **envp);
void setBorderlessWindowMode(bool enabled);
void setCustomFontPath(const std::fs::path &path);
@@ -383,20 +390,6 @@ namespace hex {
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress);
/**
* @brief Gets the current program arguments
* @return The current program arguments
*/
const ProgramArguments &getProgramArguments();
/**
* @brief Gets a program argument
* @param index The index of the argument to get
* @return The argument at the given index
*/
std::optional<std::u8string> getProgramArgument(int index);
/**
* @brief Gets the current target FPS
* @return The current target FPS
@@ -460,7 +453,7 @@ namespace hex {
* @brief Gets the current custom font path
* @return The current custom font path
*/
const std::filesystem::path &getCustomFontPath();
std::filesystem::path &getCustomFontPath();
/**
* @brief Gets the current font size
@@ -486,7 +479,7 @@ namespace hex {
* @brief Gets the currently set additional folder paths
* @return The currently set additional folder paths
*/
const std::vector<std::filesystem::path> &getAdditionalFolderPaths();
std::vector<std::filesystem::path> &getAdditionalFolderPaths();
/**
* @brief Sets the additional folder paths
@@ -507,11 +500,62 @@ namespace hex {
*/
bool isPortableVersion();
/**
* @brief Gets the current Operating System name
* @return Operating System name
*/
std::string getOSName();
/**
* @brief Gets the current Operating System version
* @return Operating System version
*/
std::string getOSVersion();
/**
* @brief Gets the current CPU architecture
* @return CPU architecture
*/
std::string getArchitecture();
/**
* @brief Gets the current ImHex version
* @return ImHex version
*/
std::string getImHexVersion();
/**
* @brief Gets the current git commit hash
* @param longHash Whether to return the full hash or the shortened version
* @return Git commit hash
*/
std::string getCommitHash(bool longHash = false);
/**
* @brief Gets the current git commit branch
* @return Git commit branch
*/
std::string getCommitBranch();
}
/**
* @brief Cross-instance messaging system
* This allows you to send messages to the "main" instance of ImHex running, from any other instance
*/
namespace Messaging {
namespace impl {
using MessagingHandler = std::function<void(const std::vector<u8> &)>;
std::map<std::string, MessagingHandler> &getHandlers();
void runHandler(const std::string &eventName, const std::vector<u8> &args);
}
/**
* @brief Register the handler for this specific event name
*/
void registerHandler(const std::string &eventName, const impl::MessagingHandler &handler);
}
}

View File

@@ -413,9 +413,6 @@ namespace hex {
* @brief Clear all shortcuts
*/
static void clearShortcuts();
private:
static std::map<Shortcut, std::function<void()>> s_globalShortcuts;
};
}

View File

@@ -18,22 +18,48 @@ namespace hex {
std::fs::path path;
};
/**
* @brief Save the current layout
* @param name Name of the layout
*/
static void save(const std::string &name);
/**
* @brief Load a layout from a file
* @param path Path to the layout file
*/
static void load(const std::fs::path &path);
/**
* @brief Load a layout from a string
* @param content Layout string
*/
static void loadString(const std::string &content);
/**
* @brief Get a list of all layouts
* @return List of all added layouts
*/
static std::vector<Layout> getLayouts();
/**
* @brief Handles loading of layouts if needed
* @note This function should only be called by ImHex
*/
static void process();
/**
* @brief Reload all layouts
*/
static void reload();
/**
* @brief Reset the layout manager
*/
static void reset();
private:
LayoutManager() = default;
static std::optional<std::fs::path> s_layoutPathToLoad;
static std::optional<std::string> s_layoutStringToLoad;
static std::vector<Layout> s_layouts;
};
}

View File

@@ -39,11 +39,10 @@ namespace hex {
static void resetLanguageStrings();
static const std::string &getSelectedLanguage();
private:
std::string m_unlocalizedString;
static std::string s_fallbackLanguage;
static std::map<std::string, std::string> s_currStrings;
};
std::string operator+(const std::string &&left, const LangEntry &&right);
@@ -64,6 +63,6 @@ template<>
struct fmt::formatter<hex::LangEntry> : fmt::formatter<std::string_view> {
template<typename FormatContext>
auto format(const hex::LangEntry &entry, FormatContext &ctx) {
return fmt::formatter<std::string_view>::format(entry, ctx);
return fmt::formatter<std::string_view>::format(entry.get(), ctx);
}
};

View File

@@ -5,6 +5,7 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/fs.hpp>
#include <span>
#include <string>
#if defined(OS_WINDOWS)
@@ -17,6 +18,12 @@ struct ImGuiContext;
namespace hex {
struct SubCommand {
std::string commandKey;
std::string commandDesc;
std::function<void(const std::vector<std::string>&)> callback;
};
class Plugin {
public:
explicit Plugin(const std::fs::path &path);
@@ -36,6 +43,8 @@ namespace hex {
[[nodiscard]] bool isLoaded() const;
[[nodiscard]] std::span<SubCommand> getSubCommands() const;
private:
using InitializePluginFunc = void (*)();
using GetPluginNameFunc = const char *(*)();
@@ -44,6 +53,7 @@ namespace hex {
using GetCompatibleVersionFunc = const char *(*)();
using SetImGuiContextFunc = void (*)(ImGuiContext *);
using IsBuiltinPluginFunc = bool (*)();
using GetSubCommandsFunc = void* (*)();
#if defined(OS_WINDOWS)
HMODULE m_handle = nullptr;
@@ -61,6 +71,7 @@ namespace hex {
GetCompatibleVersionFunc m_getCompatibleVersionFunction = nullptr;
SetImGuiContextFunc m_setImGuiContextFunction = nullptr;
IsBuiltinPluginFunc m_isBuiltinPluginFunction = nullptr;
GetSubCommandsFunc m_getSubCommandsFunction = nullptr;
template<typename T>
[[nodiscard]] auto getPluginFunction(const std::string &symbol) {
@@ -79,13 +90,7 @@ namespace hex {
static void unload();
static void reload();
static const auto &getPlugins() {
return PluginManager::s_plugins;
}
private:
static std::fs::path s_pluginFolder;
static std::vector<Plugin> s_plugins;
static const std::vector<Plugin> &getPlugins();
};
}

View File

@@ -47,7 +47,7 @@ namespace hex {
*/
static void setProjectFunctions(
const std::function<bool(const std::fs::path&)> &loadFun,
const std::function<bool(std::optional<std::fs::path>)> &storeFun
const std::function<bool(std::optional<std::fs::path>, bool)> &storeFun
);
/**
@@ -63,10 +63,11 @@ namespace hex {
* @brief Store a project file
*
* @param filePath Path to the project file
* @param updateLocation update the project location so subssequent saves will save there
* @return true if the project file was stored successfully
* @return false if the project file was not stored successfully
*/
static bool store(std::optional<std::fs::path> filePath = std::nullopt);
static bool store(std::optional<std::fs::path> filePath = std::nullopt, bool updateLocation = true);
/**
* @brief Check if a project file is currently loaded
@@ -115,27 +116,16 @@ namespace hex {
* @brief Get the list of registered handlers
* @return List of registered handlers
*/
static std::vector<Handler>& getHandlers() {
return s_handlers;
}
static std::vector<Handler>& getHandlers();
/**
* @brief Get the list of registered per-provider handlers
* @return List of registered per-provider handlers
*/
static std::vector<ProviderHandler>& getProviderHandlers() {
return s_providerHandlers;
}
static std::vector<ProviderHandler>& getProviderHandlers();
private:
ProjectFile() = default;
static std::function<bool(const std::fs::path&)> s_loadProjectFunction;
static std::function<bool(std::optional<std::fs::path>)> s_storeProjectFunction;
static std::fs::path s_currProjectPath;
static std::vector<Handler> s_handlers;
static std::vector<ProviderHandler> s_providerHandlers;
};
}

View File

@@ -115,6 +115,11 @@ namespace hex {
std::weak_ptr<Task> m_task;
};
struct Timer {
std::chrono::time_point<std::chrono::steady_clock> elapseTime;
std::function<void()> callback;
};
/**
* @brief The Task Manager is responsible for running and managing asynchronous tasks
*/
@@ -144,7 +149,6 @@ namespace hex {
*/
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
/**
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
* @param function Function to be executed
@@ -157,6 +161,12 @@ namespace hex {
*/
static void runWhenTasksFinished(const std::function<void()> &function);
/**
* @brief Creates a callback that will be executed after the given time
* @param duration Time to wait
* @param function Function to be executed
*/
static void doAfter(std::chrono::duration<i64> duration, const std::function<void()> &function);
static void collectGarbage();
@@ -164,20 +174,10 @@ namespace hex {
static size_t getRunningBackgroundTaskCount();
static std::list<std::shared_ptr<Task>> &getRunningTasks();
static std::list<Timer> &getTimers();
static void runDeferredCalls();
private:
static std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;
static std::list<std::shared_ptr<Task>> s_tasks;
static std::list<std::shared_ptr<Task>> s_taskQueue;
static std::list<std::function<void()>> s_deferredCalls;
static std::list<std::function<void()>> s_tasksFinishedCallbacks;
static std::mutex s_queueMutex;
static std::condition_variable s_jobCondVar;
static std::vector<std::jthread> s_workers;
static void runner(const std::stop_token &stopToken);
};

View File

@@ -58,7 +58,7 @@ namespace hex {
static std::vector<std::string> getThemeNames();
static const std::string &getThemeImagePostfix();
static const std::string &getImageTheme();
static std::optional<ImColor> parseColorString(const std::string &colorString);
@@ -78,18 +78,11 @@ namespace hex {
StyleMap styleMap;
};
static std::map<std::string, ThemeHandler>& getThemeHandlers() { return s_themeHandlers; }
static std::map<std::string, StyleHandler>& getStyleHandlers() { return s_styleHandlers; }
static std::map<std::string, ThemeHandler>& getThemeHandlers();
static std::map<std::string, StyleHandler>& getStyleHandlers();
private:
ThemeManager() = default;
static std::map<std::string, nlohmann::json> s_themes;
static std::map<std::string, ThemeHandler> s_themeHandlers;
static std::map<std::string, StyleHandler> s_styleHandlers;
static std::string s_imagePostfix;
static std::string s_currTheme;
};
}

View File

@@ -51,10 +51,7 @@ namespace hex::dp {
[[nodiscard]] std::vector<u8>& getDefaultData() { return this->m_defaultData; }
static void setIdCounter(int id) {
if (id > Attribute::s_idCounter)
Attribute::s_idCounter = id;
}
static void setIdCounter(int id);
private:
int m_id;
@@ -69,8 +66,6 @@ namespace hex::dp {
friend class Node;
void setParentNode(Node *node) { this->m_parentNode = node; }
static int s_idCounter;
};
}

View File

@@ -14,16 +14,11 @@ namespace hex::dp {
[[nodiscard]] int getFromId() const { return this->m_from; }
[[nodiscard]] int getToId() const { return this->m_to; }
static void setIdCounter(int id) {
if (id > Link::s_idCounter)
Link::s_idCounter = id;
}
static void setIdCounter(int id);
private:
int m_id;
int m_from, m_to;
static int s_idCounter;
};
}

View File

@@ -69,18 +69,15 @@ namespace hex::dp {
return this->m_position;
}
static void setIdCounter(int id) {
if (id > Node::s_idCounter)
Node::s_idCounter = id;
}
static void setIdCounter(int id);
const std::vector<u8>& getBufferOnInput(u32 index);
const i128& getIntegerOnInput(u32 index);
const long double& getFloatOnInput(u32 index);
const double& getFloatOnInput(u32 index);
void setBufferOnOutput(u32 index, std::span<const u8> data);
void setIntegerOnOutput(u32 index, i128 integer);
void setFloatOnOutput(u32 index, long double floatingPoint);
void setFloatOnOutput(u32 index, double floatingPoint);
private:
int m_id;
@@ -90,8 +87,6 @@ namespace hex::dp {
prv::Overlay *m_overlay = nullptr;
ImVec2 m_position;
static int s_idCounter;
Attribute& getAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");

View File

@@ -26,9 +26,11 @@ namespace hex {
RISCV = CS_ARCH_RISCV,
MOS65XX = CS_ARCH_MOS65XX,
BPF = CS_ARCH_BPF,
SH = CS_ARCH_SH,
TRICORE = CS_ARCH_TRICORE,
#endif
MAX = CS_ARCH_MAX,
MAX = TRICORE,
MIN = ARM
};
@@ -43,7 +45,7 @@ namespace hex {
}
constexpr static auto ArchitectureNames = [](){
std::array<const char *, static_cast<u32>(Architecture::MAX)> names = { };
std::array<const char *, static_cast<u32>(Architecture::MAX) + 1> names = { };
names[CS_ARCH_ARM] = "ARM";
names[CS_ARCH_ARM64] = "AArch64";
@@ -63,6 +65,8 @@ namespace hex {
names[CS_ARCH_RISCV] = "RISC-V";
names[CS_ARCH_MOS65XX] = "MOS Technology 65xx";
names[CS_ARCH_BPF] = "Berkeley Packet Filter";
names[CS_ARCH_SH] = "SuperH";
names[CS_ARCH_TRICORE] = "Tricore";
#endif
return names;
@@ -75,7 +79,7 @@ namespace hex {
return supportedCount;
}
for (supportedCount = static_cast<i32>(Architecture::MIN); supportedCount < static_cast<i32>(Architecture::MAX); supportedCount++) {
for (supportedCount = static_cast<i32>(Architecture::MIN); supportedCount < static_cast<i32>(Architecture::MAX) + 1; supportedCount++) {
if (!cs_support(supportedCount)) {
break;
}

View File

@@ -37,11 +37,14 @@ namespace hex {
[[nodiscard]] const std::string& getTableContent() const { return this->m_tableContent; }
[[nodiscard]] const std::string& getName() const { return this->m_name; }
private:
void parse(const std::string &content);
bool m_valid = false;
std::string m_name;
std::string m_tableContent;
std::unique_ptr<std::map<size_t, std::map<std::vector<u8>, std::string>>> m_mapping;
size_t m_longestSequence = 0;

View File

@@ -16,4 +16,10 @@ namespace hex {
fmt::print(fmt::runtime(format), args...);
}
template<typename... Args>
inline void println(std::string_view format, Args... args) {
fmt::print(fmt::runtime(format), args...);
fmt::print("\n");
}
}

View File

@@ -75,8 +75,6 @@ namespace hex {
this->m_url = std::move(other.m_url);
this->m_headers = std::move(other.m_headers);
this->m_body = std::move(other.m_body);
this->m_caCert = std::move(other.m_caCert);
}
HttpRequest& operator=(HttpRequest &&other) noexcept {
@@ -88,18 +86,10 @@ namespace hex {
this->m_headers = std::move(other.m_headers);
this->m_body = std::move(other.m_body);
this->m_caCert = std::move(other.m_caCert);
return *this;
}
static void setCACert(std::string data) {
HttpRequest::s_caCertData = std::move(data);
}
static void setProxy(std::string proxy) {
HttpRequest::s_proxyUrl = std::move(proxy);
}
static void setProxy(std::string proxy);
void setMethod(std::string method) {
this->m_method = std::move(method);
@@ -286,9 +276,7 @@ namespace hex {
char *url = nullptr;
curl_easy_getinfo(this->m_curl, CURLINFO_EFFECTIVE_URL, &url);
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", this->m_method, url, u32(result), curl_easy_strerror(result));
if (!HttpRequest::s_proxyUrl.empty()){
log::info("A custom proxy '{0}' is in use. Is it working correctly?", HttpRequest::s_proxyUrl);
}
checkProxyErrors();
return { };
}
@@ -300,11 +288,13 @@ namespace hex {
return Result<T>(statusCode, { data.begin(), data.end() });
}
[[maybe_unused]] static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData);
static size_t writeToVector(void *contents, size_t size, size_t nmemb, void *userdata);
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata);
static int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
private:
static void checkProxyErrors();
private:
CURL *m_curl;
@@ -318,9 +308,6 @@ namespace hex {
std::atomic<float> m_progress = 0.0F;
std::atomic<bool> m_canceled = false;
[[maybe_unused]] std::unique_ptr<mbedtls_x509_crt> m_caCert;
static std::string s_caCertData, s_proxyUrl;
};
}

View File

@@ -20,12 +20,20 @@ namespace hex::log {
bool isRedirected();
[[maybe_unused]] void redirectToFile();
extern std::mutex s_loggerMutex;
extern std::mutex g_loggerMutex;
struct LogEntry {
std::string project;
std::string level;
std::string message;
};
std::vector<LogEntry>& getLogEntries();
}
namespace {
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
@@ -37,26 +45,33 @@ namespace hex::log {
fmt::print(dest, ts, "{0} ", level);
fmt::print(dest, "[{0}] ", IMHEX_PROJECT_NAME);
constexpr static auto ProjectNameLength = std::char_traits<char>::length(IMHEX_PROJECT_NAME);
fmt::print(dest, "{}", std::string(ProjectNameLength > 10 ? 0 : 10 - ProjectNameLength, ' '));
}
template<typename... T>
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
std::scoped_lock lock(impl::s_loggerMutex);
std::scoped_lock lock(impl::g_loggerMutex);
auto dest = impl::getDestination();
printPrefix(dest, ts, level);
fmt::print(dest, fmt::runtime(fmt), args...);
fmt::print(dest, "\n");
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}\n", message);
fflush(dest);
impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, level, std::move(message) });
}
}
[[maybe_unused]] void debug(const std::string &fmt, auto &&...args) {
#if defined(DEBUG)
hex::log::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
#else
hex::unused(fmt, args...);
#endif
#if defined(DEBUG)
hex::log::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
#else
impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, "[DEBUG]", fmt::format(fmt::runtime(fmt), args...) });
#endif
}
[[maybe_unused]] void info(const std::string &fmt, auto &&...args) {

View File

@@ -0,0 +1,9 @@
#pragma once
#if defined(OS_LINUX)
namespace hex {
void executeCmd(const std::vector<std::string> &argsVector);
}
#endif

View File

@@ -1,9 +1,14 @@
#pragma once
#include <string>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex.hpp>
#include <hex/api/plugin_manager.hpp>
#include <wolv/utils/string.hpp>
/**
* This macro is used to define all the required entry points for a plugin.
@@ -21,3 +26,20 @@
GImGui = ctx; \
} \
extern "C" [[gnu::visibility("default")]] void initializePlugin()
/**
* This macro is used to define subcommands defined by the plugin
* A subcommand consists of a key, a description, and a callback
* The key is what the first argument to ImHex should be, prefixed by `--`
* For example, if the key if `help`, ImHex should be started with `--help` as its first argument to trigger the subcommand
* when the subcommand is triggerred, it's callback will be executed. The callback is executed BEFORE most of ImHex initialization
* so to do anything meaningful, you should subscribe to an event (like EventImHexStartupFinished) and run your code there.
*/
#define IMHEX_PLUGIN_SUBCOMMANDS() IMHEX_PLUGIN_SUBCOMMANDS_IMPL()
#define IMHEX_PLUGIN_SUBCOMMANDS_IMPL() \
extern std::vector<hex::SubCommand> g_subCommands; \
extern "C" [[gnu::visibility("default")]] void* getSubCommands() { \
return &g_subCommands; \
} \
std::vector<hex::SubCommand> g_subCommands

View File

@@ -36,11 +36,68 @@ namespace hex::prv {
Provider();
virtual ~Provider();
/**
* @brief Opens this provider
* @note The return value of this function allows to ensure the provider is available,
* so calling Provider::isAvailable() just after a call to open() that returned true is redundant.
* @note This is not related to the EventProviderOpened event
* @return true if the provider was opened successfully, else false
*/
[[nodiscard]] virtual bool open() = 0;
/**
* @brief Closes this provider
* @note This function is called when the user requests for a provider to be closed, e.g. by closing a tab.
* In general, this function should close the underlying data source but leave the provider in a state where
* it can be opened again later by calling the open() function again.
*/
virtual void close() = 0;
/**
* @brief Checks if this provider is open and can be used to access data
* @return Generally, if the open() function succeeded and the data source was successfully opened, this
* function should return true
*/
[[nodiscard]] virtual bool isAvailable() const = 0;
/**
* @brief Checks if the data in this provider can be read
* @return True if the provider is readable, false otherwise
*/
[[nodiscard]] virtual bool isReadable() const = 0;
/**
* @brief Controls if the user can write data to this specific provider.
* This may be false for e.g. a file opened in read-only
*/
[[nodiscard]] virtual bool isWritable() const = 0;
/**
* @brief Controls if the user can resize this provider
* @return True if the provider is resizable, false otherwise
*/
[[nodiscard]] virtual bool isResizable() const = 0;
[[nodiscard]] virtual bool isSavable() const = 0;
/**
* @brief Controls whether the provider can be saved ("saved", not "saved as")
* This is mainly used by providers that aren't buffered, and so don't need to be saved
* This function will usually return false for providers that aren't writable, but this isn't guaranted
*/
[[nodiscard]] virtual bool isSavable() const = 0;
/**
* @brief Controls whether we can dump data from this provider (e.g. "save as", or "export -> ..").
* Typically disabled for process with sparse data, like the Process memory provider
* where the virtual address space is several TiBs large.
* Default implementation returns true.
*/
[[nodiscard]] virtual bool isDumpable() const;
/**
* @brief Controls whether this provider can be saved as a recent entry
* Typically used for providers that do not retain data, e.g. the memory provider
*/
[[nodiscard]] virtual bool isSavableAsRecent() const { return true; }
/**
* @brief Read data from this provider, applying overlays and patches
@@ -59,20 +116,13 @@ namespace hex::prv {
*/
virtual void write(u64 offset, const void *buffer, size_t size);
virtual void resize(size_t newSize);
virtual void insert(u64 offset, size_t size);
virtual void remove(u64 offset, size_t size);
virtual void save();
virtual void saveAs(const std::fs::path &path);
/**
* @brief Read data from this provider, without applying overlays and patches
* @param offset offset to start reading the data
* @param buffer buffer to write read data
* @param size number of bytes to read
*/
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
/**
* @brief Write data directly to this provider
* @param offset offset to start writing the data
@@ -80,7 +130,39 @@ namespace hex::prv {
* @param size number of bytes to write
*/
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
[[nodiscard]] virtual size_t getActualSize() const = 0;
/**
* @brief Get the full size of the data in this provider
* @return The size of the entire available data of this provider
*/
[[nodiscard]] virtual size_t getActualSize() const = 0;
/**
* @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"
* @return The provider's type name
*/
[[nodiscard]] virtual std::string getTypeName() const = 0;
/**
* @brief Gets a human readable representation of the current provider
* @note This is mainly used to display the provider in the UI. For example, the file provider
* will return the file name here
* @return The name of the current provider
*/
[[nodiscard]] virtual std::string getName() const = 0;
virtual void resize(size_t newSize);
virtual void insert(u64 offset, size_t size);
virtual void remove(u64 offset, size_t size);
virtual void save();
virtual void saveAs(const std::fs::path &path);
void applyOverlays(u64 offset, void *buffer, size_t size);
@@ -90,7 +172,7 @@ namespace hex::prv {
[[nodiscard]] Overlay *newOverlay();
void deleteOverlay(Overlay *overlay);
[[nodiscard]] const std::list<Overlay *> &getOverlays();
[[nodiscard]] const std::list<std::unique_ptr<Overlay>> &getOverlays();
[[nodiscard]] size_t getPageSize() const;
void setPageSize(size_t pageSize);
@@ -105,20 +187,9 @@ namespace hex::prv {
[[nodiscard]] virtual size_t getSize() const;
[[nodiscard]] virtual std::optional<u32> getPageOfAddress(u64 address) const;
[[nodiscard]] virtual std::string getName() const = 0;
[[nodiscard]] virtual std::vector<Description> getDataDescription() const = 0;
[[nodiscard]] virtual std::vector<Description> getDataDescription() const;
[[nodiscard]] virtual std::variant<std::string, i128> queryInformation(const std::string &category, const std::string &argument);
/**
* @brief Opens this provider
* the return value of this function allows to ensure the provider is available,
* so calling Provider::isAvailable() just after a call to open() that returned true is dedundant.
* @note This is not related to the EventProviderOpened event
* @return true if the provider was opened sucessfully, else false
*/
[[nodiscard]] virtual bool open() = 0;
virtual void close() = 0;
void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false);
void createUndoPoint();
@@ -131,9 +202,7 @@ namespace hex::prv {
[[nodiscard]] virtual bool hasFilePicker() const;
virtual bool handleFilePicker();
virtual std::vector<MenuEntry> getMenuEntries() {
return { };
};
virtual std::vector<MenuEntry> getMenuEntries() { return { }; }
[[nodiscard]] virtual bool hasLoadInterface() const;
[[nodiscard]] virtual bool hasInterface() const;
@@ -146,8 +215,6 @@ namespace hex::prv {
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings = { }) const;
virtual void loadSettings(const nlohmann::json &settings);
[[nodiscard]] virtual std::string getTypeName() const = 0;
void markDirty(bool dirty = true) { this->m_dirty = dirty; }
[[nodiscard]] bool isDirty() const { return this->m_dirty; }
@@ -165,7 +232,7 @@ namespace hex::prv {
std::list<std::map<u64, u8>> m_patches;
decltype(m_patches)::iterator m_currPatches;
std::list<Overlay *> m_overlays;
std::list<std::unique_ptr<Overlay>> m_overlays;
u32 m_id;
@@ -187,9 +254,6 @@ namespace hex::prv {
std::string m_errorMessage;
size_t m_pageSize = MaxPageSize;
private:
static u32 s_idCounter;
};
}

View File

@@ -82,6 +82,22 @@ namespace hex {
EventManager::subscribe<EventImHexClosing>(this, [this] {
this->m_data.clear();
});
// moves the data of this PerProvider instance from one provider to another
EventManager::subscribe<MovePerProviderData>(this, [this](prv::Provider *from, prv::Provider *to) {
// get the value from the old provider, (removes it from the map)
auto node = m_data.extract(from);
// ensure the value existed
if (node.empty()) return;
// delete the value from the new provider, that we want to replace
this->m_data.erase(to);
// re-insert it with the key of the new provider
node.key() = to;
this->m_data.insert(std::move(node));
});
}
void onDestroy() {

View File

@@ -0,0 +1,30 @@
#pragma once
#include<vector>
#include<string>
#include<functional>
namespace hex::subcommands {
/**
* @brief Internal method - takes all the arguments ImHex received from the command line,
* and determine which subcommands to run, with which arguments.
* In some cases, the subcommand or this function directly might exit the program
* (e.g. --help, or when forwarding providers to open to another instance)
* and so this function might not return
*/
void processArguments(const std::vector<std::string> &args);
/**
* @brief Forward the given command to the main instance (might be this instance)
* The callback will be executed after EventImHexStartupFinished
*/
void forwardSubCommand(const std::string &cmdName, const std::vector<std::string> &args);
using ForwardCommandHandler = std::function<void(const std::vector<std::string> &)>;
/**
* @brief Register the handler for this specific command name
*/
void registerSubCommand(const std::string &cmdName, const ForwardCommandHandler &handler);
}

View File

@@ -2,14 +2,18 @@
#include <hex.hpp>
#include <cstddef>
#include <functional>
#include <string>
#include <span>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex/helpers/fmt.hpp>
#include <wolv/utils/string.hpp>
enum ImGuiCustomCol {
ImGuiCustomCol_DescButton,
ImGuiCustomCol_DescButtonHovered,
@@ -46,6 +50,7 @@ namespace ImGui {
public:
Texture() = default;
Texture(const ImU8 *buffer, int size, int width = 0, int height = 0);
Texture(std::span<const std::byte> bytes, int width = 0, int height = 0);
explicit Texture(const char *path);
Texture(unsigned int texture, int width, int height);
Texture(const Texture&) = delete;
@@ -141,6 +146,24 @@ namespace ImGui {
ImGui::TextUnformatted(hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
}
inline void TextFormattedSelectable(const std::string &fmt, auto &&...args) {
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
ImGui::PushID(text.c_str());
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::PopItemWidth();
ImGui::PopStyleColor();
ImGui::PopStyleVar();
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());
}
@@ -153,6 +176,35 @@ namespace ImGui {
ImGui::TextWrapped("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
}
inline void TextFormattedWrappedSelectable(const std::string &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)...),
ImGui::CalcTextSize("M").x,
ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ScrollbarSize - ImGui::GetStyle().FrameBorderSize
);
ImGui::PushID(text.c_str());
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
ImGui::PushItemWidth(-FLT_MIN);
ImGui::InputTextMultiline(
"##",
const_cast<char *>(text.c_str()),
text.size(),
ImVec2(0, -FLT_MIN),
ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll
);
ImGui::PopItemWidth();
ImGui::PopStyleColor();
ImGui::PopStyleVar();
ImGui::PopID();
}
inline void TextFormattedCentered(const std::string &fmt, auto &&...args) {
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
auto availableSpace = ImGui::GetContentRegionAvail();
@@ -165,6 +217,18 @@ namespace ImGui {
ImGui::PopTextWrapPos();
}
inline void TextFormattedCenteredHorizontal(const std::string &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);
ImGui::SetCursorPosX(((availableSpace - textSize) / 2.0F).x);
ImGui::PushTextWrapPos(availableSpace.x * 0.75F);
ImGui::TextFormattedWrapped("{}", text);
ImGui::PopTextWrapPos();
}
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
@@ -179,5 +243,7 @@ namespace ImGui {
bool DimmedButton(const char* label);
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
bool DimmedIconToggle(const char *icon, bool *v);
void TextOverlay(const char *text, ImVec2 pos);
}

View File

@@ -34,9 +34,7 @@ namespace hex {
return { 0, 0 };
}
[[nodiscard]] static std::vector<std::unique_ptr<PopupBase>> &getOpenPopups() {
return s_openPopups;
}
[[nodiscard]] static std::vector<std::unique_ptr<PopupBase>> &getOpenPopups();
[[nodiscard]] const std::string &getUnlocalizedName() const {
return this->m_unlocalizedName;
@@ -58,9 +56,6 @@ namespace hex {
return this->m_close;
}
protected:
static std::vector<std::unique_ptr<PopupBase>> s_openPopups;
private:
std::string m_unlocalizedName;
@@ -84,7 +79,7 @@ namespace hex {
auto popup = std::make_unique<T>(std::forward<Args>(args)...);
s_openPopups.emplace_back(std::move(popup));
getOpenPopups().emplace_back(std::move(popup));
}
};

View File

@@ -51,20 +51,17 @@ namespace hex {
return LangEntry(unlocalizedName) + "###" + unlocalizedName;
}
static ImFontAtlas *getFontAtlas() { return View::s_fontAtlas; }
static void setFontAtlas(ImFontAtlas *atlas) { View::s_fontAtlas = atlas; }
static ImFontAtlas *getFontAtlas();
static void setFontAtlas(ImFontAtlas *atlas);
static ImFontConfig getFontConfig() { return View::s_fontConfig; }
static void setFontConfig(ImFontConfig config) { View::s_fontConfig = config; }
static ImFontConfig getFontConfig();
static void setFontConfig(ImFontConfig config);
private:
std::string m_unlocalizedViewName;
bool m_windowOpen = false;
std::map<Shortcut, std::function<void()>> m_shortcuts;
static ImFontAtlas *s_fontAtlas;
static ImFontConfig s_fontConfig;
friend class ShortcutManager;
};

View File

@@ -0,0 +1,223 @@
#include <hex/api/achievement_manager.hpp>
#include <nlohmann/json.hpp>
namespace hex {
std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>> &AchievementManager::getAchievements() {
static std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>> achievements;
return achievements;
}
std::unordered_map<std::string, std::list<AchievementManager::AchievementNode>>& AchievementManager::getAchievementNodes(bool rebuild) {
static std::unordered_map<std::string, std::list<AchievementNode>> nodeCategoryStorage;
if (!nodeCategoryStorage.empty() || !rebuild)
return nodeCategoryStorage;
nodeCategoryStorage.clear();
// Add all achievements to the node storage
for (auto &[categoryName, achievements] : getAchievements()) {
auto &nodes = nodeCategoryStorage[categoryName];
for (auto &[achievementName, achievement] : achievements) {
nodes.emplace_back(achievement.get());
}
}
return nodeCategoryStorage;
}
std::unordered_map<std::string, std::vector<AchievementManager::AchievementNode*>>& AchievementManager::getAchievementStartNodes(bool rebuild) {
static std::unordered_map<std::string, std::vector<AchievementNode*>> startNodes;
if (!startNodes.empty() || !rebuild)
return startNodes;
auto &nodeCategoryStorage = getAchievementNodes();
startNodes.clear();
// Add all parents and children to the nodes
for (auto &[categoryName, achievements] : nodeCategoryStorage) {
for (auto &achievementNode : achievements) {
for (auto &requirement : achievementNode.achievement->getRequirements()) {
for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) {
auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) {
return node.achievement->getUnlocalizedName() == requirement;
});
if (iter != requirementAchievements.end()) {
achievementNode.parents.emplace_back(&*iter);
iter->children.emplace_back(&achievementNode);
}
}
}
for (auto &requirement : achievementNode.achievement->getVisibilityRequirements()) {
for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) {
auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) {
return node.achievement->getUnlocalizedName() == requirement;
});
if (iter != requirementAchievements.end()) {
achievementNode.visibilityParents.emplace_back(&*iter);
}
}
}
}
}
for (auto &[categoryName, achievements] : nodeCategoryStorage) {
for (auto &achievementNode : achievements) {
if (!achievementNode.hasParents()) {
startNodes[categoryName].emplace_back(&achievementNode);
}
for (const auto &parent : achievementNode.parents) {
if (parent->achievement->getUnlocalizedCategory() != achievementNode.achievement->getUnlocalizedCategory())
startNodes[categoryName].emplace_back(&achievementNode);
}
}
}
return startNodes;
}
void AchievementManager::unlockAchievement(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
auto &categories = getAchievements();
auto categoryIter = categories.find(unlocalizedCategory);
if (categoryIter == categories.end()) {
return;
}
auto &[categoryName, achievements] = *categoryIter;
auto achievementIter = achievements.find(unlocalizedName);
if (achievementIter == achievements.end()) {
return;
}
auto &nodes = getAchievementNodes()[categoryName];
for (const auto &node : nodes) {
auto &achievement = node.achievement;
if (achievement->getUnlocalizedCategory() != unlocalizedCategory) {
continue;
}
if (achievement->getUnlocalizedName() != unlocalizedName) {
continue;
}
if (node.achievement->isUnlocked()) {
return;
}
for (const auto &requirement : node.parents) {
if (!requirement->achievement->isUnlocked()) {
return;
}
}
achievement->setUnlocked(true);
if (achievement->isUnlocked())
EventManager::post<EventAchievementUnlocked>(*achievement);
}
}
void AchievementManager::clear() {
getAchievements().clear();
getAchievementStartNodes(false).clear();
getAchievementNodes(false).clear();
}
void AchievementManager::clearTemporary() {
auto &categories = getAchievements();
for (auto &[categoryName, achievements] : categories) {
std::erase_if(achievements, [](auto &data) {
auto &[achievementName, achievement] = data;
return achievement->isTemporary();
});
}
std::erase_if(categories, [](auto &data) {
auto &[categoryName, achievements] = data;
return achievements.empty();
});
getAchievementStartNodes(false).clear();
getAchievementNodes(false).clear();
}
void AchievementManager::achievementAdded() {
getAchievementStartNodes(false).clear();
getAchievementNodes(false).clear();
}
constexpr static auto AchievementsFile = "achievements.json";
void AchievementManager::loadProgress() {
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
auto path = directory / AchievementsFile;
if (!wolv::io::fs::exists(path)) {
continue;
}
wolv::io::File file(path, wolv::io::File::Mode::Read);
if (!file.isValid()) {
continue;
}
try {
auto json = nlohmann::json::parse(file.readString());
for (const auto &[categoryName, achievements] : getAchievements()) {
for (const auto &[achievementName, achievement] : achievements) {
try {
achievement->setProgress(json[categoryName][achievementName]);
} catch (const std::exception &e) {
log::warn("Failed to load achievement progress for '{}::{}': {}", categoryName, achievementName, e.what());
}
}
}
} catch (const std::exception &e) {
log::error("Failed to load achievements: {}", e.what());
}
}
}
void AchievementManager::storeProgress() {
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
auto path = directory / AchievementsFile;
wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid()) {
continue;
}
nlohmann::json json;
for (const auto &[categoryName, achievements] : getAchievements()) {
json[categoryName] = nlohmann::json::object();
for (const auto &[achievementName, achievement] : achievements) {
json[categoryName][achievementName] = achievement->getProgress();
}
}
file.writeString(json.dump(4));
break;
}
}
}

View File

@@ -12,6 +12,7 @@
#include <nlohmann/json.hpp>
#include <wolv/io/file.hpp>
#include <wolv/utils/string.hpp>
namespace hex {
@@ -65,6 +66,11 @@ namespace hex {
}
void store() {
// During a crash settings can be empty, causing them to be overwritten.
if(getSettingsData().empty()) {
return;
}
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
@@ -301,7 +307,7 @@ namespace hex {
}
runtime.addDefine("__IMHEX__");
runtime.addDefine("__IMHEX_VERSION__", IMHEX_VERSION);
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion());
}
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
@@ -336,6 +342,11 @@ namespace hex {
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
}
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
log::debug("Registered new inline pattern visualizer function: {}", name);
impl::getInlineVisualizers()[name] = impl::Visualizer { parameterCount, function };
}
namespace impl {
@@ -345,6 +356,12 @@ namespace hex {
return visualizers;
}
std::map<std::string, impl::Visualizer> &getInlineVisualizers() {
static std::map<std::string, impl::Visualizer> visualizers;
return visualizers;
}
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
static std::map<std::string, pl::api::PragmaHandler> pragmas;

View File

@@ -2,7 +2,17 @@
namespace hex {
EventManager::EventList EventManager::s_events;
std::map<void *, EventManager::EventList::iterator> EventManager::s_tokenStore;
std::map<void *, EventManager::EventList::iterator>& EventManager::getTokenStore() {
static std::map<void *, EventManager::EventList::iterator> tokenStore;
return tokenStore;
}
EventManager::EventList& EventManager::getEvents() {
static EventManager::EventList events;
return events;
}
}

View File

@@ -255,6 +255,10 @@ namespace hex {
}
}
i64 getCurrentProviderIndex() {
return s_currentProvider;
}
bool isValid() {
return !s_providers.empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers.size());
}
@@ -335,8 +339,16 @@ namespace hex {
namespace ImHexApi::System {
namespace impl {
// default to true means we forward to ourselves by default
static bool s_isMainInstance = true;
void setMainInstanceStatus(bool status) {
s_isMainInstance = status;
}
static ImVec2 s_mainWindowPos;
static ImVec2 s_mainWindowSize;
void setMainWindowPosition(i32 x, i32 y) {
@@ -364,13 +376,6 @@ namespace hex {
}
static ProgramArguments s_programArguments;
void setProgramArguments(int argc, char **argv, char **envp) {
s_programArguments.argc = argc;
s_programArguments.argv = argv;
s_programArguments.envp = envp;
}
static bool s_borderlessWindowMode;
void setBorderlessWindowMode(bool enabled) {
s_borderlessWindowMode = enabled;
@@ -405,6 +410,10 @@ namespace hex {
}
bool isMainInstance() {
return impl::s_isMainInstance;
}
void closeImHex(bool noQuestions) {
EventManager::post<RequestCloseImHex>(noQuestions);
}
@@ -418,25 +427,6 @@ namespace hex {
EventManager::post<EventSetTaskBarIconState>(u32(state), u32(type), progress);
}
const ProgramArguments &getProgramArguments() {
return impl::s_programArguments;
}
std::optional<std::u8string> getProgramArgument(int index) {
if (index >= impl::s_programArguments.argc) {
return std::nullopt;
}
#if defined(OS_WINDOWS)
std::wstring wideArg = ::CommandLineToArgvW(::GetCommandLineW(), &impl::s_programArguments.argc)[index];
std::string byteArg = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(wideArg);
return std::u8string(byteArg.begin(), byteArg.end());
#else
return std::u8string(reinterpret_cast<const char8_t *>(impl::s_programArguments.argv[index]));
#endif
}
static float s_targetFPS = 14.0F;
@@ -480,7 +470,7 @@ namespace hex {
return initArgs;
}
const std::fs::path &getCustomFontPath() {
std::fs::path &getCustomFontPath() {
return impl::s_customFontPath;
}
@@ -504,13 +494,13 @@ namespace hex {
}
static std::vector<std::fs::path> s_additionalFolderPaths;
const std::vector<std::fs::path> &getAdditionalFolderPaths() {
return s_additionalFolderPaths;
std::vector<std::fs::path> &getAdditionalFolderPaths() {
static std::vector<std::fs::path> additionalFolderPaths;
return additionalFolderPaths;
}
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths) {
s_additionalFolderPaths = paths;
getAdditionalFolderPaths() = paths;
}
@@ -586,6 +576,71 @@ namespace hex {
#endif
}
std::string getImHexVersion() {
#if defined IMHEX_VERSION
return IMHEX_VERSION;
#else
return "Unknown";
#endif
}
std::string getCommitHash(bool longHash) {
if (longHash) {
#if defined GIT_COMMIT_HASH_LONG
return GIT_COMMIT_HASH_LONG;
#else
return "Unknown";
#endif
}
else {
#if defined GIT_COMMIT_HASH_SHORT
return GIT_COMMIT_HASH_SHORT;
#else
return "Unknown";
#endif
}
}
std::string getCommitBranch() {
#if defined GIT_BRANCH
return GIT_BRANCH;
#else
return "Unknown";
#endif
}
}
namespace ImHexApi::Messaging {
namespace impl {
std::map<std::string, MessagingHandler> &getHandlers() {
static std::map<std::string, MessagingHandler> handlers;
return handlers;
}
void runHandler(const std::string &eventName, const std::vector<u8> &args) {
const auto& handlers = impl::getHandlers();
auto matchHandler = handlers.find(eventName);
if (matchHandler == handlers.end()) {
log::error("Forward event handler {} not found", eventName);
} else {
matchHandler->second(args);
}
}
}
void registerHandler(const std::string &eventName, const impl::MessagingHandler &handler) {
log::debug("Registered new forward event handler: {}", eventName);
impl::getHandlers().insert({ eventName, handler });
}
}
}

View File

@@ -5,10 +5,15 @@
namespace hex {
std::map<Shortcut, std::function<void()>> ShortcutManager::s_globalShortcuts;
namespace {
std::map<Shortcut, std::function<void()>> s_globalShortcuts;
}
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::function<void()> &callback) {
ShortcutManager::s_globalShortcuts.insert({ shortcut, callback });
s_globalShortcuts.insert({ shortcut, callback });
}
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::function<void()> &callback) {
@@ -48,16 +53,16 @@ namespace hex {
void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode);
if (ShortcutManager::s_globalShortcuts.contains(pressedShortcut + AllowWhileTyping)) {
ShortcutManager::s_globalShortcuts[pressedShortcut + AllowWhileTyping]();
} else if (ShortcutManager::s_globalShortcuts.contains(pressedShortcut)) {
if (s_globalShortcuts.contains(pressedShortcut + AllowWhileTyping)) {
s_globalShortcuts[pressedShortcut + AllowWhileTyping]();
} else if (s_globalShortcuts.contains(pressedShortcut)) {
if (!ImGui::GetIO().WantTextInput)
ShortcutManager::s_globalShortcuts[pressedShortcut]();
s_globalShortcuts[pressedShortcut]();
}
}
void ShortcutManager::clearShortcuts() {
ShortcutManager::s_globalShortcuts.clear();
s_globalShortcuts.clear();
}
}

View File

@@ -9,9 +9,14 @@
namespace hex {
std::optional<std::fs::path> LayoutManager::s_layoutPathToLoad;
std::optional<std::string> LayoutManager::s_layoutStringToLoad;
std::vector<LayoutManager::Layout> LayoutManager::s_layouts;
namespace {
std::optional<std::fs::path> s_layoutPathToLoad;
std::optional<std::string> s_layoutStringToLoad;
std::vector<LayoutManager::Layout> s_layouts;
}
void LayoutManager::load(const std::fs::path &path) {
s_layoutPathToLoad = path;

View File

@@ -4,8 +4,14 @@
namespace hex {
std::string LangEntry::s_fallbackLanguage;
std::map<std::string, std::string> LangEntry::s_currStrings;
namespace {
std::string s_fallbackLanguage;
std::string s_selectedLanguage;
std::map<std::string, std::string> s_currStrings;
}
LanguageDefinition::LanguageDefinition(std::map<std::string, std::string> &&entries) {
for (const auto &[key, value] : entries) {
@@ -66,7 +72,7 @@ namespace hex {
}
const std::string &LangEntry::get() const {
auto &lang = LangEntry::s_currStrings;
auto &lang = s_currStrings;
if (lang.contains(this->m_unlocalizedString))
return lang[this->m_unlocalizedString];
else
@@ -74,7 +80,7 @@ namespace hex {
}
void LangEntry::loadLanguage(const std::string &language) {
LangEntry::s_currStrings.clear();
s_currStrings.clear();
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
@@ -82,13 +88,15 @@ namespace hex {
return;
for (auto &definition : definitions[language])
LangEntry::s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end());
s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end());
const auto fallbackLanguage = LangEntry::getFallbackLanguage();
if (language != fallbackLanguage) {
for (auto &definition : definitions[fallbackLanguage])
LangEntry::s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end());
s_currStrings.insert(definition.getEntries().begin(), definition.getEntries().end());
}
s_selectedLanguage = language;
}
const std::map<std::string, std::string> &LangEntry::getSupportedLanguages() {
@@ -96,15 +104,20 @@ namespace hex {
}
void LangEntry::setFallbackLanguage(const std::string &language) {
LangEntry::s_fallbackLanguage = language;
s_fallbackLanguage = language;
}
const std::string &LangEntry::getFallbackLanguage() {
return LangEntry::s_fallbackLanguage;
return s_fallbackLanguage;
}
void LangEntry::resetLanguageStrings() {
LangEntry::s_currStrings.clear();
s_currStrings.clear();
s_selectedLanguage.clear();
}
const std::string &LangEntry::getSelectedLanguage() {
return s_selectedLanguage;
}
}

View File

@@ -1,4 +1,5 @@
#include <hex/api/plugin_manager.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
@@ -14,7 +15,7 @@ namespace hex {
#if defined(OS_WINDOWS)
this->m_handle = LoadLibraryW(path.c_str());
if (this->m_handle == nullptr) {
if (this->m_handle == INVALID_HANDLE_VALUE || this->m_handle == nullptr) {
log::error("LoadLibraryW failed: {}!", std::system_category().message(::GetLastError()));
return;
}
@@ -34,6 +35,7 @@ namespace hex {
this->m_getCompatibleVersionFunction = getPluginFunction<GetCompatibleVersionFunc>("getCompatibleVersion");
this->m_setImGuiContextFunction = getPluginFunction<SetImGuiContextFunc>("setImGuiContext");
this->m_isBuiltinPluginFunction = getPluginFunction<IsBuiltinPluginFunc>("isBuiltinPlugin");
this->m_getSubCommandsFunction = getPluginFunction<GetSubCommandsFunc>("getSubCommands");
}
Plugin::Plugin(Plugin &&other) noexcept {
@@ -47,6 +49,7 @@ namespace hex {
this->m_getCompatibleVersionFunction = other.m_getCompatibleVersionFunction;
this->m_setImGuiContextFunction = other.m_setImGuiContextFunction;
this->m_isBuiltinPluginFunction = other.m_isBuiltinPluginFunction;
this->m_getSubCommandsFunction = other.m_getSubCommandsFunction;
other.m_handle = nullptr;
other.m_initializePluginFunction = nullptr;
@@ -56,6 +59,7 @@ namespace hex {
other.m_getCompatibleVersionFunction = nullptr;
other.m_setImGuiContextFunction = nullptr;
other.m_isBuiltinPluginFunction = nullptr;
other.m_getSubCommandsFunction = nullptr;
}
Plugin::~Plugin() {
@@ -72,14 +76,28 @@ namespace hex {
if (this->m_handle == nullptr)
return false;
const auto pluginName = wolv::util::toUTF8String(this->m_path.filename());
const auto requestedVersion = getCompatibleVersion();
if (requestedVersion != IMHEX_VERSION) {
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", wolv::util::toUTF8String(this->m_path.filename()), requestedVersion);
return false;
if (requestedVersion != ImHexApi::System::getImHexVersion()) {
if (requestedVersion.empty()) {
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(this->m_path.filename()));
} else {
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", wolv::util::toUTF8String(this->m_path.filename()), requestedVersion);
return false;
}
}
if (this->m_initializePluginFunction != nullptr) {
this->m_initializePluginFunction();
try {
this->m_initializePluginFunction();
} catch (const std::exception &e) {
log::error("Plugin '{}' threw an exception on init: {}", pluginName, e.what());
return false;
} catch (...) {
log::error("Plugin '{}' threw an exception on init", pluginName);
return false;
}
} else {
return false;
}
@@ -136,6 +154,14 @@ namespace hex {
return this->m_initialized;
}
std::span<SubCommand> Plugin::getSubCommands() const {
if (this->m_getSubCommandsFunction != nullptr) {
auto result = this->m_getSubCommandsFunction();
return *reinterpret_cast<std::vector<SubCommand>*>(result);
} else
return { };
}
void *Plugin::getPluginFunction(const std::string &symbol) {
#if defined(OS_WINDOWS)
@@ -146,34 +172,42 @@ namespace hex {
}
std::fs::path PluginManager::s_pluginFolder;
std::vector<Plugin> PluginManager::s_plugins;
namespace {
std::fs::path s_pluginFolder;
std::vector<Plugin> s_plugins;
}
bool PluginManager::load(const std::fs::path &pluginFolder) {
if (!wolv::io::fs::exists(pluginFolder))
return false;
PluginManager::s_pluginFolder = pluginFolder;
s_pluginFolder = pluginFolder;
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug")
PluginManager::s_plugins.emplace_back(pluginPath.path());
s_plugins.emplace_back(pluginPath.path());
}
if (PluginManager::s_plugins.empty())
if (s_plugins.empty())
return false;
return true;
}
void PluginManager::unload() {
PluginManager::s_plugins.clear();
PluginManager::s_pluginFolder.clear();
s_plugins.clear();
s_pluginFolder.clear();
}
void PluginManager::reload() {
PluginManager::unload();
PluginManager::load(PluginManager::s_pluginFolder);
PluginManager::load(s_pluginFolder);
}
const std::vector<Plugin> &PluginManager::getPlugins() {
return s_plugins;
}
}

View File

@@ -11,44 +11,57 @@
namespace hex {
std::vector<ProjectFile::Handler> ProjectFile::s_handlers;
std::vector<ProjectFile::ProviderHandler> ProjectFile::s_providerHandlers;
namespace {
std::fs::path ProjectFile::s_currProjectPath;
std::vector<ProjectFile::Handler> s_handlers;
std::vector<ProjectFile::ProviderHandler> s_providerHandlers;
std::fs::path s_currProjectPath;
std::function<bool(const std::fs::path&)> s_loadProjectFunction;
std::function<bool(std::optional<std::fs::path>, bool)> s_storeProjectFunction;
}
std::function<bool(const std::fs::path&)> ProjectFile::s_loadProjectFunction;
std::function<bool(std::optional<std::fs::path>)> ProjectFile::s_storeProjectFunction;
void ProjectFile::setProjectFunctions(
const std::function<bool(const std::fs::path&)> &loadFun,
const std::function<bool(std::optional<std::fs::path>)> &storeFun
const std::function<bool(std::optional<std::fs::path>, bool)> &storeFun
) {
ProjectFile::s_loadProjectFunction = loadFun;
ProjectFile::s_storeProjectFunction = storeFun;
s_loadProjectFunction = loadFun;
s_storeProjectFunction = storeFun;
}
bool ProjectFile::load(const std::fs::path &filePath) {
return s_loadProjectFunction(filePath);
}
bool ProjectFile::store(std::optional<std::fs::path> filePath) {
return s_storeProjectFunction(filePath);
bool ProjectFile::store(std::optional<std::fs::path> filePath, bool updateLocation) {
return s_storeProjectFunction(filePath, updateLocation);
}
bool ProjectFile::hasPath() {
return !ProjectFile::s_currProjectPath.empty();
return !s_currProjectPath.empty();
}
void ProjectFile::clearPath() {
ProjectFile::s_currProjectPath.clear();
s_currProjectPath.clear();
}
std::fs::path ProjectFile::getPath() {
return ProjectFile::s_currProjectPath;
return s_currProjectPath;
}
void ProjectFile::setPath(const std::fs::path &path) {
ProjectFile::s_currProjectPath = path;
s_currProjectPath = path;
}
std::vector<ProjectFile::Handler> &ProjectFile::getHandlers() {
return s_handlers;
}
std::vector<ProjectFile::ProviderHandler> &ProjectFile::getProviderHandlers() {
return s_providerHandlers;
}
}

View File

@@ -14,15 +14,21 @@
namespace hex {
std::mutex TaskManager::s_deferredCallsMutex, TaskManager::s_tasksFinishedMutex;
namespace {
std::list<std::shared_ptr<Task>> TaskManager::s_tasks, TaskManager::s_taskQueue;
std::list<std::function<void()>> TaskManager::s_deferredCalls;
std::list<std::function<void()>> TaskManager::s_tasksFinishedCallbacks;
std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;
std::list<std::shared_ptr<Task>> s_tasks, s_taskQueue;
std::list<Timer> s_timers;
std::list<std::function<void()>> s_deferredCalls;
std::list<std::function<void()>> s_tasksFinishedCallbacks;
std::mutex s_queueMutex;
std::condition_variable s_jobCondVar;
std::vector<std::jthread> s_workers;
}
std::mutex TaskManager::s_queueMutex;
std::condition_variable TaskManager::s_jobCondVar;
std::vector<std::jthread> TaskManager::s_workers;
static void setThreadName(const std::string &name) {
#if defined(OS_WINDOWS)
@@ -210,19 +216,19 @@ namespace hex {
log::debug("Initializing task manager thread pool with {} workers.", threadCount);
for (u32 i = 0; i < threadCount; i++)
TaskManager::s_workers.emplace_back(TaskManager::runner);
s_workers.emplace_back(TaskManager::runner);
}
void TaskManager::exit() {
for (auto &task : TaskManager::s_tasks)
for (auto &task : s_tasks)
task->interrupt();
for (auto &thread : TaskManager::s_workers)
for (auto &thread : s_workers)
thread.request_stop();
s_jobCondVar.notify_all();
TaskManager::s_workers.clear();
s_workers.clear();
}
void TaskManager::runner(const std::stop_token &stopToken) {
@@ -295,12 +301,17 @@ namespace hex {
call();
s_tasksFinishedCallbacks.clear();
}
}
std::list<std::shared_ptr<Task>> &TaskManager::getRunningTasks() {
return s_tasks;
}
std::list<Timer> &TaskManager::getTimers() {
return s_timers;
}
size_t TaskManager::getRunningTaskCount() {
std::unique_lock lock(s_queueMutex);
@@ -331,6 +342,12 @@ namespace hex {
call();
s_deferredCalls.clear();
for (const auto &timer : s_timers) {
if (timer.elapseTime >= std::chrono::steady_clock::now()) {
timer.callback();
}
}
}
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
@@ -339,4 +356,8 @@ namespace hex {
s_tasksFinishedCallbacks.push_back(function);
}
void TaskManager::doAfter(std::chrono::duration<i64> duration, const std::function<void()> &function) {
s_timers.push_back({ std::chrono::steady_clock::now() + duration, function });
}
}

View File

@@ -9,11 +9,16 @@
namespace hex {
std::map<std::string, nlohmann::json> ThemeManager::s_themes;
std::map<std::string, ThemeManager::ThemeHandler> ThemeManager::s_themeHandlers;
std::map<std::string, ThemeManager::StyleHandler> ThemeManager::s_styleHandlers;
std::string ThemeManager::s_imagePostfix;
std::string ThemeManager::s_currTheme;
namespace {
std::map<std::string, nlohmann::json> s_themes;
std::map<std::string, ThemeManager::ThemeHandler> s_themeHandlers;
std::map<std::string, ThemeManager::StyleHandler> s_styleHandlers;
std::string s_imageTheme;
std::string s_currTheme;
}
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
s_themeHandlers[name] = { colorMap, getFunction, setFunction };
@@ -62,7 +67,7 @@ namespace hex {
nlohmann::json ThemeManager::exportCurrentTheme(const std::string &name) {
nlohmann::json theme = {
{ "name", name },
{ "image_postfix", s_imagePostfix },
{ "image_theme", s_imageTheme },
{ "colors", {} },
{ "styles", {} },
{ "base", s_currTheme }
@@ -174,11 +179,12 @@ namespace hex {
}
}
if (theme.contains("image_postfix")) {
if (theme["image_postfix"].is_string()) {
s_imagePostfix = theme["image_postfix"].get<std::string>();
if (theme.contains("image_theme")) {
if (theme["image_theme"].is_string()) {
s_imageTheme = theme["image_theme"].get<std::string>();
} else {
hex::log::error("Theme '{}' has invalid image postfix!", name);
hex::log::error("Theme '{}' has invalid image theme!", name);
s_imageTheme = "dark";
}
}
@@ -187,8 +193,8 @@ namespace hex {
EventManager::post<EventThemeChanged>();
}
const std::string &ThemeManager::getThemeImagePostfix() {
return s_imagePostfix;
const std::string &ThemeManager::getImageTheme() {
return s_imageTheme;
}
std::vector<std::string> ThemeManager::getThemeNames() {
@@ -200,11 +206,20 @@ namespace hex {
}
void ThemeManager::reset() {
ThemeManager::s_themes.clear();
ThemeManager::s_styleHandlers.clear();
ThemeManager::s_themeHandlers.clear();
ThemeManager::s_imagePostfix.clear();
ThemeManager::s_currTheme.clear();
s_themes.clear();
s_styleHandlers.clear();
s_themeHandlers.clear();
s_imageTheme.clear();
s_currTheme.clear();
}
std::map<std::string, ThemeManager::ThemeHandler> &ThemeManager::getThemeHandlers() {
return s_themeHandlers;
}
std::map<std::string, ThemeManager::StyleHandler> &ThemeManager::getStyleHandlers() {
return s_styleHandlers;
}
}

View File

@@ -3,9 +3,14 @@
namespace hex::dp {
int Attribute::s_idCounter = 1;
namespace {
Attribute::Attribute(IOType ioType, Type type, std::string unlocalizedName) : m_id(Attribute::s_idCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(std::move(unlocalizedName)) {
int s_idCounter = 1;
}
Attribute::Attribute(IOType ioType, Type type, std::string unlocalizedName) : m_id(s_idCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(std::move(unlocalizedName)) {
}
Attribute::~Attribute() {
@@ -13,4 +18,9 @@ namespace hex::dp {
attr->removeConnectedAttribute(linkId);
}
void Attribute::setIdCounter(int id) {
if (id > s_idCounter)
s_idCounter = id;
}
}

View File

@@ -3,9 +3,16 @@
namespace hex::dp {
int Link::s_idCounter = 1;
namespace {
Link::Link(int from, int to) : m_id(Link::s_idCounter++), m_from(from), m_to(to) { }
int s_idCounter = 1;
}
Link::Link(int from, int to) : m_id(s_idCounter++), m_from(from), m_to(to) { }
void Link::setIdCounter(int id) {
if (id > s_idCounter)
s_idCounter = id;
}
}

View File

@@ -7,9 +7,13 @@
namespace hex::dp {
int Node::s_idCounter = 1;
namespace {
Node::Node(std::string unlocalizedTitle, std::vector<Attribute> attributes) : m_id(Node::s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
int s_idCounter = 1;
}
Node::Node(std::string unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
for (auto &attr : this->m_attributes)
attr.setParentNode(this);
}
@@ -60,7 +64,7 @@ namespace hex::dp {
return *reinterpret_cast<i128 *>(outputData.data());
}
const long double& Node::getFloatOnInput(u32 index) {
const double& Node::getFloatOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index);
auto &outputData = [&] -> std::vector<u8>& {
@@ -80,10 +84,10 @@ namespace hex::dp {
if (outputData.empty())
throwNodeError("No data available at connected attribute");
if (outputData.size() < sizeof(long double))
if (outputData.size() < sizeof(double))
throwNodeError("Not enough data provided for float");
return *reinterpret_cast<long double *>(outputData.data());
return *reinterpret_cast<double *>(outputData.data());
}
void Node::setBufferOnOutput(u32 index, std::span<const u8> data) {
@@ -95,6 +99,9 @@ namespace hex::dp {
if (attribute.getIOType() != Attribute::IOType::Out)
throwNodeError("Tried to set output data of an input attribute!");
if (attribute.getType() != Attribute::Type::Buffer)
throwNodeError("Tried to set buffer on non-buffer attribute!");
attribute.getOutputData() = { data.begin(), data.end() };
}
@@ -107,13 +114,16 @@ namespace hex::dp {
if (attribute.getIOType() != Attribute::IOType::Out)
throwNodeError("Tried to set output data of an input attribute!");
if (attribute.getType() != Attribute::Type::Integer)
throwNodeError("Tried to set integer on non-integer attribute!");
std::vector<u8> buffer(sizeof(integer), 0);
std::memcpy(buffer.data(), &integer, sizeof(integer));
attribute.getOutputData() = buffer;
}
void Node::setFloatOnOutput(u32 index, long double floatingPoint) {
void Node::setFloatOnOutput(u32 index, double floatingPoint) {
if (index >= this->getAttributes().size())
throwNodeError("Attribute index out of bounds!");
@@ -122,6 +132,9 @@ namespace hex::dp {
if (attribute.getIOType() != Attribute::IOType::Out)
throwNodeError("Tried to set output data of an input attribute!");
if (attribute.getType() != Attribute::Type::Float)
throwNodeError("Tried to set float on non-float attribute!");
std::vector<u8> buffer(sizeof(floatingPoint), 0);
std::memcpy(buffer.data(), &floatingPoint, sizeof(floatingPoint));
@@ -136,4 +149,9 @@ namespace hex::dp {
this->m_overlay->getData() = data;
}
void Node::setIdCounter(int id) {
if (id > s_idCounter)
s_idCounter = id;
}
}

View File

@@ -390,16 +390,22 @@ namespace hex::crypt {
std::vector<u8> decode16(const std::string &input) {
std::vector<u8> output(input.length() / 2, 0x00);
mbedtls_mpi ctx;
mbedtls_mpi_init(&ctx);
ON_SCOPE_EXIT { mbedtls_mpi_free(&ctx); };
if (mbedtls_mpi_read_string(&ctx, 16, input.c_str()))
return {};
// read buffered
constexpr static auto BufferSize = 0x100;
for (size_t offset = 0; offset < input.size(); offset += BufferSize) {
std::string inputPart = input.substr(offset, std::min<size_t>(BufferSize, input.size() - offset));
if (mbedtls_mpi_read_string(&ctx, 16, inputPart.c_str()))
return {};
if (mbedtls_mpi_write_binary(&ctx, output.data(), output.size()))
return {};
if (mbedtls_mpi_write_binary(&ctx, output.data() + offset / 2, inputPart.size() / 2))
return {};
}
return output;
}

View File

@@ -16,6 +16,7 @@ namespace hex {
this->m_tableContent = other.m_tableContent;
this->m_longestSequence = other.m_longestSequence;
this->m_valid = other.m_valid;
this->m_name = other.m_name;
}
EncodingFile::EncodingFile(EncodingFile &&other) {
@@ -23,6 +24,7 @@ namespace hex {
this->m_tableContent = std::move(other.m_tableContent);
this->m_longestSequence = other.m_longestSequence;
this->m_valid = other.m_valid;
this->m_name = std::move(other.m_name);
}
EncodingFile::EncodingFile(Type type, const std::fs::path &path) : EncodingFile() {
@@ -35,6 +37,14 @@ namespace hex {
return;
}
{
this->m_name = path.stem().string();
this->m_name = wolv::util::replaceStrings(this->m_name, "_", " ");
if (!this->m_name.empty())
this->m_name[0] = std::toupper(this->m_name[0]);
}
this->m_valid = true;
}
@@ -47,6 +57,7 @@ namespace hex {
return;
}
this->m_name = "Unknown";
this->m_valid = true;
}
@@ -56,6 +67,7 @@ namespace hex {
this->m_tableContent = other.m_tableContent;
this->m_longestSequence = other.m_longestSequence;
this->m_valid = other.m_valid;
this->m_name = other.m_name;
return *this;
}
@@ -65,6 +77,7 @@ namespace hex {
this->m_tableContent = std::move(other.m_tableContent);
this->m_longestSequence = other.m_longestSequence;
this->m_valid = other.m_valid;
this->m_name = std::move(other.m_name);
return *this;
}

View File

@@ -4,6 +4,7 @@
#include <hex/api/project_file_manager.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/utils_linux.hpp>
#include <xdg.hpp>
@@ -17,9 +18,11 @@
#include <algorithm>
#include <filesystem>
#include <utility>
#include <wolv/io/file.hpp>
#include <wolv/io/fs.hpp>
#include <wolv/utils/string.hpp>
namespace hex::fs {
@@ -43,9 +46,7 @@ namespace hex::fs {
hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str()
));
#elif defined(OS_LINUX)
hex::unused(system(
hex::format("xdg-open {}", wolv::util::toUTF8String(filePath)).c_str()
));
executeCmd({"xdg-open", wolv::util::toUTF8String(filePath)});
#endif
}
@@ -62,9 +63,7 @@ namespace hex::fs {
hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str()
));
#elif defined(OS_LINUX)
hex::unused(system(
hex::format("xdg-open {}", wolv::util::toUTF8String(dirPath)).c_str()
));
executeCmd({"xdg-open", wolv::util::toUTF8String(dirPath)});
#endif
}
@@ -87,9 +86,7 @@ namespace hex::fs {
#elif defined(OS_LINUX)
// fallback to only opening the folder for now
// TODO actually select the file
hex::unused(system(
hex::format("xdg-open {}", wolv::util::toUTF8String(selectedFilePath.parent_path())).c_str()
));
executeCmd({"xdg-open", wolv::util::toUTF8String(selectedFilePath.parent_path())});
#endif
}
@@ -174,9 +171,6 @@ namespace hex::fs {
#endif
for (auto &path : paths)
path = path / "imhex";
#if defined(OS_MACOS)
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
@@ -184,6 +178,9 @@ namespace hex::fs {
#else
for (auto &path : paths)
path = path / "imhex";
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(executablePath->parent_path());

View File

@@ -2,8 +2,12 @@
namespace hex {
std::string HttpRequest::s_caCertData;
std::string HttpRequest::s_proxyUrl;
namespace {
std::string s_proxyUrl;
}
HttpRequest::HttpRequest(std::string method, std::string url) : m_method(std::move(method)), m_url(std::move(url)) {
AT_FIRST_TIME {
@@ -36,31 +40,6 @@ namespace hex {
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
curl_easy_setopt(this->m_curl, CURLOPT_PROXY, s_proxyUrl.c_str());
#if defined(IMHEX_USE_BUNDLED_CA)
curl_easy_setopt(this->m_curl, CURLOPT_CAINFO, nullptr);
curl_easy_setopt(this->m_curl, CURLOPT_CAPATH, nullptr);
curl_easy_setopt(this->m_curl, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(this->m_curl, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
this->m_caCert = std::make_unique<mbedtls_x509_crt>();
curl_easy_setopt(this->m_curl, CURLOPT_SSL_CTX_DATA, this->m_caCert.get());
#endif
}
CURLcode HttpRequest::sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
hex::unused(ctx, userData);
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
auto crt = static_cast<mbedtls_x509_crt*>(userData);
mbedtls_x509_crt_init(crt);
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(HttpRequest::s_caCertData.data()), HttpRequest::s_caCertData.size());
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
return CURLE_OK;
}
size_t HttpRequest::writeToVector(void *contents, size_t size, size_t nmemb, void *userdata) {
@@ -94,4 +73,14 @@ namespace hex {
return request.m_canceled ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
}
void HttpRequest::setProxy(std::string proxy) {
s_proxyUrl = std::move(proxy);
}
void HttpRequest::checkProxyErrors() {
if (!s_proxyUrl.empty()){
log::info("A custom proxy '{0}' is in use. Is it working correctly?", s_proxyUrl);
}
}
}

View File

@@ -7,7 +7,7 @@
namespace hex::log::impl {
static wolv::io::File s_loggerFile;
std::mutex s_loggerMutex;
std::mutex g_loggerMutex;
FILE *getDestination() {
if (s_loggerFile.isValid())
@@ -36,4 +36,20 @@ namespace hex::log::impl {
}
}
std::vector<LogEntry>& getLogEntries() {
static std::vector<LogEntry> logEntries;
return logEntries;
}
void assertionHandler(bool expr, const char* expr_str, const char* file, int line) {
if (!expr) {
log::error("Assertion failed: {} at {}:{}", expr_str, file, line);
#if defined (DEBUG)
std::abort();
#endif
}
}
}

View File

@@ -2,6 +2,7 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/utils/string.hpp>
@@ -13,6 +14,7 @@
#include <string>
#include <magic.h>
#include <unistd.h>
#if defined(OS_WINDOWS)
#define MAGIC_PATH_SEPARATOR ";"
@@ -52,7 +54,32 @@ namespace hex::magic {
if (!magicFiles.has_value())
return false;
return magic_compile(ctx, magicFiles->c_str()) == 0;
std::array<char, 1024> cwd = { 0x00 };
if (getcwd(cwd.data(), cwd.size()) == nullptr)
return false;
std::optional<std::fs::path> magicFolder;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
if (std::fs::exists(dir) && fs::isPathWritable(dir)) {
magicFolder = dir;
break;
}
}
if (!magicFolder.has_value()) {
log::error("Could not find a writable magic folder");
return false;
}
if (chdir(wolv::util::toUTF8String(*magicFolder).c_str()) != 0)
return false;
auto result = magic_compile(ctx, magicFiles->c_str()) == 0;
if (chdir(cwd.data()) != 0)
return false;
return result;
}
std::string getDescription(const std::vector<u8> &data) {

View File

@@ -1,6 +1,8 @@
#include <hex/helpers/stacktrace.hpp>
#include <hex/helpers/fmt.hpp>
#include <array>
#if defined(OS_WINDOWS)
#include <windows.h>
@@ -116,10 +118,10 @@
static std::vector<StackFrame> result;
std::array<void*, 128> addresses;
auto count = backtrace(addresses.data(), addresses.size());
size_t count = backtrace(addresses.data(), addresses.size());
auto functions = backtrace_symbols(addresses.data(), count);
for (i32 i = 0; i < count; i++)
for (size_t i = 0; i < count; i++)
result.push_back(StackFrame { "", functions[i], 0 });
return result;
@@ -179,7 +181,7 @@
namespace hex::stacktrace {
void initialize() { }
std::vector<StackFrame> getStackTrace() { return { }; }
std::vector<StackFrame> getStackTrace() { return { StackFrame { "??", "Stacktrace collecting not available!", 0 } }; }
}

View File

@@ -88,7 +88,13 @@ namespace hex {
bool Tar::contains(const std::fs::path &path) {
mtar_header_t header;
return mtar_find(&this->m_ctx, path.string().c_str(), &header) == MTAR_ESUCCESS;
auto fixedPath = path.string();
#if defined(OS_WINDOWS)
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
#endif
return mtar_find(&this->m_ctx, fixedPath.c_str(), &header) == MTAR_ESUCCESS;
}
std::string Tar::getOpenErrorString(){

View File

@@ -8,6 +8,7 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/crypto.hpp>
#include <hex/helpers/utils_linux.hpp>
#include <imgui.h>
#include <imgui_internal.h>
@@ -313,14 +314,12 @@ namespace hex {
void runCommand(const std::string &command) {
#if defined(OS_WINDOWS)
auto result = system(hex::format("start {0}", command).c_str());
hex::unused(system(hex::format("start {0}", command).c_str()));
#elif defined(OS_MACOS)
auto result = system(hex::format("open {0}", command).c_str());
hex::unused(system(hex::format("open {0}", command).c_str()));
#elif defined(OS_LINUX)
auto result = system(hex::format("xdg-open {0}", command).c_str());
executeCmd({"xdg-open", command});
#endif
hex::unused(result);
}
void openWebpage(std::string url) {
@@ -332,8 +331,7 @@ namespace hex {
#elif defined(OS_MACOS)
openWebpageMacos(url.c_str());
#elif defined(OS_LINUX)
auto result = system(hex::format("xdg-open {0}", url).c_str());
hex::unused(result);
executeCmd({"xdg-open", url});
#else
#warning "Unknown OS, can't open webpages"
#endif

View File

@@ -0,0 +1,27 @@
#if defined(OS_LINUX)
#include<hex/helpers/logger.hpp>
#include<vector>
#include<string>
#include<unistd.h>
namespace hex {
void executeCmd(const std::vector<std::string> &argsVector) {
std::vector<char*> cArgsVector;
for (const auto &str : argsVector) {
cArgsVector.push_back(const_cast<char*>(str.c_str()));
}
cArgsVector.push_back(nullptr);
if (fork() == 0) {
execvp(cArgsVector[0], &cArgsVector[0]);
log::error("execvp() failed: {}", strerror(errno));
exit(EXIT_FAILURE);
}
}
}
#endif

View File

@@ -13,7 +13,12 @@
namespace hex::prv {
u32 Provider::s_idCounter = 0;
namespace {
u32 s_idCounter = 0;
}
Provider::Provider() : m_id(s_idCounter++) {
this->m_patches.emplace_back();
@@ -21,9 +26,10 @@ namespace hex::prv {
}
Provider::~Provider() {
for (auto overlay : this->m_overlays)
delete overlay;
this->m_overlays.clear();
if (auto selection = ImHexApi::HexEditor::getSelection(); selection.has_value() && selection->provider == this)
EventManager::post<EventRegionSelected>(ImHexApi::HexEditor::ProviderRegion { { 0x00, 0x00 }, nullptr });
}
void Provider::read(u64 offset, void *buffer, size_t size, bool overlays) {
@@ -138,6 +144,14 @@ namespace hex::prv {
if (!this->isWritable())
return;
this->m_patches.emplace_back();
for (auto &[patchAddress, patch] : getPatches()) {
u8 value = 0x00;
this->readRaw(patchAddress - this->getBaseAddress(), &value, 1);
this->m_patches.back().insert({ patchAddress, value });
}
for (auto &[patchAddress, patch] : getPatches()) {
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
}
@@ -145,19 +159,21 @@ namespace hex::prv {
this->markDirty();
this->m_patches.emplace_back();
this->m_currPatches = std::prev(this->m_patches.end());
}
Overlay *Provider::newOverlay() {
return this->m_overlays.emplace_back(new Overlay());
return this->m_overlays.emplace_back(std::make_unique<Overlay>()).get();
}
void Provider::deleteOverlay(Overlay *overlay) {
this->m_overlays.remove(overlay);
delete overlay;
this->m_overlays.remove_if([overlay](const auto &item) {
return item.get() == overlay;
});
}
const std::list<Overlay *> &Provider::getOverlays() {
const std::list<std::unique_ptr<Overlay>> &Provider::getOverlays() {
return this->m_overlays;
}
@@ -213,6 +229,10 @@ namespace hex::prv {
return page;
}
std::vector<Provider::Description> Provider::getDataDescription() const {
return { };
}
void Provider::addPatch(u64 offset, const void *buffer, size_t size, bool createUndo) {
if (createUndo) {
// Delete all patches after the current one if a modification is made while
@@ -226,7 +246,7 @@ namespace hex::prv {
for (u64 i = 0; i < size; i++) {
u8 patch = reinterpret_cast<const u8 *>(buffer)[i];
u8 originalValue = 0x00;
this->readRaw(offset + i, &originalValue, sizeof(u8));
this->readRaw((offset + i) - this->getBaseAddress(), &originalValue, sizeof(u8));
if (patch == originalValue)
getPatches().erase(offset + i);
@@ -356,4 +376,8 @@ namespace hex::prv {
return 0;
}
[[nodiscard]] bool Provider::isDumpable() const {
return true;
}
}

View File

@@ -0,0 +1,120 @@
#include<iostream>
#include<numeric>
#include<string_view>
#include<ranges>
#include<stdlib.h>
#include "hex/subcommands/subcommands.hpp"
#include <hex/api/event.hpp>
#include <hex/api/plugin_manager.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/logger.hpp>
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) {
return subCommand;
}
}
}
return std::nullopt;
}
void processArguments(const std::vector<std::string> &args) {
// 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;
std::vector<std::pair<SubCommand, std::vector<std::string>>> subCommands;
auto argsIter = args.begin();
// get subcommand associated with the first argument
std::optional<SubCommand> currentSubCommand = findSubCommand(*argsIter);
if (currentSubCommand) {
argsIter++;
// if it is a valid subcommand, remove it from the argument list
} else {
// if no (valid) subcommand was provided, the default one is --open
currentSubCommand = findSubCommand("--open");
}
// arguments of the current subcommand
std::vector<std::string> currentSubCommandArgs;
// compute all subcommands to run
while (argsIter != args.end()) {
const std::string &arg = *argsIter;
if (arg == "--othercmd") {
// save command to run
if (currentSubCommand) {
subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs);
}
currentSubCommand = std::nullopt;
currentSubCommandArgs = { };
} else if (currentSubCommand) {
// add current argument to the current command
currentSubCommandArgs.push_back(arg);
} else {
// get next subcommand from current argument
currentSubCommand = findSubCommand(arg);
if (!currentSubCommand) {
log::error("No subcommand named '{}' found", arg);
exit(EXIT_FAILURE);
}
}
argsIter++;
}
// save last command to run
if (currentSubCommand) {
subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs);
}
// run the subcommands
for (auto& subCommandPair : subCommands) {
subCommandPair.first.callback(subCommandPair.second);
}
// exit the process if its not the main instance (the commands have been forwarded to another instance)
if (!ImHexApi::System::isMainInstance()) {
exit(0);
}
}
void forwardSubCommand(const std::string &cmdName, const std::vector<std::string> &args) {
log::debug("Forwarding subcommand {} (maybe to us)", cmdName);
std::string dataStr = std::accumulate(args.begin(), args.end(), std::string("\0"));
std::vector<u8> data(dataStr.begin(), dataStr.end());
EventManager::post<SendMessageToMainInstance>(hex::format("command/{}", cmdName), data);
}
void registerSubCommand(const std::string &cmdName, const ForwardCommandHandler &handler) {
log::debug("Registered new forward command handler: {}", cmdName);
ImHexApi::Messaging::impl::getHandlers().insert({ hex::format("command/{}", cmdName), [handler](const std::vector<u8> &eventData){
std::string str((const char*) eventData.data(), eventData.size());
std::vector<std::string> args;
for (const auto &arg_view : std::views::split(str, '\0')) {
std::string arg(arg_view.data(), arg_view.size());
args.push_back(arg);
}
handler(args);
}});
}
}

View File

@@ -35,8 +35,8 @@ namespace ImGui {
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@@ -48,6 +48,8 @@ namespace ImGui {
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
}
Texture::Texture(std::span<const std::byte> bytes, int width, int height) : Texture(reinterpret_cast<const ImU8*>(bytes.data()), bytes.size(), width, height) { }
Texture::Texture(const char *path) {
unsigned char *imageData = stbi_load(path, &this->m_width, &this->m_height, nullptr, 4);
if (imageData == nullptr)
@@ -788,4 +790,37 @@ namespace ImGui {
return res;
}
bool DimmedIconToggle(const char *icon, bool *v) {
bool pushed = false;
bool toggled = false;
if (*v) {
ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive));
pushed = true;
}
if (ImGui::DimmedIconButton(icon, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
*v = !*v;
toggled = true;
}
if (pushed)
ImGui::PopStyleColor();
return toggled;
}
void TextOverlay(const char *text, ImVec2 pos) {
const auto textSize = ImGui::CalcTextSize(text);
const auto textPos = pos - textSize / 2;
const auto margin = ImGui::GetStyle().FramePadding * 2;
const auto textRect = ImRect(textPos - margin, textPos + textSize + margin);
auto drawList = ImGui::GetForegroundDrawList();
drawList->AddRectFilled(textRect.Min, textRect.Max, ImGui::GetColorU32(ImGuiCol_WindowBg) | 0xFF000000);
drawList->AddRect(textRect.Min, textRect.Max, ImGui::GetColorU32(ImGuiCol_Border));
drawList->AddText(textPos, ImGui::GetColorU32(ImGuiCol_Text), text);
}
}

View File

@@ -2,6 +2,12 @@
namespace hex::impl {
std::vector<std::unique_ptr<PopupBase>> PopupBase::s_openPopups;
[[nodiscard]] std::vector<std::unique_ptr<PopupBase>> &PopupBase::getOpenPopups() {
static std::vector<std::unique_ptr<PopupBase>> openPopups;
return openPopups;
}
}

View File

@@ -8,8 +8,12 @@
namespace hex {
ImFontAtlas *View::s_fontAtlas;
ImFontConfig View::s_fontConfig;
namespace {
ImFontAtlas *s_fontAtlas;
ImFontConfig s_fontConfig;
}
View::View(std::string unlocalizedName) : m_unlocalizedViewName(std::move(unlocalizedName)) { }
@@ -62,4 +66,10 @@ namespace hex {
rightButtonFn();
}
ImFontAtlas *View::getFontAtlas() { return s_fontAtlas; }
void View::setFontAtlas(ImFontAtlas *atlas) { s_fontAtlas = atlas; }
ImFontConfig View::getFontConfig() { return s_fontConfig; }
void View::setFontConfig(ImFontConfig config) { s_fontConfig = config; }
}

View File

@@ -9,6 +9,11 @@ add_executable(main ${APPLICATION_TYPE}
source/window/macos_window.cpp
source/window/linux_window.cpp
source/messaging/common.cpp
source/messaging/linux.cpp
source/messaging/macos.cpp
source/messaging/win.cpp
source/init/splash_window.cpp
source/init/tasks.cpp
@@ -23,11 +28,28 @@ set(LIBROMFS_PROJECT_NAME imhex)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/main/libromfs EXCLUDE_FROM_ALL)
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(main PROPERTIES
if (WIN32)
# HACK: `imhex` -> `imhex-gui` and we add a forwarder as `imhex`, so that the user can just run `imhex` and it will start the GUI
# Workaround for .NET plugin crashing caused by the console window being freed.
set(IMHEX_APPLICATION_NAME "imhex-gui")
add_executable(imhex-forwarder
source/forwarder/main.cpp
${IMHEX_ICON})
target_link_libraries(imhex-forwarder PRIVATE libwolv-io ${FMT_LIBRARIES})
set_target_properties(imhex-forwarder PROPERTIES
OUTPUT_NAME "imhex"
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
CXX_VISIBILITY_PRESET hidden
POSITION_INDEPENDENT_CODE ON)
else ()
set(IMHEX_APPLICATION_NAME "imhex")
endif ()
set_target_properties(main PROPERTIES
OUTPUT_NAME ${IMHEX_APPLICATION_NAME}
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/..
CXX_VISIBILITY_PRESET hidden
POSITION_INDEPENDENT_CODE ON)
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")

View File

@@ -3,4 +3,5 @@
namespace hex::crash {
void setupCrashHandlers();
}

View File

@@ -12,6 +12,14 @@ namespace hex::init {
using TaskFunction = std::function<bool()>;
enum FrameResult{ success, failure, wait };
struct Highlight {
ImVec2 start;
size_t count;
ImColor color;
};
class WindowSplash {
public:
WindowSplash();
@@ -19,6 +27,9 @@ namespace hex::init {
bool loop();
FrameResult fullFrame();
void startStartupTasks();
void addStartupTask(const std::string &taskName, const TaskFunction &task, bool async) {
this->m_tasks.emplace_back(taskName, task, async);
}
@@ -27,10 +38,11 @@ namespace hex::init {
GLFWwindow *m_window;
std::mutex m_progressMutex;
std::atomic<float> m_progress = 0;
std::string m_currTaskName;
std::list<std::string> m_currTaskNames;
void initGLFW();
void initImGui();
void initMyself();
void exitGLFW();
void exitImGui();
@@ -40,6 +52,12 @@ namespace hex::init {
std::vector<std::tuple<std::string, TaskFunction, bool>> m_tasks;
std::string m_gpuVendor;
ImGui::Texture splashBackgroundTexture;
ImGui::Texture splashTextTexture;
std::future<bool> tasksSucceeded;
std::array<Highlight, 3> highlights;
float progressLerp = 0.0F;
};
}

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