Compare commits

...

180 Commits

Author SHA1 Message Date
WerWolv
54b31b8a55 build: Bumped version to 1.19.3 2022-07-26 16:13:07 +02:00
WerWolv
93aa1247df fix: Switching page when jumping to selection not working 2022-07-26 15:01:21 +02:00
WerWolv
fb4c21b97a build: Fix weird macOS build errors (#591)
* cleanup

* Remove prints
2022-07-26 14:59:08 +02:00
WerWolv
d356993e33 fix: Various search issues 2022-07-26 13:28:21 +02:00
WerWolv
cf017540e2 ui: Fixed rendering of advanced decoding highlighting with multi-byte visualizers 2022-07-25 23:46:32 +02:00
WerWolv
c776bb6c03 ui: Fixed hex editor highlighting with multi-byte visualizers 2022-07-25 15:13:26 +02:00
Polshakov Dmitry
e7399d223d fix: Bitfields not being displayed correctly in Pattern Data view (#580)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-07-25 12:09:28 +02:00
Forrest
8aff20b374 docs: Correct minor typo in windows.md (#582)
should read msys2 instead of mys2
2022-07-25 12:08:41 +02:00
catsout
3b8b95a22f fix: Add Config/DataHomeDir paths before Config/DataDirs paths (#586)
fix not saving to "XDG_DATA_HOME", when "XDG_DATA_DIRS" is available.  
fix "Content Store" persist in flatpak.

XDG specification specifies how to find config and data directories on
linux systems. Specifically, it says this:

- Data should be written to $XDG_DATA_HOME
- Config should be written to $XDG_CONFIG_HOME
- Data should be read from $XDG_DATA_HOME:$XDG_DATA_DIRS
- Config should be read from $XDG_CONFIG_HOME:$XDG_CONFIG_DIRS
2022-07-25 12:08:10 +02:00
xtexChooser
2cb65aac72 lang: Fix typo in Chinese translation (#589) 2022-07-25 12:07:18 +02:00
WerWolv
0c8deecfc5 patterns: Updated pattern language 2022-07-25 11:50:46 +02:00
WerWolv
74f17fd638 ui: Properly hide hidden patterns in hex editor view 2022-07-25 11:33:30 +02:00
WerWolv
f3f13ae4d3 fix: Jumping to selection not working correctly with set base address 2022-07-23 21:31:54 +02:00
WerWolv
daffa4e555 fix: Edit -> Create Bookmark shortcut creating bookmark at wrong address 2022-07-23 21:17:17 +02:00
WerWolv
c618eec843 fix: Hex editor selection not working correctly when setting base address 2022-07-23 20:46:20 +02:00
WerWolv
71a7ae70d0 git: Fixed Arch Linux CI build issue 2022-07-23 20:42:59 +02:00
WerWolv
c1a2697e42 ui: Added filter to bookmarks view 2022-07-23 20:38:38 +02:00
WerWolv
d4dd57c7c8 fix: Setting base address causing hex editor to display zeros 2022-07-23 18:21:37 +02:00
WerWolv
9e3c6898ad fix: Multi-byte hex editor visualizers displaying incorrect bytes 2022-07-23 15:21:24 +02:00
WerWolv
b6d7fd6984 git: Make analysis workflow also pull latest patterns 2022-07-18 20:18:41 +02:00
WerWolv
d8eb027c94 git: Make tests also pull latest patterns 2022-07-18 20:15:14 +02:00
WerWolv
80d47b658e git: Fixed CI, updated all env var names 2022-07-18 20:13:01 +02:00
WerWolv
51f2b24daa git: Create new ImHex-Patterns release on new ImHex release 2022-07-18 20:02:12 +02:00
WerWolv
fe86f69da3 fix: Duplicate pattern data view entries when sorting the list
Fixes #584
2022-07-18 11:40:49 +02:00
WerWolv
2fb51d1a56 patterns: Fixed Bit and Bool operator mixup 2022-07-18 11:39:50 +02:00
WerWolv
ca3b5b72ca ui: Fixed highlighting color and tooltips 2022-07-17 13:12:28 +02:00
WerWolv
3db8e2aec2 build: Bumped version to 1.19.2 2022-07-16 13:41:37 +02:00
WerWolv
499b68b7ad build: Updated nativefiledialog library 2022-07-16 13:26:07 +02:00
WerWolv
2e3bb8e555 patterns: Don't display empty strings in pattern data view 2022-07-16 13:08:08 +02:00
WerWolv
0c9eab70d5 fix: Crash when searching for an empty string 2022-07-16 13:01:40 +02:00
WerWolv
0d3eaa5d86 patterns: Updated pattern language 2022-07-16 12:57:33 +02:00
WerWolv
c20634e093 sys: Fixed crash on exit 2022-07-16 12:14:15 +02:00
WerWolv
5ee3b550bc ui: Fixed advanced decoding cell sizes 2022-07-16 12:14:06 +02:00
WerWolv
831dac9b47 patterns: Updated pattern language 2022-07-15 11:38:46 +02:00
WerWolv
626c34dce8 sys: Upgrade codebase to C++23 2022-07-15 11:37:10 +02:00
Lukas Cone
ed67c20cba fix: User folders didnt load at startup (#578) 2022-07-14 11:38:23 +02:00
Lukas Cone
35c209c791 fix: In/Out variables not working, add recusive pattern scan (#579) 2022-07-14 11:37:02 +02:00
WerWolv
315109aa1f fix: Open File shortcut only working when Hex Editor view is selected
Fixes #576
2022-07-08 14:26:13 +02:00
WerWolv
a57fa34f82 build: Added option for Offline builds 2022-07-08 14:17:22 +02:00
iTrooz_
d1a2f7d6ed build: Cleanup package dependencies (#573)
* removed DEBIAN/imhex.desktop

* added licence to cmake install directory + fixed PKGBUILD to copy desktop file/licence

* removed gtk3 from packaging files

* added xdg-desktop-portal dependency

* adwaita theme should not be needed anymore

* added dbus dependency
2022-07-08 09:23:53 +02:00
WerWolv
8382f68601 fix: Data inspector string row not being editable correctly
Fixes #575
2022-07-08 09:21:49 +02:00
WerWolv
3aa1dd1e06 build: Added usp10 library to maybe provide Windows 7 support 2022-07-07 23:30:09 +02:00
WerWolv
0571fe383c fix: Duplicate file chooser popup entries not being selectable 2022-07-07 23:29:50 +02:00
WerWolv
461c5eac3e fix: Crash when closing the file picker without picking a file 2022-07-07 23:28:40 +02:00
KokaKiwi
e34f94bb79 build: Add xdg-desktop-portal for AUR package (#572)
* Add xdg-desktop-portal for AUR package

* Fix archlinux package build
2022-07-07 22:08:27 +02:00
WerWolv
071bae345e patterns: Fixed passing placed values to functions 2022-07-07 21:32:25 +02:00
WerWolv
9f4625aa00 fix: Editing float and double data inspector rows yielding wrong values
Fixes #571
2022-07-07 18:35:10 +02:00
iTrooz_
9837473810 git: Automatically create PatternLanguage release on new ImHex releases (#570) 2022-07-07 16:10:21 +02:00
WerWolv
9d3759c6cd build: Bumped version to 1.19.1 2022-07-07 08:48:37 +02:00
WerWolv
6aa55eb056 git: Make nightly download options more clear 2022-07-07 08:01:20 +02:00
WerWolv
c8b7f350ad ui: Fix rendering and default view initializing 2022-07-07 07:16:38 +02:00
WerWolv
b6b5045340 build: Downgrade nativefiledialog again 2022-07-06 16:58:36 +02:00
WerWolv
ab4f17a6f4 patterns: Fixed provider operation crash 2022-07-06 16:46:33 +02:00
WerWolv
541f1d5550 ui: Fixed positioning of UI 2022-07-06 16:40:30 +02:00
WerWolv
12942a4e71 build: Updated libromfs 2022-07-06 16:29:26 +02:00
WerWolv
1a378381bd build: Updated pattern language 2022-07-06 11:30:23 +02:00
WerWolv
1354c913a4 fix: UI stuttering when resizing or restoring window 2022-07-06 11:30:06 +02:00
WerWolv
c752fba1c4 ui: Added backdrop image when no views are open 2022-07-06 11:30:06 +02:00
WerWolv
d40a445f33 build: Updated various dependencies 2022-07-06 11:30:06 +02:00
WerWolv
e0cae1dacb patterns: Improved pattern formatting 2022-07-06 11:30:06 +02:00
WerWolv
31a746f3fc fix: Issue opening files that contain special characters on Linux
This is a (hopefully temporary) hack. Fixes #568
2022-07-06 11:29:24 +02:00
WerWolv
b401059678 ux: Automatically restore default layout when no view is open and a file is loaded 2022-07-05 12:10:54 +02:00
iTrooz_
a30f49c75e git: Improve size of Full Sources tar (#569)
* remove .git directories from Full sources

* actually compress Full sources
2022-07-05 10:12:16 +02:00
WerWolv
e981fa53f3 fix: std::u8string usage with nlohmann::json 2022-07-05 09:01:09 +02:00
WerWolv
4cd390ab02 fix: Various more unicode issues 2022-07-05 00:00:00 +02:00
WerWolv
716d6ae850 build: Bumped version to 1.19.0 2022-07-04 21:53:18 +02:00
iTrooz_
ceb07b7425 build: Added AUR/ArchLinux support (#566)
* store version in file

* use version file in release workflow

* use new version file in build workflow

* ArchLinux build

* setup cache for ArchLinux

* add version check in release CI

* edit step description

* update pkgbuild to install correctly

* AUR deploy

* rename version file to VERSION

* install all default plugins in PKGBUILD

* Added emojis to build workflow

* Added emojis to release workflow

* separate update packages and install dependencies in two steps

* fix Release CI

* add md5Sums to PKGBUILD

* make PKGBUILD point to the official repo + set v in tag
2022-07-04 21:40:22 +02:00
WerWolv
4885175ac6 build: Go back to macOS 11 to hopefully still support Catalina 2022-07-04 00:11:47 +02:00
WerWolv
d0f1a40f16 fix: Command Palette focus not working 2022-07-02 21:38:58 +02:00
WerWolv
fc20d751bb build: Use Portal instead of GTK file dialogs on Linux 2022-07-02 20:11:43 +02:00
iTrooz_
dfc22abf35 build: Fix AppImage file chooser crash (#567)
* add librsvg2-common

* removed that comment I should not have made in the first place
2022-07-02 19:04:51 +02:00
WerWolv
de269e7a48 sys: Remove remaining references to hex.builtin from libimhex 2022-07-02 17:53:13 +02:00
WerWolv
0ed885fe0f sys: Removed all references to hex.builtin from main application 2022-07-02 16:22:38 +02:00
WerWolv
f9fc7051fc tests: Added UTF-8 file operation tests 2022-07-02 10:05:25 +02:00
WerWolv
ab1f4df9d9 fix: In/Out variables not being added to the interface when using menu item to load pattern 2022-07-01 19:56:28 +02:00
WerWolv
710771b8b1 patterns: Cleanup pattern search 2022-07-01 19:12:01 +02:00
WerWolv
2d982e2088 fix: Drastically improve pattern highlighting performance 2022-07-01 19:05:53 +02:00
Shiroki Satsuki
ef5fbba56b feature: Added network proxy support for hex::Net (#562)
* feat(i18n): update Chinese(Simplified) translation

* feat: proxy setting

* refactor: add hex::Net::setProxy

* fix: undefined symbol: hex::Net::m_proxyUrl

* style: m_proxyUrl -> s_proxyUrl
2022-07-01 14:05:32 +02:00
WerWolv
eadcc6f38c sys: Modernize some constexpr arrays 2022-07-01 12:14:15 +02:00
WerWolv
3db50a690c fix: Various issues with UTF-8 paths 2022-06-30 19:39:06 +02:00
WerWolv
96aa929c31 fix: Removed additional } 2022-06-30 15:33:21 +02:00
WerWolv
e07fc76abf fix: MacOS include 2022-06-30 15:28:51 +02:00
WerWolv
f01e227c87 sys: Added missing macOS includes 2022-06-30 15:20:13 +02:00
iTrooz_
cd34d567a7 build: Install pattern files in the right place (#564) 2022-06-30 15:11:00 +02:00
WerWolv
bb429aae62 fix: Theme detection issues on all OSes 2022-06-30 15:09:57 +02:00
WerWolv
19f99bab0c fix: Issues when opening files with unicode names 2022-06-30 14:57:05 +02:00
WerWolv
1f433fc36d sys: Fixed byte units 2022-06-30 11:43:40 +02:00
WerWolv
034cc0cd2f ui: Improved byte selection text 2022-06-30 11:29:20 +02:00
WerWolv
3efdc02fed patterns: Improved automatic heap management 2022-06-30 11:19:37 +02:00
WerWolv
501d141e13 patterns: Added support for custom local types 2022-06-30 08:14:33 +02:00
WerWolv
9c1006f3ae fix: Compile errors because of Windows function defined on all systems 2022-06-30 07:47:32 +02:00
WerWolv
5b0813478e fix: Copying to clipboard not working correctly with non-english locales
Fixes #563
2022-06-30 07:44:22 +02:00
WerWolv
ac964dc5ec fix: Path handling and plugin loading breaking with non-ASCII paths 2022-06-29 21:34:17 +02:00
iTrooz_
11c2f240a1 git: Add version to artifact names (#559)
* Version file test

* change artifacts names

* Release updated

* Set release job name

* set branch to the branch used to release

* Set version for Windows Portable

* git: New cache update (#558)

* add CMakeCache.txt to cache

* added workflow_dispatch to workflows

* remove restore-keys from workflows

* Separated cache

* re-added restore-keys

* put the version file for all OS

* fix: In/Out parameters not working correctly when using the preprocessor

* update submodules

Co-authored-by: WerWolv <werwolv98@gmail.com>
2022-06-29 15:01:08 +02:00
WerWolv
8db2bdb6a7 fix: In/Out parameters not working correctly when using the preprocessor 2022-06-29 10:25:30 +02:00
iTrooz_
7242eb8f4c git: New cache update (#558)
* add CMakeCache.txt to cache

* added workflow_dispatch to workflows

* remove restore-keys from workflows

* Separated cache

* re-added restore-keys
2022-06-29 00:24:53 +02:00
Shiroki Satsuki
60c6abbfcc lang: Update Chinese(Simplified) translation (#556)
* feat(i18n): update Chinese(Simplified) translation

* format: plugins/builtin/source/lang/zh_CN.cpp

* feat(i18n): update Chinese(Simplified) translation

* fix: revert submodule downgrade
2022-06-28 08:39:30 +02:00
WerWolv
a4c432f435 git: Moved build instructions from the readme to individual files 2022-06-27 21:11:35 +02:00
WerWolv
d50be26771 lang: Fixed hardcoded localization string
#556
2022-06-27 18:41:13 +02:00
WerWolv
673027c82d fix: Crash on exit 2022-06-27 17:01:21 +02:00
WerWolv
e02ccd9b9b patterns: Actually fixed endian inversion in functions 2022-06-27 16:27:19 +02:00
WerWolv
956276d1ee patterns: Fixed endian inversion in functions
Fixes #555
2022-06-27 15:15:10 +02:00
WerWolv
a936cf1ce4 fix: Another file read issue 2022-06-27 15:08:22 +02:00
WerWolv
5800546369 fix: Tar extraction and file string read error 2022-06-27 14:58:40 +02:00
iTrooz_
01adc8a2cd build: Fix various CI caching issues (#553)
* removed restore-keys

* updated cache for Ubuntu 22

* using ccache on OBJC and OBJCXX

* Bonus: fix release workflow
2022-06-27 00:20:32 +02:00
WerWolv
b1b33b2ae4 ui: Added back missing selection byte count value 2022-06-25 23:01:38 +02:00
WerWolv
6506291e4e ui: Updated About page icon 2022-06-25 12:29:16 +02:00
WerWolv
3471b314dd build: Switch to GCC on MacOS (#552)
* build: Experimentally switch to gcc on macOS

* build: Corrected gcc paths

* build: Enable objective c support on macOS

* build: Enable ObjC and ObjC++ on macOS

* build: Add ObjC and ObjC++ flags

* build: Try compiling objc with clang

* build: Remove invalid flags again

* fix: Let's not include objc headers in C++ code

* sys: Move macos utils code to its own file

* fix: Missing unistd include on mac

* sys: Removed loader script stuff since it's currently unused and broken

* fix: Missing include

* fix: Another missing include

* fix: CFURLCreateWithBytes wants a pointer to mutable data

* fix: Try disabling name mangling of ObjC functions

* sys: Move macos utils declarations to its own header file

* fix: C Linkage

* fix: Move objc function prototypes to C++ headers

* fix: More missing includes

* fix: Warning error

* sys: Call ObjC with C ABI instead of trying to use C++

* build: Update libraries

* sys: Fixed build errors

* sys: No const correctness I guess

* sys: Fixed prototypes

* sys: This is C now

* sys: More nullptr -> NULL

* sys: Fix crash on exit

* sys: Try using proper std concepts instead of custom ones

* sys: Replaced another hex::is_signed

* build: Upgrade to gcc 12 and MacOS Monterey

* build: Fixed MacOS runner name

* build: Cache correct ccache folder on macOS
2022-06-25 12:19:59 +02:00
iTrooz_
546d0a4922 build: Fix the .dmg structure (#550)
* build: Initial attempt to fix .dmg mess

* build: Still download database resources on other OSes

* build: Try fixing path recursion error

* build: Move main executable and database files to correct folder

* build: Install main executable without installing python stuff

* build: Move things around to maybe get them to be bundled

* I wanna die

* renamed imhex.app to Imhex.app

* net.WerWolv.ImHex

Co-authored-by: WerWolv <werwolv98@gmail.com>
2022-06-24 00:27:35 +02:00
iTrooz_
c6989c2ef7 build: Fixed various issues with the CI and Linux packages (#548)
* Ci: added workflow_dispatch trigger

* Ci: removed fetch depth

* Ci: Add information to generated artifacts

* Ci: Updated Linux runner to Ubuntu 22.04

* Packaging: Updated .deb dependencies

* Ci: Removed ELF artifact

* Ci: Upgraded actions versions

* Ci: Switch to gcc-11 for unit tests and analysis
2022-06-23 23:48:02 +02:00
WerWolv
a5aa002752 patterns: Moved most built-in functions to the pattern language repo 2022-06-23 19:33:30 +02:00
Zakhar Afonin
b89490bca3 ui: New icons, as discussed in #545 (#546)
* Restyled macOS icon for Big Sur

* Update other icons

* Different gradients

* Reverted macOS icon because of design guidelines

* Final version of new icons
2022-06-20 14:12:34 +02:00
iTrooz_
e33726f526 git: Added automatic release and source tar upload on release (#537)
* added release.yml

* Build CI now only triggers on branch push
2022-06-19 15:16:03 +02:00
WerWolv
c238767750 fix: Hex editor selection moving with shift + arrow keys not working correctly 2022-06-19 15:09:38 +02:00
WerWolv
116aeede2d lang: Fixed some localization issues 2022-06-17 14:35:54 +02:00
Polshakov Dmitry
662d80abea feat: Add ability to remove bytes (#531)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-06-17 14:21:56 +02:00
WerWolv
f6ddb3c5e7 fix: Hex editor cell editing value taking value of next cell when double clicking
Fixes #541
2022-06-17 14:08:12 +02:00
WerWolv
6490e565d3 patterns: Fixed formatting issue with values of static arrays
Fixes #540
2022-06-17 13:47:49 +02:00
WerWolv
6b7ade8d61 fix: MacOS build error 2022-06-17 10:42:54 +02:00
WerWolv
9b77d7b5e2 fix: MacOS build error 2022-06-17 10:31:28 +02:00
WerWolv
1785088456 fix: MacOS looking for plugins in wrong folder inside of bundle
Hopefully addresses #539
2022-06-17 10:23:28 +02:00
WerWolv
4dcd26a21f fix: Editing value not being updated correctly when moving to next hex cell
Fixes #538
2022-06-17 10:16:58 +02:00
WerWolv
12e99a9d4c build: Output plugin files to correct path on build on Windows as well 2022-06-16 15:42:27 +02:00
WerWolv
5e67a1f27b sys: Refactor tar file operations into their own class 2022-06-16 15:42:08 +02:00
WerWolv
2a76e45dc5 build: Output plugin files to correct path on build on Linux
Fixes #536
2022-06-16 06:55:57 +02:00
WerWolv
6266883e81 fix: Crash when undocking hex editor view 2022-06-14 13:37:37 +02:00
WerWolv
aed9d15625 ux: Fix hex editor selection sometimes setting end to max address 2022-06-14 11:58:50 +02:00
WerWolv
5551e82fea ui: Fix hash function name localization 2022-06-14 11:54:34 +02:00
WerWolv
653a688fe6 fix: Very inefficient iterating over static array patterns
Fixes #532
2022-06-14 10:29:41 +02:00
WerWolv
dfc1dc2529 fix: Highlighting of static arrays that start at uneven addresses
Fixes #534
2022-06-14 10:19:59 +02:00
WerWolv
1e511acf37 fix: More vector out of bounds accesses 2022-06-14 10:17:50 +02:00
WerWolv
141ee62af9 ui: Fixed various background color issues with the new hex editor view
Closes #533
2022-06-13 23:43:34 +02:00
WerWolv
a5d202ffc8 fix: Vector out of bounds access 2022-06-13 21:56:02 +02:00
Polshakov Dmitry
f243ac7464 fix: correctly show checked plugin files (#529)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-06-09 15:58:40 +02:00
Polshakov Dmitry
91ac9ca120 fix: change displayEnd by reference in case of double click (#530)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-06-09 15:58:18 +02:00
WerWolv
a56ba50cf9 ux: Improved scrolling behaviour in hex editor view
Fixes #528
2022-06-09 15:57:25 +02:00
WerWolv
fdaad55cc6 ui: Fix misaligned selection highlighting in very big files 2022-06-09 15:10:33 +02:00
dependabot[bot]
9d19214be9 build(deps): Bump regex from 1.5.4 to 1.5.6 in /lib/libimhex-rs (#526)
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.4 to 1.5.6.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.4...1.5.6)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-08 16:19:16 +02:00
gordon--
038a6b9757 fix: Fallback languge being set to Portuguese (#524) 2022-06-04 15:52:02 +02:00
WerWolv
bad109ef8d fix: Resize and Insert bytes popups not working correctly 2022-06-03 18:47:03 +02:00
WerWolv
5623e1342b fix: Crashes when parsing invalid wstrings 2022-06-03 18:46:38 +02:00
WerWolv
6bad50c78b build: Bumped version to 1.18.2 2022-06-03 13:33:21 +02:00
WerWolv
6929ffb865 lang: Hooked up Brazilian Portuguese translation to the interface 2022-06-03 11:34:31 +02:00
WerWolv
2d7fdc0896 ui: Added hovering zoom popup to all visualizer nodes
Closes #519
2022-06-03 11:17:41 +02:00
WerWolv
d1d73bcff6 fix: Editing bytes in the hex editor being broken
Fixed #521
2022-06-03 10:53:03 +02:00
WerWolv
bf1441223c fix: Crash when no monitors have been defined by the OS 2022-06-03 10:35:47 +02:00
WerWolv
fadca9a34a fix: Bookmark header collapsing when name gets changed 2022-06-03 10:35:47 +02:00
Douglas Vianna
2ef3a0c157 lang: Added Brazilian Portuguese translation (#520)
* Add files via upload

* Add files via upload

* Update pt_BR.cpp
2022-06-01 20:17:28 +02:00
WerWolv
c96a0a7bda lang: Added missing localization for the hash view rewrite 2022-05-30 16:53:01 +02:00
WerWolv
fe6be686b7 ui/ux: Complete rewrite of the Hash view 2022-05-30 16:36:46 +02:00
WerWolv
05862ae991 ui: Make pattern editor error popup text more readable
Closes #517
2022-05-29 21:54:40 +02:00
WerWolv
6a6b6b94cf fix: std::pow on macOS not supporting i128 2022-05-29 20:52:22 +02:00
WerWolv
4701b1b67c fix: Pasting bytes in hex editor yielding wrong results
Closes #516
2022-05-29 19:00:21 +02:00
WerWolv
f1b2d5881e tools: Added IEEE 756 floating point number tester 2022-05-29 14:57:59 +02:00
WerWolv
efed07ac8b ux: Fixed another hex editor scroll issue 2022-05-28 22:31:40 +02:00
WerWolv
e5ff987392 build: Bumped version to 1.18.1 2022-05-28 20:14:30 +02:00
WerWolv
8a24517fb9 fix: Disable warnings only on GCC 12 and higher 2022-05-28 19:59:38 +02:00
WerWolv
a4c8bcab18 fix: Disable another warning to make macOS happy 2022-05-28 16:36:00 +02:00
WerWolv
4fd8ada4ff fix: Crash on exit 2022-05-28 16:33:52 +02:00
WerWolv
7bf94ffe42 fix: Compile errors on platforms that don't support -Wstringop-overread yet 2022-05-28 16:24:57 +02:00
WerWolv
088205385f fix: Workaround that broke functionality. Instead disable warnings
This actually fixes #515 for now
2022-05-28 16:19:08 +02:00
WerWolv
39c743631b fix: Weird build error on GCC 12.1.0 again
This fixes #515
2022-05-28 15:46:39 +02:00
WerWolv
603a95debb patterns: Updated pattern language 2022-05-28 14:14:12 +02:00
WerWolv
28a8adb26d fix: Hex editor selection scrolling not working correctly 2022-05-28 13:38:36 +02:00
WerWolv
e2bfd26bb3 fix: Bookmark menu entry causing wrong region to be marked 2022-05-28 12:56:26 +02:00
WerWolv
857aadfa61 build: Bumped version to 1.18.0 2022-05-28 11:44:56 +02:00
WerWolv
b8bbbd5489 feature: Added bool, DOS Date and DOS Time data inspector line 2022-05-27 20:49:38 +02:00
WerWolv
ffb9a8b7ed feature: Added Invert option to data inspector 2022-05-27 20:46:16 +02:00
WerWolv
b751f98e91 ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512)
* ui/ux: Initial recreation of the hex editor view

* ui/ux: Added back support for editing cells

* ux: Make scrolling and selecting bytes feel nice again

* ui/ux: Improved byte selecting, added footer

* sys: Make math evaluator more generic to support integer only calculations

* patterns: Moved value formatting into pattern language

* ui/ux: Added Goto and Search popups, improved selection

* ui: Added better tooltips for bookmarks and patterns

* sys: Use worse hex search algorithm on macOS

Sadly it still doesn't support `std::boyer_moore_horsepool_searcher`

* ui: Added back missing events, menu items and shortcuts

* fix: Bookmark highlighting being rendered off by one

* fix: Various macOS build errors

* fix: size_t is not u64 on macos

* fix: std::fmod and std::pow not working with integer types on macos

* fix: Missing semicolons

* sys: Added proper integer pow function

* ui: Added back support for custom encodings

* fix: Editor not jumping to selection when selection gets changed

* ui: Turn Hexii setting into a data visualizer

* sys: Added back remaining shortcuts

* sys: Remove old hex editor files

* sys: Moved more legacy things away from the hex editor view, updated localization

* fix: Hex editor scrolling behaving weirdly and inconsistently

* sys: Cleaned up Hex editor code

* sys: Added selection color setting, localized all new settings

* fix: Search feature not working correctly

* ui: Replace custom ImGui::Disabled function with native ImGui ones

* ui: Fix bookmark tooltip rendering issues

* fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
Matthias Mailänder
c0ceaa4195 build: Fixed the .desktop file (#513)
* Don't hardcode the path in here

* This is not a GNOME application
2022-05-27 20:20:42 +02:00
WerWolv
6121c35e02 git: Remove yaru icon theme from AppImage bundling 2022-05-23 13:44:36 +02:00
iTrooz_
c3ea0c74ee git: Fixed libicu version for AppImages (#510) 2022-05-23 10:13:20 +02:00
xtexChooser
610f189839 feat(wiki): Support custom language for Wikipedia (#505)
* sys: support typeless settings

* feat(wiki): support custom language for Wikipedia

* update
2022-05-22 23:26:46 +02:00
iTrooz_
5b74739c51 git: Fixed CI failing with AppImages (#509) 2022-05-22 23:23:54 +02:00
WerWolv
775e87ff1f patterns: Updated pattern language 2022-05-22 09:27:02 +02:00
WerWolv
c4b7d89713 fix: Random build errors with GCC 12.1.0 2022-05-17 20:46:42 +02:00
WerWolv
5f17d7aa75 fix: Narrowing conversion error in Encoding File parsing 2022-05-17 17:49:14 +02:00
xtexChooser
3595a94b67 feat(i18n): update Chinese(Simplified) translation (#502) 2022-05-11 21:52:50 +02:00
WerWolv
435edad604 patterns: Updated pattern language 2022-04-29 23:02:10 +02:00
WerWolv
87e616ad23 patterns: Fixed MIME pragma not being registered correctly 2022-04-27 08:54:38 +02:00
156 changed files with 8017 additions and 5486 deletions

View File

@@ -3,11 +3,12 @@ name: "CodeQL"
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
jobs:
codeql:
name: 🐛 CodeQL
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
permissions:
actions: read
contents: read
@@ -15,24 +16,30 @@ jobs:
steps:
- name: 🧰 Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: ✋ Initialize CodeQL
uses: github/codeql-action/init@v1
uses: github/codeql-action/init@v2
with:
languages: 'cpp'
- name: 📜 Restore cache
uses: actions/cache@v2
- name: 📜 Restore ccache
uses: actions/cache@v3
with:
path: |
~/.ccache
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update
@@ -42,15 +49,16 @@ jobs:
run: |
mkdir -p build
cd build
CC=gcc-10 CXX=g++-10 cmake \
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-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" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
..
make -j 4 install
- name: 🗯️ Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
uses: github/codeql-action/analyze@v2

View File

@@ -2,7 +2,9 @@ name: Build
on:
push:
branches: ["*"]
pull_request:
workflow_dispatch:
env:
BUILD_TYPE: Release
@@ -22,11 +24,33 @@ jobs:
CCACHE_COMPRESS: "true"
steps:
- name: 🧰 Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: 📜 Prepare Cache
id: prep-ccache
shell: bash
run: |
mkdir -p "${CCACHE_DIR}"
echo "::set-output name=dir::$CCACHE_DIR"
- name: 📜 Restore ccache
uses: actions/cache@v3
id: cache-ccache
with:
path: |
${{ steps.prep-ccache.outputs.dir }}
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🟦 Install msys2
uses: msys2/setup-msys2@v2
with:
@@ -52,21 +76,6 @@ jobs:
$USERPROFILE/.cargo/bin/rustup.exe target add x86_64-pc-windows-gnu
$USERPROFILE/.cargo/bin/rustup.exe default nightly
- name: 📜 Prepare Cache
id: prep-ccache
shell: bash
run: |
mkdir -p "${CCACHE_DIR}"
echo "::set-output name=dir::$CCACHE_DIR"
- name: 📜 Restore Cache
uses: actions/cache@v1
id: cache-ccache
with:
path: ${{ steps.prep-ccache.outputs.dir }}
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🛠️ Build
run: |
mkdir -p build
@@ -84,20 +93,23 @@ jobs:
-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_PATTERNS_PULL_MASTER=ON \
..
mingw32-make -j4 install
cpack
- name: ⬆️ Upload Portable ZIP
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: Windows Portable ZIP
name: Windows Portable
path: |
build/install/*
- name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: Windows Installer
path: |
@@ -105,72 +117,90 @@ jobs:
# MacOS build
macos:
runs-on: macos-11.0
runs-on: macos-11
name: 🍎 macOS 11.0
steps:
- name: 🧰 Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: 📜 Restore ccache
uses: actions/cache@v3
with:
path: |
~/Library/Caches/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
brew bundle --no-lock --file dist/Brewfile
- name: 📜 Restore cache
uses: actions/cache@v2
with:
path: |
~/.ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🛠️ Build
run: |
mkdir -p build
cd build
CC=$(brew --prefix llvm)/bin/clang \
CXX=$(brew --prefix llvm)/bin/clang++ \
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.15" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
MACOSX_DEPLOYMENT_TARGET="10.15" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
..
make -j4 package
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: macOS DMG
path: build/*.dmg
# Linux build
linux:
runs-on: ubuntu-20.04
name: 🐧 Ubuntu 20.04
runs-on: ubuntu-22.04
name: 🐧 Ubuntu 22.04
steps:
- name: 🧰 Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: 📜 Restore cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: |
~/.ccache
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
- name: 📜 Restore other caches
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
.flatpak-builder
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo rm -rf /usr/share/dotnet
@@ -184,7 +214,7 @@ jobs:
sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
sudo chmod +x /usr/local/bin/appimagetool
sudo pip3 install appimage-builder
sudo pip3 install appimage-builder==1.0.0
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
sh rustup-init.sh -y --default-toolchain none
@@ -197,17 +227,24 @@ jobs:
run: |
mkdir -p build
cd build
CC=gcc-11 CXX=g++-11 cmake \
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DRUST_PATH="$HOME/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
..
make -j 4 install DESTDIR=AppDir
- name: 📜 Set version variable
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
#- name: 📦 Bundle Flatpak
# run: |
# sudo apt install flatpak flatpak-builder
@@ -217,45 +254,125 @@ jobs:
# flatpak-builder --jobs=4 --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
# flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
- name: ⬆️ Upload ELF
uses: actions/upload-artifact@v2
with:
name: Linux ELF
path: |
build/AppDir/*
- name: 📦 Bundle DEB
run: |
cp -r build/DEBIAN build/AppDir
dpkg-deb --build build/AppDir
mv build/AppDir.deb imhex.deb
mv build/AppDir.deb imhex-${{env.IMHEX_VERSION}}.deb
rm -rf build/AppDir/DEBIAN
- name: 📦 Bundle AppImage
run: |
cd build
appimage-builder --recipe ../dist/AppImageBuilder.yml
mv ImHex-AppImage-x86_64.AppImage ../imhex.AppImage
mv ImHex-AppImage-x86_64.AppImage ../imhex-${{env.IMHEX_VERSION}}.AppImage
cd ..
#- name: ⬆️ Upload Flatpak
# uses: actions/upload-artifact@v2
# uses: actions/upload-artifact@v3
# with:
# name: Linux Flatpak
# path: |
# imhex.flatpak
- name: ⬆️ Upload DEB
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: Linux DEB
path: |
imhex.deb
name: Linux DEB (Ubuntu 22.04)
path: '*.deb'
- name: ⬆️ Upload AppImage
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: Linux AppImage
path: |
imhex.AppImage
path: '*.AppImage'
archlinux-build:
name: 🐧 ArchLinux
runs-on: ubuntu-latest
container:
image: archlinux:base-devel
steps:
- name: ⬇️ Update all packages
run: |
pacman -Syyu --noconfirm
- name: ⬇️ Install setup dependencies
run: |
pacman -Syu git ccache --noconfirm
- name: 🧰 Checkout
uses: actions/checkout@v3
with:
submodules: recursive
- name: ⬇️ Install ImHex dependencies
run: |
dist/get_deps_archlinux.sh --noconfirm
- name: 📜 Restore ccache
uses: actions/cache@v3
with:
path: |
~/.cache/ccache
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🛠️ Build
run: |
mkdir -p build
cd build
CC=gcc CXX=g++ cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DRUST_PATH="$HOME/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
..
make -j 4 install DESTDIR=installDir
- name: 📜 Set version variable
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
- name: ✒️ Prepare PKGBUILD
run: |
cp dist/Arch/PKGBUILD build
sed -i 's/%version%/${{env.IMHEX_VERSION}}/g' build/PKGBUILD
# makepkg doesn't want to run as root, so I had to chmod 777 all over
- name: 📦 Package ArchLinux .pkg.tar.zst
run: |
cd build
# the name is a small trick to make makepkg recognize it as the source
# else, it would try to download the file from the release
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst -C installDir .
chmod -R 777 .
sudo -u nobody makepkg
# Remplace the old file
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
uses: actions/upload-artifact@v3
with:
name: ArchLinux .pkg.tar.zst
path: |
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst

112
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,112 @@
permissions:
contents: write
name: Release
on:
release:
types: [published]
jobs:
release:
runs-on: ubuntu-latest
name: Release
steps:
- name: 🧰 Checkout
uses: actions/checkout@v3
with:
path: ImHex
submodules: recursive
- name: 📜 Verify version and set version variable
run: |
project_version=`cat ImHex/VERSION`
tag_version="${{github.event.release.tag_name}}"
tag_version="${tag_version:1}"
if [ "$project_version" != "$tag_version" ]; then
echo "::warning::$project_version and $tag_version are not the same ! Refusing to populate release"
exit 1
fi
echo "IMHEX_VERSION=$project_version" >> $GITHUB_ENV
- name: 🗜️ Create tarball from sources with dependencies
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
- name: ⬇️ Download artifacts from latest workflow
uses: dawidd6/action-download-artifact@v2
with:
github_token: ${{secrets.GITHUB_TOKEN}}
workflow: build.yml
branch: ${{ github.event.release.target_commitish }}
workflow_conclusion: success
skip_unpack: true
- name: 🗜️ Unzip files when needed
run: |
for zipfile in ./*.zip
do
if [ `zipinfo -1 "$zipfile" | wc -l` -eq 1 ];
then
echo "unzipping $zipfile"
unzip "$zipfile"
rm "$zipfile"
else
echo "keeping $zipfile zipped"
fi
done
- name: 🟩 Rename Windows Portable Zip
run: mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
- name: ⬆️ Upload everything to release
uses: softprops/action-gh-release@v1
with:
files: '*'
- name: ✒️ Prepare PKGBUILD
run: |
cp ImHex/dist/Arch/PKGBUILD .
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst | cut -d ' ' -f 1`
sed -i 's/%version%/${{env.IMHEX_VERSION}}/g' PKGBUILD
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
- name: ⬆️ Publish AUR package
# I couldn't make the condition in the env directly for some reason
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
if: "${{ env.AUR_SSH_PRIVATE_KEY != '' }}"
uses: KSXGitHub/github-actions-deploy-aur@v2
with:
pkgname: imhex-bin
pkgbuild: ./PKGBUILD
commit_username: iTrooz
commit_email: itrooz@protonmail.com
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: Bump to version ${{env.IMHEX_VERSION}}
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
- name: 🎫 Create PatternLanguage release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: PatternLanguage
token: ${{ secrets.RELEASE_TOKEN }}
- name: 🎫 Create ImHex-Patterns release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }}

View File

@@ -5,11 +5,12 @@ on:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
jobs:
tests:
name: 🧪 Unit Tests
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
permissions:
actions: read
contents: read
@@ -17,19 +18,26 @@ jobs:
steps:
- name: 🧰 Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: 📜 Restore cache
uses: actions/cache@v2
- name: 📜 Restore ccache
uses: actions/cache@v3
with:
path: |
~/.ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies
run: |
sudo apt update
@@ -39,13 +47,14 @@ jobs:
run: |
mkdir -p build
cd build
CC=gcc-10 CXX=g++-10 cmake \
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-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" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
..
make -j4 unit_tests install

3
.idea/vcs.xml generated
View File

@@ -2,9 +2,6 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules" vcs="Git" />
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules/utils/yara-forensics" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />

View File

@@ -1,14 +1,18 @@
cmake_minimum_required(VERSION 3.16)
# Updating the version here will update it throughout ImHex as well
set(IMHEX_VERSION "1.17.0")
file(READ "VERSION" IMHEX_VERSION)
project(imhex VERSION ${IMHEX_VERSION})
message("Project version ${IMHEX_VERSION}")
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 23)
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
# Make sure project is configured correctly
setDefaultBuiltTypeIfUnset()
detectBadClone()
@@ -36,6 +40,3 @@ add_subdirectory(tests EXCLUDE_FROM_ALL)
# Configure packaging
createPackage()
# Download and install all current files from the ImHex-Patterns repo
downloadImHexPatternsFiles()

View File

@@ -122,108 +122,22 @@ To develop plugins for ImHex, use one of the following two templates projects to
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
- Windows • __x86_64__
- [MSI](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
- [EXE](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable%20ZIP.zip)
- [Installer](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
- [Portable](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable%20ZIP.zip)
- MacOS • __x86_64__
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
- Linux • __x86_64__
- [ELF](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20ELF.zip)
- [DEB](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20DEB.zip)
- [Flatpak](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20Flatpak.zip)
- [AppImage](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20AppImage.zip)
- [Arch Package](https://nightly.link/WerWolv/ImHex/workflows/build/master/ArchLinux%20.pkg.tar.zst.zip)
## Compiling
You need a C++20 compatible compiler such as GCC 10.2.0 to compile ImHex.
To compile ImHex, a C++20 compiler is required. Releases are all mainly built using GCC, however on macOS, clang is also required to compile some ObjC code.
Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
For working examples
### Windows
On Windows, ImHex is built through msys2 / mingw. To install all dependencies, open a mys2 window and run the PKGCONFIG script in the [dist/msys2](dist/msys2) folder.
After all the dependencies are installed, run the following commands to build ImHex:
```sh
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j
```
---
To create a standalone zipfile on Windows, get the Python standard library (e.g. from https://github.com/python/cpython/tree/master/Lib) and place the files and folders in `lib/python3.8` next to your built executable. Don't forget to also copy the `libpython3.8.dll` and `libwinpthread-1.dll` from your mingw setup next to the executable.
- Copy the files inside the `/resources/lib/python` folder into the `lib` folder next to your built executable.
- Place your magic databases in the `magic` folder next to your built executable
- Place your patterns in the `pattern` folder next to your built executable
- Place your include pattern files in the `include` folder next to your built executable
### macOS
To build ImHex on macOS, run the following commands:
```sh
brew bundle --no-lock --file dist/Brewfile
mkdir build
cd build
CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" cmake -DCMAKE_BUILD_TYPE=Release ..
make -j
```
Install the ImHex executable as well as libimhex.dylib to wherever ImHex should be installed.
All other files belong in `~/Library/Application Support/imhex`:
```
Patterns: ~/Library/Application Support/imhex/patterns
Pattern Includes: ~/Library/Application Support/imhex/includes
Magic files: ~/Library/Application Support/imhex/magic
Python: ~/Library/Application Support/imhex/lib/pythonX.X
Plugins: ~/Library/Application Support/imhex/plugins
Configuration: ~/Library/Application Support/imhex/config
Resources: ~/Library/Application Support/imhex/resources
```
If the build fails while trying to find the macOS libraries, make sure you have
XCode installed with `xcode-select --install`. Homebrew will also help get the
most recent SDK installed and configured with `brew doctor`.
### Linux
Dependency installation scripts are available for many common Linux distributions in the [/dist](dist) folder.
After all the dependencies are installed, run the following commands to build ImHex:
```sh
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j
```
---
Put the ImHex executable into the `/usr/bin` folder.
Put libimhex.so into the `/usr/lib` folder.
Configuration files go to `/etc/xdg/imhex` or `~/.config/imhex`.
All other files belong in `/usr/share/imhex` or `~/.local/share/imhex`:
```
Patterns: /usr/share/imhex/patterns
Pattern Includes: /usr/share/imhex/includes
Magic files: /usr/share/imhex/magic
Python: /usr/share/imhex/lib/pythonX.X
Plugins: /usr/share/imhex/plugins
Configuration: /etc/xdg/imhex/config
Resources: /usr/share/imhex/resources
```
All paths follow the XDG Base Directories standard, and can thus be modified
with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
`XDG_DATA_HOME` and `XDG_DATA_DIRS`.
## Credits
### Contributors
@@ -231,6 +145,8 @@ with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
- [Mary](https://github.com/Thog) for her immense help porting ImHex to MacOS and help during development
- [Roblabla](https://github.com/Roblabla) for adding MSI Installer support to ImHex
- [jam1garner](https://github.com/jam1garner) and [raytwo](https://github.com/raytwo) for their help with adding Rust support to plugins
- [Mailaender](https://github.com/Mailaender) for getting ImHex onto Flathub
- [iTrooz](https://github.com/iTrooz) for many improvements related to release packaging and the GitHub Action runners.
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
### Libraries

1
VERSION Normal file
View File

@@ -0,0 +1 @@
1.19.3

View File

@@ -70,19 +70,18 @@ macro(detectOS)
set(CMAKE_INSTALL_BINDIR ".")
set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins")
set(MAGIC_INSTALL_LOCATION "magic")
elseif (APPLE)
add_compile_definitions(OS_MACOS)
set(CMAKE_INSTALL_BINDIR ".")
set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins")
set(MAGIC_INSTALL_LOCATION "magic")
enable_language(OBJC)
enable_language(OBJCXX)
elseif (UNIX AND NOT APPLE)
add_compile_definitions(OS_LINUX)
set(CMAKE_INSTALL_BINDIR "bin")
set(CMAKE_INSTALL_LIBDIR "lib")
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
set(MAGIC_INSTALL_LOCATION "share/imhex/magic")
else ()
message(FATAL_ERROR "Unknown / unsupported system!")
endif()
@@ -133,14 +132,14 @@ macro(configurePackingResources)
set(MACOSX_BUNDLE_INFO_STRING "WerWolv")
set(MACOSX_BUNDLE_BUNDLE_NAME "ImHex")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "WerWolv.ImHex")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 WerWolv and Thog. All rights reserved." )
if ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
set ( bundle_path "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/imhex.app" )
set ( bundle_path "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ImHex.app" )
else ()
set ( bundle_path "${CMAKE_BINARY_DIR}/imhex.app" )
set ( bundle_path "${CMAKE_BINARY_DIR}/ImHex.app" )
endif()
endif()
endif()
@@ -151,11 +150,11 @@ macro(createPackage)
foreach (plugin IN LISTS PLUGINS)
add_subdirectory("plugins/${plugin}")
if (TARGET ${plugin})
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
get_target_property(IS_RUST_PROJECT ${plugin} RUST_PROJECT)
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
if (IS_RUST_PROJECT)
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
@@ -163,7 +162,6 @@ macro(createPackage)
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}")
else ()
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
if (WIN32)
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
elseif (APPLE)
@@ -181,7 +179,6 @@ macro(createPackage)
endif ()
endforeach()
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
if (WIN32)
@@ -218,12 +215,20 @@ macro(createPackage)
)
endforeach()
]])
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
downloadImHexPatternsFiles("./")
elseif(UNIX AND NOT APPLE)
configure_file(${CMAKE_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
configure_file(${CMAKE_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
install(FILES ${CMAKE_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ${CMAKE_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
downloadImHexPatternsFiles("./share/imhex")
endif()
if (CREATE_BUNDLE)
include(PostprocessBundle)
@@ -234,20 +239,21 @@ macro(createPackage)
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_path}/Contents/MacOS/plugins")
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_path}/Contents/Resources")
downloadImHexPatternsFiles("${bundle_path}/Contents/MacOS")
install(FILES ${IMHEX_ICON} DESTINATION "${bundle_path}/Contents/Resources")
install(TARGETS main BUNDLE DESTINATION ".")
install(FILES $<TARGET_FILE:main> DESTINATION "${bundle_path}")
# Update library references to make the bundle portable
postprocess_bundle(imhex_all main)
# Enforce DragNDrop packaging.
set(CPACK_GENERATOR "DragNDrop")
install(TARGETS main BUNDLE DESTINATION .)
else()
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if (CREATE_PACKAGE)
include(apple)
include(CPack)
@@ -283,18 +289,26 @@ macro(detectBadClone)
endmacro()
function(downloadImHexPatternsFiles)
FetchContent_Declare(
imhex_patterns
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
GIT_TAG master
)
function(downloadImHexPatternsFiles dest)
if (NOT IMHEX_OFFLINE_BUILD)
if (IMHEX_PATTERNS_PULL_MASTER)
set(PATTERNS_BRANCH master)
else ()
set(PATTERNS_BRANCH ImHex-v${IMHEX_VERSION})
endif ()
FetchContent_Populate(imhex_patterns)
FetchContent_Declare(
imhex_patterns
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
GIT_TAG master
)
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION "./")
endforeach()
FetchContent_Populate(imhex_patterns)
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest})
endforeach ()
endif ()
endfunction()

View File

@@ -1,21 +1,7 @@
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
version: 1
script:
- rm -rf AppDir | true
- CC=gcc-11 CXX=g++11 cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
- make -j3 install DESTDIR=AppDir
- mv AppDir/usr/share/imhex/plugins AppDir/usr/bin/plugins
- mv AppDir/usr/constants AppDir/usr/bin/constants
- mv AppDir/usr/encodings AppDir/usr/bin/encodings
- mv AppDir/usr/includes AppDir/usr/bin/includes
- mv AppDir/usr/magic AppDir/usr/bin/magic
- mv AppDir/usr/patterns AppDir/usr/bin/patterns
- mkdir -p AppDir/usr/share/icons/hicolor/512x512
- cp AppDir/usr/share/pixmaps/imhex.png AppDir/usr/share/icons/hicolor/512x512/imhex.png
AppDir:
path: ./AppDir
path: .AppDir
app_info:
id: imhex
name: ImHex
@@ -28,18 +14,19 @@ AppDir:
- amd64
allow_unauthenticated: true
sources:
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish multiverse
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates multiverse
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-backports main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
- sourceline: deb http://.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
universe multiverse
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security main restricted
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security universe
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security multiverse
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
include:
- librsvg2-common
- libbz2-1.0:amd64
- libcap2:amd64
- libdbus-1-3:amd64
@@ -49,12 +36,11 @@ AppDir:
- libpcre3:amd64
- libselinux1:amd64
- libtinfo6:amd64
- yaru-theme-icon
files:
include:
- /lib/x86_64-linux-gnu/libGLX.so.0
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
- /lib/x86_64-linux-gnu/libLLVM-12.so.1
- /lib/x86_64-linux-gnu/libLLVM-13.so.1
- /lib/x86_64-linux-gnu/libOpenGL.so.0
- /lib/x86_64-linux-gnu/libX11.so.6
- /lib/x86_64-linux-gnu/libXau.so.6
@@ -82,7 +68,7 @@ AppDir:
- /lib/x86_64-linux-gnu/libedit.so.2
- /lib/x86_64-linux-gnu/libelf.so.1
- /lib/x86_64-linux-gnu/libepoxy.so.0
- /lib/x86_64-linux-gnu/libffi.so.7
- /lib/x86_64-linux-gnu/libffi.so.8
- /lib/x86_64-linux-gnu/libfontconfig.so.1
- /lib/x86_64-linux-gnu/libfreetype.so.6
- /lib/x86_64-linux-gnu/libfribidi.so.0
@@ -94,31 +80,41 @@ AppDir:
- /lib/x86_64-linux-gnu/libglfw.so.3
- /lib/x86_64-linux-gnu/libglib-2.0.so.0
- /lib/x86_64-linux-gnu/libgmodule-2.0.so.0
- /lib/x86_64-linux-gnu/libgmp.so.10
- /lib/x86_64-linux-gnu/libgnutls.so.30
- /lib/x86_64-linux-gnu/libgobject-2.0.so.0
- /lib/x86_64-linux-gnu/libgraphite2.so.3
- /lib/x86_64-linux-gnu/libgtk-3.so.0
- /lib/x86_64-linux-gnu/libharfbuzz.so.0
- /lib/x86_64-linux-gnu/libicudata.so.67
- /lib/x86_64-linux-gnu/libicuuc.so.67
- /lib/x86_64-linux-gnu/libhogweed.so.6
- /lib/x86_64-linux-gnu/libicudata.so.70
- /lib/x86_64-linux-gnu/libicuuc.so.70
- /lib/x86_64-linux-gnu/libidn2.so.0
- /lib/x86_64-linux-gnu/libjpeg.so.8
- /lib/x86_64-linux-gnu/liblber-2.5.so.0
- /lib/x86_64-linux-gnu/libldap-2.5.so.0
- /lib/x86_64-linux-gnu/liblz4.so.1
- /lib/x86_64-linux-gnu/libmagic.so.1
- /lib/x86_64-linux-gnu/libmbedcrypto.so.3
- /lib/x86_64-linux-gnu/libmbedtls.so.12
- /lib/x86_64-linux-gnu/libmbedx509.so.0
- /lib/x86_64-linux-gnu/libmbedcrypto.so.7
- /lib/x86_64-linux-gnu/libmbedtls.so.14
- /lib/x86_64-linux-gnu/libmbedx509.so.1
- /lib/x86_64-linux-gnu/libmd.so.0
- /lib/x86_64-linux-gnu/libmount.so.1
- /lib/x86_64-linux-gnu/libnettle.so.8
- /lib/x86_64-linux-gnu/libp11-kit.so.0
- /lib/x86_64-linux-gnu/libpango-1.0.so.0
- /lib/x86_64-linux-gnu/libpangocairo-1.0.so.0
- /lib/x86_64-linux-gnu/libpangoft2-1.0.so.0
- /lib/x86_64-linux-gnu/libpcre2-8.so.0
- /lib/x86_64-linux-gnu/libpixman-1.so.0
- /lib/x86_64-linux-gnu/libpng16.so.16
- /lib/x86_64-linux-gnu/libpython3.8.so.1.0
- /lib/x86_64-linux-gnu/libpython3.10.so.1.0
- /lib/x86_64-linux-gnu/libsasl2.so.2
- /lib/x86_64-linux-gnu/libsensors.so.5
- /lib/x86_64-linux-gnu/libstdc++.so.6
- /lib/x86_64-linux-gnu/libsystemd.so.0
- /lib/x86_64-linux-gnu/libtasn1.so.6
- /lib/x86_64-linux-gnu/libthai.so.0
- /lib/x86_64-linux-gnu/libunistring.so.2
- /lib/x86_64-linux-gnu/libuuid.so.1
- /lib/x86_64-linux-gnu/libvulkan.so.1
- /lib/x86_64-linux-gnu/libwayland-client.so.0

39
dist/Arch/PKGBUILD vendored Normal file
View File

@@ -0,0 +1,39 @@
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
pkgname=imhex-bin
pkgver=%version%
pkgrel=1
pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM. "
arch=("x86_64")
url="https://github.com/WerWolv/ImHex"
repo=$url
license=('GPL 2.0')
groups=()
depends=(glfw mbedtls python freetype2 libglvnd dbus xdg-desktop-portal)
makedepends=(git)
checkdepends=()
optdepends=()
provides=(imhex)
conflicts=(imhex)
replaces=()
backup=()
options=()
source=($repo"/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
noextract=()
md5sums=(SKIP)
validpgpkeys=()
package() {
tar -xf imhex-$pkgver-ArchLinux.pkg.tar.zst
install -DT $srcdir/usr/bin/imhex $pkgdir/usr/bin/imhex
install -DT $srcdir/usr/lib/libimhex.so $pkgdir/usr/lib/libimhex.so
for plugin in $srcdir/usr/share/imhex/plugins/*.hexplug;
do
install -DT $plugin $pkgdir/usr/share/imhex/plugins/`basename $plugin`
done
cp -r $srcdir/usr/share/imhex/{constants,encodings,includes,magic,patterns} $pkgdir/usr/share/imhex
cp -r $srcdir/usr/share/{applications,licenses} $pkgdir/usr/share
install -d $pkgdir/usr/share
}

4
dist/Brewfile vendored
View File

@@ -7,6 +7,4 @@ brew "python3"
brew "freetype2"
brew "libmagic"
brew "pkg-config"
# TODO: Remove this when XCode version of clang will support the same level as LLVM 10
brew "llvm"
brew "gcc@12"

View File

@@ -4,7 +4,7 @@ Section: editors
Priority: optional
Architecture: amd64
License: GNU GPL-2
Depends: libglfw3-dev, libmagic-dev, libmbedtls-dev, libcapstone-dev, python3-dev, libfreetype-dev, libgtk-3-dev, libldap2-dev
Depends: libglfw3, libmagic1, libmbedtls14, libpython3.10, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
Maintainer: WerWolv <hey@werwolv.net>
Description: ImHex Hex Editor
A Hex Editor for Reverse Engineers, Programmers and

View File

@@ -1,11 +0,0 @@
[Desktop Entry]
Name=ImHex
Comment=ImHex Hex Editor
GenericName=Hex Editor
Exec=/usr/bin/imhex %U
Icon=/usr/share/pixmaps/imhex.png
Type=Application
StartupNotify=true
Categories=GNOME;GTK;Development;
StartupWMClass=imhex

3
dist/Dockerfile vendored
View File

@@ -15,7 +15,8 @@ RUN pacman -S --needed --noconfirm \
mbedtls \
python3 \
freetype2 \
gtk3
dbus \
xdg-desktop-portal
# Clone ImHex
RUN git clone https://github.com/WerWolv/ImHex --recurse-submodules /root/ImHex

View File

@@ -27,6 +27,7 @@ RDEPEND="${DEPEND}
sys-apps/file
dev-libs/mbedtls
dev-cpp/nlohmann_json
x11-libs/gtk+
dbus
xdg-desktop-portal
"
BDEPEND="${DEPEND}"

41
dist/compiling/linux.md vendored Normal file
View File

@@ -0,0 +1,41 @@
### Compiling ImHex on Linux
Dependency installation scripts are available for many common Linux distributions in the [/dist](dist) folder.
After all the dependencies are installed, run the following commands to build ImHex:
```sh
mkdir -p build
cd build
CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DRUST_PATH="$HOME/.cargo/bin/" \
..
make -j 4 install
```
---
Put the ImHex executable into the `/usr/bin` folder.
Put libimhex.so into the `/usr/lib` folder.
Configuration files go to `/usr/etc/imhex` or `~/.config/imhex`.
All other files belong in `/usr/share/imhex` or `~/.local/share/imhex`:
```
Patterns: /usr/share/imhex/patterns
Pattern Includes: /usr/share/imhex/includes
Magic files: /usr/share/imhex/magic
Python: /usr/share/imhex/lib/pythonX.X
Plugins: /usr/share/imhex/plugins
Configuration: /etc/xdg/imhex/config
```
All paths follow the XDG Base Directories standard, and can thus be modified
with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
`XDG_DATA_HOME` and `XDG_DATA_DIRS`.

41
dist/compiling/macOS.md vendored Normal file
View File

@@ -0,0 +1,41 @@
### Compiling ImHex on macOS
To build ImHex on macOS, run the following commands:
```sh
brew bundle --no-lock --file dist/Brewfile
mkdir -p build
cd build
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.15" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
..
make -j4 package
```
Open the generated .dmg file and drag-n-drop the ImHex executable to the Applications folder
All other files belong in `~/Library/Application Support/imhex`:
```
Patterns: ~/Library/Application Support/imhex/patterns
Pattern Includes: ~/Library/Application Support/imhex/includes
Magic files: ~/Library/Application Support/imhex/magic
Python: ~/Library/Application Support/imhex/lib/pythonX.X
Plugins: ~/Library/Application Support/imhex/plugins
Configuration: ~/Library/Application Support/imhex/config
```
If the build fails while trying to find the macOS libraries, make sure you have
XCode installed with `xcode-select --install`. Homebrew will also help get the
most recent SDK installed and configured with `brew doctor`.

23
dist/compiling/windows.md vendored Normal file
View File

@@ -0,0 +1,23 @@
### Compiling ImHex on Windows
On Windows, ImHex is built through msys2 / mingw. To install all dependencies, open a msys2 window and run the PKGCONFIG script in the [dist/msys2](dist/msys2) folder.
After all the dependencies are installed, run the following commands to build ImHex:
```sh
mkdir build
cd build
cmake -G "MinGW Makefiles" \
-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/" \
..
mingw32-make -j install
```
ImHex will look for any extra resources either in various folders directly next to the executable or in `%localappdata%/imhex`

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env sh
pacman -S --needed \
pacman -S $@ --needed \
cmake \
gcc \
lld \
@@ -9,4 +9,5 @@ pacman -S --needed \
mbedtls \
python3 \
freetype2 \
gtk3
dbus \
xdg-desktop-portal

View File

@@ -1,9 +1,5 @@
#!/usr/bin/env sh
echo "As of 2020-12, Debian stable does not include g++-10, needs debian testing or unstable."
# Tested on 2020-12-09 with Docker image bitnami/minideb:unstable
# Install pkgconf (adds minimum dependencies) only if the equivalent pkf-config is not already installed.
if ! which pkg-config
then
@@ -12,8 +8,8 @@ fi
apt install -y \
build-essential \
gcc-11 \
g++-11 \
gcc-12 \
g++-12 \
lld \
${PKGCONF:-} \
cmake \
@@ -25,7 +21,5 @@ apt install -y \
libmbedtls-dev \
python3-dev \
libfreetype-dev \
libgtk-3-dev \
echo "Please consider this before running cmake (useful on e.g. Ubuntu 20.04):"
echo "export CXX=g++-11"
libdbus-1-dev \
xdg-desktop-portal

View File

@@ -10,4 +10,5 @@ dnf install \
mbedtls-devel \
python-devel \
freetype-devel \
gtk3-devel
dbus \
xdg-desktop-portal

5
dist/imhex.desktop vendored
View File

@@ -2,10 +2,9 @@
Name=ImHex
Comment=ImHex Hex Editor
GenericName=Hex Editor
Exec=/usr/bin/imhex %U
Exec=imhex %U
Icon=imhex
Type=Application
StartupNotify=true
Categories=GNOME;GTK;Development;
Categories=Development;IDE;
StartupWMClass=imhex

View File

@@ -32,14 +32,14 @@ add_library(imgui OBJECT
source/implot_items.cpp
source/implot_demo.cpp
fonts/fontawesome_font.c
fonts/codicons_font.c
fonts/unifont_font.c
source/fonts/fontawesome_font.c
source/fonts/codicons_font.c
source/fonts/unifont_font.c
)
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
target_include_directories(imgui PUBLIC include fonts ${CMAKE_CURRENT_SOURCE_DIR} ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS})

View File

@@ -1,805 +0,0 @@
// Mini memory editor for Dear ImGui (to embed in your game/tools)
// Get latest version at http://www.github.com/ocornut/imgui_club
//
// Right-click anywhere to access the Options menu!
// You can adjust the keyboard repeat delay/rate in ImGuiIO.
// The code assume a mono-space font for simplicity!
// If you don't use the default font, use ImGui::PushFont()/PopFont() to switch to a mono-space font before caling this.
//
// Usage:
// // Create a window and draw memory editor inside it:
// static MemoryEditor mem_edit_1;
// static char data[0x10000];
// size_t data_size = 0x10000;
// mem_edit_1.DrawWindow("Memory Editor", data, data_size);
//
// Usage:
// // If you already have a window, use DrawContents() instead:
// static MemoryEditor mem_edit_2;
// ImGui::Begin("MyWindow")
// mem_edit_2.DrawContents(this, sizeof(*this), (size_t)this);
// ImGui::End();
//
// Changelog:
// - v0.10: initial version
// - v0.23 (2017/08/17): added to github. fixed right-arrow triggering a byte write.
// - v0.24 (2018/06/02): changed DragInt("Rows" to use a %d data format (which is desirable since imgui 1.61).
// - v0.25 (2018/07/11): fixed wording: all occurrences of "Rows" renamed to "Columns".
// - v0.26 (2018/08/02): fixed clicking on hex region
// - v0.30 (2018/08/02): added data preview for common data types
// - v0.31 (2018/10/10): added OptUpperCaseHex option to select lower/upper casing display [@samhocevar]
// - v0.32 (2018/10/10): changed signatures to use void* instead of unsigned char*
// - v0.33 (2018/10/10): added OptShowOptions option to hide all the interactive option setting.
// - v0.34 (2019/05/07): binary preview now applies endianness setting [@nicolasnoble]
// - v0.35 (2020/01/29): using ImGuiDataType available since Dear ImGui 1.69.
// - v0.36 (2020/05/05): minor tweaks, minor refactor.
// - v0.40 (2020/10/04): fix misuse of ImGuiListClipper API, broke with Dear ImGui 1.79. made cursor position appears on left-side of edit box. option popup appears on mouse release. fix MSVC warnings where _CRT_SECURE_NO_WARNINGS wasn't working in recent versions.
// - v0.41 (2020/10/05): fix when using with keyboard/gamepad navigation enabled.
// - v0.42 (2020/10/14): fix for . character in ASCII view always being greyed out.
//
// Todo/Bugs:
// - This is generally old code, it should work but please don't use this as reference!
// - Arrows are being sent to the InputText() about to disappear which for LeftArrow makes the text cursor appear at position 1 for one frame.
// - Using InputText() is awkward and maybe overkill here, consider implementing something custom.
#pragma once
#include <stdio.h> // sprintf, scanf
#include <stdint.h> // uint8_t, etc.
#include <hex.hpp>
#include <hex/api/event.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
#include <string>
#ifdef _MSC_VER
#define _PRISizeT "I"
#define ImSnprintf _snprintf
#else
#define _PRISizeT "z"
#define ImSnprintf snprintf
#endif
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4996) // warning C4996: 'sprintf': This function or variable may be unsafe.
#endif
ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
struct MemoryEditor
{
enum DataFormat
{
DataFormat_Bin = 0,
DataFormat_Dec = 1,
DataFormat_Hex = 2,
DataFormat_COUNT
};
struct DecodeData {
std::string data;
size_t advance;
ImColor color;
};
// Settings
bool ReadOnly; // = false // disable any editing.
int Cols; // = 16 // number of columns to display.
bool OptShowOptions; // = true // display options button/context menu. when disabled, options will be locked unless you provide your own UI for them.
bool OptShowHexII; // = false // display values in HexII representation instead of regular hexadecimal: hide null/zero bytes, ascii values as ".X".
bool OptShowAscii; // = true // display ASCII representation on the right side.
bool OptShowAdvancedDecoding; // = true // display advanced decoding data on the right side.
bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color.
bool OptUpperCaseHex; // = true // display hexadecimal values as "FF" instead of "ff".
bool OptShowExtraInfo; // = true // display extra information about size of data and current selection
int OptMidColsCount; // = 8 // set to 0 to disable extra spacing between every mid-cols.
int OptAddrDigitsCount; // = 0 // number of addr digits to display (default calculated based on maximum displayed addr).
ImU32 HighlightColor; // // background color of highlighted bytes.
ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes.
void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes.
bool (*HighlightFn)(const ImU8* data, size_t off, bool next);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting).
void (*HoverFn)(const ImU8 *data, size_t off);
DecodeData (*DecodeFn)(const ImU8 *data, size_t off);
// [Internal State]
bool ContentsWidthChanged;
size_t DataPreviewAddr;
size_t DataPreviewAddrOld;
size_t DataPreviewAddrEnd;
size_t DataPreviewAddrEndOld;
size_t DataEditingAddr;
bool DataEditingTakeFocus;
char DataInputBuf[32];
char AddrInputBuf[32];
size_t GotoAddr;
size_t HighlightMin, HighlightMax;
int PreviewEndianess;
ImGuiDataType PreviewDataType;
MemoryEditor()
{
// Settings
ReadOnly = false;
Cols = 16;
OptShowOptions = true;
OptShowHexII = false;
OptShowAscii = true;
OptShowAdvancedDecoding = true;
OptGreyOutZeroes = true;
OptUpperCaseHex = true;
OptMidColsCount = 8;
OptAddrDigitsCount = 0;
HighlightColor = IM_COL32(255, 255, 255, 50);
ReadFn = NULL;
WriteFn = NULL;
HighlightFn = NULL;
HoverFn = NULL;
DecodeFn = NULL;
// State/Internals
ContentsWidthChanged = false;
DataPreviewAddr = DataEditingAddr = DataPreviewAddrEnd = (size_t)-1;
DataPreviewAddrOld = DataPreviewAddrEndOld = (size_t)-1;
DataEditingTakeFocus = false;
memset(DataInputBuf, 0, sizeof(DataInputBuf));
memset(AddrInputBuf, 0, sizeof(AddrInputBuf));
GotoAddr = (size_t)-1;
HighlightMin = HighlightMax = (size_t)-1;
PreviewEndianess = 0;
PreviewDataType = ImGuiDataType_S32;
}
void GotoAddrAndHighlight(size_t addr_min, size_t addr_max)
{
GotoAddr = addr_min;
HighlightMin = addr_min;
HighlightMax = addr_max;
}
void GotoAddrAndSelect(size_t addr_min, size_t addr_max)
{
GotoAddr = addr_min;
DataPreviewAddr = addr_min;
DataPreviewAddrEnd = addr_max;
DataPreviewAddrOld = addr_min;
DataPreviewAddrEndOld = addr_max;
}
struct Sizes
{
int AddrDigitsCount;
float LineHeight;
float GlyphWidth;
float HexCellWidth;
float SpacingBetweenMidCols;
float PosHexStart;
float PosHexEnd;
float PosAsciiStart;
float PosAsciiEnd;
float PosDecodingStart;
float PosDecodingEnd;
float WindowWidth;
Sizes() { memset(this, 0, sizeof(*this)); }
};
void CalcSizes(Sizes& s, size_t mem_size, size_t base_display_addr)
{
ImGuiStyle& style = ImGui::GetStyle();
s.AddrDigitsCount = OptAddrDigitsCount;
if (s.AddrDigitsCount == 0)
for (size_t n = base_display_addr + mem_size - 1; n > 0; n >>= 4)
s.AddrDigitsCount++;
s.LineHeight = ImGui::GetTextLineHeight();
s.GlyphWidth = ImGui::CalcTextSize("F").x + 1; // We assume the font is mono-space
s.HexCellWidth = (float)(int)(s.GlyphWidth * 2.5f); // "FF " we include trailing space in the width to easily catch clicks everywhere
s.SpacingBetweenMidCols = (float)(int)(s.HexCellWidth * 0.25f); // Every OptMidColsCount columns we add a bit of extra spacing
s.PosHexStart = (s.AddrDigitsCount + 2) * s.GlyphWidth;
s.PosHexEnd = s.PosHexStart + (s.HexCellWidth * Cols);
s.PosAsciiStart = s.PosAsciiEnd = s.PosHexEnd;
if (OptShowAscii && OptShowAdvancedDecoding) {
s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1;
if (OptMidColsCount > 0)
s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth;
s.PosDecodingStart = s.PosAsciiEnd + s.GlyphWidth * 1;
if (OptMidColsCount > 0)
s.PosDecodingStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
s.PosDecodingEnd = s.PosDecodingStart + Cols * s.GlyphWidth;
} else if (OptShowAscii) {
s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1;
if (OptMidColsCount > 0)
s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth;
} else if (OptShowAdvancedDecoding) {
s.PosDecodingStart = s.PosHexEnd + s.GlyphWidth * 1;
if (OptMidColsCount > 0)
s.PosDecodingStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
s.PosDecodingEnd = s.PosDecodingStart + Cols * s.GlyphWidth;
}
s.WindowWidth = s.PosAsciiEnd + style.ScrollbarSize + style.WindowPadding.x * 2 + s.GlyphWidth;
}
// Standalone Memory Editor window
void DrawWindow(const char* title, bool *p_open, void* mem_data, size_t mem_size, size_t base_display_addr = 0x0000)
{
Sizes s;
CalcSizes(s, mem_size, base_display_addr);
if (ImGui::Begin(title, p_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNavInputs))
{
if (DataPreviewAddr != DataPreviewAddrOld || DataPreviewAddrEnd != DataPreviewAddrEndOld) {
hex::Region selectionRegion = { std::min(DataPreviewAddr, DataPreviewAddrEnd) + base_display_addr, (std::max(DataPreviewAddr, DataPreviewAddrEnd) - std::min(DataPreviewAddr, DataPreviewAddrEnd)) + 1 };
hex::EventManager::post<hex::EventRegionSelected>(selectionRegion);
}
DataPreviewAddrOld = DataPreviewAddr;
DataPreviewAddrEndOld = DataPreviewAddrEnd;
if (mem_size > 0)
DrawContents(mem_data, mem_size, base_display_addr);
if (ContentsWidthChanged)
{
CalcSizes(s, mem_size, base_display_addr);
ImGui::SetWindowSize(ImVec2(s.WindowWidth, ImGui::GetWindowSize().y));
}
}
ImGui::End();
}
// Memory Editor contents only
void DrawContents(void* mem_data_void, size_t mem_size, size_t base_display_addr = 0x0000)
{
if (Cols < 1)
Cols = 1;
ImU8* mem_data = (ImU8*)mem_data_void;
Sizes s;
CalcSizes(s, mem_size, base_display_addr);
ImGuiStyle& style = ImGui::GetStyle();
// We begin into our scrolling region with the 'ImGuiWindowFlags_NoMove' in order to prevent click from moving the window.
// This is used as a facility since our main click detection code doesn't assign an ActiveId so the click would normally be caught as a window-move.
const float height_separator = style.ItemSpacing.y;
float footer_height = 0;
if (OptShowOptions)
footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 2;
ImGui::BeginChild("offset", ImVec2(0, s.LineHeight), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
ImGui::Text("%*c ", s.AddrDigitsCount, ' ');
for (int i = 0; i < Cols; i++) {
float byte_pos_x = s.PosHexStart + s.HexCellWidth * i;
if (OptMidColsCount > 0)
byte_pos_x += (float)(i / OptMidColsCount) * s.SpacingBetweenMidCols;
ImGui::SameLine(byte_pos_x);
ImGui::TextFormatted("{:02X}", i + (base_display_addr % Cols));
}
ImGui::EndChild();
ImGui::BeginChild("##scrolling", ImVec2(0, -footer_height), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
// We are not really using the clipper API correctly here, because we rely on visible_start_addr/visible_end_addr for our scrolling function.
ImGuiListClipper clipper;
ImDrawList* draw_list = ImGui::GetWindowDrawList();
const int line_total_count = (int)((mem_size + Cols - 1) / Cols);
clipper.Begin(line_total_count, s.LineHeight);
const size_t visible_start_addr = clipper.DisplayStart * Cols;
const size_t visible_end_addr = clipper.DisplayEnd * Cols;
const size_t visible_count = visible_end_addr - visible_start_addr;
bool data_next = false;
if (DataEditingAddr >= mem_size)
DataEditingAddr = (size_t)-1;
if (DataPreviewAddr >= mem_size)
DataPreviewAddr = (size_t)-1;
if (DataPreviewAddrEnd >= mem_size)
DataPreviewAddrEnd = (size_t)-1;
size_t data_editing_addr_backup = DataEditingAddr;
size_t data_preview_addr_backup = DataPreviewAddr;
size_t data_editing_addr_next = (size_t)-1;
size_t data_preview_addr_next = (size_t)-1;
if (ImGui::IsWindowFocused()) {
// Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered)
if (DataEditingAddr != (size_t)-1) {
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataEditingAddr >= (size_t)Cols) { data_editing_addr_next = DataEditingAddr - Cols; DataEditingTakeFocus = true; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataEditingAddr < mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; DataEditingTakeFocus = true; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataEditingAddr > 0) { data_editing_addr_next = DataEditingAddr - 1; DataEditingTakeFocus = true; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = DataEditingAddr + 1; DataEditingTakeFocus = true; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)) && DataEditingAddr > 0) { data_editing_addr_next = std::max<i64>(0, DataEditingAddr - visible_count); DataEditingTakeFocus = true; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = std::min<i64>(mem_size - 1, DataEditingAddr + visible_count); DataEditingTakeFocus = true; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataEditingAddr > 0) { data_editing_addr_next = 0; DataEditingTakeFocus = true; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = mem_size - 1; DataEditingTakeFocus = true; }
} else if (DataPreviewAddr != (size_t)-1) {
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataPreviewAddr >= (size_t)Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataPreviewAddr < mem_size - Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = std::max<i64>(0, DataPreviewAddr - visible_count); if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = std::min<i64>(mem_size - 1, DataPreviewAddr + visible_count); if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = 0; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = mem_size - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
}
} else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape))) {
DataPreviewAddr = DataPreviewAddrOld = DataPreviewAddrEnd = DataPreviewAddrEndOld = data_preview_addr_next = (size_t)-1;
HighlightMin = HighlightMax = (size_t)-1;
hex::EventManager::post<hex::EventRegionSelected>(hex::Region{ (size_t)-1, 0 });
}
if (data_preview_addr_next != (size_t)-1 && (data_preview_addr_next / Cols) != (data_preview_addr_backup / Cols))
{
// Track cursor movements
const int scroll_offset = ((int)(data_preview_addr_next / Cols) - (int)(data_preview_addr_backup / Cols));
const bool scroll_desired = (scroll_offset < 0 && data_preview_addr_next < visible_start_addr + Cols * 2) || (scroll_offset > 0 && data_preview_addr_next > visible_end_addr - Cols * 2);
if (scroll_desired)
ImGui::SetScrollY(ImGui::GetScrollY() + scroll_offset * s.LineHeight);
}
if (data_editing_addr_next != (size_t)-1 && (data_editing_addr_next / Cols) != (data_editing_addr_backup / Cols))
{
// Track cursor movements
const int scroll_offset = ((int)(data_editing_addr_next / Cols) - (int)(data_editing_addr_backup / Cols));
const bool scroll_desired = (scroll_offset < 0 && data_editing_addr_next < visible_start_addr + Cols * 2) || (scroll_offset > 0 && data_editing_addr_next > visible_end_addr - Cols * 2);
if (scroll_desired)
ImGui::SetScrollY(ImGui::GetScrollY() + scroll_offset * s.LineHeight);
}
// Draw vertical separator
ImVec2 window_pos = ImGui::GetWindowPos();
float scrollX = ImGui::GetScrollX();
if (OptShowAscii)
draw_list->AddLine(ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth - scrollX, window_pos.y), ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth - scrollX, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border));
if (OptShowAdvancedDecoding)
draw_list->AddLine(ImVec2(window_pos.x + s.PosDecodingStart - s.GlyphWidth - scrollX, window_pos.y), ImVec2(window_pos.x + s.PosDecodingStart - s.GlyphWidth - scrollX, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border));
const ImU32 color_text = ImGui::GetColorU32(ImGuiCol_Text);
const ImU32 color_disabled = OptGreyOutZeroes ? ImGui::GetColorU32(ImGuiCol_TextDisabled) : color_text;
const char* format_address = OptUpperCaseHex ? "%0*" _PRISizeT "X: " : "%0*" _PRISizeT "x: ";
const char* format_data = OptUpperCaseHex ? "%0*" _PRISizeT "X" : "%0*" _PRISizeT "x";
const char* format_byte = OptUpperCaseHex ? "%02X" : "%02x";
const char* format_byte_space = OptUpperCaseHex ? "%02X " : "%02x ";
bool tooltipShown = false;
while (clipper.Step())
{
for (int line_i = clipper.DisplayStart; line_i < clipper.DisplayEnd; line_i++) // display only visible lines
{
size_t addr = (size_t)(line_i * Cols);
ImGui::Text(format_address, s.AddrDigitsCount, base_display_addr + addr);
// Draw Hexadecimal
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
{
float byte_pos_x = s.PosHexStart + s.HexCellWidth * n;
if (OptMidColsCount > 0)
byte_pos_x += (float)(n / OptMidColsCount) * s.SpacingBetweenMidCols;
ImGui::SameLine(byte_pos_x);
// Draw highlight
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
{
ImVec2 pos = ImGui::GetCursorScreenPos() - ImVec2(ImGui::GetStyle().CellPadding.x / 2, 0);
float highlight_width = s.GlyphWidth * 2 + ImGui::GetStyle().CellPadding.x / 2;
bool is_next_byte_highlighted = (addr + 1 < mem_size) &&
((HighlightMax != (size_t)-1 && addr + 1 < HighlightMax) ||
(HighlightFn && HighlightFn(mem_data, addr + 1, true)) ||
((addr + 1) >= DataPreviewAddr && (addr + 1) <= DataPreviewAddrEnd) || ((addr + 1) >= DataPreviewAddrEnd && (addr + 1) <= DataPreviewAddr));
if (is_next_byte_highlighted)
{
highlight_width = s.HexCellWidth;
if (OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 0)
highlight_width += s.SpacingBetweenMidCols;
}
ImU32 color = HighlightColor;
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), color);
if (is_highlight_from_preview) {
size_t min = std::min(DataPreviewAddr, DataPreviewAddrEnd);
size_t max = std::max(DataPreviewAddr, DataPreviewAddrEnd);
// Draw vertical line at the left of first byte and the start of the line
if (n == 0 || addr == min)
draw_list->AddLine(pos, pos + ImVec2(0, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
// Draw vertical line at the right of the last byte and the end of the line
if (n == Cols - 1 || addr == max) {
draw_list->AddRectFilled(pos + ImVec2(highlight_width, 0), pos + ImVec2(highlight_width + 1, s.LineHeight), color);
draw_list->AddLine(pos + ImVec2(highlight_width + 1, -1), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
}
// Draw horizontal line at the top of the bytes
if ((addr - Cols) < min)
draw_list->AddLine(pos, pos + ImVec2(highlight_width + 1, 0), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
// Draw horizontal line at the bottom of the bytes
if ((addr + Cols) == (max + 1) && OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 1)
draw_list->AddLine(pos + ImVec2(-s.SpacingBetweenMidCols, s.LineHeight), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
else if ((addr + Cols) > max)
draw_list->AddLine(pos + ImVec2(0, s.LineHeight), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
}
}
if (DataEditingAddr == addr)
{
// Display text input on current byte
bool data_write = false;
ImGui::PushID((void*)addr);
if (DataEditingTakeFocus)
{
ImGui::SetKeyboardFocusHere();
ImGui::CaptureKeyboardFromApp(true);
sprintf(AddrInputBuf, format_data, s.AddrDigitsCount, base_display_addr + addr);
sprintf(DataInputBuf, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
}
ImGui::PushItemWidth(s.GlyphWidth * 2);
struct UserData
{
// FIXME: We should have a way to retrieve the text edit cursor position more easily in the API, this is rather tedious. This is such a ugly mess we may be better off not using InputText() at all here.
static int Callback(ImGuiInputTextCallbackData* data)
{
UserData* user_data = (UserData*)data->UserData;
if (!data->HasSelection())
user_data->CursorPos = data->CursorPos;
if (data->SelectionStart == 0 && data->SelectionEnd == data->BufTextLen)
{
// When not editing a byte, always rewrite its content (this is a bit tricky, since InputText technically "owns" the master copy of the buffer we edit it in there)
data->DeleteChars(0, data->BufTextLen);
data->InsertChars(0, user_data->CurrentBufOverwrite);
data->SelectionStart = 0;
data->SelectionEnd = 2;
data->CursorPos = 0;
}
return 0;
}
char CurrentBufOverwrite[3]; // Input
int CursorPos; // Output
};
UserData user_data;
user_data.CursorPos = -1;
sprintf(user_data.CurrentBufOverwrite, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_AlwaysInsertMode | ImGuiInputTextFlags_CallbackAlways;
if (ImGui::InputText("##data", DataInputBuf, 32, flags, UserData::Callback, &user_data))
data_write = data_next = true;
else if (!DataEditingTakeFocus && !ImGui::IsItemActive())
DataEditingAddr = data_editing_addr_next = (size_t)-1;
DataEditingTakeFocus = false;
ImGui::PopItemWidth();
if (user_data.CursorPos >= 2)
data_write = data_next = true;
if (data_editing_addr_next != (size_t)-1)
data_write = data_next = false;
unsigned int data_input_value = 0;
if (data_write && sscanf(DataInputBuf, "%X", &data_input_value) == 1)
{
if (WriteFn)
WriteFn(mem_data, addr, (ImU8)data_input_value);
else
mem_data[addr] = (ImU8)data_input_value;
}
ImGui::PopID();
}
else
{
// NB: The trailing space is not visible but ensure there's no gap that the mouse cannot click on.
ImU8 b = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
if (OptShowHexII)
{
if ((b >= 32 && b < 128))
ImGui::Text(".%c ", b);
else if (b == 0xFF && OptGreyOutZeroes)
ImGui::TextDisabled("## ");
else if (b == 0x00)
ImGui::Text(" ");
else
ImGui::Text(format_byte_space, b);
}
else
{
if (b == 0 && OptGreyOutZeroes)
ImGui::TextDisabled("00 ");
else
ImGui::Text(format_byte_space, b);
}
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
{
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
DataEditingTakeFocus = true;
data_editing_addr_next = addr;
}
DataPreviewAddr = addr;
DataPreviewAddrEnd = addr;
}
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
DataPreviewAddrEnd = addr;
}
if (ImGui::IsItemHovered() && !tooltipShown) {
if (HoverFn) {
HoverFn(mem_data, addr);
tooltipShown = true;
}
}
}
}
if (OptShowAscii)
{
// Draw ASCII values
ImGui::SameLine(s.PosAsciiStart);
ImVec2 pos = ImGui::GetCursorScreenPos();
addr = line_i * Cols;
ImGui::PushID(-1);
ImGui::SameLine();
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
ImGui::PopID();
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
{
if (addr == DataEditingAddr)
{
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
}
unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
char display_c = (c < 32 || c >= 128) ? '.' : c;
draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1);
// Draw highlight
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
{
ImU32 color = HighlightColor;
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), color);
}
ImGui::PushID(line_i * Cols + n);
ImGui::SameLine();
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
ImGui::PopID();
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
{
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
DataEditingTakeFocus = true;
data_editing_addr_next = addr;
}
DataPreviewAddr = addr;
DataPreviewAddrEnd = addr;
}
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
DataPreviewAddrEnd = addr;
}
pos.x += s.GlyphWidth;
}
ImGui::PushID(-1);
ImGui::SameLine();
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
ImGui::PopID();
}
if (OptShowAdvancedDecoding && DecodeFn) {
// Draw decoded bytes
ImGui::SameLine(s.PosDecodingStart);
ImVec2 pos = ImGui::GetCursorScreenPos();
addr = line_i * Cols;
ImGui::PushID(-1);
ImGui::SameLine();
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
ImGui::PopID();
for (int n = 0; n < Cols && addr < mem_size;)
{
auto decodedData = DecodeFn(mem_data, addr);
auto displayData = decodedData.data;
auto glyphWidth = ImGui::CalcTextSize(displayData.c_str()).x + 1;
if (addr == DataEditingAddr)
{
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
}
draw_list->AddText(pos, decodedData.color, displayData.c_str(), displayData.c_str() + displayData.length());
// Draw highlight
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
{
ImU32 color = HighlightColor;
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), color);
}
ImGui::PushID(line_i * Cols + n);
ImGui::SameLine();
ImGui::Dummy(ImVec2(glyphWidth, s.LineHeight));
ImGui::PopID();
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
{
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
DataEditingTakeFocus = true;
data_editing_addr_next = addr;
}
DataPreviewAddr = addr;
DataPreviewAddrEnd = addr;
}
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
DataPreviewAddrEnd = addr;
}
pos.x += glyphWidth;
if (addr <= 1) {
n++;
addr++;
} else {
n += decodedData.advance;
addr += decodedData.advance;
}
}
}
}
}
ImGui::PopStyleVar(2);
ImGui::EndChild();
if (data_next && DataEditingAddr < mem_size)
{
DataEditingAddr = DataPreviewAddr = DataPreviewAddrEnd = DataEditingAddr + 1;
DataEditingTakeFocus = true;
}
else if (data_editing_addr_next != (size_t)-1)
{
DataEditingAddr = DataPreviewAddr = DataPreviewAddrEnd = data_editing_addr_next;
}
if (OptShowOptions)
{
ImGui::Separator();
DrawOptionsLine(s, mem_data, mem_size, base_display_addr);
}
// Notify the main window of our ideal child content size (FIXME: we are missing an API to get the contents size from the child)
ImGui::SetCursorPosX(s.WindowWidth);
}
void DrawOptionsLine(const Sizes& s, void* mem_data, size_t mem_size, size_t base_display_addr)
{
IM_UNUSED(mem_data);
const char* format_range = OptUpperCaseHex ? "Range 0x%0*" _PRISizeT "X..0x%0*" _PRISizeT "X" : "Range 0x%0*" _PRISizeT "x..0x%0*" _PRISizeT "x";
const char* format_selection = OptUpperCaseHex ? "Selection 0x%0*" _PRISizeT "X..0x%0*" _PRISizeT "X (%ld [0x%lX] %s)" : "Range 0x%0*" _PRISizeT "x..0x%0*" _PRISizeT "x (%ld [0x%lX] %s)";
if (this->OptShowExtraInfo) {
ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1);
if (DataPreviewAddr != (size_t)-1 && DataPreviewAddrEnd != (size_t)-1) {
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
auto selectionStart = std::min(DataPreviewAddr, DataPreviewAddrEnd);
auto selectionEnd = std::max(DataPreviewAddr, DataPreviewAddrEnd);
size_t regionSize = (selectionEnd - selectionStart) + 1;
ImGui::Text(format_selection, s.AddrDigitsCount, base_display_addr + selectionStart, s.AddrDigitsCount, base_display_addr + selectionEnd, regionSize, regionSize, regionSize == 1 ? "byte" : "bytes");
}
}
if (GotoAddr != (size_t)-1)
{
if (GotoAddr < mem_size)
{
ImGui::BeginChild("##scrolling");
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (GotoAddr / Cols) * ImGui::GetTextLineHeight());
ImGui::EndChild();
}
GotoAddr = (size_t)-1;
}
}
static bool IsBigEndian()
{
uint16_t x = 1;
char c[2];
memcpy(c, &x, 2);
return c[0] != 0;
}
static void* EndianessCopyBigEndian(void* _dst, void* _src, size_t s, int is_little_endian)
{
if (is_little_endian)
{
uint8_t* dst = (uint8_t*)_dst;
uint8_t* src = (uint8_t*)_src + s - 1;
for (int i = 0, n = (int)s; i < n; ++i)
memcpy(dst++, src--, 1);
return _dst;
}
else
{
return memcpy(_dst, _src, s);
}
}
static void* EndianessCopyLittleEndian(void* _dst, void* _src, size_t s, int is_little_endian)
{
if (is_little_endian)
{
return memcpy(_dst, _src, s);
}
else
{
uint8_t* dst = (uint8_t*)_dst;
uint8_t* src = (uint8_t*)_src + s - 1;
for (int i = 0, n = (int)s; i < n; ++i)
memcpy(dst++, src--, 1);
return _dst;
}
}
void* EndianessCopy(void* dst, void* src, size_t size) const
{
static void* (*fp)(void*, void*, size_t, int) = NULL;
if (fp == NULL)
fp = IsBigEndian() ? EndianessCopyBigEndian : EndianessCopyLittleEndian;
return fp(dst, src, size, PreviewEndianess);
}
};
#undef _PRISizeT
#undef ImSnprintf
#ifdef _MSC_VER
#pragma warning (pop)
#endif

View File

@@ -821,7 +821,7 @@ void TextEditor::Render() {
ImGui::Text("Error at line %d:", errorIt->first);
ImGui::PopStyleColor();
ImGui::Separator();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.2f, 1.0f));
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5f, 0.5f, 0.2f, 1.0f));
ImGui::Text("%s", errorIt->second.c_str());
ImGui::PopStyleColor();
ImGui::EndTooltip();

View File

@@ -47,6 +47,7 @@
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#include "imgui.h"
#include "imgui_internal.h"
#include "imgui_impl_glfw.h"
// GLFW
@@ -136,6 +137,51 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
glfwSetClipboardString((GLFWwindow*)user_data, text);
}
#if defined(OS_WINDOWS)
static const char* ImGui_ImplWin_GetClipboardText(void*)
{
ImGuiContext& g = *GImGui;
g.ClipboardHandlerData.clear();
if (!::OpenClipboard(NULL))
return NULL;
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
if (wbuf_handle == NULL)
{
::CloseClipboard();
return NULL;
}
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
{
int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
g.ClipboardHandlerData.resize(buf_len);
::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
}
::GlobalUnlock(wbuf_handle);
::CloseClipboard();
return g.ClipboardHandlerData.Data;
}
static void ImGui_ImplWin_SetClipboardText(void*, const char* text)
{
if (!::OpenClipboard(NULL))
return;
const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
if (wbuf_handle == NULL)
{
::CloseClipboard();
return;
}
WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
::GlobalUnlock(wbuf_handle);
::EmptyClipboard();
if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
::GlobalFree(wbuf_handle);
::CloseClipboard();
}
#endif
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
@@ -271,9 +317,15 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = bd->Window;
#if defined(OS_WINDOWS)
io.SetClipboardTextFn = ImGui_ImplWin_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplWin_GetClipboardText;
io.ClipboardUserData = bd->Window;
#else
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = bd->Window;
#endif
// Create mouse cursors
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,

View File

@@ -568,9 +568,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.5.4"
version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
dependencies = [
"aho-corasick",
"memchr",
@@ -579,9 +579,9 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.6.25"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "remove_dir_all"

View File

@@ -10,6 +10,7 @@ set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/microtar ${CMAKE_CURRENT_BINARY_DIR}/external/microtar EXCLUDE_FROM_ALL)
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(NFD_PORTAL ON CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL)
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
@@ -123,14 +124,14 @@ set(LIBIMHEX_SOURCES
source/helpers/patches.cpp
source/helpers/project_file_handler.cpp
source/helpers/encoding_file.cpp
source/helpers/loader_script_handler.cpp
source/helpers/logger.cpp
source/helpers/tar.cpp
source/providers/provider.cpp
source/ui/imgui_imhex_extensions.cpp
source/ui/view.cpp
)
)
if (APPLE)
set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk)
@@ -142,7 +143,9 @@ if (APPLE)
endif ()
endif ()
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/fs_macos.mm)
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
source/helpers/fs_macos.m
source/helpers/utils_macos.m)
endif ()
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")

View File

@@ -3,30 +3,8 @@
#include <cstdint>
#include <cstddef>
#include <hex/helpers/types.hpp>
#include <hex/helpers/intrinsics.hpp>
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using u128 = __uint128_t;
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using color_t = u32;
namespace hex {
struct Region {
u64 address;
size_t size;
};
}

View File

@@ -10,12 +10,16 @@
#include <functional>
#include <map>
#include <unordered_map>
#include <string>
#include <string_view>
#include <vector>
#include <nlohmann/json_fwd.hpp>
using ImGuiDataType = int;
using ImGuiInputTextFlags = int;
namespace pl {
class Evaluator;
}
@@ -152,7 +156,7 @@ namespace hex {
}
template<hex::derived_from<View> T, typename... Args>
template<std::derived_from<View> T, typename... Args>
void add(Args &&...args) {
return impl::add(new T(std::forward<Args>(args)...));
}
@@ -230,7 +234,7 @@ namespace hex {
}
template<hex::derived_from<dp::Node> T, typename... Args>
template<std::derived_from<dp::Node> T, typename... Args>
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), [=] {
auto node = new T(std::forward<Args>(args)...);
@@ -322,7 +326,7 @@ namespace hex {
}
template<hex::derived_from<hex::prv::Provider> T>
template<std::derived_from<hex::prv::Provider> T>
void add(const std::string &unlocalizedName, bool addToList = true) {
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider) {
if (name != expectedName) return;
@@ -378,6 +382,113 @@ namespace hex {
std::vector<impl::Entry> &getEntries();
}
namespace HexEditor {
class DataVisualizer {
public:
DataVisualizer(u16 bytesPerCell, u16 maxCharsPerCell)
: m_bytesPerCell(bytesPerCell), m_maxCharsPerCell(maxCharsPerCell) {}
virtual ~DataVisualizer() = default;
virtual void draw(u64 address, const u8 *data, size_t size, bool upperCase) = 0;
virtual bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) = 0;
[[nodiscard]] u16 getBytesPerCell() const { return this->m_bytesPerCell; }
[[nodiscard]] u16 getMaxCharsPerCell() const { return this->m_maxCharsPerCell; }
protected:
const static int TextInputFlags;
bool drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
private:
u16 m_bytesPerCell;
u16 m_maxCharsPerCell;
};
namespace impl {
void addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer);
std::map<std::string, DataVisualizer*> &getVisualizers();
}
template<std::derived_from<DataVisualizer> T, typename... Args>
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
}
}
namespace Hashes {
class Hash {
public:
Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
class Function {
public:
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
Function(const Hash *type, std::string name, Callback callback)
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {
}
[[nodiscard]] const Hash *getType() const { return this->m_type; }
[[nodiscard]] const std::string &getName() const { return this->m_name; }
const std::vector<u8>& get(const Region& region, prv::Provider *provider) {
if (this->m_cache.empty()) {
this->m_cache = this->m_callback(region, provider);
}
return this->m_cache;
}
void reset() {
this->m_cache.clear();
}
private:
const Hash *m_type;
std::string m_name;
Callback m_callback;
std::vector<u8> m_cache;
};
virtual void draw() { }
[[nodiscard]] virtual Function create(std::string name) = 0;
[[nodiscard]] const std::string &getUnlocalizedName() const {
return this->m_unlocalizedName;
}
protected:
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const {
return { this, name, callback };
}
private:
std::string m_unlocalizedName;
};
namespace impl {
std::vector<Hash*> &getHashes();
void add(Hash* hash);
}
template<typename T, typename ... Args>
void add(Args && ... args) {
impl::add(new T(std::forward<Args>(args)...));
}
}
};
}

View File

@@ -129,6 +129,12 @@ namespace hex {
EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
EVENT_DEF(QuerySelection, Region &);
EVENT_DEF(RequestShowInfoPopup, std::string);
EVENT_DEF(RequestShowErrorPopup, std::string);
EVENT_DEF(RequestShowFatalErrorPopup, std::string);
EVENT_DEF(RequestShowYesNoQuestionPopup, std::string, std::function<void()>, std::function<void()>);
EVENT_DEF(RequestShowFileChooserPopup, std::vector<std::fs::path>, std::vector<nfdfilteritem_t>, std::function<void(std::fs::path)>);
EVENT_DEF(QuerySelection, std::optional<Region> &);
}

View File

@@ -6,10 +6,13 @@
#include <optional>
#include <string>
#include <vector>
#include <variant>
#include <map>
#include <hex/helpers/concepts.hpp>
#include <hex/api/task.hpp>
#include <hex/api/keybinding.hpp>
#include <hex/helpers/fs.hpp>
using ImGuiID = unsigned int;
struct ImVec2;
@@ -31,37 +34,69 @@ namespace hex {
namespace HexEditor {
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
class Highlighting {
public:
Highlighting() = default;
Highlighting(Region region, color_t color, std::string tooltip = "");
Highlighting(Region region, color_t color);
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
[[nodiscard]] const std::string &getTooltip() const { return this->m_tooltip; }
private:
Region m_region = {};
color_t m_color = 0x00;
std::string m_tooltip;
};
class Tooltip {
public:
Tooltip() = default;
Tooltip(Region region, std::string value, color_t color);
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
[[nodiscard]] const std::string &getValue() const { return this->m_value; }
private:
Region m_region = {};
std::string m_value;
color_t m_color = 0x00;
};
namespace impl {
using HighlightingFunction = std::function<std::optional<Highlighting>(u64)>;
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t)>;
std::map<u32, Highlighting> &getHighlights();
std::map<u32, HighlightingFunction> &getHighlightingFunctions();
std::map<u32, Highlighting> &getBackgroundHighlights();
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions();
std::map<u32, Highlighting> &getForegroundHighlights();
std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions();
std::map<u32, Tooltip> &getTooltips();
std::map<u32, TooltipFunction> &getTooltipFunctions();
}
u32 addHighlight(const Region &region, color_t color, const std::string &tooltip = "");
void removeHighlight(u32 id);
u32 addBackgroundHighlight(const Region &region, color_t color);
void removeBackgroundHighlight(u32 id);
u32 addHighlightingProvider(const impl::HighlightingFunction &function);
void removeHighlightingProvider(u32 id);
u32 addForegroundHighlight(const Region &region, color_t color);
void removeForegroundHighlight(u32 id);
Region getSelection();
u32 addTooltip(Region region, std::string value, color_t color);
void removeTooltip(u32 id);
u32 addTooltipProvider(TooltipFunction function);
void removeTooltipProvider(u32 id);
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function);
void removeBackgroundHighlightingProvider(u32 id);
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function);
void removeForegroundHighlightingProvider(u32 id);
bool isSelectionValid();
std::optional<Region> getSelection();
void setSelection(const Region &region);
void setSelection(u64 address, size_t size);
@@ -76,8 +111,6 @@ namespace hex {
std::string comment;
u32 color;
bool locked;
u32 highlightId;
};
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
@@ -95,7 +128,7 @@ namespace hex {
void add(prv::Provider *provider);
template<hex::derived_from<prv::Provider> T>
template<std::derived_from<prv::Provider> T>
void add(auto &&...args) {
add(new T(std::forward<decltype(args)>(args)...));
}
@@ -126,6 +159,11 @@ namespace hex {
void setProgramArguments(int argc, char **argv, char **envp);
void setBorderlessWindowMode(bool enabled);
void setCustomFontPath(const std::fs::path &path);
void setFontSize(float size);
void setGPUVendor(const std::string &vendor);
}
struct ProgramArguments {
@@ -134,6 +172,12 @@ namespace hex {
char **envp;
};
enum class Theme {
Dark = 1,
Light = 2,
Classic = 3
};
const ProgramArguments &getProgramArguments();
float getTargetFPS();
@@ -149,6 +193,19 @@ namespace hex {
std::map<std::string, std::string> &getInitArguments();
const std::fs::path &getCustomFontPath();
float getFontSize();
void setTheme(Theme theme);
Theme getTheme();
void enableSystemThemeDetection(bool enabled);
bool usesSystemThemeDetection();
const std::vector<std::fs::path> &getAdditionalFolderPaths();
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths);
const std::string &getGPUVendor();
}
}

View File

@@ -7,6 +7,12 @@
#include <string>
#if defined(OS_WINDOWS)
#include <windows.h>
#else
#include <dlfcn.h>
#endif
struct ImGuiContext;
namespace hex {
@@ -39,7 +45,11 @@ namespace hex {
using SetImGuiContextFunc = void (*)(ImGuiContext *);
using IsBuiltinPluginFunc = bool (*)();
void *m_handle = nullptr;
#if defined(OS_WINDOWS)
HMODULE m_handle = nullptr;
#else
void *m_handle = nullptr;
#endif
std::fs::path m_path;
mutable bool m_initialized = false;

View File

@@ -5,151 +5,7 @@
#include <type_traits>
#include <memory>
namespace hex {
template<typename>
struct is_integral_helper : public std::false_type { };
template<>
struct is_integral_helper<u8> : public std::true_type { };
template<>
struct is_integral_helper<i8> : public std::true_type { };
template<>
struct is_integral_helper<u16> : public std::true_type { };
template<>
struct is_integral_helper<i16> : public std::true_type { };
template<>
struct is_integral_helper<u32> : public std::true_type { };
template<>
struct is_integral_helper<i32> : public std::true_type { };
template<>
struct is_integral_helper<u64> : public std::true_type { };
template<>
struct is_integral_helper<i64> : public std::true_type { };
template<>
struct is_integral_helper<u128> : public std::true_type { };
template<>
struct is_integral_helper<i128> : public std::true_type { };
template<>
struct is_integral_helper<bool> : public std::true_type { };
template<>
struct is_integral_helper<char> : public std::true_type { };
template<>
struct is_integral_helper<char8_t> : public std::true_type { };
template<>
struct is_integral_helper<char16_t> : public std::true_type { };
template<>
struct is_integral_helper<char32_t> : public std::true_type { };
template<>
struct is_integral_helper<wchar_t> : public std::true_type { };
template<typename T>
struct is_integral : public is_integral_helper<std::remove_cvref_t<T>>::type { };
template<typename>
struct is_signed_helper : public std::false_type { };
template<>
struct is_signed_helper<i8> : public std::true_type { };
template<>
struct is_signed_helper<i16> : public std::true_type { };
template<>
struct is_signed_helper<i32> : public std::true_type { };
template<>
struct is_signed_helper<i64> : public std::true_type { };
template<>
struct is_signed_helper<i128> : public std::true_type { };
template<>
struct is_signed_helper<char> : public std::true_type { };
template<>
struct is_signed_helper<float> : public std::true_type { };
template<>
struct is_signed_helper<double> : public std::true_type { };
template<>
struct is_signed_helper<long double> : public std::true_type { };
template<typename T>
struct is_signed : public is_signed_helper<std::remove_cvref_t<T>>::type { };
template<typename>
struct is_floating_point_helper : public std::false_type { };
template<>
struct is_floating_point_helper<float> : public std::true_type { };
template<>
struct is_floating_point_helper<double> : public std::true_type { };
template<>
struct is_floating_point_helper<long double> : public std::true_type { };
template<typename T>
struct is_floating_point : public is_floating_point_helper<std::remove_cvref_t<T>>::type { };
}
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 12000
#if __has_include(<concepts>)
// Make sure we break when derived_from is implemented in libc++. Then we can fix a compatibility version above
#include <concepts>
#endif
// libcxx 12 still doesn't have many default concepts implemented, as a result we need to define it ourself using clang built-ins.
// [concept.derived] (patch from https://reviews.llvm.org/D74292)
namespace hex {
template<class _Dp, class _Bp>
concept derived_from =
__is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp *, const volatile _Bp *);
}
#else
// Assume supported
#include <concepts>
namespace hex {
using std::derived_from;
}
#endif
// [concepts.arithmetic]
namespace hex {
template<class T>
concept integral = hex::is_integral<T>::value;
template<class T>
concept signed_integral = integral<T> && hex::is_signed<T>::value;
template<class T>
concept unsigned_integral = integral<T> && !signed_integral<T>;
template<class T>
concept floating_point = std::is_floating_point<T>::value;
}
#include <concepts>
namespace hex {
@@ -159,11 +15,6 @@ namespace hex {
template<typename T, size_t Size>
concept has_size = sizeof(T) == Size;
}
namespace hex {
template<typename T>
class Cloneable {
public:

View File

@@ -2,11 +2,22 @@
#include <hex.hpp>
#include <map>
#include <string_view>
#include <vector>
// TODO: Workaround for weird issue picked up by GCC 12.1.0 and later. This seems like a compiler bug mentioned in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98465
#pragma GCC diagnostic push
#if (__GNUC__ >= 12)
#pragma GCC diagnostic ignored "-Wrestrict"
#pragma GCC diagnostic ignored "-Wstringop-overread"
#endif
#include <map>
#include <string_view>
#include <vector>
#pragma GCC diagnostic pop
#include <hex/helpers/fs.hpp>
#include <hex/helpers/file.hpp>
namespace hex {
@@ -26,12 +37,12 @@ namespace hex {
[[nodiscard]] bool valid() const { return this->m_valid; }
private:
void parseThingyFile(std::ifstream &content);
void parseThingyFile(fs::File &file);
bool m_valid = false;
std::map<u32, std::map<std::vector<u8>, std::string>> m_mapping;
std::map<size_t, std::map<std::vector<u8>, std::string>> m_mapping;
size_t m_longestSequence = 0;
};
}
}

View File

@@ -47,10 +47,12 @@ namespace hex::fs {
size_t readBuffer(u8 *buffer, size_t size);
std::vector<u8> readBytes(size_t numBytes = 0);
std::string readString(size_t numBytes = 0);
std::u8string readU8String(size_t numBytes = 0);
void write(const u8 *buffer, size_t size);
void write(const std::vector<u8> &bytes);
void write(const std::string &string);
void write(const std::u8string &string);
[[nodiscard]] size_t getSize() const;
void setSize(u64 size);

View File

@@ -50,6 +50,12 @@ namespace hex::fs {
return std::filesystem::remove(path, error) && !error;
}
[[maybe_unused]]
static inline bool removeAll(const std::fs::path &path) {
std::error_code error;
return std::filesystem::remove_all(path, error) && !error;
}
[[maybe_unused]]
static inline uintmax_t getFileSize(const std::fs::path &path) {
std::error_code error;
@@ -61,6 +67,8 @@ namespace hex::fs {
bool isPathWritable(const std::fs::path &path);
std::fs::path toShortPath(const std::fs::path &path);
enum class DialogMode
{
Open,

View File

@@ -1,10 +0,0 @@
#pragma once
#if defined(OS_MACOS)
#include <hex/helpers/fs.hpp>
namespace hex {
std::string getMacExecutableDirectoryPath();
std::string getMacApplicationSupportDirectoryPath();
}
#endif

View File

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

View File

@@ -1,38 +0,0 @@
#pragma once
#include <string>
#include <string_view>
#include <hex/helpers/fs.hpp>
struct _object;
typedef struct _object PyObject;
namespace hex {
namespace prv {
class Provider;
}
class LoaderScript {
public:
LoaderScript() = delete;
static bool processFile(const std::fs::path &scriptPath);
static void setFilePath(const std::fs::path &filePath) { LoaderScript::s_filePath = filePath; }
static void setDataProvider(prv::Provider *provider) { LoaderScript::s_dataProvider = provider; }
private:
static inline std::fs::path s_filePath;
static inline prv::Provider *s_dataProvider;
static PyObject *Py_getFilePath(PyObject *self, PyObject *args);
static PyObject *Py_addPatch(PyObject *self, PyObject *args);
static PyObject *Py_addBookmark(PyObject *self, PyObject *args);
static PyObject *Py_addStruct(PyObject *self, PyObject *args);
static PyObject *Py_addUnion(PyObject *self, PyObject *args);
};
}

View File

@@ -44,11 +44,14 @@ namespace hex {
std::future<Response<void>> downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
[[nodiscard]] std::string encode(const std::string &input);
[[nodiscard]] std::string decode(const std::string &input);
[[nodiscard]] float getProgress() const { return this->m_progress; }
void cancel() { this->m_shouldCancel = true; }
static void setProxy(const std::string &url);
private:
void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
std::optional<i32> execute();
@@ -62,6 +65,8 @@ namespace hex {
std::mutex m_transmissionActive;
float m_progress = 0.0F;
bool m_shouldCancel = false;
static std::string s_proxyUrl;
};
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/fs.hpp>
#include <microtar.h>
namespace hex {
class Tar {
public:
enum class Mode {
Read,
Write,
Create
};
Tar() = default;
Tar(const std::fs::path &path, Mode mode);
~Tar();
std::vector<u8> read(const std::fs::path &path);
void write(const std::fs::path &path, const std::vector<u8> &data);
std::vector<std::fs::path> listEntries();
void extract(const std::fs::path &path, const std::fs::path &outputPath);
void extractAll(const std::fs::path &outputPath);
private:
mtar_t m_ctx = { };
};
}

View File

@@ -0,0 +1,44 @@
#pragma once
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using u128 = __uint128_t;
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using color_t = u32;
namespace hex {
struct Region {
u64 address;
size_t size;
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress());
}
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress());
}
[[nodiscard]] constexpr u64 getStartAddress() const {
return this->address;
}
[[nodiscard]] constexpr u64 getEndAddress() const {
return this->address + this->size - 1;
}
[[nodiscard]] constexpr size_t getSize() const {
return this->size;
}
};
}

View File

@@ -43,7 +43,7 @@ namespace hex {
std::string encodeByteString(const std::vector<u8> &bytes);
std::vector<u8> decodeByteString(const std::string &string);
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
if (from < to) std::swap(from, to);
using ValueType = std::remove_cvref_t<decltype(value)>;
@@ -72,6 +72,18 @@ namespace hex {
return (value ^ mask) - mask;
}
template<std::integral T>
constexpr inline T swapBitOrder(size_t numBits, T value) {
T result = 0x00;
for (size_t bit = 0; bit < numBits; bit++) {
result <<= 1;
result |= (value & (1 << bit)) != 0;
}
return result;
}
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts>
@@ -188,6 +200,24 @@ namespace hex {
return T(1) << bit_width(T(x - 1));
}
template<std::integral T, std::integral U>
auto powi(T base, U exp) {
using ResultType = decltype(T{} * U{});
if (exp < 0)
return ResultType(0);
ResultType result = 1;
while (exp != 0) {
if ((exp & 0b1) == 0b1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
template<typename T, typename... Args>
void moveToVector(std::vector<T> &buffer, T &&first, Args &&...rest) {
buffer.push_back(std::move(first));
@@ -234,7 +264,7 @@ namespace hex {
return result;
}
inline std::string toBinaryString(hex::unsigned_integral auto number) {
inline std::string toBinaryString(std::unsigned_integral auto number) {
if (number == 0) return "0";
std::string result;
@@ -287,6 +317,13 @@ namespace hex {
return *value;
}
template<std::integral T>
T alignTo(T value, T alignment) {
T remainder = value % alignment;
return remainder != 0 ? value + (alignment - remainder) : value;
}
bool isProcessElevated();
std::optional<std::string> getEnvironmentVariable(const std::string &env);

View File

@@ -0,0 +1,10 @@
#pragma once
#if defined(OS_MACOS)
#include <string>
extern "C" void openWebpageMacos(const char *url);
extern "C" bool isMacosSystemDarkModeEnabled();
#endif

View File

@@ -0,0 +1,232 @@
#pragma once
#include <span>
#include <vector>
#include <hex/providers/provider.hpp>
namespace hex::prv {
class BufferedReader {
public:
explicit BufferedReader(Provider *provider, size_t bufferSize = 0xFF'FFFF) : m_provider(provider), m_maxBufferSize(bufferSize), m_buffer(bufferSize) { }
void seek(u64 address) {
this->m_baseAddress = address;
}
[[nodiscard]] std::vector<u8> read(u64 address, size_t size) {
if (size > this->m_buffer.size()) {
std::vector<u8> result;
result.resize(size);
this->m_provider->read(address, result.data(), result.size());
return result;
}
this->updateBuffer(address, size);
auto result = &this->m_buffer[address - this->m_baseAddress];
return { result, result + std::min(size, this->m_buffer.size()) };
}
[[nodiscard]] std::vector<u8> readReverse(u64 address, size_t size) {
if (size > this->m_buffer.size()) {
std::vector<u8> result;
result.resize(size);
this->m_provider->read(address, result.data(), result.size());
return result;
}
this->updateBuffer(address - std::min<u64>(address, this->m_buffer.size()), size);
auto result = &this->m_buffer[address - this->m_baseAddress];
return { result, result + std::min(size, this->m_buffer.size()) };
}
class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = u8;
using pointer = const value_type*;
using reference = const value_type&;
Iterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
Iterator& operator++() {
this->m_address++;
return *this;
}
Iterator operator++(int) {
auto copy = *this;
this->m_address++;
return copy;
}
Iterator& operator+=(i64 offset) {
this->m_address += offset;
return *this;
}
Iterator& operator-=(i64 offset) {
this->m_address -= offset;
return *this;
}
value_type operator*() const {
return (*this)[0];
}
[[nodiscard]] u64 getAddress() const {
return this->m_address;
}
difference_type operator-(const Iterator &other) const {
return this->m_address - other.m_address;
}
Iterator operator+(i64 offset) const {
return { this->m_reader, this->m_address + offset };
}
value_type operator[](i64 offset) const {
auto result = this->m_reader->read(this->m_address + offset, 1);
if (result.empty())
return 0x00;
return result[0];
}
friend bool operator== (const Iterator& left, const Iterator& right) { return left.m_address == right.m_address; };
friend bool operator!= (const Iterator& left, const Iterator& right) { return left.m_address != right.m_address; };
friend bool operator> (const Iterator& left, const Iterator& right) { return left.m_address > right.m_address; };
friend bool operator< (const Iterator& left, const Iterator& right) { return left.m_address < right.m_address; };
friend bool operator>= (const Iterator& left, const Iterator& right) { return left.m_address >= right.m_address; };
friend bool operator<= (const Iterator& left, const Iterator& right) { return left.m_address <= right.m_address; };
private:
BufferedReader *m_reader;
u64 m_address;
};
class ReverseIterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = u8;
using pointer = const value_type*;
using reference = const value_type&;
ReverseIterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
ReverseIterator& operator++() {
this->m_address--;
return *this;
}
ReverseIterator operator++(int) {
auto copy = *this;
this->m_address--;
return copy;
}
ReverseIterator& operator+=(i64 offset) {
this->m_address -= offset;
return *this;
}
ReverseIterator& operator-=(i64 offset) {
this->m_address += offset;
return *this;
}
value_type operator*() const {
return (*this)[0];
}
[[nodiscard]] u64 getAddress() const {
return this->m_address;
}
difference_type operator-(const ReverseIterator &other) const {
return other.m_address - this->m_address;
}
ReverseIterator operator+(i64 offset) const {
return { this->m_reader, this->m_address - offset };
}
value_type operator[](i64 offset) const {
auto result = this->m_reader->readReverse(this->m_address + offset, 1);
if (result.empty())
return 0x00;
return result[0];
}
friend bool operator== (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address == right.m_address; };
friend bool operator!= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address != right.m_address; };
friend bool operator> (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address > right.m_address; };
friend bool operator< (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address < right.m_address; };
friend bool operator>= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address >= right.m_address; };
friend bool operator<= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address <= right.m_address; };
private:
BufferedReader *m_reader;
u64 m_address = 0x00;
};
Iterator begin() {
return { this, this->m_baseAddress };
}
Iterator end() {
return { this, this->m_provider->getActualSize() };
}
ReverseIterator rbegin() {
return { this, this->m_baseAddress };
}
ReverseIterator rend() {
return { this, std::numeric_limits<u64>::max() };
}
private:
void updateBuffer(u64 address, size_t size) {
if (!this->m_bufferValid || address < this->m_baseAddress || address + size > (this->m_baseAddress + this->m_buffer.size())) {
const auto remainingBytes = this->m_provider->getActualSize() - address;
if (remainingBytes < this->m_maxBufferSize)
this->m_buffer.resize(remainingBytes);
this->m_provider->read(address, this->m_buffer.data(), this->m_buffer.size());
this->m_baseAddress = address;
this->m_bufferValid = true;
}
}
private:
Provider *m_provider;
size_t m_maxBufferSize;
bool m_bufferValid = false;
u64 m_baseAddress = 0x00;
std::vector<u8> m_buffer;
};
}

View File

@@ -35,6 +35,7 @@ namespace hex::prv {
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);

View File

@@ -63,7 +63,6 @@ namespace ImGui {
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
void Disabled(const std::function<void()> &widgets, bool disabled);
void TextSpinner(const char *label);
void Header(const char *label, bool firstEntry = false);
@@ -75,7 +74,8 @@ namespace ImGui {
bool ToolBarButton(const char *symbol, ImVec4 color);
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
bool InputIntegerPrefix(const char* label, const char *prefix, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
inline bool HasSecondPassed() {
@@ -130,5 +130,13 @@ namespace ImGui {
}
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
void HideTooltip();
bool BitCheckbox(const char* label, bool* v);
}

View File

@@ -7,8 +7,8 @@
#include <imgui_internal.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <fontawesome_font.h>
#include <codicons_font.h>
#include <fonts/fontawesome_font.h>
#include <fonts/codicons_font.h>
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
@@ -34,11 +34,9 @@ namespace hex {
[[nodiscard]] virtual bool isAvailable() const;
[[nodiscard]] virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
static void drawCommonInterfaces();
static void showMessagePopup(const std::string &message);
static void showErrorPopup(const std::string &errorMessage);
static void showFatalPopup(const std::string &errorMessage);
static void showInfoPopup(const std::string &message);
static void showErrorPopup(const std::string &message);
static void showFatalPopup(const std::string &message);
static void showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback);
static void showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback);
@@ -71,15 +69,6 @@ namespace hex {
bool m_windowOpen = false;
std::map<Shortcut, std::function<void()>> m_shortcuts;
static std::string s_popupMessage;
static std::function<void()> s_yesCallback, s_noCallback;
static u32 s_selectableFileIndex;
static std::vector<std::fs::path> s_selectableFiles;
static std::function<void(std::fs::path)> s_selectableFileOpenCallback;
static std::vector<nfdfilteritem_t> s_selectableFilesValidExtensions;
static ImFontAtlas *s_fontAtlas;
static ImFontConfig s_fontConfig;

View File

@@ -536,4 +536,64 @@ namespace hex {
}
namespace ContentRegistry::HexEditor {
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
struct UserData {
u8 *data;
i32 maxChars;
bool editingDone;
};
UserData userData = {
.data = data,
.maxChars = this->getMaxCharsPerCell(),
.editingDone = false
};
ImGui::PushID(reinterpret_cast<void*>(address));
ImGui::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
if (data->BufTextLen >= userData.maxChars)
userData.editingDone = true;
return 0;
}, &userData);
ImGui::PopID();
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter);
}
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
getVisualizers().insert({ unlocalizedName, visualizer });
}
std::map<std::string, DataVisualizer*> &impl::getVisualizers() {
static std::map<std::string, DataVisualizer*> visualizers;
return visualizers;
}
}
namespace ContentRegistry::Hashes {
std::vector<Hash *> &impl::getHashes() {
static std::vector<Hash *> hashes;
return hashes;
}
void impl::add(Hash *hash) {
getHashes().push_back(hash);
}
}
}

View File

@@ -1,13 +1,16 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
#include <utility>
#include <utility>
#include <unistd.h>
#include <imgui.h>
#include <nlohmann/json.hpp>
namespace hex {
namespace ImHexApi::Common {
@@ -29,32 +32,55 @@ namespace hex {
namespace ImHexApi::HexEditor {
Highlighting::Highlighting(Region region, color_t color, std::string tooltip)
: m_region(region), m_color(color), m_tooltip(std::move(tooltip)) {
Highlighting::Highlighting(Region region, color_t color)
: m_region(region), m_color(color) {
}
Tooltip::Tooltip(Region region, std::string value, color_t color) : m_region(region), m_value(std::move(value)), m_color(color) {
}
namespace impl {
static std::map<u32, Highlighting> s_highlights;
std::map<u32, Highlighting> &getHighlights() {
return s_highlights;
static std::map<u32, Highlighting> s_backgroundHighlights;
std::map<u32, Highlighting> &getBackgroundHighlights() {
return s_backgroundHighlights;
}
static std::map<u32, HighlightingFunction> s_highlightingFunctions;
std::map<u32, HighlightingFunction> &getHighlightingFunctions() {
return s_highlightingFunctions;
static std::map<u32, HighlightingFunction> s_backgroundHighlightingFunctions;
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions() {
return s_backgroundHighlightingFunctions;
}
static std::map<u32, Highlighting> s_foregroundHighlights;
std::map<u32, Highlighting> &getForegroundHighlights() {
return s_foregroundHighlights;
}
static std::map<u32, HighlightingFunction> s_foregroundHighlightingFunctions;
std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions() {
return s_foregroundHighlightingFunctions;
}
static std::map<u32, Tooltip> s_tooltips;
std::map<u32, Tooltip> &getTooltips() {
return s_tooltips;
}
static std::map<u32, TooltipFunction> s_tooltipFunctions;
std::map<u32, TooltipFunction> &getTooltipFunctions() {
return s_tooltipFunctions;
}
}
u32 addHighlight(const Region &region, color_t color, const std::string &tooltip) {
auto &highlights = impl::getHighlights();
static u64 id = 0;
u32 addBackgroundHighlight(const Region &region, color_t color) {
static u32 id = 0;
id++;
highlights.insert({
id, Highlighting {region, color, tooltip}
impl::getBackgroundHighlights().insert({
id, Highlighting {region, color}
});
EventManager::post<EventHighlightingChanged>();
@@ -62,37 +88,101 @@ namespace hex {
return id;
}
void removeHighlight(u32 id) {
impl::getHighlights().erase(id);
void removeBackgroundHighlight(u32 id) {
impl::getBackgroundHighlights().erase(id);
EventManager::post<EventHighlightingChanged>();
}
u32 addHighlightingProvider(const impl::HighlightingFunction &function) {
auto &highlightFuncs = impl::getHighlightingFunctions();
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function) {
static u32 id = 0;
auto id = highlightFuncs.size();
id++;
highlightFuncs.insert({ id, function });
impl::getBackgroundHighlightingFunctions().insert({ id, function });
EventManager::post<EventHighlightingChanged>();
return id;
}
void removeHighlightingProvider(u32 id) {
impl::getHighlightingFunctions().erase(id);
void removeBackgroundHighlightingProvider(u32 id) {
impl::getBackgroundHighlightingFunctions().erase(id);
EventManager::post<EventHighlightingChanged>();
}
Region getSelection() {
static Region selectedRegion;
EventManager::subscribe<EventRegionSelected>([](const Region &region) {
selectedRegion = region;
u32 addForegroundHighlight(const Region &region, color_t color) {
static u32 id = 0;
id++;
impl::getForegroundHighlights().insert({
id, Highlighting {region, color}
});
return selectedRegion;
EventManager::post<EventHighlightingChanged>();
return id;
}
void removeForegroundHighlight(u32 id) {
impl::getForegroundHighlights().erase(id);
EventManager::post<EventHighlightingChanged>();
}
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function) {
static u32 id = 0;
id++;
impl::getForegroundHighlightingFunctions().insert({ id, function });
EventManager::post<EventHighlightingChanged>();
return id;
}
void removeForegroundHighlightingProvider(u32 id) {
impl::getForegroundHighlightingFunctions().erase(id);
EventManager::post<EventHighlightingChanged>();
}
static u32 tooltipId = 0;
u32 addTooltip(Region region, std::string value, color_t color) {
tooltipId++;
impl::getTooltips().insert({ tooltipId, { region, std::move(value), color } });
return tooltipId;
}
void removeTooltip(u32 id) {
impl::getTooltips().erase(id);
}
static u32 tooltipFunctionId;
u32 addTooltipProvider(TooltipFunction function) {
tooltipFunctionId++;
impl::getTooltipFunctions().insert({ tooltipFunctionId, std::move(function) });
return tooltipFunctionId;
}
void removeTooltipProvider(u32 id) {
impl::getTooltipFunctions().erase(id);
}
bool isSelectionValid() {
return getSelection().has_value();
}
std::optional<Region> getSelection() {
std::optional<Region> selection;
EventManager::post<QuerySelection>(selection);
return selection;
}
void setSelection(const Region &region) {
@@ -144,7 +234,7 @@ namespace hex {
}
bool isValid() {
return !s_providers.empty();
return !s_providers.empty() && s_currentProvider < s_providers.size();
}
void add(prv::Provider *provider) {
@@ -159,7 +249,7 @@ namespace hex {
s_providers.erase(it);
if (it - s_providers.begin() == s_currentProvider)
if (it - s_providers.begin() == s_currentProvider && !s_providers.empty())
setCurrentProvider(0);
delete provider;
@@ -210,7 +300,7 @@ namespace hex {
}
static float s_globalScale;
static float s_globalScale = 1.0;
void setGlobalScale(float scale) {
s_globalScale = scale;
}
@@ -228,6 +318,21 @@ namespace hex {
s_borderlessWindowMode = enabled;
}
static std::fs::path s_customFontPath;
void setCustomFontPath(const std::fs::path &path) {
s_customFontPath = path;
}
static float s_fontSize;
void setFontSize(float size) {
s_fontSize = size;
}
static std::string s_gpuVendor;
void setGPUVendor(const std::string &vendor) {
s_gpuVendor = vendor;
}
}
@@ -273,6 +378,54 @@ namespace hex {
return initArgs;
}
const std::fs::path &getCustomFontPath() {
return impl::s_customFontPath;
}
float getFontSize() {
return impl::s_fontSize;
}
static Theme s_theme;
static bool s_systemThemeDetection;
void setTheme(Theme theme) {
s_theme = theme;
EventManager::post<EventSettingsChanged>();
}
Theme getTheme() {
return s_theme;
}
void enableSystemThemeDetection(bool enabled) {
s_systemThemeDetection = enabled;
EventManager::post<EventSettingsChanged>();
}
bool usesSystemThemeDetection() {
return s_systemThemeDetection;
}
static std::vector<std::fs::path> s_additionalFolderPaths;
const std::vector<std::fs::path> &getAdditionalFolderPaths() {
return s_additionalFolderPaths;
}
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths) {
s_additionalFolderPaths = paths;
}
const std::string &getGPUVendor() {
return impl::s_gpuVendor;
}
}
}

View File

@@ -3,19 +3,26 @@
#include <hex/helpers/logger.hpp>
#include <filesystem>
#include <dlfcn.h>
#include <system_error>
namespace hex {
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
#if defined(OS_WINDOWS)
this->m_handle = LoadLibraryW(path.c_str());
if (this->m_handle == nullptr) {
log::error("dlopen failed: {}", dlerror());
return;
}
if (this->m_handle == nullptr) {
log::error("LoadLibraryW failed: {}!", std::system_category().message(::GetLastError()));
return;
}
#else
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
auto pluginName = std::fs::path(path).stem().string();
if (this->m_handle == nullptr) {
log::error("dlopen failed: {}!", dlerror());
return;
}
#endif
this->m_initializePluginFunction = getPluginFunction<InitializePluginFunc>("initializePlugin");
this->m_getPluginNameFunction = getPluginFunction<GetPluginNameFunc>("getPluginName");
@@ -49,8 +56,13 @@ namespace hex {
}
Plugin::~Plugin() {
if (this->m_handle != nullptr)
dlclose(this->m_handle);
#if defined(OS_WINDOWS)
if (this->m_handle != nullptr)
FreeLibrary(this->m_handle);
#else
if (this->m_handle != nullptr)
dlclose(this->m_handle);
#endif
}
bool Plugin::initializePlugin() const {
@@ -120,7 +132,11 @@ namespace hex {
void *Plugin::getPluginFunction(const std::string &symbol) {
return dlsym(this->m_handle, symbol.c_str());
#if defined(OS_WINDOWS)
return reinterpret_cast<void *>(GetProcAddress(this->m_handle, symbol.c_str()));
#else
return dlsym(this->m_handle, symbol.c_str());
#endif
}
@@ -135,7 +151,7 @@ namespace hex {
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug")
PluginManager::s_plugins.emplace_back(pluginPath.path().string());
PluginManager::s_plugins.emplace_back(pluginPath.path());
}
if (PluginManager::s_plugins.empty())

View File

@@ -2,6 +2,7 @@
#include <hex/providers/provider.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/concepts.hpp>
#include <mbedtls/version.h>
#include <mbedtls/base64.h>
@@ -15,7 +16,6 @@
#include <array>
#include <span>
#include <concepts>
#include <functional>
#include <algorithm>
#include <cstddef>

View File

@@ -2,16 +2,13 @@
#include <hex/helpers/utils.hpp>
#include <fstream>
namespace hex {
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
std::ifstream encodingFile(path.c_str());
auto file = fs::File(path, fs::File::Mode::Read);
switch (type) {
case Type::Thingy:
parseThingyFile(encodingFile);
parseThingyFile(file);
break;
default:
return;
@@ -34,29 +31,30 @@ namespace hex {
return { ".", 1 };
}
void EncodingFile::parseThingyFile(std::ifstream &content) {
for (std::string line; std::getline(content, line);) {
void EncodingFile::parseThingyFile(fs::File &file) {
for (const auto &line : splitString(file.readString(), "\n")) {
std::string from, to;
{
auto delimiterPos = line.find('=', 0);
auto delimiterPos = line.find('=');
if (delimiterPos == std::string::npos)
if (delimiterPos >= line.length())
continue;
from = line.substr(0, delimiterPos);
to = line.substr(delimiterPos + 1);
hex::trim(from);
hex::trim(to);
if (from.empty()) continue;
if (to.empty()) to = " ";
}
auto fromBytes = hex::parseByteString(from);
if (fromBytes.empty()) continue;
if (to.length() > 1)
hex::trim(to);
if (to.empty())
to = " ";
if (!this->m_mapping.contains(fromBytes.size()))
this->m_mapping.insert({ fromBytes.size(), {} });
this->m_mapping[fromBytes.size()].insert({ fromBytes, to });

View File

@@ -1,16 +1,28 @@
#include <hex/helpers/file.hpp>
#include <unistd.h>
#include <cstring>
namespace hex::fs {
File::File(const std::fs::path &path, Mode mode) noexcept : m_path(path) {
if (mode == File::Mode::Read)
this->m_file = fopen64(path.string().c_str(), "rb");
else if (mode == File::Mode::Write)
this->m_file = fopen64(path.string().c_str(), "r+b");
#if defined(OS_WINDOWS)
if (mode == File::Mode::Read)
this->m_file = _wfopen(path.c_str(), L"rb");
else if (mode == File::Mode::Write)
this->m_file = _wfopen(path.c_str(), L"r+b");
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
this->m_file = fopen64(path.string().c_str(), "w+b");
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
this->m_file = _wfopen(path.c_str(), L"w+b");
#else
if (mode == File::Mode::Read)
this->m_file = fopen64(path.string().c_str(), "rb");
else if (mode == File::Mode::Write)
this->m_file = fopen64(path.string().c_str(), "r+b");
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
this->m_file = fopen64(path.string().c_str(), "w+b");
#endif
}
File::File() noexcept {
@@ -77,7 +89,22 @@ namespace hex::fs {
if (bytes.empty())
return "";
return { reinterpret_cast<char *>(bytes.data()), bytes.size() };
auto cString = reinterpret_cast<const char *>(bytes.data());
return { cString, std::min(bytes.size(), std::strlen(cString)) };
}
std::u8string File::readU8String(size_t numBytes) {
if (!isValid()) return {};
if (getSize() == 0) return {};
auto bytes = readBytes(numBytes);
if (bytes.empty())
return u8"";
auto cString = reinterpret_cast<const char8_t *>(bytes.data());
return { cString, std::min(bytes.size(), std::strlen(reinterpret_cast<const char*>(bytes.data()))) };
}
void File::write(const u8 *buffer, size_t size) {
@@ -98,6 +125,12 @@ namespace hex::fs {
std::fwrite(string.data(), string.size(), 1, this->m_file);
}
void File::write(const std::u8string &string) {
if (!isValid()) return;
std::fwrite(string.data(), string.size(), 1, this->m_file);
}
size_t File::getSize() const {
if (!isValid()) return 0;

View File

@@ -1,9 +1,10 @@
#include <hex/helpers/fs.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fs_macos.h>
#include <hex/helpers/fs_macos.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/intrinsics.hpp>
#include <hex/helpers/net.hpp>
#include <xdg.hpp>
@@ -22,8 +23,8 @@ namespace hex::fs {
std::optional<std::fs::path> getExecutablePath() {
#if defined(OS_WINDOWS)
std::string exePath(MAX_PATH, '\0');
if (GetModuleFileName(nullptr, exePath.data(), exePath.length()) == 0)
std::wstring exePath(MAX_PATH, '\0');
if (GetModuleFileNameW(nullptr, exePath.data(), exePath.length()) == 0)
return std::nullopt;
return exePath;
@@ -34,7 +35,15 @@ namespace hex::fs {
return exePath;
#elif defined(OS_MACOS)
return getMacExecutableDirectoryPath();
std::string result;
{
auto string = getMacExecutableDirectoryPath();
result = string;
macFree(string);
}
return result;
#else
return std::nullopt;
#endif
@@ -62,7 +71,7 @@ namespace hex::fs {
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath) {
NFD::Init();
nfdchar_t *outPath;
nfdchar_t *outPath = nullptr;
nfdresult_t result;
switch (mode) {
case DialogMode::Open:
@@ -78,8 +87,8 @@ namespace hex::fs {
hex::unreachable();
}
if (result == NFD_OKAY) {
callback(reinterpret_cast<const char8_t *>(outPath));
if (result == NFD_OKAY && outPath != nullptr) {
callback(reinterpret_cast<char8_t*>(outPath));
NFD::FreePath(outPath);
}
@@ -92,8 +101,7 @@ namespace hex::fs {
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
std::vector<std::fs::path> result;
const auto exePath = getExecutablePath();
const std::string settingName { "hex.builtin.setting.folders" };
auto userDirs = ContentRegistry::Settings::read(settingName, settingName, std::vector<std::string> {});
auto userDirs = ImHexApi::System::getAdditionalFolderPaths();
[[maybe_unused]]
auto addUserDirs = [&userDirs](auto &paths) {
@@ -105,11 +113,11 @@ namespace hex::fs {
#if defined(OS_WINDOWS)
std::fs::path appDataDir;
{
LPWSTR wAppDataPath = nullptr;
PWSTR wAppDataPath = nullptr;
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath)))
throw std::runtime_error("Failed to get APPDATA folder path");
appDataDir = wAppDataPath;
appDataDir = std::wstring(wAppDataPath);
CoTaskMemFree(wAppDataPath);
}
@@ -122,60 +130,60 @@ namespace hex::fs {
case ImHexPath::Patterns:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "patterns").string();
return path / "patterns";
});
break;
case ImHexPath::PatternsInclude:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "includes").string();
return path / "includes";
});
break;
case ImHexPath::Magic:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "magic").string();
return path / "magic";
});
break;
case ImHexPath::Python:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "python").string();
return path / "python";
});
break;
case ImHexPath::Plugins:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "plugins").string();
return path / "plugins";
});
break;
case ImHexPath::Yara:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "yara").string();
return path / "yara";
});
break;
case ImHexPath::Config:
return { (appDataDir / "imhex" / "config").string() };
return { appDataDir / "imhex" / "config" };
case ImHexPath::Resources:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "resources").string();
return path / "resources";
});
break;
case ImHexPath::Constants:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "constants").string();
return path / "constants";
});
break;
case ImHexPath::Encodings:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "encodings").string();
return path / "encodings";
});
break;
case ImHexPath::Logs:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "logs").string();
return path / "logs";
});
break;
default:
@@ -183,48 +191,54 @@ namespace hex::fs {
}
#elif defined(OS_MACOS)
// Get path to special directories
const std::fs::path applicationSupportDir(getMacApplicationSupportDirectoryPath());
std::string applicationSupportDir;
{
auto string = getMacApplicationSupportDirectoryPath();
applicationSupportDir = string;
macFree(string);
}
const std::fs::path applicationSupportDirPath(applicationSupportDir);
std::vector<std::fs::path> paths = { applicationSupportDir };
std::vector<std::fs::path> paths = { applicationSupportDirPath };
if (exePath)
paths.push_back(exePath->parent_path());
if (exePath.has_value())
paths.push_back(exePath.value());
switch (path) {
case ImHexPath::Patterns:
result.push_back((applicationSupportDir / "patterns").string());
result.push_back(applicationSupportDirPath / "patterns");
break;
case ImHexPath::PatternsInclude:
result.push_back((applicationSupportDir / "includes").string());
result.push_back(applicationSupportDirPath / "includes");
break;
case ImHexPath::Magic:
result.push_back((applicationSupportDir / "magic").string());
result.push_back(applicationSupportDirPath / "magic");
break;
case ImHexPath::Python:
result.push_back((applicationSupportDir / "python").string());
result.push_back(applicationSupportDirPath / "python");
break;
case ImHexPath::Plugins:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "plugins").string();
return path / "plugins";
});
break;
case ImHexPath::Yara:
result.push_back((applicationSupportDir / "yara").string());
result.push_back(applicationSupportDirPath / "yara");
break;
case ImHexPath::Config:
result.push_back((applicationSupportDir / "config").string());
result.push_back(applicationSupportDirPath / "config");
break;
case ImHexPath::Resources:
result.push_back((applicationSupportDir / "resources").string());
result.push_back(applicationSupportDirPath / "resources");
break;
case ImHexPath::Constants:
result.push_back((applicationSupportDir / "constants").string());
result.push_back(applicationSupportDirPath / "constants");
break;
case ImHexPath::Encodings:
result.push_back((applicationSupportDir / "encodings").string());
result.push_back(applicationSupportDirPath / "encodings");
break;
case ImHexPath::Logs:
result.push_back((applicationSupportDir / "logs").string());
result.push_back(applicationSupportDirPath / "logs");
break;
default:
hex::unreachable();
@@ -233,8 +247,8 @@ namespace hex::fs {
std::vector<std::fs::path> configDirs = xdg::ConfigDirs();
std::vector<std::fs::path> dataDirs = xdg::DataDirs();
configDirs.push_back(xdg::ConfigHomeDir());
dataDirs.push_back(xdg::DataHomeDir());
configDirs.insert(configDirs.begin(), xdg::ConfigHomeDir());
dataDirs.insert(dataDirs.begin(), xdg::DataHomeDir());
for (auto &dir : dataDirs)
dir = dir / "imhex";
@@ -245,43 +259,43 @@ namespace hex::fs {
switch (path) {
case ImHexPath::Patterns:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "patterns").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "patterns"; });
break;
case ImHexPath::PatternsInclude:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "includes").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "includes"; });
break;
case ImHexPath::Magic:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "magic").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "magic"; });
break;
case ImHexPath::Python:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p).string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p; });
break;
case ImHexPath::Plugins:
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "plugins").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "plugins"; });
break;
case ImHexPath::Yara:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "yara").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "yara"; });
break;
case ImHexPath::Config:
std::transform(configDirs.begin(), configDirs.end(), std::back_inserter(result), [](auto p) { return (p / "imhex").string(); });
std::transform(configDirs.begin(), configDirs.end(), std::back_inserter(result), [](auto p) { return p / "imhex"; });
break;
case ImHexPath::Resources:
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "resources").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "resources"; });
break;
case ImHexPath::Constants:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "constants").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "constants"; });
break;
case ImHexPath::Encodings:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "encodings").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "encodings"; });
break;
case ImHexPath::Logs:
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "logs").string(); });
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "logs"; });
break;
default:
hex::unreachable();
@@ -299,4 +313,20 @@ namespace hex::fs {
return result;
}
std::fs::path toShortPath(const std::fs::path &path) {
#if defined(OS_WINDOWS)
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0) * sizeof(TCHAR);
if (size == 0)
return path;
std::wstring newPath(size, 0x00);
GetShortPathNameW(path.c_str(), newPath.data(), newPath.size());
return newPath;
#else
return path;
#endif
}
}

View File

@@ -0,0 +1,44 @@
#if defined(OS_MACOS)
#include <string.h>
#include <stdlib.h>
#include <Foundation/Foundation.h>
char* getMacExecutableDirectoryPath() {
@autoreleasepool {
const char *pathString = [[[[[NSBundle mainBundle] executableURL] URLByDeletingLastPathComponent] path] UTF8String];
char *result = malloc(strlen(pathString) + 1);
strcpy(result, pathString);
return result;
}
}
char* getMacApplicationSupportDirectoryPath() {
@autoreleasepool {
NSError* error = nil;
NSURL* dirUrl = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:&error];
if (error != nil) {
return NULL;
}
const char *pathString = [[[dirUrl URLByAppendingPathComponent:(@"imhex")] path] UTF8String];
char *result = malloc(strlen(pathString) + 1);
strcpy(result, pathString);
return result;
}
}
void macFree(void *ptr) {
free(ptr);
}
#endif

View File

@@ -1,30 +0,0 @@
#if defined(OS_MACOS)
#include <hex/helpers/fs_macos.h>
#include <Foundation/Foundation.h>
namespace hex {
std::string getMacExecutableDirectoryPath() {
@autoreleasepool {
return {[[[[[NSBundle mainBundle] executableURL] URLByDeletingLastPathComponent] path] UTF8String]};
}
}
std::string getMacApplicationSupportDirectoryPath() {
@autoreleasepool {
NSError* error = nil;
NSURL* dirUrl = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:YES
error:&error];
if (error != nil) {
__builtin_unreachable();
}
return {[[[dirUrl URLByAppendingPathComponent:(@"imhex")] path] UTF8String]};
}
}
}
#endif

View File

@@ -1,240 +0,0 @@
#include <hex/helpers/loader_script_handler.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/file.hpp>
#include <hex/ui/view.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/intrinsics.hpp>
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>
#include <cstring>
#include <filesystem>
using namespace std::literals::string_literals;
namespace hex {
PyObject *LoaderScript::Py_getFilePath(PyObject *self, PyObject *args) {
hex::unused(self, args);
return PyUnicode_FromString(LoaderScript::s_filePath.string().c_str());
}
PyObject *LoaderScript::Py_addPatch(PyObject *self, PyObject *args) {
hex::unused(self);
u64 address;
u8 *patches;
Py_ssize_t count;
if (!PyArg_ParseTuple(args, "K|y#", &address, &patches, &count)) {
PyErr_BadArgument();
return nullptr;
}
if (patches == nullptr || count == 0) {
PyErr_SetString(PyExc_TypeError, "Invalid patch provided");
return nullptr;
}
if (address >= LoaderScript::s_dataProvider->getActualSize()) {
PyErr_SetString(PyExc_IndexError, "address out of range");
return nullptr;
}
LoaderScript::s_dataProvider->write(address, patches, count);
Py_RETURN_NONE;
}
PyObject *LoaderScript::Py_addBookmark(PyObject *self, PyObject *args) {
hex::unused(self);
u64 address;
size_t size;
char *name = nullptr;
char *comment = nullptr;
if (!PyArg_ParseTuple(args, "K|n|s|s", &address, &size, &name, &comment)) {
PyErr_BadArgument();
return nullptr;
}
if (name == nullptr || comment == nullptr) {
PyErr_SetString(PyExc_IndexError, "address out of range");
return nullptr;
}
ImHexApi::Bookmarks::add(address, size, name, comment);
Py_RETURN_NONE;
}
static PyObject *createStructureType(const std::string &keyword, PyObject *args) {
auto type = PyTuple_GetItem(args, 0);
if (type == nullptr) {
PyErr_BadArgument();
return nullptr;
}
auto instance = PyObject_CallObject(type, nullptr);
if (instance == nullptr) {
PyErr_BadArgument();
return nullptr;
}
ON_SCOPE_EXIT { Py_DECREF(instance); };
if (instance->ob_type->tp_base == nullptr || instance->ob_type->tp_base->tp_name != "ImHexType"s) {
PyErr_SetString(PyExc_TypeError, "class type must extend from ImHexType");
return nullptr;
}
auto dict = instance->ob_type->tp_dict;
if (dict == nullptr) {
PyErr_BadArgument();
return nullptr;
}
auto annotations = PyDict_GetItemString(dict, "__annotations__");
if (annotations == nullptr) {
PyErr_BadArgument();
return nullptr;
}
auto list = PyDict_Items(annotations);
if (list == nullptr) {
PyErr_BadArgument();
return nullptr;
}
ON_SCOPE_EXIT { Py_DECREF(list); };
std::string code = keyword + " " + instance->ob_type->tp_name + " {\n";
for (Py_ssize_t i = 0; i < PyList_Size(list); i++) {
auto item = PyList_GetItem(list, i);
auto memberName = PyUnicode_AsUTF8(PyTuple_GetItem(item, 0));
auto memberType = PyTuple_GetItem(item, 1);
if (memberType == nullptr) {
PyErr_SetString(PyExc_TypeError, "member needs to have a annotation extending from ImHexType");
return nullptr;
}
// Array already is an object
if (memberType->ob_type->tp_name == "array"s) {
auto arrayType = PyObject_GetAttrString(memberType, "array_type");
if (arrayType == nullptr) {
PyErr_BadArgument();
return nullptr;
}
code += " "s + arrayType->ob_type->tp_name + " " + memberName;
auto arraySize = PyObject_GetAttrString(memberType, "size");
if (arraySize == nullptr) {
PyErr_BadArgument();
return nullptr;
}
if (PyUnicode_Check(arraySize))
code += "["s + PyUnicode_AsUTF8(arraySize) + "];\n";
else if (PyLong_Check(arraySize))
code += "["s + std::to_string(PyLong_AsLong(arraySize)) + "];\n";
else {
PyErr_SetString(PyExc_TypeError, "invalid array size type. Expected string or int");
return nullptr;
}
} else {
auto memberTypeInstance = PyObject_CallObject(memberType, nullptr);
if (memberTypeInstance == nullptr || memberTypeInstance->ob_type->tp_base == nullptr || memberTypeInstance->ob_type->tp_base->tp_name != "ImHexType"s) {
PyErr_SetString(PyExc_TypeError, "member needs to have a annotation extending from ImHexType");
if (memberTypeInstance != nullptr)
Py_DECREF(memberTypeInstance);
return nullptr;
}
code += " "s + memberTypeInstance->ob_type->tp_name + " "s + memberName + ";\n";
Py_DECREF(memberTypeInstance);
}
}
code += "};\n";
EventManager::post<RequestSetPatternLanguageCode>(code);
Py_RETURN_NONE;
}
PyObject *LoaderScript::Py_addStruct(PyObject *self, PyObject *args) {
hex::unused(self);
return createStructureType("struct", args);
}
PyObject *LoaderScript::Py_addUnion(PyObject *self, PyObject *args) {
hex::unused(self);
return createStructureType("union", args);
}
bool LoaderScript::processFile(const std::fs::path &scriptPath) {
Py_SetProgramName(Py_DecodeLocale("ImHex", nullptr));
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Python)) {
if (fs::exists(std::fs::path(dir / "lib" / "python" PYTHON_VERSION_MAJOR_MINOR))) {
Py_SetPythonHome(Py_DecodeLocale(dir.string().c_str(), nullptr));
break;
}
}
PyImport_AppendInittab("_imhex", []() -> PyObject * {
static PyMethodDef ImHexMethods[] = {
{"get_file_path", &LoaderScript::Py_getFilePath, METH_NOARGS, "Returns the path of the file being loaded."},
{ "patch", &LoaderScript::Py_addPatch, METH_VARARGS, "Patches a region of memory" },
{ "add_bookmark", &LoaderScript::Py_addBookmark, METH_VARARGS, "Adds a bookmark" },
{ "add_struct", &LoaderScript::Py_addStruct, METH_VARARGS, "Adds a struct" },
{ "add_union", &LoaderScript::Py_addUnion, METH_VARARGS, "Adds a union" },
{ nullptr, nullptr, 0, nullptr }
};
static PyModuleDef ImHexModule = {
PyModuleDef_HEAD_INIT, "imhex", nullptr, -1, ImHexMethods, nullptr, nullptr, nullptr, nullptr
};
auto module = PyModule_Create(&ImHexModule);
if (module == nullptr)
return nullptr;
return module;
});
Py_Initialize();
{
auto sysPath = PySys_GetObject("path");
auto path = PyUnicode_FromString("lib");
PyList_Insert(sysPath, 0, path);
}
fs::File scriptFile(scriptPath, fs::File::Mode::Read);
PyRun_SimpleFile(scriptFile.getHandle(), scriptFile.getPath().string().c_str());
Py_Finalize();
return true;
}
}

View File

@@ -26,8 +26,9 @@ namespace hex::magic {
std::error_code error;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc")))
magicFiles += entry.path().string() + MAGIC_PATH_SEPARATOR;
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc"))) {
magicFiles += fs::toShortPath(entry.path()).string() + MAGIC_PATH_SEPARATOR;
}
}
}

View File

@@ -4,6 +4,8 @@
#include <hex/helpers/file.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/api/content_registry.hpp>
#include <filesystem>
#include <cstdio>
@@ -113,12 +115,14 @@ namespace hex {
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
#endif
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
}
std::optional<i32> Net::execute() {
CURLcode result = curl_easy_perform(this->m_ctx);
if (result != CURLE_OK)
log::error("Net request failed with error {0}: '{1}'", result, curl_easy_strerror(result));
log::error("Net request failed with error {0}: '{1}'", u32(result), curl_easy_strerror(result));
i32 responseCode = 0;
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
@@ -176,7 +180,7 @@ namespace hex {
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
fs::File file(filePath.string(), fs::File::Mode::Read);
fs::File file(filePath, fs::File::Mode::Read);
if (!file.isValid())
return Response<std::string> { 400, {} };
@@ -214,7 +218,7 @@ namespace hex {
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
fs::File file(filePath.string(), fs::File::Mode::Create);
fs::File file(filePath, fs::File::Mode::Create);
if (!file.isValid())
return Response<void> { 400 };
@@ -241,4 +245,23 @@ namespace hex {
return {};
}
std::string Net::decode(const std::string &input) {
auto unescapedString = curl_easy_unescape(this->m_ctx, input.c_str(), std::strlen(input.c_str()), nullptr);
if (unescapedString != nullptr) {
std::string output = unescapedString;
curl_free(unescapedString);
return output;
}
return {};
}
std::string Net::s_proxyUrl;
void Net::setProxy(const std::string &url) {
Net::s_proxyUrl = url;
}
}

View File

@@ -52,10 +52,10 @@ namespace hex {
json projectFileData;
try {
std::ifstream projectFile(filePath.c_str());
std::ifstream projectFile(filePath);
projectFile >> projectFileData;
ProjectFile::s_filePath = std::fs::path(projectFileData["filePath"].get<std::string>());
ProjectFile::s_filePath = std::fs::path(projectFileData["filePath"].get<std::u8string>());
ProjectFile::s_pattern = projectFileData["pattern"];
ProjectFile::s_patches = projectFileData["patches"].get<Patches>();
ProjectFile::s_dataProcessorContent = projectFileData["dataProcessor"];
@@ -89,7 +89,7 @@ namespace hex {
filePath = ProjectFile::s_currProjectFilePath;
try {
projectFileData["filePath"] = ProjectFile::s_filePath.string();
projectFileData["filePath"] = ProjectFile::s_filePath.u8string();
projectFileData["pattern"] = ProjectFile::s_pattern;
projectFileData["patches"] = ProjectFile::s_patches;
projectFileData["dataProcessor"] = ProjectFile::s_dataProcessorContent;

View File

@@ -0,0 +1,99 @@
#include <hex/helpers/tar.hpp>
#include <hex/helpers/literals.hpp>
#include <hex/helpers/file.hpp>
namespace hex {
using namespace hex::literals;
Tar::Tar(const std::fs::path &path, Mode mode) {
if (mode == Tar::Mode::Read)
mtar_open(&this->m_ctx, path.string().c_str(), "r");
else if (mode == Tar::Mode::Write)
mtar_open(&this->m_ctx, path.string().c_str(), "a");
else if (mode == Tar::Mode::Create)
mtar_open(&this->m_ctx, path.string().c_str(), "w");
}
Tar::~Tar() {
mtar_finalize(&this->m_ctx);
mtar_close(&this->m_ctx);
}
std::vector<std::fs::path> Tar::listEntries() {
std::vector<std::fs::path> result;
const std::string PaxHeaderName = "@PaxHeader";
mtar_header_t header;
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
if (header.name != PaxHeaderName) {
result.emplace_back(header.name);
}
mtar_next(&this->m_ctx);
}
return result;
}
std::vector<u8> Tar::read(const std::fs::path &path) {
mtar_header_t header;
mtar_find(&this->m_ctx, path.string().c_str(), &header);
std::vector<u8> result(header.size, 0x00);
mtar_read_data(&this->m_ctx, result.data(), result.size());
return result;
}
void Tar::write(const std::fs::path &path, const std::vector<u8> &data) {
if (path.has_parent_path()) {
std::fs::path pathPart;
for (const auto &part : path.parent_path()) {
pathPart /= part;
mtar_write_dir_header(&this->m_ctx, pathPart.string().c_str());
}
}
mtar_write_file_header(&this->m_ctx, path.string().c_str(), data.size());
mtar_write_data(&this->m_ctx, data.data(), data.size());
}
static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) {
constexpr static u64 BufferSize = 1_MiB;
fs::File outputFile(path, fs::File::Mode::Create);
std::vector<u8> buffer;
for (u64 offset = 0; offset < header->size; offset += BufferSize) {
buffer.resize(std::min<u64>(BufferSize, header->size - offset));
mtar_read_data(ctx, buffer.data(), buffer.size());
outputFile.write(buffer);
}
}
void Tar::extract(const std::fs::path &path, const std::fs::path &outputPath) {
mtar_header_t header;
mtar_find(&this->m_ctx, path.string().c_str(), &header);
writeFile(&this->m_ctx, &header, outputPath);
}
void Tar::extractAll(const std::fs::path &outputPath) {
mtar_header_t header;
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
const auto filePath = std::fs::absolute(outputPath / std::fs::path(header.name));
if (filePath.filename() != "@PaxHeader") {
std::fs::create_directories(filePath.parent_path());
writeFile(&this->m_ctx, &header, filePath);
}
mtar_next(&this->m_ctx);
}
}
}

View File

@@ -2,8 +2,6 @@
#include <cstdio>
#include <codecvt>
#include <locale>
#include <filesystem>
#include <hex/api/imhex_api.hpp>
@@ -18,13 +16,10 @@
#elif defined(OS_LINUX)
#include <unistd.h>
#elif defined(OS_MACOS)
#include <CoreFoundation/CFBundle.h>
#include <ApplicationServices/ApplicationServices.h>
#include <hex/helpers/utils_macos.hpp>
#include <unistd.h>
#endif
#include <hex/helpers/logger.hpp>
#include <hex/helpers/file.hpp>
namespace hex {
long double operator""_scaled(long double value) {
@@ -83,29 +78,34 @@ namespace hex {
break;
}
std::string result = hex::format("{0:.2f}", value);
std::string result;
if (unitIndex == 0)
result = hex::format("{0:}", value);
else
result = hex::format("{0:.2f}", value);
switch (unitIndex) {
case 0:
result += " Bytes";
result += ((value == 1) ? " Byte" : " Bytes");
break;
case 1:
result += " kB";
result += " kiB";
break;
case 2:
result += " MB";
result += " MiB";
break;
case 3:
result += " GB";
result += " GiB";
break;
case 4:
result += " TB";
result += " TiB";
break;
case 5:
result += " PB";
result += " PiB";
break;
case 6:
result += " EB";
result += " EiB";
break;
default:
result = "A lot!";
@@ -204,11 +204,15 @@ namespace hex {
}
std::vector<std::string> splitString(const std::string &string, const std::string &delimiter) {
size_t start = 0, end;
size_t start = 0, end = 0;
std::string token;
std::vector<std::string> res;
while ((end = string.find(delimiter, start)) != std::string::npos) {
size_t size = end - start;
if (start + size > string.length())
break;
token = string.substr(start, end - start);
start = end + delimiter.length();
res.push_back(token);
@@ -248,13 +252,14 @@ namespace hex {
void runCommand(const std::string &command) {
#if defined(OS_WINDOWS)
auto result = system(hex::format("start {0}", command).c_str());
#elif defined(OS_MACOS)
auto result = system(hex::format("open {0}", command).c_str());
#elif defined(OS_LINUX)
auto result = system(hex::format("xdg-open {0}", command).c_str());
#endif
#if defined(OS_WINDOWS)
auto result = system(hex::format("start {0}", command).c_str());
#elif defined(OS_MACOS)
auto result = system(hex::format("open {0}", command).c_str());
#elif defined(OS_LINUX)
auto result = system(hex::format("xdg-open {0}", command).c_str());
#endif
hex::unused(result);
}
@@ -263,18 +268,16 @@ namespace hex {
if (url.find("://") == std::string::npos)
url = "https://" + url;
#if defined(OS_WINDOWS)
ShellExecute(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
#elif defined(OS_MACOS)
CFURLRef urlRef = CFURLCreateWithBytes(nullptr, reinterpret_cast<u8 *>(url.data()), url.length(), kCFStringEncodingASCII, nullptr);
LSOpenCFURLRef(urlRef, nullptr);
CFRelease(urlRef);
#elif defined(OS_LINUX)
auto result = system(hex::format("xdg-open {0}", url).c_str());
hex::unused(result);
#else
#warning "Unknown OS, can't open webpages"
#endif
#if defined(OS_WINDOWS)
ShellExecute(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
#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);
#else
#warning "Unknown OS, can't open webpages"
#endif
}
std::string encodeByteString(const std::vector<u8> &bytes) {

View File

@@ -0,0 +1,28 @@
#if defined(OS_MACOS)
#include <CoreFoundation/CFBundle.h>
#include <ApplicationServices/ApplicationServices.h>
#include <Foundation/NSUserDefaults.h>
#include <Foundation/Foundation.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
void openWebpageMacos(const char *url) {
CFURLRef urlRef = CFURLCreateWithBytes(NULL, (uint8_t*)(url), strlen(url), kCFStringEncodingASCII, NULL);
LSOpenCFURLRef(urlRef, NULL);
CFRelease(urlRef);
}
bool isMacosSystemDarkModeEnabled() {
NSString * appleInterfaceStyle = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
if (appleInterfaceStyle && [appleInterfaceStyle length] > 0) {
return [[appleInterfaceStyle lowercaseString] containsString:@"dark"];
} else {
return false;
}
}
#endif

View File

@@ -2,25 +2,17 @@
#include <hex.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/event.hpp>
#include <hex/ui/view.hpp>
#include <cmath>
#include <cstring>
#include <map>
#include <optional>
#include <string>
#include <pl/pattern_language.hpp>
namespace hex::prv {
Provider::Provider() {
this->m_patches.emplace_back();
this->m_patternLanguageRuntime = ContentRegistry::PatternLanguage::createDefaultRuntime(this);
if (this->hasLoadInterface())
EventManager::post<RequestOpenPopup>(View::toWindowName("hex.builtin.view.provider_settings.load_popup"));
}
Provider::~Provider() {
@@ -63,6 +55,22 @@ namespace hex::prv {
patches.insert({ address + size, value });
}
void Provider::remove(u64 offset, size_t size) {
auto &patches = getPatches();
std::vector<std::pair<u64, u8>> patchesToMove;
for (auto &[address, value] : patches) {
if (address > offset)
patchesToMove.emplace_back(address, value);
}
for (const auto &[address, value] : patchesToMove)
patches.erase(address);
for (const auto &[address, value] : patchesToMove)
patches.insert({ address - size, value });
}
void Provider::applyOverlays(u64 offset, void *buffer, size_t size) {
for (auto &overlay : this->m_overlays) {
auto overlayOffset = overlay->getAddress();

View File

@@ -19,7 +19,7 @@ namespace ImGui {
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
auto &string = *static_cast<std::string *>(data->UserData);
string.resize(data->BufSize);
string.resize(data->BufTextLen);
data->Buf = string.data();
}
@@ -191,16 +191,6 @@ namespace ImGui {
PopStyleColor();
}
void Disabled(const std::function<void()> &widgets, bool disabled) {
if (disabled) {
BeginDisabled();
widgets();
EndDisabled();
} else {
widgets();
}
}
void TextSpinner(const char *label) {
ImGui::Text("[%c] %s", "|/-\\"[ImU32(ImGui::GetTime() * 20) % 4], label);
}
@@ -344,8 +334,8 @@ namespace ImGui {
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
@@ -497,7 +487,7 @@ namespace ImGui {
return pressed;
}
bool InputIntegerPrefix(const char *label, const char *prefix, u64 *value, ImGuiInputTextFlags flags) {
bool InputIntegerPrefix(const char *label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags) {
auto window = ImGui::GetCurrentWindow();
const ImGuiID id = window->GetID(label);
const ImGuiStyle &style = GImGui->Style;
@@ -510,7 +500,7 @@ namespace ImGui {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), ImGuiDataType_U64, value, "%llX");
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, "%llX");
bool value_changed = false;
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), flags))
@@ -529,8 +519,12 @@ namespace ImGui {
return value_changed;
}
bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, flags | ImGuiInputTextFlags_CharsHexadecimal);
}
bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, flags | ImGuiInputTextFlags_CharsHexadecimal);
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, flags | ImGuiInputTextFlags_CharsHexadecimal);
}
void SmallProgressBar(float fraction, float yOffset) {
@@ -559,8 +553,96 @@ namespace ImGui {
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
}
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags) {
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
}
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags) {
return ImGui::InputText(label, reinterpret_cast<char *>(buffer.data()), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
}
bool InputTextMultiline(const char *label, std::string &buffer, const ImVec2 &size, ImGuiInputTextFlags flags) {
return ImGui::InputTextMultiline(label, buffer.data(), buffer.size() + 1, size, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
}
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
if (format == NULL)
format = DataTypeGetInfo(data_type)->PrintFmt;
char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
bool value_changed = false;
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
flags |= ImGuiInputTextFlags_CharsDecimal;
flags |= ImGuiInputTextFlags_AutoSelectAll;
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags, callback, user_data))
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format);
if (value_changed)
MarkItemEdited(g.LastItemData.ID);
return value_changed;
}
void HideTooltip() {
char window_name[16];
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", GImGui->TooltipOverrideCount);
if (ImGuiWindow* window = FindWindowByName(window_name); window != nullptr) {
if (window->Active)
window->Hidden = true;
}
}
bool BitCheckbox(const char* label, bool* v) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
const ImVec2 pos = window->DC.CursorPos;
const ImRect total_bb(pos, pos + size);
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
{
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false;
}
bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
if (pressed)
{
*v = !(*v);
MarkItemEdited(id);
}
const ImRect check_bb(pos, pos + size);
RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
RenderText(check_bb.Min + style.FramePadding, *v ? "1" : "0");
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
if (label_size.x > 0.0f)
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
}

View File

@@ -8,15 +8,6 @@
namespace hex {
std::string View::s_popupMessage;
std::function<void()> View::s_yesCallback, View::s_noCallback;
u32 View::s_selectableFileIndex;
std::vector<std::fs::path> View::s_selectableFiles;
std::function<void(std::fs::path)> View::s_selectableFileOpenCallback;
std::vector<nfdfilteritem_t> View::s_selectableFilesValidExtensions;
ImFontAtlas *View::s_fontAtlas;
ImFontConfig View::s_fontConfig;
@@ -26,123 +17,21 @@ namespace hex {
return ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->isAvailable();
}
void View::drawCommonInterfaces() {
auto windowSize = ImHexApi::System::getMainWindowSize();
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.info"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
ImGui::CloseCurrentPopup();
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
ImGui::CloseCurrentPopup();
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.fatal"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape)) {
ImHexApi::Common::closeImHex();
ImGui::CloseCurrentPopup();
}
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.question"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
View::confirmButtons(
"hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [] {
s_yesCallback();
ImGui::CloseCurrentPopup(); }, [] {
s_noCallback();
ImGui::CloseCurrentPopup(); });
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
bool opened = true;
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
if (ImGui::BeginPopupModal("hex.builtin.common.choose_file"_lang, &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
if (ImGui::BeginListBox("##files", ImVec2(300_scaled, 0))) {
u32 index = 0;
for (auto &path : View::s_selectableFiles) {
if (ImGui::Selectable(path.filename().string().c_str(), index == View::s_selectableFileIndex))
View::s_selectableFileIndex = index;
index++;
}
ImGui::EndListBox();
}
if (ImGui::Button("hex.builtin.common.open"_lang)) {
View::s_selectableFileOpenCallback(View::s_selectableFiles[View::s_selectableFileIndex]);
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("hex.builtin.common.browse"_lang)) {
fs::openFileBrowser(fs::DialogMode::Open, View::s_selectableFilesValidExtensions, [](const auto &path) {
View::s_selectableFileOpenCallback(path);
ImGui::CloseCurrentPopup();
});
}
ImGui::EndPopup();
}
void View::showInfoPopup(const std::string &message) {
EventManager::post<RequestShowInfoPopup>(message);
}
void View::showMessagePopup(const std::string &message) {
s_popupMessage = message;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.info"_lang); });
void View::showErrorPopup(const std::string &message) {
EventManager::post<RequestShowErrorPopup>(message);
}
void View::showErrorPopup(const std::string &errorMessage) {
s_popupMessage = errorMessage;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.error"_lang); });
}
void View::showFatalPopup(const std::string &errorMessage) {
s_popupMessage = errorMessage;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.fatal"_lang); });
void View::showFatalPopup(const std::string &message) {
EventManager::post<RequestShowFatalErrorPopup>(message);
}
void View::showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback) {
s_popupMessage = message;
EventManager::post<RequestShowYesNoQuestionPopup>(message, yesCallback, noCallback);
s_yesCallback = yesCallback;
s_noCallback = noCallback;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.question"_lang); });
}
void View::showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback) {
@@ -151,12 +40,7 @@ namespace hex {
callback(path);
});
} else {
View::s_selectableFileIndex = 0;
View::s_selectableFiles = paths;
View::s_selectableFilesValidExtensions = validExtensions;
View::s_selectableFileOpenCallback = callback;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.choose_file"_lang); });
EventManager::post<RequestShowFileChooserPopup>(paths, validExtensions, callback);
}
}

View File

@@ -26,7 +26,7 @@ set_target_properties(main PROPERTIES
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
if (WIN32)
target_link_libraries(main PUBLIC libimhex wsock32 ws2_32 Dwmapi.lib)
target_link_libraries(main PUBLIC usp10 libimhex wsock32 ws2_32 Dwmapi.lib)
else ()
target_link_libraries(main PUBLIC libimhex pthread)
endif ()

View File

@@ -23,8 +23,6 @@ namespace hex::init {
this->m_tasks.emplace_back(taskName, task);
}
[[nodiscard]] const std::string &getGPUVendor() const { return this->m_gpuVendor; }
private:
GLFWwindow *m_window;
std::mutex m_progressMutex;

View File

@@ -54,6 +54,8 @@ namespace hex {
std::vector<int> m_pressedKeys;
std::fs::path m_imguiSettingsPath;
bool m_mouseButtonDown = false;
};
}

View File

@@ -13,7 +13,7 @@
#include <hex/ui/imgui_imhex_extensions.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <fontawesome_font.h>
#include <fonts/fontawesome_font.h>
#include <GLFW/glfw3.h>
#include <unistd.h>
@@ -30,7 +30,7 @@ namespace hex::init {
this->initGLFW();
this->initImGui();
this->m_gpuVendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
ImHexApi::System::impl::setGPUVendor(reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
}
WindowSplash::~WindowSplash() {
@@ -173,18 +173,20 @@ namespace hex::init {
auto meanScale = std::midpoint(xScale, yScale);
// On Macs with a retina display (basically all modern ones we care about), the OS reports twice
// the actual monitor scale for some obscure reason. Get rid of this here so ImHex doesn't look
// extremely huge with native scaling on macOS.
#if defined(OS_MACOS)
meanScale /= 2;
#endif
// On Macs with a retina display (basically all modern ones we care about), the OS reports twice
// the actual monitor scale for some obscure reason. Get rid of this here so ImHex doesn't look
// extremely huge with native scaling on macOS.
#if defined(OS_MACOS)
meanScale /= 2;
#endif
if (meanScale <= 0) {
if (meanScale <= 0.0) {
meanScale = 1.0;
}
ImHexApi::System::impl::setGlobalScale(meanScale);
} else {
ImHexApi::System::impl::setGlobalScale(1.0);
}
this->m_window = glfwCreateWindow(640_scaled, 400_scaled, "Starting ImHex...", nullptr, nullptr);

View File

@@ -9,9 +9,9 @@
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <fontawesome_font.h>
#include <codicons_font.h>
#include <unifont_font.h>
#include <fonts/fontawesome_font.h>
#include <fonts/codicons_font.h>
#include <fonts/unifont_font.h>
#include <hex/api/plugin_manager.hpp>
@@ -93,23 +93,6 @@ namespace hex::init {
auto fonts = IM_NEW(ImFontAtlas)();
ImFontConfig cfg = {};
std::fs::path fontFile = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "");
if (!fs::exists(fontFile))
fontFile.clear();
// If no custom font has been specified, search for a file called "font.ttf" in one of the resource folders
if (fontFile.empty()) {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) {
auto path = dir / "font.ttf";
if (fs::exists(path)) {
log::info("Loading custom front from {}", path.string());
fontFile = path;
break;
}
}
}
ImVector<ImWchar> ranges;
{
ImFontGlyphRangesBuilder glyphRangesBuilder;
@@ -135,7 +118,8 @@ namespace hex::init {
0x0100, 0xFFF0, 0
};
float fontSize = 13.0F * ImHexApi::System::getGlobalScale();
auto fontFile = ImHexApi::System::getCustomFontPath();
float fontSize = ImHexApi::System::getFontSize();
if (fontFile.empty()) {
// Load default font if no custom one has been specified
@@ -147,8 +131,6 @@ namespace hex::init {
} else {
// Load custom font
fontSize = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13) * ImHexApi::System::getGlobalScale();
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
cfg.SizePixels = fontSize;
@@ -170,24 +152,34 @@ namespace hex::init {
}
bool deleteSharedData() {
ImHexApi::System::getInitArguments().clear();
ImHexApi::Tasks::getDeferredCalls().clear();
ImHexApi::HexEditor::impl::getHighlights().clear();
ImHexApi::HexEditor::impl::getHighlightingFunctions().clear();
while (ImHexApi::Provider::isValid())
ImHexApi::Provider::remove(ImHexApi::Provider::get());
ContentRegistry::Provider::getEntries().clear();
ImHexApi::System::getInitArguments().clear();
ImHexApi::Tasks::getDeferredCalls().clear();
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
ImHexApi::HexEditor::impl::getForegroundHighlights().clear();
ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear();
ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions().clear();
ImHexApi::HexEditor::impl::getTooltips().clear();
ImHexApi::HexEditor::impl::getTooltipFunctions().clear();
ContentRegistry::Settings::getEntries().clear();
ContentRegistry::Settings::getSettingsData().clear();
ContentRegistry::CommandPaletteCommands::getEntries().clear();
ContentRegistry::PatternLanguage::getFunctions().clear();
for (auto &[name, view] : ContentRegistry::Views::getEntries())
delete view;
ContentRegistry::Views::getEntries().clear();
ContentRegistry::PatternLanguage::getFunctions().clear();
ContentRegistry::PatternLanguage::getPragmas().clear();
{
auto &views = ContentRegistry::Views::getEntries();
for (auto &[name, view] : views)
delete view;
views.clear();
}
ContentRegistry::Tools::getEntries().clear();
ContentRegistry::DataInspector::getEntries().clear();
@@ -214,6 +206,13 @@ namespace hex::init {
ContentRegistry::DataFormatter::getEntries().clear();
ContentRegistry::FileHandler::getEntries().clear();
{
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
for (auto &[name, visualizer] : visualizers)
delete visualizer;
visualizers.clear();
}
return true;
}
@@ -286,28 +285,6 @@ namespace hex::init {
return false;
}
float interfaceScaling = 1.0F;
switch (ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0)) {
default:
case 0:
// Native scaling
break;
case 1:
interfaceScaling = 0.5F;
break;
case 2:
interfaceScaling = 1.0F;
break;
case 3:
interfaceScaling = 1.5F;
break;
case 4:
interfaceScaling = 2.0F;
break;
}
ImHexApi::System::impl::setGlobalScale(interfaceScaling);
return true;
}

View File

@@ -25,17 +25,6 @@ int main(int argc, char **argv, char **envp) {
init::WindowSplash splashWindow;
// Intel's OpenGL driver has weird bugs that cause the drawn window to be offset to the bottom right.
// This can be fixed by either using Mesa3D's OpenGL Software renderer or by simply disabling it.
// If you want to try if it works anyways on your GPU, set the hex.builtin.setting.interface.force_borderless_window_mode setting to 1
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
bool isIntelGPU = hex::containsIgnoreCase(splashWindow.getGPUVendor(), "Intel");
ImHexApi::System::impl::setBorderlessWindowMode(!isIntelGPU);
if (isIntelGPU)
log::warn("Intel GPU detected! Intel's OpenGL driver has bugs that can cause issues when using ImHex. If you experience any rendering bugs, please try the Mesa3D Software Renderer");
}
for (const auto &[name, task] : init::getInitTasks())
splashWindow.addStartupTask(name, task);

View File

@@ -2,6 +2,7 @@
#if defined(OS_LINUX)
#include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/event.hpp>
@@ -21,7 +22,7 @@ namespace hex {
}
void Window::setupNativeWindow() {
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
bool themeFollowSystem = ImHexApi::System::usesSystemThemeDetection();
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem] {
if (!themeFollowSystem) return;
@@ -38,7 +39,7 @@ namespace hex {
auto exitCode = WEXITSTATUS(pclose(pipe));
if (exitCode != 0) return;
EventManager::post<RequestChangeTheme>(hex::containsIgnoreCase(result, "dark") ? 1 : 2);
EventManager::post<RequestChangeTheme>(hex::containsIgnoreCase(result, "light") ? 2 : 1);
});
if (themeFollowSystem)

View File

@@ -2,9 +2,11 @@
#if defined(OS_MACOS)
#include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/event.hpp>
#include <hex/helpers/utils_macos.hpp>
#include <hex/helpers/logger.hpp>
#include <nlohmann/json.hpp>
@@ -19,12 +21,14 @@ namespace hex {
}
void Window::setupNativeWindow() {
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
bool themeFollowSystem = ImHexApi::System::usesSystemThemeDetection();
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem] {
if (!themeFollowSystem) return;
// TODO: Implement this when MacOS build is working again
EventManager::post<RequestChangeTheme>(1);
if (!isMacosSystemDarkModeEnabled())
EventManager::post<RequestChangeTheme>(2);
else
EventManager::post<RequestChangeTheme>(1);
});
if (themeFollowSystem)

View File

@@ -9,7 +9,7 @@
#include <imgui.h>
#include <imgui_internal.h>
#include <codicons_font.h>
#include <fonts/codicons_font.h>
#include <nlohmann/json.hpp>

View File

@@ -30,7 +30,7 @@
#include <imnodes.h>
#include <imnodes_internal.h>
#include <codicons_font.h>
#include <fonts/codicons_font.h>
#include <hex/helpers/project_file_handler.hpp>
@@ -118,7 +118,7 @@ namespace hex {
return;
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) {
if (ProjectFile::store((std::fs::path(path) / CrashBackupFileName).string()))
if (ProjectFile::store(std::fs::path(path) / CrashBackupFileName))
break;
}
});
@@ -177,9 +177,10 @@ namespace hex {
glfwWaitEvents();
} else {
double timeout = (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime);
timeout = timeout > 0 ? timeout : 0;
glfwWaitEventsTimeout(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 ? 0 : timeout);
const bool frameRateThrottled = !(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 || this->m_mouseButtonDown);
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime));
glfwWaitEventsTimeout(frameRateThrottled ? timeout : 0);
}
@@ -197,7 +198,7 @@ namespace hex {
ImGuiViewport *viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowSize(ImHexApi::System::getMainWindowSize() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing()));
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
@@ -347,11 +348,12 @@ namespace hex {
ImGui::TableHeadersRow();
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Plugins, true)) {
const auto filePath = path / "builtin.hexplug";
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(path.string().c_str());
ImGui::TextUnformatted(filePath.string().c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(fs::exists(path) ? ICON_VS_CHECK : ICON_VS_CLOSE);
ImGui::TextUnformatted(fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
}
ImGui::EndTable();
}
@@ -419,8 +421,6 @@ namespace hex {
calls.clear();
}
View::drawCommonInterfaces();
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
@@ -558,7 +558,8 @@ namespace hex {
});
glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) {
ImHexApi::System::impl::setMainWindowSize(width, height);
if (!glfwGetWindowAttrib(window, GLFW_ICONIFIED))
ImHexApi::System::impl::setMainWindowSize(width, height);
if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return;
@@ -568,23 +569,32 @@ namespace hex {
win->frameEnd();
});
glfwSetMouseButtonCallback(this->m_window, [](GLFWwindow *window, int button, int action, int mods) {
hex::unused(button, mods);
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
if (action == GLFW_PRESS)
win->m_mouseButtonDown = true;
else if (action == GLFW_RELEASE)
win->m_mouseButtonDown = false;
});
glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) {
auto keyName = glfwGetKeyName(key, scancode);
if (keyName != nullptr)
key = std::toupper(keyName[0]);
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
auto &io = ImGui::GetIO();
if (action == GLFW_PRESS) {
auto &io = ImGui::GetIO();
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
win->m_pressedKeys.push_back(key);
io.KeysDown[key] = true;
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
} else if (action == GLFW_RELEASE) {
auto &io = ImGui::GetIO();
io.KeysDown[key] = false;
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
@@ -643,8 +653,9 @@ namespace hex {
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
{
if (glfwGetPrimaryMonitor() != nullptr) {
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
if (!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland"))
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}

View File

@@ -20,6 +20,9 @@ add_library(${PROJECT_NAME} SHARED
source/content/layouts.cpp
source/content/main_menu_items.cpp
source/content/welcome_screen.cpp
source/content/data_visualizers.cpp
source/content/events.cpp
source/content/hashes.cpp
source/content/providers/file_provider.cpp
source/content/providers/gdb_provider.cpp
@@ -55,6 +58,7 @@ add_library(${PROJECT_NAME} SHARED
source/lang/it_IT.cpp
source/lang/zh_CN.cpp
source/lang/ja_JP.cpp
source/lang/pt_BR.cpp
)
# Add additional include directories here #

View File

@@ -32,6 +32,7 @@ namespace hex::plugin::builtin::prv {
void resize(size_t newSize) override;
void insert(u64 offset, size_t size) override;
void remove(u64 offset, size_t size) override;
void readRaw(u64 offset, void *buffer, size_t size) override;
void writeRaw(u64 offset, const void *buffer, size_t size) override;

View File

@@ -16,6 +16,7 @@ namespace hex::plugin::builtin {
private:
std::list<ImHexApi::Bookmarks::Entry> m_bookmarks;
std::string m_currFilter;
};
}

View File

@@ -29,6 +29,7 @@ namespace hex::plugin::builtin {
std::endian m_endian = std::endian::native;
ContentRegistry::DataInspector::NumberDisplayStyle m_numberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle::Decimal;
bool m_invert = false;
u64 m_startAddress = 0;
size_t m_validBytes = 0;

View File

@@ -1,5 +1,7 @@
#pragma once
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
#include <array>
@@ -16,35 +18,10 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
enum class HashFunctions
{
Crc8,
Crc16,
Crc32,
Md5,
Sha1,
Sha224,
Sha256,
Sha384,
Sha512
};
ContentRegistry::Hashes::Hash *m_selectedHash = nullptr;
std::string m_newHashName;
bool m_shouldInvalidate = true;
int m_currHashFunction = 0;
u64 m_hashRegion[2] = { 0 };
bool m_shouldMatchSelection = false;
static constexpr std::array hashFunctionNames {
std::pair {HashFunctions::Crc8, "CRC8" },
std::pair { HashFunctions::Crc16, "CRC16" },
std::pair { HashFunctions::Crc32, "CRC32" },
std::pair { HashFunctions::Md5, "MD5" },
std::pair { HashFunctions::Sha1, "SHA-1" },
std::pair { HashFunctions::Sha224, "SHA-224"},
std::pair { HashFunctions::Sha256, "SHA-256"},
std::pair { HashFunctions::Sha384, "SHA-384"},
std::pair { HashFunctions::Sha512, "SHA-512"},
};
std::vector<ContentRegistry::Hashes::Hash::Function> m_hashFunctions;
};
}

View File

@@ -1,96 +1,146 @@
#pragma once
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/encoding_file.hpp>
#include <imgui_memory_editor.h>
#include <list>
#include <tuple>
#include <random>
#include <vector>
namespace hex::prv {
class Provider;
}
#include <algorithm>
#include <limits>
namespace hex::plugin::builtin {
using SearchFunction = std::vector<std::pair<u64, u64>> (*)(prv::Provider *&provider, std::string string);
struct HighlightBlock {
struct Highlight {
color_t color;
std::vector<std::string> tooltips;
};
constexpr static size_t Size = 0x2000;
u64 base = 0x00;
std::array<Highlight, Size> highlight;
};
class ViewHexEditor : public View {
public:
ViewHexEditor();
~ViewHexEditor() override;
void drawContent() override;
void drawAlwaysVisible() override;
private:
MemoryEditor m_memoryEditor;
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
std::vector<char> m_searchStringBuffer;
std::vector<char> m_searchHexBuffer;
SearchFunction m_searchFunction = nullptr;
std::vector<std::pair<u64, u64>> *m_lastSearchBuffer = nullptr;
bool m_searchRequested = false;
i64 m_lastSearchIndex = 0;
std::vector<std::pair<u64, u64>> m_lastStringSearch;
std::vector<std::pair<u64, u64>> m_lastHexSearch;
std::string m_gotoAddressInput;
bool m_gotoRequested = false;
bool m_evaluateGoto = false;
u64 m_baseAddress = 0;
u64 m_resizeSize = 0;
std::vector<u8> m_dataToSave;
std::set<pl::Pattern *> m_highlightedPatterns;
std::string m_loaderScriptScriptPath;
std::string m_loaderScriptFilePath;
hex::EncodingFile m_currEncodingFile;
u8 m_highlightAlpha = 0x80;
std::list<HighlightBlock> m_highlights;
bool m_processingImportExport = false;
bool m_advancedDecodingEnabled = false;
void drawSearchPopup();
void drawSearchInput(std::vector<char> *currBuffer, ImGuiInputTextFlags flags);
void performSearch(const char *buffer);
void performSearchNext();
void performSearchPrevious();
static int inputCallback(ImGuiInputTextCallbackData *data);
void drawGotoPopup();
void drawEditPopup();
void openFile(const std::fs::path &path);
void copyBytes() const;
void pasteBytes() const;
void copyString() const;
void registerEvents();
void registerShortcuts();
void registerEvents();
void registerMenuItems();
void drawCell(u64 address, u8 *data, size_t size, bool hovered);
void drawPopup();
void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize);
public:
void setSelection(const Region &region) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
void setSelection(u128 start, u128 end) {
if (!ImHexApi::Provider::isValid())
return;
if (start == InvalidSelection && end == InvalidSelection)
return;
if (start == InvalidSelection)
start = end;
if (end == InvalidSelection)
end = start;
auto provider = ImHexApi::Provider::get();
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
if (this->m_selectionChanged) {
EventManager::post<EventRegionSelected>(this->getSelection());
}
}
[[nodiscard]] Region getSelection() const {
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd);
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
const size_t size = end - start + 1;
return { start, size };
}
[[nodiscard]] bool isSelectionValid() const {
return this->m_selectionStart != InvalidSelection && this->m_selectionEnd != InvalidSelection;
}
void jumpToSelection() {
this->m_shouldJumpToSelection = true;
}
void scrollToSelection() {
this->m_shouldScrollToSelection = true;
}
void jumpIfOffScreen() {
this->m_shouldJumpWhenOffScreen = true;
}
public:
class Popup {
public:
virtual ~Popup() = default;
virtual void draw(ViewHexEditor *editor) = 0;
};
[[nodiscard]] bool isAnyPopupOpen() const {
return this->m_currPopup != nullptr;
}
template<std::derived_from<Popup> T>
[[nodiscard]] bool isPopupOpen() const {
return dynamic_cast<T*>(this->m_currPopup.get()) != nullptr;
}
template<std::derived_from<Popup> T, typename ... Args>
void openPopup(Args && ...args) {
this->m_currPopup = std::make_unique<T>(std::forward<Args>(args)...);
this->m_shouldOpenPopup = true;
}
void closePopup() {
this->m_currPopup.reset();
}
private:
void drawEditor(const ImVec2 &size);
void drawFooter(const ImVec2 &size);
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
private:
u16 m_bytesPerRow = 16;
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
bool m_shouldJumpToSelection = false;
bool m_shouldScrollToSelection = false;
bool m_shouldJumpWhenOffScreen = false;
bool m_selectionChanged = false;
u64 m_selectionStart = InvalidSelection;
u64 m_selectionEnd = InvalidSelection;
u16 m_visibleRowCount = 0;
std::optional<u64> m_editingAddress;
bool m_shouldModifyValue = false;
bool m_enteredEditingMode = false;
bool m_shouldUpdateEditingValue = false;
std::vector<u8> m_editingBytes;
color_t m_selectionColor = 0x00;
bool m_upperCaseHex = true;
bool m_grayOutZero = true;
bool m_showAscii = true;
bool m_shouldOpenPopup = false;
std::unique_ptr<Popup> m_currPopup;
std::optional<EncodingFile> m_currCustomEncoding;
};
}

View File

@@ -21,7 +21,7 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
std::map<prv::Provider *, std::vector<std::shared_ptr<pl::Pattern>>> m_sortedPatterns;
std::map<prv::Provider *, std::vector<pl::Pattern*>> m_sortedPatterns;
hex::PatternDrawer m_patternDrawer;
};

View File

@@ -12,6 +12,8 @@
#include <TextEditor.h>
namespace pl { class Pattern; }
namespace hex::plugin::builtin {
class ViewPatternEditor : public View {
@@ -23,7 +25,7 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
pl::PatternLanguage *m_parserRuntime;
std::unique_ptr<pl::PatternLanguage> m_parserRuntime;
std::vector<std::fs::path> m_possiblePatternFiles;
u32 m_selectedPatternFile = 0;
@@ -54,7 +56,6 @@ namespace hex::plugin::builtin {
};
std::map<std::string, PatternVariable> m_patternVariables;
std::vector<std::string> m_patternTypes;
enum class EnvVarType
{
@@ -91,6 +92,8 @@ namespace hex::plugin::builtin {
void drawEnvVars(ImVec2 size);
void drawVariableSettings(ImVec2 size);
void drawPatternTooltip(pl::Pattern *pattern);
void loadPatternFile(const std::fs::path &path);
void clearPatterns();
@@ -98,4 +101,4 @@ namespace hex::plugin::builtin {
void evaluatePattern(const std::string &code);
};
}
}

View File

@@ -21,10 +21,12 @@ namespace hex::plugin::builtin {
u64 address;
size_t size;
bool wholeDataMatch;
u32 highlightId;
u32 tooltipId;
};
std::vector<std::pair<std::string, std::string>> m_rules;
std::vector<std::pair<std::fs::path, std::fs::path>> m_rules;
std::vector<YaraMatch> m_matches;
u32 m_selectedRule = 0;
bool m_matching = false;

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