Compare commits

...

178 Commits

Author SHA1 Message Date
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
WerWolv
9d556ecc0f build: Bumped version to 1.17.0 2022-04-18 01:53:01 +02:00
WerWolv
ea2c2df614 sys: Updated pattern language library 2022-04-18 01:22:06 +02:00
Lukas Cone
202a02af10 fix: Crash on linux when opened file gets modified (#487) 2022-04-17 23:07:14 +02:00
WerWolv
6ee71e3a9e sys: Fixed log spam when displaying the custom paths settings tab 2022-04-17 23:05:03 +02:00
WerWolv
1e7ed14810 tests: Removed pattern language tests as they are now done in their own repo 2022-04-17 18:11:39 +02:00
WerWolv
17383083fb patterns: Use standalone pattern language library instead of built-in one 2022-04-17 16:57:30 +02:00
WerWolv
f5fe49923b fix: Let's not cause UB on every event call... 2022-04-15 19:02:36 +02:00
WerWolv
457d338a97 ui: Include null byte in InputText fields 2022-04-14 15:29:54 +02:00
Polshakov Dmitry
4928c044af patterns: Move pattern drawer into builtin plugin (#482)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-04-08 16:08:02 +02:00
WerWolv
299c69686e git: Move pattern repo link further up to make it easier to find 2022-04-08 14:26:56 +02:00
WerWolv
b7132af214 patterns: Added missing override 2022-04-07 18:19:19 +02:00
WerWolv
74a5c974e6 patterns: Fixed comments behind pre-processor defines 2022-04-07 13:15:07 +02:00
WerWolv
942a4e9616 patterns: Fixed selection of static array entries 2022-04-07 12:59:23 +02:00
WerWolv
76f732dc53 patterns: Fixed various render issues 2022-04-07 12:47:45 +02:00
WerWolv
0462cc3d0c sys: Enable -Wall, -Wextra, -Werror and fix all warnings on all Platforms (#483)
* sys: Make ImHex compile with -Wall -Wextra -Werror

* sys: Fixed various build errors on Linux

* sys: Explicitly ignore return value of `system` function

* sys: More fixes for the warnings GitHub Actions enables somehow

* sys: More fixes

* sys: Remove -Werror again to see all GitHub Actions warnings

* sys: Hopefully fixed all remaining warnings

* sys: Added back -Werror

* git: Change windows icon in GitHub Actions
2022-03-27 00:01:28 +01:00
WerWolv
965207d688 ui: Replace data inspector endian and format radio boxes with sliders 2022-03-26 17:44:01 +01:00
WerWolv
0f0a836fa0 ui: Enable undo and redo menu items only if that action is available 2022-03-26 17:21:51 +01:00
WerWolv
29fb1de882 ui/ux: Make information view plots not capture scroll, removed plot background 2022-03-26 17:19:08 +01:00
WerWolv
a807dc81a0 ui: Fixed displaying of file stat times in information view 2022-03-26 17:18:40 +01:00
WerWolv
a4d3173da9 ux: Moved bookmark remove button from body to header 2022-03-26 16:55:48 +01:00
WerWolv
4b6a76bf02 fix: Bookmarks not always creating new highlights correctly 2022-03-26 16:54:15 +01:00
WerWolv
35a520f132 ux: Disable various menu items when no provider is active 2022-03-26 16:42:11 +01:00
WerWolv
1c53d2c123 ux: Automatically remove recently opened file entries if the file doesn't exist anymore 2022-03-26 16:34:29 +01:00
WerWolv
591d98b55b sys: Improved string search filtering 2022-03-25 21:08:38 +01:00
WerWolv
f39ec58435 ui: Use pretty hexadecimal input fields in more places 2022-03-25 21:07:41 +01:00
WerWolv
e72a30ca59 patterns: Make default parameters work properly with parameter packs 2022-03-25 09:53:58 +01:00
WerWolv
368c943040 patterns: Added default parameters 2022-03-24 20:31:45 +01:00
WerWolv
a16e387dff patterns: Fixed copying of type decl nodes 2022-03-24 18:00:00 +01:00
WerWolv
95cf828975 patterns: Prevent usage of incomplete types 2022-03-24 17:00:10 +01:00
WerWolv
c09d85f46d patterns: Allow forward declaring of types 2022-03-24 16:57:12 +01:00
WerWolv
c2803fe1e2 sys: Fixed build errors and warnings on Unix 2022-03-22 09:34:26 +01:00
WerWolv
98dfc2e286 sys: Replace __builtin_unreachable() with hex::unreachable() 2022-03-22 09:08:34 +01:00
WerWolv
ea848dbfc0 ux: Added support for mathematical expressions in goto fields 2022-03-22 09:06:02 +01:00
WerWolv
f7cfee55d5 ui: Enable multi viewports on Linux again if you're not on Wayland 2022-03-22 08:20:14 +01:00
WerWolv
26a7b3325d patterns: Unified displaying and stringifying string patterns 2022-03-22 08:19:46 +01:00
WerWolv
47fd5bdc00 patterns: Fixed pointer type displaying causing crashes
Fixes #480
2022-03-22 08:19:14 +01:00
Polshakov Dmitry
5dfa9cf501 patterns: Move logic to draw patterns into separate class (#472)
* refactor(patterns): add visitor interface

* refactor(patterns): add public accessors

* refactor(patterns): add method to get pattern value

* refactor(pattern): make some methods public

* refactor(pattern): extract code to draw GUI

* refactor(patterns): remove GUI related code from patterns

* refactor: move common GUI function from pattern to pattern_drawer

* refactor(pattern_drawer): extract common code into methods

* refactor: rename ImGuiDrawer -> PatternDrawer

* refactor(patternr): move displayEnd into PatternDrawer

* refactor: use ArrayPattern concept to restrict argument type

Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-03-21 13:52:07 +01:00
WerWolv
854c99bafa build: Replace manual AppImage bundling with appimage-builder script (#477)
* build: Tried to streamline and fix AppImage building

* build: Tried fixing build

* build: Added back version key

* build: Fixed AppImage name

* build: Fixed python bundling, fixed ELF uploading

* build: Don't upload a bunch of AppImage garbage files in the portable ELF version

* build: Fixed another wrong library path

* build: Removed old manual AppImage building scripts
2022-03-20 23:43:55 +01:00
Polshakov Dmitry
937ccbc5bd patterns: Restore data offset for local variables / added array, nested structs and functions tests (#475)
* fix(eval): restore data offset for local variables

* test(pattern_lang): add tests for arrays, nested structs and functions

Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-03-20 21:42:21 +01:00
WerWolv
bc7c494316 patterns: Fixed highlighting of static array entries 2022-03-19 00:47:36 +01:00
WerWolv
17a2be41da patterns: Fixed crash when applying certain attributes to types 2022-03-19 00:24:41 +01:00
Lukas Cone
ab5966fa9d ui: fixed theme not changing on startup (#474) 2022-03-18 17:01:39 +01:00
WerWolv
89fe063b02 patterns: Fixed struct members that overlap with [[no_unique_address]] members not being highlighted 2022-03-17 23:32:22 +01:00
WerWolv
7061a1ebfa patterns: Allow bitfield fields to be selected 2022-03-17 23:31:36 +01:00
WerWolv
ec9a947259 patterns: Fixed highlight colors of arrays not matching color shown in pattern data view 2022-03-17 23:31:16 +01:00
WerWolv
11441d632b patterns: Fixed indentation of inlined variables 2022-03-17 23:30:38 +01:00
WerWolv
a17b647e79 patterns: Fixed static arrays showing same value for all entries 2022-03-17 23:29:52 +01:00
WerWolv
2d87d29fa0 patterns: Fixed recursive types 2022-03-17 00:10:16 +01:00
WerWolv
844845223f fix: Saving interface.ini file failing if imhex is installed in a non-writable location
Fixes #473
2022-03-16 13:23:36 +01:00
WerWolv
f2159e26d2 build: Updated libromfs 2022-03-16 00:15:06 +01:00
Polshakov Dmitry
d677762dff perf(pattern): save display value in cache (#466)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-03-16 00:01:01 +01:00
WerWolv
3801e0d60b build: Remove yara's cuckoo module again since we don't have jansson available 2022-03-15 23:54:55 +01:00
WerWolv
f6a498854c ui: Added console to yara view, add support for yara's new console module 2022-03-15 23:48:49 +01:00
WerWolv
29ded2483c sys: Make sure deferred call adding is thread safe 2022-03-15 23:46:02 +01:00
WerWolv
050e17298a build: Updated various dependencies 2022-03-15 23:45:33 +01:00
WerWolv
af882b172e sys: Cache provider validity when drawing toolbar items
Possibly addresses issue mentioned in #465
2022-03-13 17:46:59 +01:00
WerWolv
caad8c25ad sys: Prevent splash screen from creating a imgui.ini save file
Fixes #467
2022-03-13 17:36:50 +01:00
WerWolv
74ef9ece30 ui: Properly clear highlighting cache when switching provider
Fixes #471
2022-03-13 17:33:27 +01:00
WerWolv
97bfb4004b fix: Crash when custom font file can't be found
Fixes #468
2022-03-13 17:11:02 +01:00
Lukas Cone
3da1b3f05d ui/patterns: Added settings tooltips, fixed pattern crash (#464)
* fix: pattern segfault typo

* ui: added few tooltips into settings

Co-authored-by: WerWolv <werwolv98@gmail.com>
2022-03-05 23:32:30 +01:00
xtexChooser
f21b22ae15 feat(i18n): update Chinese(Simplified) translations (#463)
* feat(i18n): update Chinese(Simplified) translations

* fix(i18n): fix typo

* feat(i18n): update translations
2022-03-05 23:30:21 +01:00
WerWolv
327e904dbc sys: Fixed many clang tidy warnings and typos 2022-03-04 20:52:39 +01:00
WerWolv
57c449936f sys: Improved math evaluator 2022-03-04 19:20:21 +01:00
WerWolv
efe6137067 ui: Improved look of the about page 2022-03-04 19:06:29 +01:00
WerWolv
96e9400761 sys: Fixed unit test building 2022-03-04 14:34:37 +01:00
WerWolv
6a517feda3 sys: More Linux and macOS build fixes 2022-03-04 14:00:02 +01:00
WerWolv
3b7a928313 sys: Fixed missing includes on Unix 2022-03-04 11:44:11 +01:00
WerWolv
2739320f10 sys: Refactor of filesystem functions. Fixed crashes where fs errors weren't caught correctly
Addresses the crash mentioned in #462
2022-03-04 11:36:37 +01:00
WerWolv
7866e3fc2a build: Bumped version to 1.16.2 2022-03-03 14:32:30 +01:00
WerWolv
2abf89cd16 tests: Fixed build 2022-03-03 13:35:12 +01:00
WerWolv
8b2dcf976f patterns: Fixed auto parameter crash 2022-03-03 13:34:05 +01:00
WerWolv
559b86efe1 patterns: Display actual type name of types declared with using 2022-03-03 13:33:45 +01:00
WerWolv
949a26ca0e patterns: Fixed memory leak when using format attribute 2022-03-03 12:11:47 +01:00
WerWolv
2880ca00da patterns: Fixed crash when using attributes 2022-03-03 11:19:46 +01:00
WerWolv
39da62532b fix: Trailing zero at end of string input buffers 2022-03-03 09:27:27 +01:00
WerWolv
483ba95d80 fix: Some text boxes not being writable 2022-03-03 09:24:09 +01:00
WerWolv
2300b0c692 fix: Searching not working at all 2022-03-03 09:06:10 +01:00
WerWolv
cc59b36c54 patterns: Properly reset back current control flow type in arrays
Fixes issue mentioned in #460
2022-03-01 20:57:21 +01:00
WerWolv
61d9918dae patterns: Evaluate return value before setting control flow type
Fixes another issue mentioned in #460
2022-03-01 20:37:27 +01:00
WerWolv
2c361f9b0a build: Don't bundle yara rules anymore because Microsoft Defender is a little cry baby 2022-03-01 20:27:19 +01:00
WerWolv
775b3e8c52 patterns: Fixed crash when using control flow statements without value
Fixes #460
2022-03-01 20:17:03 +01:00
WerWolv
2a989c6cc1 build: Bumped version to 1.16.1 2022-03-01 18:18:56 +01:00
WerWolv
3d7adf6483 patterns: Make std::mem::find_sequence_in_range return -1 when no sequence is found 2022-03-01 16:55:45 +01:00
WerWolv
56079f70c7 ui: Added alpha preview to color picker tool 2022-03-01 16:36:06 +01:00
WerWolv
6c9e969099 ui: Improved base address setter popup 2022-03-01 16:23:53 +01:00
WerWolv
76f8e6d6ef fix: Crash when searching for empty strings 2022-03-01 16:18:39 +01:00
WerWolv
174cf3ed95 fix: Crash when entering too much text in various text boxes 2022-03-01 16:12:00 +01:00
WerWolv
540f468e8a patterns: Fixed offset being incorrectly incremented when calling functions 2022-03-01 09:40:08 +01:00
WerWolv
6b2423cdce build: Bumped version to 1.16.0 2022-03-01 08:49:48 +01:00
WerWolv
e4a3181e1d fix: Crash when saving projects 2022-03-01 00:03:39 +01:00
WerWolv
b57730c28b sys: Disable buffering on log files 2022-03-01 00:03:28 +01:00
WerWolv
5a02c38fcd store: Fixed more download issues when some folders don't have write perms 2022-02-28 23:10:04 +01:00
Lukas Cone
2847098020 patterns: Added bitfield_order pragma (#457) 2022-02-28 00:07:04 +01:00
WerWolv
0cc6d90e3d patterns: Fixed off-by-one error when calculating unsized array sizes
Closes #453, thanks to @Dyddye
2022-02-27 23:28:34 +01:00
WerWolv
66d1b3fd2f patterns: Huge refactor of Pattern Language runtime to use smart pointers (#458)
* patterns: Initial work to refactor pattern language to use smart pointers

* patterns: Fixed remaining issues, moved patterns to unique files

* sys: Added missing includes for macOS
2022-02-27 23:25:39 +01:00
WerWolv
b28eaf2dbf sys: Catch error produced in file size querying 2022-02-26 17:15:35 +01:00
WerWolv
191a99f91b fix: Crash when trying to read from an empty file or a directory 2022-02-26 16:43:38 +01:00
WerWolv
f3f1ac939a fix: Executable directory not getting added to paths correctly on Linux 2022-02-26 16:25:15 +01:00
Lukas Cone
9737b9cd62 patterns: Added find_sequence_in_range function (#448) 2022-02-26 15:53:18 +01:00
WerWolv
e3fbb490df fix: ImHex not properly loading plugins on first launch 2022-02-26 00:10:23 +01:00
WerWolv
73d74f6cde fix: Crash when changing font size 2022-02-23 10:16:27 +01:00
WerWolv
1487f760b0 build: Bundle files from the ImHex-Patterns repo with the installation 2022-02-21 22:47:56 +01:00
WerWolv
bdb2ac3a0b fix: imgui.ini file being created in the working directory sometimes
Fixes #450
2022-02-21 21:55:04 +01:00
WerWolv
75bd7805c9 ux: Added custom font and font size setting to settings menu, improve rebooting behaviour 2022-02-21 21:46:25 +01:00
WerWolv
ef8e9a83bb patterns: Properly treat arrays and custom types as references 2022-02-21 20:00:54 +01:00
WerWolv
7d9c24ff51 net: Increase store load timeout to 30 seconds 2022-02-21 18:57:53 +01:00
WerWolv
a8e83154f0 fix: Remove button of content store entries not updating correctly 2022-02-21 18:40:51 +01:00
WerWolv
27c2c4dc33 fix: Compile error because of prematurely committed change 2022-02-21 13:52:13 +01:00
WerWolv
a9a538cec8 build: Fixed circular dependency on the imhex target 2022-02-21 13:46:35 +01:00
jam1garner
57e1f7ee10 Rework libimhex-rs to use autocxx (#451)
* Rework libimhex-rs to use autocxx

* Remove Bookmarks::add overload

* Remove manual usage of cxx-rs
2022-02-20 19:14:11 -05:00
WerWolv
754eb89f04 patterns: Fixed jumping to and displaying tooltips of static array entries 2022-02-20 23:54:31 +01:00
WerWolv
2e95184d30 patterns: Allow variables to be named the same as types 2022-02-20 20:50:02 +01:00
WerWolv
9deab9c497 pattern: Allow many variable attributes to be applied directly to custom types 2022-02-19 18:03:07 +01:00
WerWolv
5ae6c8a627 fix: ImGui::TextFormattedCentered didn't properly pass format arguments forward 2022-02-19 18:02:44 +01:00
WerWolv
05104aef6c build: Properly define DEBUG macro again in debug mode 2022-02-19 18:02:10 +01:00
WerWolv
08da408471 ui: Added help text to data processor 2022-02-19 16:54:43 +01:00
WerWolv
4a4d5ac694 lang: Fixed broken localization in the Slice node 2022-02-19 16:31:04 +01:00
Lukas Cone
3b4d6d465b fix: Welcome screen corrupted banner when settings are open (#447) 2022-02-19 00:35:07 +01:00
Lukas Cone
26f998ecb6 feature: User now can add custom directories (#444)
* feat: user directories

* ux: show setting categories in order they were created

* feat: add descriptable setting categories
2022-02-18 22:34:54 +01:00
WerWolv
60a717365c ui: Remove unifont glyphs from the ASCII range 2022-02-18 16:19:12 +01:00
Polshakov Dmitry
07ae00aa20 fix: misuse of clipper (#445)
clipper.Step() should be called in a loop until it returns false.
You don't need to call End() after it.

Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-02-18 13:32:36 +01:00
Polshakov Dmitry
39cc845df3 Fix crash on typing "#include " (#446)
* fix: scan include name until end of line

* fix: correctly check file existance

Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-02-18 13:32:05 +01:00
Lukas Cone
6c8b75a05f pattern: add single_color attribute, fixed static array color override (#443) 2022-02-18 13:31:44 +01:00
WerWolv
4c8efed256 fix: Crashing when scrolling through the hex editor too quickly 2022-02-17 21:49:40 +01:00
WerWolv
faaa90fa0d fix: Borderless window mode getting enabled when it shouldn't 2022-02-17 15:22:29 +01:00
WerWolv
7e075e5ebb sys: Added editing support for strings and chars in the data inspector 2022-02-17 14:43:04 +01:00
WerWolv
b9508d853e build: Fixed building and loading of Rust plugins 2022-02-17 11:42:56 +01:00
WerWolv
716d52f3e3 sys: Register languages before registering any other things 2022-02-16 21:32:33 +01:00
WerWolv
90753f4d42 sys: Fixed logging to file omitting all tags and new lines 2022-02-16 21:31:47 +01:00
WerWolv
7117592f38 sys: Add highlighting provider function support, move pattern highlighting code out of hex editor 2022-02-16 14:57:13 +01:00
WerWolv
b9030d7e47 fix: Issue with erasing characters when pasting then into ImHex 2022-02-16 10:54:17 +01:00
WerWolv
b79cfa213d fix: Opening recent files with unicode characters in their path 2022-02-16 10:53:48 +01:00
WerWolv
60af9970c1 fix: Opening files with unicode characters in their path 2022-02-16 10:04:05 +01:00
WerWolv
33a1e7f055 sys: Added setting to override borderless window mode even on Intel 2022-02-15 23:07:48 +01:00
WerWolv
f72e9700ab sys: Move Windows theme detection to Windows plugin 2022-02-15 22:50:04 +01:00
WerWolv
4357d68462 sys: Automatically disable borderless window mode if Intel CPU is used 2022-02-15 22:36:36 +01:00
WerWolv
adfaa95149 lang: Added translation to long double inspector line 2022-02-15 21:53:39 +01:00
WerWolv
d6b887b7db sys: Added basic editing support to data inspector 2022-02-15 21:50:27 +01:00
WerWolv
227040f82f fix: Undo points not being created correctly 2022-02-15 21:50:02 +01:00
215 changed files with 9850 additions and 14414 deletions

View File

@@ -12,7 +12,7 @@ jobs:
# Windows build
win:
runs-on: windows-2022
name: 🟦 Windows MINGW64
name: 🪟 Windows MINGW64
defaults:
run:
shell: msys2 {0}
@@ -180,6 +180,11 @@ jobs:
sudo apt update
sudo bash dist/get_deps_debian.sh
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==1.0.0
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
sh rustup-init.sh -y --default-toolchain none
@@ -192,16 +197,16 @@ jobs:
run: |
mkdir -p build
cd build
CC=gcc-10 CXX=g++-10 cmake \
CC=gcc-11 CXX=g++-11 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install/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" \
-DRUST_PATH="$HOME/.cargo/bin/" \
..
make -j 4 install
make -j 4 install DESTDIR=AppDir
#- name: 📦 Bundle Flatpak
# run: |
@@ -212,33 +217,35 @@ 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: 📦 Bundle DEB
run: |
cp -r build/DEBIAN build/install
dpkg-deb --build build/install
mv build/install.deb imhex.deb
rm -rf build/install/DEBIAN
- name: 📦 Bundle AppImage
run: |
dist/AppImage/package.sh build
mv build/ImHex-x86_64.AppImage imhex.AppImage
- name: ⬆️ Upload ELF
uses: actions/upload-artifact@v2
with:
name: Linux ELF
path: |
build/install/*
build/AppDir/*
- name: ⬆️ Upload Flatpak
uses: actions/upload-artifact@v2
with:
name: Linux Flatpak
path: |
imhex.flatpak
- name: 📦 Bundle DEB
run: |
cp -r build/DEBIAN build/AppDir
dpkg-deb --build build/AppDir
mv build/AppDir.deb imhex.deb
rm -rf build/AppDir/DEBIAN
- name: ⬆️ Upload .deb
- name: 📦 Bundle AppImage
run: |
cd build
appimage-builder --recipe ../dist/AppImageBuilder.yml
mv ImHex-AppImage-x86_64.AppImage ../imhex.AppImage
cd ..
#- name: ⬆️ Upload Flatpak
# uses: actions/upload-artifact@v2
# with:
# name: Linux Flatpak
# path: |
# imhex.flatpak
- name: ⬆️ Upload DEB
uses: actions/upload-artifact@v2
with:
name: Linux DEB

2
.gitignore vendored
View File

@@ -12,3 +12,5 @@ imgui.ini
plugins/.rustc_info.json
**/target
plugins/example_rust/Cargo.lock

5
.gitmodules vendored
View File

@@ -21,6 +21,11 @@
[submodule "lib/external/capstone"]
path = lib/external/capstone
url = https://github.com/capstone-engine/capstone
ignore = dirty
[submodule "lib/external/libromfs"]
path = lib/external/libromfs
url = https://github.com/WerWolv/libromfs
ignore = dirty
[submodule "lib/external/pattern_language"]
path = lib/external/pattern_language
url = https://github.com/WerWolv/PatternLanguage

2
.idea/vcs.xml generated
View File

@@ -7,6 +7,8 @@
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
</component>

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16)
# Updating the version here will update it throughout ImHex as well
set(IMHEX_VERSION "1.15.0")
set(IMHEX_VERSION "1.18.2")
project(imhex VERSION ${IMHEX_VERSION})
set(CMAKE_CXX_STANDARD 20)
@@ -28,10 +28,14 @@ configurePackingResources()
# Add ImHex sources
add_subdirectory(lib/libimhex)
add_subdirectory(main)
add_custom_target(imhex ALL DEPENDS main)
add_custom_target(imhex_all ALL DEPENDS main)
# Add unit tests
enable_testing()
add_subdirectory(tests EXCLUDE_FROM_ALL)
# Configure packaging
createPackage()
# Download and install all current files from the ImHex-Patterns repo
downloadImHexPatternsFiles()

View File

@@ -33,7 +33,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
- Hex string
- C, C++, C#, Rust, Python, Java & JavaScript array
- ASCII-Art hex view
- HTML self contained div
- HTML self-contained div
- String and hex search
- Colorful highlighting
- Goto from start, end and current cursor position
@@ -84,7 +84,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
- Built-in Content Store
- Download all files found in the database directly from within ImHex
- Yara Rules support
- Quickly scan a file for vulnearabilities with official yara rules
- Quickly scan a file for vulnerabilities with official yara rules
- Helpful tools
- Itanium and MSVC demangler
- ASCII table
@@ -98,7 +98,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
- File utilities
- File splitter
- File combiner
- File shredderer
- File shredder
- Built-in cheat sheet for pattern language and Math evaluator
- Doesn't burn out your retinas when used in late-night sessions
@@ -106,15 +106,16 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
## Database
For format patterns, includable libraries magic and constant files, check out the [ImHex-Patterns](https://github.com/WerWolv/ImHex-Patterns) repository. Feel free to PR your own files there as well!
## Plugin development
To develop plugins for ImHex, use one of the following two templates projects to get startet. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
## Additional Files
For format patterns, includable libraries and magic files, check out the [ImHex-Patterns](https://github.com/WerWolv/ImHex-Patterns) repository. Feel free to PR your own files there as well!
## Nightly builds
@@ -230,7 +231,7 @@ 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
- All other people that have been reporting issues on Discord or GitHub that I had great conversations with :)
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
### Libraries

View File

@@ -1,3 +1,5 @@
include(FetchContent)
macro(addVersionDefines)
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/.git")
# Get the current working branch
@@ -21,19 +23,18 @@ macro(addVersionDefines)
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
add_compile_definitions(
$<$<CONFIG:Release>:IMHEX_VERSION="${IMHEX_VERSION}">
$<$<CONFIG:Debug>:IMHEX_VERSION="${IMHEX_VERSION}-Debug">
$<$<CONFIG:RelWithDebInfo>:IMHEX_VERSION="${IMHEX_VERSION}-ReleaseWithDebugInfo">
$<$<CONFIG:MinSizeRel>:IMHEX_VERSION="${IMHEX_VERSION}-ReleaseMinimumSize">
)
if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-Debug)
add_compile_definitions(DEBUG)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-RelWithDebInfo)
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-MinSizeRel)
endif ()
add_compile_definitions(
$<$<CONFIG:Release>:RELEASE>
$<$<CONFIG:Debug>:DEBUG>
$<$<CONFIG:RelWithDebInfo>:RELEASE>
$<$<CONFIG:MinSizeRel>:RELEASE>
)
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
endmacro()
@@ -176,7 +177,7 @@ macro(createPackage)
endif ()
endif ()
add_dependencies(imhex ${plugin})
add_dependencies(imhex_all ${plugin})
endif ()
endforeach()
@@ -227,7 +228,7 @@ macro(createPackage)
include(PostprocessBundle)
# Fix rpath
add_custom_command(TARGET imhex POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
# FIXME: Remove this once we move/integrate the plugins directory.
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_path}/Contents/MacOS/plugins")
@@ -236,7 +237,7 @@ macro(createPackage)
install(FILES ${IMHEX_ICON} DESTINATION "${bundle_path}/Contents/Resources")
# Update library references to make the bundle portable
postprocess_bundle(imhex main)
postprocess_bundle(imhex_all main)
# Enforce DragNDrop packaging.
set(CPACK_GENERATOR "DragNDrop")
@@ -279,4 +280,21 @@ macro(detectBadClone)
message(FATAL_ERROR "External dependency ${EXTERNAL_DIR} is empty!\nMake sure to correctly clone ImHex using the --recurse-submodules git option or initialize the submodules manually.")
endif()
endforeach ()
endmacro()
endmacro()
function(downloadImHexPatternsFiles)
FetchContent_Declare(
imhex_patterns
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
GIT_TAG master
)
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 "./")
endforeach()
endfunction()

View File

@@ -1,40 +0,0 @@
FROM debian:bullseye-slim
LABEL maintainer Example <example@example.com>
ARG TAG=master
ARG REPO=https://github.com/WerWolv/ImHex.git
USER root
# Bring packages up to date
RUN apt-get update \
&& apt-get upgrade -y \
&& apt-get autoremove -y \
&& apt-get install -y \
git \
cmake \
curl \
squashfs-tools
# Fetch source and dependencies
RUN mkdir -p /source \
&& cd /source \
&& git clone $REPO \
&& cd ImHex \
&& git checkout $TAG \
&& git submodule update --init --recursive \
&& cd /source/ImHex/dist \
&& ./get_deps_debian.sh
ARG CXX=g++-10
# Build ImHex
RUN mkdir -p /source/ImHex/build \
&& cd /source/ImHex/build \
&& cmake --install-prefix /usr -DCMAKE_BUILD_TYPE=Release .. \
&& make -j
# Prepare for AppImage
RUN cd /source/ImHex/dist/AppImage \
&& ./package.sh /source/ImHex/build \
&& mv /source/ImHex/build/ImHex-x86_64.AppImage /

View File

@@ -1,6 +0,0 @@
[Desktop Entry]
Name=ImHex
Exec=imhex
Icon=imhex
Type=Application
Categories=Utility;

View File

@@ -1,22 +0,0 @@
# Building an AppImage
There are two ways of building an AppImage for ImHex, using the provided
tools here.
If you want to create an AppImage and do not have a build to work from
already, you can use docker to build ImHex and package an AppImage.
Alternatively you can create an AppImage using an existing build.
## Using docker
First run `build.sh` to create a docker image. Then run `extract.sh` to get the
AppImage out. This needs to be in two steps, as a docker build cannot copy
files out. Nor can docker build use volume mounts.
The environment variable TAG can be set to build for a specific git tag.
Without the master branch is build.
## Using an existing build
Run `package.sh` with the build dir as an argument. E.g.:
```
./package.sh ../../build
```

View File

@@ -1,16 +0,0 @@
#!/bin/bash
# Set the TAG environment variable to build a specific tag
# Set the REPO environment variable to point at a different git repository
# Make sure we're in the same directory as this script
pushd $(dirname "$(realpath "$0")")
BUILDARG=""
SUFFIX=""
[ -n "${TAG}" ] && BUILDARG="${BUILDARG} --build-arg=TAG=${TAG}" && SUFFIX=":${TAG}"
[ -n "${REPO}" ] && BUILDARG="${BUILDARG} --build-arg=REPO=${REPO}"
docker build ${BUILDARG} -t imhex-appimage-build${SUFFIX} .
popd

View File

@@ -1,26 +0,0 @@
#!/bin/bash
# Set the TAG environment variable to move to a versioned name while extracting
# Make sure we're in the same directory as this script
pushd $(dirname "$(realpath "$0")")
SUFFIX=""
[ -n "$TAG" ] && SUFFIX=":$TAG"
# Remove old containers
docker rm imhex 2>&1 > /dev/null
docker run -d --name imhex imhex-appimage-build${SUFFIX} sleep 30 &
sleep 15
docker cp imhex:/ImHex-x86_64.AppImage .
# Move to tagged name if $TAG set
if [ -n "$TAG" ]; then
mv ImHex-x86_64.AppImage ImHex-${TAG}-x86_64.AppImage
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-${TAG}-x86_64.AppImage\n\n"
else
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-x86_64.AppImage\n\n"
fi
popd

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -1,58 +0,0 @@
#!/bin/bash
set -e # Exit on error
set -o pipefail # Bash specific
usage() {
echo "Tool to package an ImHex build into an AppImage"
echo
echo "Usage:"
echo "$0 <build dir>"
echo
exit
}
MYDIR=$(dirname "$(realpath "$0")")
# Check is a build dir has been specified and it's a dir
[ -z "$1" ] && usage
[ -d "$1" ] || usage
set -u # Throw errors when unset variables are used
BUILDDIR=$1
APPDIR=${BUILDDIR}/ImHex.AppDir
APPIMAGE=${BUILDDIR}/ImHex-x86_64.AppImage
# Prepare for AppImage
## Fetch the needed AppImage binaries
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/AppRun-x86_64 -o ${MYDIR}/AppRun-x86_64
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/runtime-x86_64 -o ${MYDIR}/runtime-x86_64
## Setup directory structure
mkdir -p ${BUILDDIR}/ImHex.AppDir/usr/{bin,lib} ${BUILDDIR}/ImHex.AppDir/usr/share/imhex/plugins
## Add ImHex files to structure
cp ${BUILDDIR}/imhex ${APPDIR}/usr/bin
cp ${BUILDDIR}/plugins/builtin/builtin.hexplug ${APPDIR}/usr/share/imhex/plugins
cp ${MYDIR}/{AppRun-x86_64,ImHex.desktop,imhex.png} ${APPDIR}/
mv ${BUILDDIR}/ImHex.AppDir/AppRun-x86_64 ${APPDIR}/AppRun
chmod a+x ${BUILDDIR}/ImHex.AppDir/AppRun
## Add all dependencies
ldd ${BUILDDIR}/imhex | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
ldd ${BUILDDIR}/plugins/builtin/builtin.hexplug | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
ldd ${BUILDDIR}/lib/libimhex/libimhex.so | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
# Package it up as described here:
# https://github.com/AppImage/AppImageKit#appimagetool-usage
# under 'If you want to generate an AppImage manually'
# This builds a v2 AppImage according to
# https://github.com/AppImage/AppImageSpec/blob/master/draft.md#type-2-image-format
mksquashfs ${APPDIR} ${BUILDDIR}/ImHex.squashfs -root-owned -noappend
cat ${MYDIR}/runtime-x86_64 > ${APPIMAGE}
cat ${BUILDDIR}/ImHex.squashfs >> ${APPIMAGE}
chmod a+x ${APPIMAGE}
if [ ! -f /.dockerenv ]; then
echo -e "\nThe created AppImage can be found here:\n ${APPIMAGE}\n\n"
fi

142
dist/AppImageBuilder.yml vendored Normal file
View File

@@ -0,0 +1,142 @@
# 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
app_info:
id: imhex
name: ImHex
icon: imhex
version: AppImage
exec: usr/bin/imhex
exec_args: $@
apt:
arch:
- 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
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
include:
- libbz2-1.0:amd64
- libcap2:amd64
- libdbus-1-3:amd64
- libgpg-error0:amd64
- liblzma5:amd64
- libnss-mdns:amd64
- libpcre3:amd64
- libselinux1:amd64
- libtinfo6:amd64
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/libOpenGL.so.0
- /lib/x86_64-linux-gnu/libX11.so.6
- /lib/x86_64-linux-gnu/libXau.so.6
- /lib/x86_64-linux-gnu/libXcomposite.so.1
- /lib/x86_64-linux-gnu/libXcursor.so.1
- /lib/x86_64-linux-gnu/libXdamage.so.1
- /lib/x86_64-linux-gnu/libXdmcp.so.6
- /lib/x86_64-linux-gnu/libXext.so.6
- /lib/x86_64-linux-gnu/libXfixes.so.3
- /lib/x86_64-linux-gnu/libXi.so.6
- /lib/x86_64-linux-gnu/libXinerama.so.1
- /lib/x86_64-linux-gnu/libXrandr.so.2
- /lib/x86_64-linux-gnu/libXrender.so.1
- /lib/x86_64-linux-gnu/libXxf86vm.so.1
- /lib/x86_64-linux-gnu/libatk-1.0.so.0
- /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0
- /lib/x86_64-linux-gnu/libatspi.so.0
- /lib/x86_64-linux-gnu/libblkid.so.1
- /lib/x86_64-linux-gnu/libbrotlicommon.so.1
- /lib/x86_64-linux-gnu/libbrotlidec.so.1
- /lib/x86_64-linux-gnu/libbsd.so.0
- /lib/x86_64-linux-gnu/libcairo-gobject.so.2
- /lib/x86_64-linux-gnu/libcairo.so.2
- /lib/x86_64-linux-gnu/libdatrie.so.1
- /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/libfontconfig.so.1
- /lib/x86_64-linux-gnu/libfreetype.so.6
- /lib/x86_64-linux-gnu/libfribidi.so.0
- /lib/x86_64-linux-gnu/libgcrypt.so.20
- /lib/x86_64-linux-gnu/libgdk-3.so.0
- /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0
- /lib/x86_64-linux-gnu/libgio-2.0.so.0
- /lib/x86_64-linux-gnu/libglapi.so.0
- /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/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.66
- /lib/x86_64-linux-gnu/libicuuc.so.66
- /lib/x86_64-linux-gnu/libjpeg.so.8
- /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/libmd.so.0
- /lib/x86_64-linux-gnu/libmount.so.1
- /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/libsensors.so.5
- /lib/x86_64-linux-gnu/libstdc++.so.6
- /lib/x86_64-linux-gnu/libsystemd.so.0
- /lib/x86_64-linux-gnu/libthai.so.0
- /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
- /lib/x86_64-linux-gnu/libwayland-cursor.so.0
- /lib/x86_64-linux-gnu/libwayland-egl.so.1
- /lib/x86_64-linux-gnu/libxcb-dri2.so.0
- /lib/x86_64-linux-gnu/libxcb-dri3.so.0
- /lib/x86_64-linux-gnu/libxcb-present.so.0
- /lib/x86_64-linux-gnu/libxcb-sync.so.1
- /lib/x86_64-linux-gnu/libxkbcommon.so.0
- /lib/x86_64-linux-gnu/libxml2.so.2
- /lib/x86_64-linux-gnu/libxshmfence.so.1
- /lib/x86_64-linux-gnu/libzstd.so.1
exclude:
- usr/share/man
- usr/share/doc/*/README.*
- usr/share/doc/*/changelog.*
- usr/share/doc/*/NEWS.*
- usr/share/doc/*/TODO.*
AppImage:
arch: x86_64
update-information: guess

View File

@@ -12,8 +12,8 @@ fi
apt install -y \
build-essential \
gcc-10 \
g++-10 \
gcc-11 \
g++-11 \
lld \
${PKGCONF:-} \
cmake \
@@ -28,4 +28,4 @@ apt install -y \
libgtk-3-dev \
echo "Please consider this before running cmake (useful on e.g. Ubuntu 20.04):"
echo "export CXX=g++-10"
echo "export CXX=g++-11"

7
dist/imhex.desktop vendored
View File

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

View File

@@ -1,803 +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 <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::Text("%02llX", 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);
clipper.Step();
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 != -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;
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;
}
}
}
}
IM_ASSERT(clipper.Step() == false);
clipper.End();
ImGui::PopStyleVar(2);
ImGui::EndChild();
if (data_next && DataEditingAddr < mem_size)
{
DataEditingAddr = DataPreviewAddr = 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);
ImGuiStyle& style = ImGui::GetStyle();
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

@@ -81,17 +81,19 @@ set(LIBYARA_SOURCE
)
set(LIBYARA_MODULES
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
${LIBYARA_SOURCE_PATH}/modules/elf/elf.c
${LIBYARA_SOURCE_PATH}/modules/math/math.c
${LIBYARA_SOURCE_PATH}/modules/time/time.c
${LIBYARA_SOURCE_PATH}/modules/macho/macho.c
${LIBYARA_SOURCE_PATH}/modules/hash/hash.c
${LIBYARA_SOURCE_PATH}/modules/console/console.c
${LIBYARA_SOURCE_PATH}/modules/dex/dex.c
${LIBYARA_SOURCE_PATH}/modules/dotnet/dotnet.c
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c)
${LIBYARA_SOURCE_PATH}/modules/elf/elf.c
${LIBYARA_SOURCE_PATH}/modules/hash/hash.c
${LIBYARA_SOURCE_PATH}/modules/macho/macho.c
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c
${LIBYARA_SOURCE_PATH}/modules/math/math.c
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
${LIBYARA_SOURCE_PATH}/modules/time/time.c
)
# Add mbedtls crypto wrappers
add_compile_definitions("HAVE_MBEDTLS")

View File

@@ -2,6 +2,149 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "aquamarine"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96e14cb2a51c8b45d26a4219981985c7350fc05eacb7b5b2939bceb2ffefdf3e"
dependencies = [
"itertools 0.9.0",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocxx"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13e6384cb95b48be8c5b83764ef800858322436f57aa17974915d23dadb6a7d5"
dependencies = [
"aquamarine",
"autocxx-engine",
"autocxx-macro",
"cxx",
"moveit",
]
[[package]]
name = "autocxx-bindgen"
version = "0.59.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e603c1eb79e21068072ef990e5463f613e0cedddd6712ff11afeae2a90b2510"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"clap",
"env_logger",
"itertools 0.10.3",
"lazy_static",
"lazycell",
"log",
"peeking_take_while",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"which",
]
[[package]]
name = "autocxx-build"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f5b45a4fe71d3ac68d8b4fd11abe54c791046ec4def7effe27961269b6ab3"
dependencies = [
"autocxx-engine",
"env_logger",
"syn",
]
[[package]]
name = "autocxx-engine"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02323905bec49fde96ff028fcff1c478d0eba14fa34ea5eb5e4d17439748e42a"
dependencies = [
"aquamarine",
"autocxx-bindgen",
"autocxx-parser",
"cc",
"cxx",
"cxx-gen",
"indoc",
"itertools 0.10.3",
"log",
"once_cell",
"proc-macro2",
"quote",
"serde_json",
"strum_macros",
"syn",
"tempfile",
"unzip-n",
"version_check",
]
[[package]]
name = "autocxx-macro"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8106ca477cbe6edf188311f2e05606b81bf463c41748ce7120c31d1b11875515"
dependencies = [
"autocxx-parser",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocxx-parser"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad0ad08260adcecc119b08f460b0633b6e306ea2f6fda4f27e4dd28e20b9a2f4"
dependencies = [
"log",
"proc-macro2",
"quote",
"serde",
"serde_derive",
"syn",
]
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -14,6 +157,15 @@ version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
[[package]]
name = "cexpr"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
dependencies = [
"nom",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -26,6 +178,32 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6"
[[package]]
name = "clang-sys"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21"
dependencies = [
"glob",
"libc",
"libloading",
]
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "codespan-reporting"
version = "0.11.1"
@@ -49,17 +227,14 @@ dependencies = [
]
[[package]]
name = "cxx-build"
version = "1.0.55"
name = "cxx-gen"
version = "0.7.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83363b96cfd226eb820e37a21088c30c55e47f9fc8299c2d08a6090d50414ccc"
checksum = "836e95ae34fc21fb39c206444879afda2c6e704424c9c621662764f1b459e83a"
dependencies = [
"cc",
"codespan-reporting",
"lazy_static",
"proc-macro2",
"quote",
"scratch",
"syn",
]
@@ -81,15 +256,63 @@ dependencies = [
]
[[package]]
name = "libimhex-rs"
version = "0.1.0"
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"cxx",
"cxx-build",
"imgui",
"macros",
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "fastrand"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [
"instant",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "imgui"
version = "0.8.0"
@@ -107,6 +330,23 @@ dependencies = [
"chlorine",
]
[[package]]
name = "imhex-macros"
version = "0.1.0"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "indoc"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e"
dependencies = [
"unindent",
]
[[package]]
name = "instant"
version = "0.1.11"
@@ -116,18 +356,69 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "itertools"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
version = "0.2.103"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
[[package]]
name = "libimhex-rs"
version = "0.1.0"
dependencies = [
"autocxx",
"autocxx-build",
"cxx",
"imgui",
"imhex-macros",
]
[[package]]
name = "libloading"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
dependencies = [
"cfg-if",
"winapi",
]
[[package]]
name = "link-cplusplus"
version = "1.0.5"
@@ -147,13 +438,52 @@ dependencies = [
]
[[package]]
name = "macros"
version = "0.1.0"
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"quote",
"syn",
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
name = "moveit"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd833d6adefa6bcfc56948d061c1d697dfa3ab63711963c7ef4aa23eda945676"
dependencies = [
"cxx",
]
[[package]]
name = "nom"
version = "7.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
dependencies = [
"memchr",
"minimal-lexical",
"version_check",
]
[[package]]
name = "once_cell"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "parking_lot"
version = "0.11.2"
@@ -179,6 +509,36 @@ dependencies = [
"winapi",
]
[[package]]
name = "peeking_take_while"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.29"
@@ -206,6 +566,50 @@ dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustversion"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
[[package]]
name = "ryu"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "scopeguard"
version = "1.1.0"
@@ -213,10 +617,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scratch"
version = "1.0.0"
name = "serde"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e114536316b51a5aa7a0e59fc49661fd263c5507dd08bd28de052e57626ce69"
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
[[package]]
name = "serde_derive"
version = "1.0.136"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "shlex"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "smallvec"
@@ -224,6 +656,25 @@ version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strum_macros"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "1.0.77"
@@ -235,6 +686,20 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.2"
@@ -244,6 +709,21 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
[[package]]
name = "unicode-width"
version = "0.1.9"
@@ -256,6 +736,46 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "unindent"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8"
[[package]]
name = "unzip-n"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e7e85a0596447f0f2ac090e16bc4c516c6fe91771fb0c0ccf7fa3dae896b9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "which"
version = "4.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2"
dependencies = [
"either",
"lazy_static",
"libc",
]
[[package]]
name = "winapi"
version = "0.3.9"

View File

@@ -11,6 +11,8 @@ imhex-macros = { path = "proc_macros" }
imgui = { path = "imgui-rs" }
cxx = "1.0.55"
autocxx = "0.16"
[build-dependencies]
cxx-build = "1.0.55"
autocxx-build = "0.16"
#cxx-build = "1.0.55"

View File

@@ -1,15 +1,26 @@
fn main() {
println!("cargo:rustc-link-lib=dylib=imhex");
println!("cargo:rustc-link-search=all={}", env!("LIBIMHEX_OUTPUT_DIRECTORY"));
println!(
"cargo:rustc-link-search=all={}",
env!("LIBIMHEX_OUTPUT_DIRECTORY")
);
println!("cargo:rerun-if-changed=src/lib.rs");
println!("cargo:rerun-if-changed=src/imhex_api.rs");
cxx_build::bridge("src/imhex_api.rs")
let include = format!("-I{}/include", env!("LIBIMHEX_SOURCE_DIRECTORY"));
let path = std::path::PathBuf::from("src");
let mut build = autocxx_build::Builder::new("src/lib.rs", &[&path])
.extra_clang_args(&[&include, "-x", "c++", "-std=gnu++20"])
.auto_allowlist(true)
.expect_build();
build
.include(format!("{}/include", env!("LIBIMHEX_SOURCE_DIRECTORY")))
.flag_if_supported("-std=gnu++20")
.flag_if_supported("-std=gnu++2a")
.flag_if_supported("-fconcepts")
.compiler(env!("CXX_COMPILER"))
.compile("libimhex-bridge");
}
}

View File

@@ -13,17 +13,6 @@ impl Parse for AttrList {
}
}
fn symbol(name: &str) -> String {
let pkg_name = std::env::var("CARGO_PKG_NAME").unwrap();
format!(
"_ZN3hex6plugin{}{}8internal{}{}Ev",
pkg_name.len(),
pkg_name,
name.len(),
name,
)
}
#[proc_macro_attribute]
pub fn plugin_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
let args = syn::parse_macro_input!(attr as AttrList)
@@ -36,11 +25,14 @@ pub fn plugin_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
let function = syn::parse_macro_input!(item as syn::ItemFn);
let plugin_name_export = symbol("getPluginName");
let plugin_author_export = symbol("getPluginAuthor");
let plugin_desc_export = symbol("getPluginDescription");
let plugin_init_export = symbol("initializePlugin");
let plugin_set_imgui_ctxt_export = symbol("setImGuiContext");
let plugin_name_export = "getPluginName";
let plugin_author_export = "getPluginAuthor";
let plugin_desc_export = "getPluginDescription";
let plugin_version_export = "getCompatibleVersion";
let plugin_init_export = "initializePlugin";
let plugin_set_imgui_ctx_export = "setImGuiContext";
let imhex_version = std::env::var("IMHEX_VERSION").unwrap();
quote!(
#[export_name = #plugin_name_export]
@@ -58,11 +50,16 @@ pub fn plugin_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
concat!(#description, "\0").as_ptr()
}
#[export_name = #plugin_set_imgui_ctxt_export]
#[export_name = #plugin_set_imgui_ctx_export]
pub unsafe extern "C" fn set_imgui_context(context: *mut ::hex::imgui::sys::ImGuiContext) {
::hex::imgui::sys::igSetCurrentContext(context);
}
#[export_name = #plugin_version_export]
pub unsafe extern "C" fn plugin_version() -> *const u8 {
concat!(#imhex_version, "\0").as_ptr()
}
#[export_name = #plugin_init_export]
pub extern "C" #function
)

View File

@@ -0,0 +1,27 @@
use autocxx::c_ulong;
use crate::Color;
use std::ops::Range;
/// Add a bookmark to a region of the current imhex view with an optionally provided color
///
/// ```rust,ignore
/// use hex::bookmarks;
///
/// bookmarks::add(0..0x10, "header", "this is the header of the file", None);
///
/// let red = Color::new(0xFF, 0, 0, 0xFF);
/// bookmarks::add(0x10..0x30, "table", "this is the table of the file", red);
/// ```
pub fn add(region: Range<u64>, name: &str, comment: &str, color: impl Into<Option<Color>>) {
cxx::let_cxx_string!(cpp_name = name);
cxx::let_cxx_string!(cpp_comment = comment);
crate::ffi::hex::ImHexApi::Bookmarks::add(
region.start,
c_ulong::from(region.end.saturating_sub(region.start)),
&cpp_name,
&cpp_comment,
color.into().unwrap_or(crate::Color::new(0, 0, 0, 0)).rgba(),
);
}

View File

@@ -0,0 +1,11 @@
use crate::ffi::hex::ImHexApi::Common;
/// Close ImHex, optionally prompting the user if they'd like to quit
pub fn close_imhex(without_question: bool) {
Common::closeImHex(without_question)
}
/// Close and reopen ImHex
pub fn restart_imhex() {
Common::restartImHex()
}

View File

@@ -1,99 +1,17 @@
pub mod ffi {
pub mod ImHexApi {
#[cxx::bridge]
pub mod Common {
#[namespace = "hex::ImHexApi::Common"]
extern "C++" {
include!("hex/api/imhex_api.hpp");
pub unsafe fn closeImHex(no_questions: bool);
pub unsafe fn restartImHex();
}
}
#[cxx::bridge]
pub mod Bookmarks {
#[namespace = "hex::ImHexApi::Bookmarks"]
extern "C++" {
include!("hex/api/imhex_api.hpp");
pub unsafe fn add(addr : u64, size : usize, name : &CxxString, comment : &CxxString, color : u32);
}
}
}
}
pub struct Region {
pub address : u64,
pub size : usize
}
/// A highlight color for use with the bookmarks API
pub struct Color {
pub a : u8,
pub g : u8,
pub b : u8,
pub r : u8
}
impl Region {
pub fn new(address : u64, size : usize) -> Self {
Region { address, size }
}
pub a: u8,
pub g: u8,
pub b: u8,
pub r: u8,
}
impl Color {
pub fn new(r : u8, g : u8, b : u8, a : u8) -> Self {
pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
Color { a, g, b, r }
}
pub fn rgba(self) -> u32 {
pub const fn rgba(self) -> u32 {
(self.a as u32) << 24 | (self.b as u32) << 16 | (self.g as u32) << 8 | (self.r as u32) << 0
}
}
pub mod ImHexApi {
pub mod Common {
pub fn closeImHex() {
unsafe {
crate::imhex_api::ffi::ImHexApi::Common::closeImHex(false);
}
}
pub fn restartImmHex() {
unsafe {
crate::imhex_api::ffi::ImHexApi::Common::restartImHex();
}
}
}
pub mod Bookmarks {
pub fn add(region : crate::Region, name : &str, comment : &str, color : Option<crate::Color>) {
cxx::let_cxx_string!(cpp_name = name);
cxx::let_cxx_string!(cpp_comment = comment);
unsafe {
crate::imhex_api::ffi::ImHexApi::Bookmarks::add(region.address, region.size, &cpp_name, &cpp_comment, color.unwrap_or(crate::Color::new(0, 0, 0, 0)).rgba());
}
}
}
}

View File

@@ -1,9 +1,42 @@
#![allow(non_snake_case)]
use autocxx::prelude::*;
include_cpp! {
#include "hex/api/imhex_api.hpp"
safety!(unsafe)
generate!("hex::ImHexApi::Common::closeImHex")
generate!("hex::ImHexApi::Common::restartImHex")
generate!("hex::ImHexApi::Bookmarks::add")
}
//pub use crate::ffi::*;
/// API for working with imhex bookmarks/highlights
pub mod bookmarks;
/// API for working with imhex itself
pub mod imhex;
mod imhex_api;
pub use imhex_macros::plugin_setup;
pub use imhex_api::ImHexApi;
pub use imhex_api::Region;
pub use imgui;
#[doc(inline)]
pub use imhex_api::Color;
pub use imgui;
/// A macro for declaring the init function for your plugin
///
/// ## Example
///
/// ```
/// #[hex::plugin_setup(
/// /* Display name*/ "Example Rust",
/// /* Author */ "WerWolv",
/// /* Description */ "Example Rust plugin used as template for plugin devs"
/// )]
/// fn init() {
/// // plugin initialization logic here
/// }
/// ```
pub use imhex_macros::plugin_setup;

View File

@@ -71,15 +71,16 @@ if (NOT USE_SYSTEM_CAPSTONE)
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/capstone ${CMAKE_CURRENT_BINARY_DIR}/external/capstone EXCLUDE_FROM_ALL)
set_target_properties(capstone-static PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(CAPSTONE_LIBRARIES "capstone-static")
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(CAPSTONE_LIBRARIES "capstone")
set(CAPSTONE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../external/capstone/include)
else()
find_package(PkgConfig REQUIRED)
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
endif()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/pattern_language ${CMAKE_CURRENT_BINARY_DIR}/external/pattern_language EXCLUDE_FROM_ALL)
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
find_package(mbedTLS 2.26.0 REQUIRED)
configurePython()
@@ -113,7 +114,7 @@ set(LIBIMHEX_SOURCES
source/data_processor/node.cpp
source/helpers/utils.cpp
source/helpers/paths.cpp
source/helpers/fs.cpp
source/helpers/magic.cpp
source/helpers/crypto.cpp
source/helpers/net.cpp
@@ -125,14 +126,6 @@ set(LIBIMHEX_SOURCES
source/helpers/loader_script_handler.cpp
source/helpers/logger.cpp
source/pattern_language/pattern_language.cpp
source/pattern_language/preprocessor.cpp
source/pattern_language/lexer.cpp
source/pattern_language/parser.cpp
source/pattern_language/validator.cpp
source/pattern_language/evaluator.cpp
source/pattern_language/log_console.cpp
source/providers/provider.cpp
source/ui/imgui_imhex_extensions.cpp
@@ -149,13 +142,14 @@ if (APPLE)
endif ()
endif ()
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm)
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/fs_macos.mm)
endif ()
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_compile_options(libimhex PRIVATE -Wall -Wextra -Werror)
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS})
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
@@ -165,4 +159,4 @@ if (APPLE)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs)
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl)

View File

@@ -3,28 +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

@@ -2,27 +2,33 @@
#include <hex.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/pattern_language/token.hpp>
#include <pl/pattern_language.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#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;
}
namespace hex {
class View;
class LanguageDefinition;
namespace pl {
class Evaluator;
}
namespace dp {
class Node;
}
@@ -43,14 +49,31 @@ namespace hex {
struct Entry {
std::string name;
bool requiresRestart;
Callback callback;
};
struct Category {
std::string name;
size_t slot = 0;
bool operator<(const Category &other) const {
return name < other.name;
}
operator const std::string &() const {
return name;
}
};
void load();
void store();
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart = false);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart = false);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart = false);
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription);
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value);
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
@@ -60,7 +83,8 @@ namespace hex {
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue = {});
std::map<std::string, std::vector<Entry>> &getEntries();
std::map<Category, std::vector<Entry>> &getEntries();
std::map<std::string, std::string> &getCategoryDescriptions();
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
nlohmann::json &getSettingsData();
}
@@ -68,7 +92,8 @@ namespace hex {
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
namespace CommandPaletteCommands {
enum class Type : u32 {
enum class Type : u32
{
SymbolCommand,
KeywordCommand
};
@@ -98,37 +123,28 @@ namespace hex {
namespace impl {
struct ColorPalette {
struct FunctionDefinition {
pl::api::Namespace ns;
std::string name;
std::vector<u32> colors;
pl::api::FunctionParameterCount parameterCount;
pl::api::FunctionCallback callback;
bool dangerous;
};
}
constexpr static u32 UnlimitedParameters = 0xFFFF'FFFF;
constexpr static u32 MoreParametersThan = 0x8000'0000;
constexpr static u32 LessParametersThan = 0x4000'0000;
constexpr static u32 ExactlyOrMoreParametersThan = 0x2000'0000;
constexpr static u32 NoParameters = 0x0000'0000;
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider);
using Namespace = std::vector<std::string>;
using Callback = std::function<std::optional<hex::pl::Token::Literal>(hex::pl::Evaluator *, const std::vector<hex::pl::Token::Literal> &)>;
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
struct Function {
u32 parameterCount;
Callback func;
bool dangerous;
};
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
void addFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func);
void addDangerousFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func);
std::map<std::string, ContentRegistry::PatternLanguage::Function> &getFunctions();
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
std::vector<impl::FunctionDefinition> &getFunctions();
std::vector<impl::ColorPalette> &getPalettes();
void addColorPalette(const std::string &unlocalizedName, const std::vector<u32> &colors);
void setSelectedPalette(u32 index);
u32 getNextColor();
void resetPalette();
}
/* View Registry. Allows adding of new windows */
@@ -173,7 +189,8 @@ namespace hex {
/* Data Inspector Registry. Allows adding of new types to the data inspector */
namespace DataInspector {
enum class NumberDisplayStyle {
enum class NumberDisplayStyle
{
Decimal,
Hexadecimal,
Octal
@@ -182,17 +199,19 @@ namespace hex {
namespace impl {
using DisplayFunction = std::function<std::string()>;
using EditingFunction = std::function<std::vector<u8>(std::string, std::endian)>;
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>;
struct Entry {
std::string unlocalizedName;
size_t requiredSize;
impl::GeneratorFunction generatorFunction;
std::optional<impl::EditingFunction> editingFunction;
};
}
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction function);
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
std::vector<impl::Entry> &getEntries();
}
@@ -350,7 +369,7 @@ namespace hex {
namespace impl {
using Callback = std::function<bool(fs::path)>;
using Callback = std::function<bool(std::fs::path)>;
struct Entry {
std::vector<std::string> extensions;
Callback callback;
@@ -363,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<hex::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 name) : m_name(std::move(name)) {}
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 &getName() const {
return this->m_name;
}
protected:
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const {
return { this, name, callback };
}
private:
std::string m_name;
};
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

@@ -8,7 +8,7 @@
#include <functional>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#define EVENT_DEF(event_name, ...) \
struct event_name final : public hex::Event<__VA_ARGS__> { \
@@ -16,7 +16,11 @@
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
}
class GLFWwindow;
struct GLFWwindow;
namespace pl {
class Pattern;
}
namespace hex {
@@ -87,7 +91,7 @@ namespace hex {
static void post(auto &&...args) noexcept {
for (const auto &[id, event] : s_events) {
if (id == E::id)
(*reinterpret_cast<E *>(event))(std::forward<decltype(args)>(args)...);
(*static_cast<E *const>(event))(std::forward<decltype(args)>(args)...);
}
}
@@ -96,12 +100,8 @@ namespace hex {
static EventList s_events;
};
namespace pl {
class PatternData;
}
/* Default Events */
EVENT_DEF(EventFileLoaded, fs::path);
EVENT_DEF(EventFileLoaded, std::fs::path);
EVENT_DEF(EventFileUnloaded);
EVENT_DEF(EventDataChanged);
EVENT_DEF(EventHighlightingChanged);
@@ -116,6 +116,7 @@ namespace hex {
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
EVENT_DEF(EventFrameBegin);
EVENT_DEF(EventFrameEnd);
EVENT_DEF(EventWindowInitialized);
EVENT_DEF(RequestOpenWindow, std::string);
EVENT_DEF(RequestSelectionChange, Region);
@@ -123,11 +124,11 @@ namespace hex {
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
EVENT_DEF(RequestChangeWindowTitle, std::string);
EVENT_DEF(RequestCloseImHex, bool);
EVENT_DEF(RequestOpenFile, fs::path);
EVENT_DEF(RequestOpenFile, std::fs::path);
EVENT_DEF(RequestChangeTheme, u32);
EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
EVENT_DEF(QuerySelection, Region &);
EVENT_DEF(QuerySelection, std::optional<Region> &);
}

View File

@@ -3,14 +3,18 @@
#include <hex.hpp>
#include <list>
#include <vector>
#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 <imgui.h>
using ImGuiID = unsigned int;
struct ImVec2;
namespace hex {
@@ -29,26 +33,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, const 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;
std::string m_tooltip;
Region m_region = {};
color_t m_color = 0x00;
};
u32 addHighlight(const Region &region, color_t color, std::string tooltip = "");
void removeHighlight(u32 id);
std::map<u32, Highlighting> &getHighlights();
class Tooltip {
public:
Tooltip() = default;
Tooltip(Region region, std::string value, color_t color);
Region getSelection();
[[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<color_t>(u64, const u8*, size_t)>;
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 addBackgroundHighlight(const Region &region, color_t color);
void removeBackgroundHighlight(u32 id);
u32 addForegroundHighlight(const Region &region, color_t color);
void removeForegroundHighlight(u32 id);
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);
@@ -63,11 +110,8 @@ namespace hex {
std::string comment;
u32 color;
bool locked;
u32 highlightId;
};
void add(Region region, const std::string &name, const std::string &comment, color_t color = 0x00000000);
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
}
@@ -112,6 +156,8 @@ namespace hex {
void setGlobalScale(float scale);
void setProgramArguments(int argc, char **argv, char **envp);
void setBorderlessWindowMode(bool enabled);
}
struct ProgramArguments {
@@ -131,6 +177,8 @@ namespace hex {
ImVec2 getMainWindowSize();
ImGuiID getMainDockSpaceId();
bool isBorderlessWindowModeEnabled();
std::map<std::string, std::string> &getInitArguments();
}

View File

@@ -11,9 +11,10 @@ struct ImGuiWindow;
namespace hex {
struct View;
class View;
enum class Keys {
enum class Keys
{
Space = GLFW_KEY_SPACE,
Apostrophe = GLFW_KEY_APOSTROPHE,
Comma = GLFW_KEY_COMMA,
@@ -141,6 +142,9 @@ namespace hex {
class Shortcut {
public:
Shortcut() = default;
Shortcut(Keys key) : m_keys({ key }) { }
Shortcut operator+(const Key &other) const {
Shortcut result = *this;
result.m_keys.insert(other);

View File

@@ -11,7 +11,7 @@ namespace hex {
public:
LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries);
const std::map<std::string, std::string> &getEntries() const;
[[nodiscard]] const std::map<std::string, std::string> &getEntries() const;
private:
std::map<std::string, std::string> m_entries;
@@ -20,7 +20,7 @@ namespace hex {
class LangEntry {
public:
explicit LangEntry(const char *unlocalizedString);
explicit LangEntry(const std::string &unlocalizedString);
explicit LangEntry(std::string unlocalizedString);
explicit LangEntry(std::string_view unlocalizedString);
operator std::string() const;

View File

@@ -3,7 +3,7 @@
#include <hex.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#include <string>
@@ -13,7 +13,7 @@ namespace hex {
class Plugin {
public:
explicit Plugin(const fs::path &path);
explicit Plugin(const std::fs::path &path);
Plugin(const Plugin &) = delete;
Plugin(Plugin &&other) noexcept;
~Plugin();
@@ -26,7 +26,7 @@ namespace hex {
void setImGuiContext(ImGuiContext *ctx) const;
[[nodiscard]] bool isBuiltinPlugin() const;
[[nodiscard]] const fs::path &getPath() const;
[[nodiscard]] const std::fs::path &getPath() const;
[[nodiscard]] bool isLoaded() const;
@@ -40,7 +40,7 @@ namespace hex {
using IsBuiltinPluginFunc = bool (*)();
void *m_handle = nullptr;
fs::path m_path;
std::fs::path m_path;
mutable bool m_initialized = false;
@@ -65,7 +65,7 @@ namespace hex {
public:
PluginManager() = delete;
static bool load(const fs::path &pluginFolder);
static bool load(const std::fs::path &pluginFolder);
static void unload();
static void reload();
@@ -74,7 +74,7 @@ namespace hex {
}
private:
static fs::path s_pluginFolder;
static std::fs::path s_pluginFolder;
static std::vector<Plugin> s_plugins;
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/intrinsics.hpp>
#include <hex/data_processor/attribute.hpp>
#include <set>
@@ -38,8 +39,8 @@ namespace hex::dp {
virtual void drawNode() { }
virtual void process() = 0;
virtual void store(nlohmann::json &j) { }
virtual void load(nlohmann::json &j) { }
virtual void store(nlohmann::json &j) { hex::unused(j); }
virtual void load(nlohmann::json &j) { hex::unused(j); }
using NodeError = std::pair<Node *, std::string>;
@@ -90,11 +91,11 @@ namespace hex::dp {
}
std::vector<u8> getBufferOnInput(u32 index);
u64 getIntegerOnInput(u32 index);
i64 getIntegerOnInput(u32 index);
float getFloatOnInput(u32 index);
void setBufferOnOutput(u32 index, std::vector<u8> data);
void setIntegerOnOutput(u32 index, u64 integer);
void setBufferOnOutput(u32 index, const std::vector<u8> &data);
void setIntegerOnOutput(u32 index, i64 integer);
void setFloatOnOutput(u32 index, float floatingPoint);
void setOverlayData(u64 address, const std::vector<u8> &data);

View File

@@ -3,6 +3,7 @@
#include <hex.hpp>
#include <type_traits>
#include <memory>
namespace hex {
@@ -166,7 +167,7 @@ namespace hex {
template<typename T>
class Cloneable {
public:
[[nodiscard]] virtual T *clone() const = 0;
[[nodiscard]] virtual std::unique_ptr<T> clone() const = 0;
};
}

View File

@@ -31,12 +31,12 @@ namespace hex {
class Disassembler {
public:
static constexpr cs_arch toCapstoneArchictecture(Architecture architecture) {
static constexpr cs_arch toCapstoneArchitecture(Architecture architecture) {
return static_cast<cs_arch>(architecture);
}
static inline bool isSupported(Architecture architecture) {
return cs_support(toCapstoneArchictecture(architecture));
return cs_support(toCapstoneArchitecture(architecture));
}
constexpr static const char *const ArchitectureNames[] = { "ARM32", "ARM64", "MIPS", "x86", "PowerPC", "Sparc", "SystemZ", "XCore", "68K", "TMS320C64x", "680X", "Ethereum", "MOS65XX", "WebAssembly", "Berkeley Packet Filter", "RISC-V" };

View File

@@ -2,22 +2,34 @@
#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
#include <hex/helpers/paths.hpp>
#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 {
class EncodingFile {
public:
enum class Type {
enum class Type
{
Thingy
};
EncodingFile() = default;
EncodingFile(Type type, const fs::path &path);
EncodingFile(Type type, const std::fs::path &path);
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(const std::vector<u8> &buffer) const;
[[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
@@ -25,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

@@ -6,7 +6,7 @@
#include <string>
#include <vector>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#if defined(OS_MACOS)
#define off64_t off_t
@@ -16,17 +16,18 @@
#define ftruncate64 ftruncate
#endif
namespace hex {
namespace hex::fs {
class File {
public:
enum class Mode {
enum class Mode
{
Read,
Write,
Create
};
explicit File(const fs::path &path, Mode mode) noexcept;
explicit File(const std::fs::path &path, Mode mode) noexcept;
File() noexcept;
File(const File &) = delete;
File(File &&other) noexcept;
@@ -36,7 +37,9 @@ namespace hex {
File &operator=(File &&other) noexcept;
[[nodiscard]] bool isValid() const { return this->m_file != nullptr; }
[[nodiscard]] bool isValid() const {
return this->m_file != nullptr && fs::exists(this->m_path) && !fs::isDirectory(this->m_path);
}
void seek(u64 offset);
void close();
@@ -53,14 +56,16 @@ namespace hex {
void setSize(u64 size);
void flush();
void remove();
bool remove();
auto getHandle() { return this->m_file; }
const fs::path &getPath() { return this->m_path; }
const std::fs::path &getPath() { return this->m_path; }
void disableBuffering();
private:
FILE *m_file;
fs::path m_path;
std::fs::path m_path;
};
}

View File

@@ -0,0 +1,92 @@
#pragma once
#include <optional>
#include <string>
#include <vector>
#include <filesystem>
#include <functional>
#include <nfd.hpp>
namespace std::fs {
using namespace std::filesystem;
}
namespace hex::fs {
[[maybe_unused]]
static inline bool exists(const std::fs::path &path) {
std::error_code error;
return std::filesystem::exists(path, error) && !error;
}
[[maybe_unused]]
static inline bool createDirectories(const std::fs::path &path) {
std::error_code error;
return std::filesystem::create_directories(path, error) && !error;
}
[[maybe_unused]]
static inline bool isRegularFile(const std::fs::path &path) {
std::error_code error;
return std::filesystem::is_regular_file(path, error) && !error;
}
[[maybe_unused]]
static inline bool copyFile(const std::fs::path &from, const std::fs::path &to, std::fs::copy_options = std::fs::copy_options::none) {
std::error_code error;
return std::filesystem::copy_file(from, to, error) && !error;
}
[[maybe_unused]]
static inline bool isDirectory(const std::fs::path &path) {
std::error_code error;
return std::filesystem::is_directory(path, error) && !error;
}
[[maybe_unused]]
static inline bool remove(const std::fs::path &path) {
std::error_code error;
return std::filesystem::remove(path, error) && !error;
}
[[maybe_unused]]
static inline uintmax_t getFileSize(const std::fs::path &path) {
std::error_code error;
auto size = std::filesystem::file_size(path, error);
if (error) return 0;
else return size;
}
bool isPathWritable(const std::fs::path &path);
enum class DialogMode
{
Open,
Save,
Folder
};
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {});
enum class ImHexPath
{
Patterns,
PatternsInclude,
Magic,
Python,
Plugins,
Yara,
Config,
Resources,
Constants,
Encodings,
Logs
};
std::optional<std::fs::path> getExecutablePath();
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
}

View File

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

View File

@@ -0,0 +1,13 @@
#pragma once
namespace hex {
[[noreturn]] inline void unreachable() {
__builtin_unreachable();
}
inline void unused(auto && ... x) {
((void)x, ...);
}
}

View File

@@ -3,7 +3,7 @@
#include <string>
#include <string_view>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
struct _object;
typedef struct _object PyObject;
@@ -18,13 +18,13 @@ namespace hex {
public:
LoaderScript() = delete;
static bool processFile(const fs::path &scriptPath);
static bool processFile(const std::fs::path &scriptPath);
static void setFilePath(const fs::path &filePath) { LoaderScript::s_filePath = filePath; }
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 fs::path s_filePath;
static inline std::fs::path s_filePath;
static inline prv::Provider *s_dataProvider;
static PyObject *Py_getFilePath(PyObject *self, PyObject *args);

View File

@@ -1,5 +1,7 @@
#pragma once
#include <hex.hpp>
#include <chrono>
#include <fmt/core.h>
@@ -13,44 +15,54 @@ namespace hex::log {
namespace {
void printPrefix(const fmt::text_style &ts, const std::string &level) {
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
const auto now = fmt::localtime(std::chrono::system_clock::now());
fmt::print("[{0:%H:%M:%S}] ", now);
fmt::print(ts, "{0} ", level);
fmt::print("[{0}] ", IMHEX_PROJECT_NAME);
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
if (isRedirected())
fmt::print(dest, "{0} ", level);
else
fmt::print(dest, ts, "{0} ", level);
fmt::print(dest, "[{0}] ", IMHEX_PROJECT_NAME);
}
template<typename... T>
void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
printPrefix(ts, level);
fmt::print(getDestination(), fmt::runtime(fmt), args...);
fmt::print("\n");
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
auto dest = getDestination();
printPrefix(dest, ts, level);
fmt::print(dest, fmt::runtime(fmt), args...);
fmt::print(dest, "\n");
}
}
void debug(const std::string &fmt, auto &&...args) {
[[maybe_unused]] void debug(const std::string &fmt, auto &&...args) {
#if defined(DEBUG)
log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
hex::log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
#else
hex::unused(fmt, args...);
#endif
}
void info(const std::string &fmt, auto &&...args) {
log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
[[maybe_unused]] void info(const std::string &fmt, auto &&...args) {
hex::log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
}
void warn(const std::string &fmt, auto &&...args) {
log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
[[maybe_unused]] void warn(const std::string &fmt, auto &&...args) {
hex::log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
}
void error(const std::string &fmt, auto &&...args) {
log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
[[maybe_unused]] void error(const std::string &fmt, auto &&...args) {
hex::log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
}
void fatal(const std::string &fmt, auto &&...args) {
log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
[[maybe_unused]] void fatal(const std::string &fmt, auto &&...args) {
hex::log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
}
void redirectToFile();
[[maybe_unused]] void redirectToFile();
}

View File

@@ -12,7 +12,7 @@
#include <nlohmann/json_fwd.hpp>
#include <curl/system.h>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
using CURL = void;
struct curl_slist;
@@ -35,11 +35,13 @@ namespace hex {
Net();
~Net();
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = 2000);
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = 2000);
static constexpr u32 DefaultTimeout = 2'000;
std::future<Response<std::string>> uploadFile(const std::string &url, const fs::path &filePath, u32 timeout = 2000);
std::future<Response<void>> downloadFile(const std::string &url, const fs::path &filePath, u32 timeout = 2000);
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout);
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout);
std::future<Response<std::string>> uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
std::future<Response<void>> downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
[[nodiscard]] std::string encode(const std::string &input);

View File

@@ -1,29 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <filesystem>
namespace hex {
namespace fs = std::filesystem;
enum class ImHexPath {
Patterns,
PatternsInclude,
Magic,
Python,
Plugins,
Yara,
Config,
Resources,
Constants,
Encodings,
Logs
};
std::string getExecutablePath();
std::vector<fs::path> getPath(ImHexPath path, bool listNonExisting = false);
}

View File

@@ -8,7 +8,7 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
namespace hex {
@@ -16,8 +16,8 @@ namespace hex {
public:
ProjectFile() = delete;
static bool load(const fs::path &filePath);
static bool store(fs::path filePath = {});
static bool load(const std::fs::path &filePath);
static bool store(std::fs::path filePath = {});
[[nodiscard]] static bool hasUnsavedChanges() {
return ProjectFile::s_hasUnsavedChanged;
@@ -29,10 +29,10 @@ namespace hex {
ProjectFile::s_hasUnsavedChanged = true;
if (setWindowTitle)
EventManager::post<RequestChangeWindowTitle>(fs::path(getFilePath()).filename().string());
EventManager::post<RequestChangeWindowTitle>(std::fs::path(getFilePath()).filename().string());
}
[[nodiscard]] static const fs::path &getProjectFilePath() {
[[nodiscard]] static const std::fs::path &getProjectFilePath() {
return ProjectFile::s_currProjectFilePath;
}
@@ -41,11 +41,11 @@ namespace hex {
}
[[nodiscard]] static const fs::path &getFilePath() {
[[nodiscard]] static const std::fs::path &getFilePath() {
return ProjectFile::s_filePath;
}
static void setFilePath(const fs::path &filePath) {
static void setFilePath(const std::fs::path &filePath) {
ProjectFile::s_filePath = filePath;
EventManager::post<RequestChangeWindowTitle>(filePath.filename().string());
@@ -92,10 +92,10 @@ namespace hex {
}
private:
static fs::path s_currProjectFilePath;
static std::fs::path s_currProjectFilePath;
static bool s_hasUnsavedChanged;
static fs::path s_filePath;
static std::fs::path s_filePath;
static std::string s_pattern;
static Patches s_patches;
static std::list<ImHexApi::Bookmarks::Entry> s_bookmarks;

View File

@@ -26,7 +26,7 @@ namespace hex {
public:
Socket() = default;
Socket(const Socket &) = delete;
Socket(Socket &&other);
Socket(Socket &&other) noexcept;
Socket(const std::string &address, u16 port);
~Socket();
@@ -36,8 +36,8 @@ namespace hex {
[[nodiscard]] bool isConnected() const;
std::string readString(size_t size = 0x1000) const;
std::vector<u8> readBytes(size_t size = 0x1000) const;
[[nodiscard]] std::string readString(size_t size = 0x1000) const;
[[nodiscard]] std::vector<u8> readBytes(size_t size = 0x1000) const;
void writeString(const std::string &string) const;
void writeBytes(const std::vector<u8> &bytes) const;

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

@@ -3,7 +3,8 @@
#include <hex.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/intrinsics.hpp>
#include <array>
#include <bit>
@@ -18,8 +19,6 @@
#include <variant>
#include <vector>
#include <nfd.hpp>
#define TOKEN_CONCAT_IMPL(x, y) x##y
#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y)
#define ANONYMOUS_VARIABLE(prefix) TOKEN_CONCAT(prefix, __COUNTER__)
@@ -41,6 +40,9 @@ namespace hex {
void runCommand(const std::string &command);
void openWebpage(std::string url);
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) {
if (from < to) std::swap(from, to);
@@ -53,9 +55,6 @@ namespace hex {
[[nodiscard]] inline u64 extract(u32 from, u32 to, const std::vector<u8> &bytes) {
u8 index = 0;
while (from > 32 && to > 32) {
if (from - 8 < 0 || to - 8 < 0)
return 0;
from -= 8;
to -= 8;
index++;
@@ -73,6 +72,18 @@ namespace hex {
return (value ^ mask) - mask;
}
template<hex::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>
@@ -127,7 +138,7 @@ namespace hex {
swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64);
break;
default:
__builtin_unreachable();
hex::unreachable();
}
T result;
@@ -167,7 +178,7 @@ namespace hex {
swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64);
break;
default:
__builtin_unreachable();
hex::unreachable();
}
T result = 0;
@@ -189,6 +200,40 @@ namespace hex {
return T(1) << bit_width(T(x - 1));
}
template<hex::integral T, hex::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));
if constexpr (sizeof...(rest) > 0)
moveToVector(buffer, std::move(rest)...);
}
template<typename T, typename... Args>
std::vector<T> moveToVector(T &&first, Args &&...rest) {
std::vector<T> result;
moveToVector(result, T(std::move(first)), std::move(rest)...);
return result;
}
std::vector<std::string> splitString(const std::string &string, const std::string &delimiter);
std::string combineStrings(const std::vector<std::string> &strings, const std::string &delimiter = "");
@@ -247,14 +292,6 @@ namespace hex {
trimRight(s);
}
enum class DialogMode {
Open,
Save,
Folder
};
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(fs::path)> &callback, const std::string &defaultPath = {});
float float16ToFloat32(u16 float16);
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
@@ -280,12 +317,21 @@ namespace hex {
return *value;
}
template<hex::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);
namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
#define ON_SCOPE_EXIT [[maybe_unused]] auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
template<class F>
class ScopeGuard {
@@ -294,7 +340,7 @@ namespace hex {
bool m_active;
public:
constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
explicit constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
~ScopeGuard() {
if (this->m_active) { this->m_func(); }
}
@@ -307,7 +353,9 @@ namespace hex {
ScopeGuard &operator=(ScopeGuard &&) = delete;
};
enum class ScopeGuardOnExit { };
enum class ScopeGuardOnExit
{
};
template<typename F>
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F &&f) {
@@ -318,17 +366,19 @@ namespace hex {
namespace first_time_exec {
#define FIRST_TIME static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
template<class F>
class FirstTimeExecute {
public:
constexpr FirstTimeExecute(F func) { func(); }
explicit constexpr FirstTimeExecute(F func) { func(); }
FirstTimeExecute &operator=(FirstTimeExecute &&) = delete;
};
enum class FirstTimeExecutor { };
enum class FirstTimeExecutor
{
};
template<typename F>
constexpr FirstTimeExecute<F> operator+(FirstTimeExecutor, F &&f) {
@@ -339,20 +389,22 @@ namespace hex {
namespace final_cleanup {
#define FINAL_CLEANUP static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
template<class F>
class FinalCleanupExecute {
F m_func;
public:
constexpr FinalCleanupExecute(F func) : m_func(func) { }
explicit constexpr FinalCleanupExecute(F func) : m_func(func) { }
constexpr ~FinalCleanupExecute() { this->m_func(); }
FinalCleanupExecute &operator=(FinalCleanupExecute &&) = delete;
};
enum class FinalCleanupExecutor { };
enum class FinalCleanupExecutor
{
};
template<typename F>
constexpr FinalCleanupExecute<F> operator+(FinalCleanupExecutor, F &&f) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +0,0 @@
#pragma once
#include <hex.hpp>
#include <stdexcept>
#include <string>
namespace hex::pl {
class PatternLanguageError : public std::exception {
public:
PatternLanguageError(u32 lineNumber, std::string message) : m_lineNumber(lineNumber), m_message(std::move(message)) { }
[[nodiscard]] const char *what() const noexcept override {
return this->m_message.c_str();
}
[[nodiscard]] u32 getLineNumber() const {
return this->m_lineNumber;
}
private:
u32 m_lineNumber;
std::string m_message;
};
}

View File

@@ -1,276 +0,0 @@
#pragma once
#include <atomic>
#include <bit>
#include <map>
#include <optional>
#include <vector>
#include <hex/pattern_language/log_console.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/concepts.hpp>
namespace hex::prv {
class Provider;
}
namespace hex::pl {
enum class DangerousFunctionPermission
{
Ask,
Deny,
Allow
};
enum class ControlFlowStatement
{
None,
Continue,
Break,
Return
};
class PatternData;
class PatternCreationLimiter;
class ASTNode;
class Evaluator {
public:
Evaluator() = default;
std::optional<std::vector<PatternData *>> evaluate(const std::vector<ASTNode *> &ast);
[[nodiscard]] LogConsole &getConsole() {
return this->m_console;
}
struct ParameterPack {
std::string name;
std::vector<Token::Literal> values;
};
struct Scope {
PatternData *parent;
std::vector<PatternData *> *scope;
std::optional<ParameterPack> parameterPack;
};
void pushScope(PatternData *parent, std::vector<PatternData *> &scope) {
if (this->m_scopes.size() > this->getEvaluationDepth())
LogConsole::abortEvaluation(hex::format("evaluation depth exceeded set limit of {}", this->getEvaluationDepth()));
this->handleAbort();
this->m_scopes.push_back({ parent, &scope });
}
void popScope() {
this->m_scopes.pop_back();
}
Scope &getScope(i32 index) {
return this->m_scopes[this->m_scopes.size() - 1 + index];
}
const Scope &getScope(i32 index) const {
return this->m_scopes[this->m_scopes.size() - 1 + index];
}
Scope &getGlobalScope() {
return this->m_scopes.front();
}
const Scope &getGlobalScope() const {
return this->m_scopes.front();
}
size_t getScopeCount() {
return this->m_scopes.size();
}
bool isGlobalScope() {
return this->m_scopes.size() == 1;
}
void setProvider(prv::Provider *provider) {
this->m_provider = provider;
}
void setInVariables(const std::map<std::string, Token::Literal> &inVariables) {
this->m_inVariables = inVariables;
}
[[nodiscard]] std::map<std::string, Token::Literal> getOutVariables() const {
std::map<std::string, Token::Literal> result;
for (const auto &[name, offset] : this->m_outVariables) {
result.insert({ name, this->getStack()[offset] });
}
return result;
}
[[nodiscard]] prv::Provider *getProvider() const {
return this->m_provider;
}
void setDefaultEndian(std::endian endian) {
this->m_defaultEndian = endian;
}
[[nodiscard]] std::endian getDefaultEndian() const {
return this->m_defaultEndian;
}
void setEvaluationDepth(u64 evalDepth) {
this->m_evalDepth = evalDepth;
}
[[nodiscard]] u64 getEvaluationDepth() const {
return this->m_evalDepth;
}
void setArrayLimit(u64 arrayLimit) {
this->m_arrayLimit = arrayLimit;
}
[[nodiscard]] u64 getArrayLimit() const {
return this->m_arrayLimit;
}
void setPatternLimit(u64 limit) {
this->m_patternLimit = limit;
}
[[nodiscard]] u64 getPatternLimit() {
return this->m_patternLimit;
}
[[nodiscard]] u64 getPatternCount() {
return this->m_currPatternCount;
}
void setLoopLimit(u64 limit) {
this->m_loopLimit = limit;
}
[[nodiscard]] u64 getLoopLimit() {
return this->m_loopLimit;
}
u64 &dataOffset() { return this->m_currOffset; }
bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguage::Callback &function) {
const auto [iter, inserted] = this->m_customFunctions.insert({
name, {numParams, function}
});
return inserted;
}
[[nodiscard]] const std::map<std::string, ContentRegistry::PatternLanguage::Function> &getCustomFunctions() const {
return this->m_customFunctions;
}
[[nodiscard]] std::vector<Token::Literal> &getStack() {
return this->m_stack;
}
[[nodiscard]] const std::vector<Token::Literal> &getStack() const {
return this->m_stack;
}
void createParameterPack(const std::string &name, const std::vector<Token::Literal> &values);
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt, bool outVariable = false);
void setVariable(const std::string &name, const Token::Literal &value);
void abort() {
this->m_aborted = true;
}
void handleAbort() {
if (this->m_aborted)
LogConsole::abortEvaluation("evaluation aborted by user");
}
[[nodiscard]] std::optional<Token::Literal> getEnvVariable(const std::string &name) const {
if (this->m_envVariables.contains(name))
return this->m_envVariables.at(name);
else
return std::nullopt;
}
void setEnvVariable(const std::string &name, const Token::Literal &value) {
this->m_envVariables[name] = value;
}
[[nodiscard]] bool hasDangerousFunctionBeenCalled() const {
return this->m_dangerousFunctionCalled;
}
void dangerousFunctionCalled() {
this->m_dangerousFunctionCalled = true;
}
void allowDangerousFunctions(bool allow) {
this->m_allowDangerousFunctions = allow ? DangerousFunctionPermission::Allow : DangerousFunctionPermission::Deny;
this->m_dangerousFunctionCalled = false;
}
[[nodiscard]] DangerousFunctionPermission getDangerousFunctionPermission() const {
return this->m_allowDangerousFunctions;
}
void setCurrentControlFlowStatement(ControlFlowStatement statement) {
this->m_currControlFlowStatement = statement;
}
[[nodiscard]] ControlFlowStatement getCurrentControlFlowStatement() const {
return this->m_currControlFlowStatement;
}
[[nodiscard]] std::optional<Token::Literal> getMainResult() {
return this->m_mainResult;
}
private:
void patternCreated();
void patternDestroyed();
private:
u64 m_currOffset;
prv::Provider *m_provider = nullptr;
LogConsole m_console;
std::endian m_defaultEndian = std::endian::native;
u64 m_evalDepth;
u64 m_arrayLimit;
u64 m_patternLimit;
u64 m_loopLimit;
u64 m_currPatternCount;
std::atomic<bool> m_aborted;
std::vector<Scope> m_scopes;
std::map<std::string, ContentRegistry::PatternLanguage::Function> m_customFunctions;
std::vector<ASTNode *> m_customFunctionDefinitions;
std::vector<Token::Literal> m_stack;
std::optional<Token::Literal> m_mainResult;
std::map<std::string, Token::Literal> m_envVariables;
std::map<std::string, Token::Literal> m_inVariables;
std::map<std::string, size_t> m_outVariables;
std::atomic<bool> m_dangerousFunctionCalled = false;
std::atomic<DangerousFunctionPermission> m_allowDangerousFunctions = DangerousFunctionPermission::Ask;
ControlFlowStatement m_currControlFlowStatement;
friend class PatternCreationLimiter;
};
}

View File

@@ -1,28 +0,0 @@
#pragma once
#include <hex.hpp>
#include <hex/pattern_language/token.hpp>
#include <optional>
#include <string>
#include <vector>
namespace hex::pl {
class Lexer {
public:
Lexer() = default;
std::optional<std::vector<Token>> lex(const std::string &code);
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
private:
std::optional<PatternLanguageError> m_error;
[[noreturn]] static void throwLexerError(const std::string &error, u32 lineNumber) {
throw PatternLanguageError(lineNumber, "Lexer: " + error);
}
};
}

View File

@@ -1,44 +0,0 @@
#pragma once
#include <hex.hpp>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <hex/pattern_language/error.hpp>
namespace hex::pl {
class ASTNode;
class LogConsole {
public:
enum Level
{
Debug,
Info,
Warning,
Error
};
[[nodiscard]] const auto &getLog() const { return this->m_consoleLog; }
void log(Level level, const std::string &message);
[[noreturn]] static void abortEvaluation(const std::string &message, const ASTNode *node = nullptr);
void clear();
void setHardError(const PatternLanguageError &error) { this->m_lastHardError = error; }
[[nodiscard]] const std::optional<PatternLanguageError> &getLastHardError() { return this->m_lastHardError; };
private:
std::vector<std::pair<Level, std::string>> m_consoleLog;
std::optional<PatternLanguageError> m_lastHardError;
};
}

View File

@@ -1,292 +0,0 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/pattern_language/error.hpp>
#include <hex/pattern_language/token.hpp>
#include <hex/pattern_language/ast_node.hpp>
#include <unordered_map>
#include <stdexcept>
#include <utility>
#include <vector>
namespace hex::pl {
class Parser {
public:
using TokenIter = std::vector<Token>::const_iterator;
Parser() = default;
~Parser() = default;
std::optional<std::vector<ASTNode *>> parse(const std::vector<Token> &tokens);
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
private:
std::optional<PatternLanguageError> m_error;
TokenIter m_curr;
TokenIter m_originalPosition, m_partOriginalPosition;
std::unordered_map<std::string, ASTNode *> m_types;
std::vector<TokenIter> m_matchedOptionals;
std::vector<std::vector<std::string>> m_currNamespace;
u32 getLineNumber(i32 index) const {
return this->m_curr[index].lineNumber;
}
auto *create(auto *node) {
node->setLineNumber(this->getLineNumber(-1));
return node;
}
template<typename T>
const T &getValue(i32 index) const {
auto value = std::get_if<T>(&this->m_curr[index].value);
if (value == nullptr)
throwParserError("failed to decode token. Invalid type.", getLineNumber(index));
return *value;
}
Token::Type getType(i32 index) const {
return this->m_curr[index].type;
}
std::string getNamespacePrefixedName(const std::string &name) {
std::string result;
for (const auto &part : this->m_currNamespace.back()) {
result += part + "::";
}
result += name;
return result;
}
ASTNode *parseFunctionCall();
ASTNode *parseStringLiteral();
std::string parseNamespaceResolution();
ASTNode *parseScopeResolution();
ASTNode *parseRValue();
ASTNode *parseRValue(ASTNodeRValue::Path &path);
ASTNode *parseFactor();
ASTNode *parseCastExpression();
ASTNode *parseUnaryExpression();
ASTNode *parseMultiplicativeExpression();
ASTNode *parseAdditiveExpression();
ASTNode *parseShiftExpression();
ASTNode *parseBinaryAndExpression();
ASTNode *parseBinaryXorExpression();
ASTNode *parseBinaryOrExpression();
ASTNode *parseBooleanAnd();
ASTNode *parseBooleanXor();
ASTNode *parseBooleanOr();
ASTNode *parseRelationExpression();
ASTNode *parseEqualityExpression();
ASTNode *parseTernaryConditional();
ASTNode *parseMathematicalExpression();
ASTNode *parseFunctionDefinition();
ASTNode *parseFunctionVariableDecl();
ASTNode *parseFunctionStatement();
ASTNode *parseFunctionVariableAssignment(const std::string &lvalue);
ASTNode *parseFunctionVariableCompoundAssignment(const std::string &lvalue);
ASTNode *parseFunctionControlFlowStatement();
std::vector<ASTNode *> parseStatementBody();
ASTNode *parseFunctionConditional();
ASTNode *parseFunctionWhileLoop();
ASTNode *parseFunctionForLoop();
void parseAttribute(Attributable *currNode);
ASTNode *parseConditional();
ASTNode *parseWhileStatement();
ASTNodeTypeDecl *parseType(bool allowFunctionTypes = false);
ASTNode *parseUsingDeclaration();
ASTNode *parsePadding();
ASTNode *parseMemberVariable(ASTNodeTypeDecl *type);
ASTNode *parseMemberArrayVariable(ASTNodeTypeDecl *type);
ASTNode *parseMemberPointerVariable(ASTNodeTypeDecl *type);
ASTNode *parseMember();
ASTNode *parseStruct();
ASTNode *parseUnion();
ASTNode *parseEnum();
ASTNode *parseBitfield();
ASTNode *parseVariablePlacement(ASTNodeTypeDecl *type);
ASTNode *parseArrayVariablePlacement(ASTNodeTypeDecl *type);
ASTNode *parsePointerVariablePlacement(ASTNodeTypeDecl *type);
ASTNode *parsePlacement();
std::vector<ASTNode *> parseNamespace();
std::vector<ASTNode *> parseStatements();
ASTNodeTypeDecl *addType(const std::string &name, ASTNode *node, std::optional<std::endian> endian = std::nullopt);
std::vector<ASTNode *> parseTillToken(Token::Type endTokenType, const auto value) {
std::vector<ASTNode *> program;
auto guard = SCOPE_GUARD {
for (auto &node : program)
delete node;
};
while (this->m_curr->type != endTokenType || (*this->m_curr) != value) {
for (auto statement : parseStatements())
program.push_back(statement);
}
this->m_curr++;
guard.release();
return program;
}
[[noreturn]] void throwParserError(const std::string &error, i32 token = -1) const {
throw PatternLanguageError(this->m_curr[token].lineNumber, "Parser: " + error);
}
/* Token consuming */
enum class Setting
{
};
constexpr static auto Normal = static_cast<Setting>(0);
constexpr static auto Not = static_cast<Setting>(1);
bool begin() {
this->m_originalPosition = this->m_curr;
this->m_matchedOptionals.clear();
return true;
}
bool partBegin() {
this->m_partOriginalPosition = this->m_curr;
this->m_matchedOptionals.clear();
return true;
}
void reset() {
this->m_curr = this->m_originalPosition;
}
void partReset() {
this->m_curr = this->m_partOriginalPosition;
}
bool resetIfFailed(bool value) {
if (!value) reset();
return value;
}
template<Setting S = Normal>
bool sequenceImpl() {
if constexpr (S == Normal)
return true;
else if constexpr (S == Not)
return false;
else
__builtin_unreachable();
}
template<Setting S = Normal>
bool sequenceImpl(Token::Type type, auto value, auto... args) {
if constexpr (S == Normal) {
if (!peek(type, value)) {
partReset();
return false;
}
this->m_curr++;
if (!sequenceImpl<Normal>(args...)) {
partReset();
return false;
}
return true;
} else if constexpr (S == Not) {
if (!peek(type, value))
return true;
this->m_curr++;
if (!sequenceImpl<Normal>(args...))
return true;
partReset();
return false;
} else
__builtin_unreachable();
}
template<Setting S = Normal>
bool sequence(Token::Type type, auto value, auto... args) {
return partBegin() && sequenceImpl<S>(type, value, args...);
}
template<Setting S = Normal>
bool oneOfImpl() {
if constexpr (S == Normal)
return false;
else if constexpr (S == Not)
return true;
else
__builtin_unreachable();
}
template<Setting S = Normal>
bool oneOfImpl(Token::Type type, auto value, auto... args) {
if constexpr (S == Normal)
return sequenceImpl<Normal>(type, value) || oneOfImpl(args...);
else if constexpr (S == Not)
return sequenceImpl<Not>(type, value) && oneOfImpl(args...);
else
__builtin_unreachable();
}
template<Setting S = Normal>
bool oneOf(Token::Type type, auto value, auto... args) {
return partBegin() && oneOfImpl<S>(type, value, args...);
}
bool variantImpl(Token::Type type1, auto value1, Token::Type type2, auto value2) {
if (!peek(type1, value1)) {
if (!peek(type2, value2)) {
partReset();
return false;
}
}
this->m_curr++;
return true;
}
bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) {
return partBegin() && variantImpl(type1, value1, type2, value2);
}
bool optionalImpl(Token::Type type, auto value) {
if (peek(type, value)) {
this->m_matchedOptionals.push_back(this->m_curr);
this->m_curr++;
}
return true;
}
bool optional(Token::Type type, auto value) {
return partBegin() && optionalImpl(type, value);
}
bool peek(Token::Type type, auto value, i32 index = 0) {
return this->m_curr[index].type == type && this->m_curr[index] == value;
}
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,79 +0,0 @@
#pragma once
#include <hex.hpp>
#include <bit>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include <hex/pattern_language/log_console.hpp>
#include <hex/pattern_language/token.hpp>
namespace hex::prv {
class Provider;
}
namespace hex::pl {
class Preprocessor;
class Lexer;
class Parser;
class Validator;
class Evaluator;
class PatternData;
class ASTNode;
class PatternLanguage {
public:
PatternLanguage();
~PatternLanguage();
[[nodiscard]] std::optional<std::vector<ASTNode *>> parseString(const std::string &code);
[[nodiscard]] bool executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = {}, const std::map<std::string, Token::Literal> &inVariables = {}, bool checkResult = true);
[[nodiscard]] bool executeFile(prv::Provider *provider, const fs::path &path, const std::map<std::string, Token::Literal> &envVars = {}, const std::map<std::string, Token::Literal> &inVariables = {});
[[nodiscard]] std::pair<bool, std::optional<Token::Literal>> executeFunction(prv::Provider *provider, const std::string &code);
[[nodiscard]] const std::vector<ASTNode *> &getCurrentAST() const;
void abort();
[[nodiscard]] const std::vector<std::pair<LogConsole::Level, std::string>> &getConsoleLog();
[[nodiscard]] const std::optional<PatternLanguageError> &getError();
[[nodiscard]] std::map<std::string, Token::Literal> getOutVariables() const;
[[nodiscard]] u32 getCreatedPatternCount();
[[nodiscard]] u32 getMaximumPatternCount();
[[nodiscard]] bool hasDangerousFunctionBeenCalled() const;
void allowDangerousFunctions(bool allow);
[[nodiscard]] const std::vector<PatternData *> &getPatterns() {
const static std::vector<PatternData *> empty;
if (isRunning()) return empty;
else return this->m_patterns;
}
void reset();
[[nodiscard]] bool isRunning() const { return this->m_running; }
private:
Preprocessor *m_preprocessor;
Lexer *m_lexer;
Parser *m_parser;
Validator *m_validator;
Evaluator *m_evaluator;
std::vector<ASTNode *> m_currAST;
std::optional<PatternLanguageError> m_currError;
std::vector<PatternData *> m_patterns;
bool m_running = false;
};
}

View File

@@ -1,51 +0,0 @@
#pragma once
#include <hex.hpp>
#include <functional>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include <hex/helpers/paths.hpp>
#include <hex/pattern_language/error.hpp>
namespace hex::pl {
class Preprocessor {
public:
Preprocessor() = default;
std::optional<std::string> preprocess(const std::string &code, bool initialRun = true);
void addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string &)> &function);
void removePragmaHandler(const std::string &pragmaType);
void addDefaultPragmaHandlers();
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
bool shouldOnlyIncludeOnce() {
return this->m_onlyIncludeOnce;
}
private:
[[noreturn]] static void throwPreprocessorError(const std::string &error, u32 lineNumber) {
throw PatternLanguageError(lineNumber, "Preprocessor: " + error);
}
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
std::set<std::tuple<std::string, std::string, u32>> m_defines;
std::set<std::tuple<std::string, std::string, u32>> m_pragmas;
std::set<fs::path> m_onceIncludedFiles;
std::optional<PatternLanguageError> m_error;
bool m_onlyIncludeOnce = false;
};
}

View File

@@ -1,358 +0,0 @@
#pragma once
#include <hex.hpp>
#include <utility>
#include <string>
#include <variant>
#include <hex/helpers/utils.hpp>
#include <hex/pattern_language/log_console.hpp>
namespace hex::pl {
class PatternData;
class Token {
public:
enum class Type : u64 {
Keyword,
ValueType,
Operator,
Integer,
String,
Identifier,
Separator
};
enum class Keyword {
Struct,
Union,
Using,
Enum,
Bitfield,
LittleEndian,
BigEndian,
If,
Else,
Parent,
This,
While,
For,
Function,
Return,
Namespace,
In,
Out,
Break,
Continue
};
enum class Operator {
AtDeclaration,
Assignment,
Inherit,
Plus,
Minus,
Star,
Slash,
Percent,
ShiftLeft,
ShiftRight,
BitOr,
BitAnd,
BitXor,
BitNot,
BoolEquals,
BoolNotEquals,
BoolGreaterThan,
BoolLessThan,
BoolGreaterThanOrEquals,
BoolLessThanOrEquals,
BoolAnd,
BoolOr,
BoolXor,
BoolNot,
TernaryConditional,
Dollar,
AddressOf,
SizeOf,
ScopeResolution
};
enum class ValueType {
Unsigned8Bit = 0x10,
Signed8Bit = 0x11,
Unsigned16Bit = 0x20,
Signed16Bit = 0x21,
Unsigned32Bit = 0x40,
Signed32Bit = 0x41,
Unsigned64Bit = 0x80,
Signed64Bit = 0x81,
Unsigned128Bit = 0x100,
Signed128Bit = 0x101,
Character = 0x13,
Character16 = 0x23,
Boolean = 0x14,
Float = 0x42,
Double = 0x82,
String = 0x15,
Auto = 0x16,
CustomType = 0x00,
Padding = 0x1F,
Unsigned = 0xFF00,
Signed = 0xFF01,
FloatingPoint = 0xFF02,
Integer = 0xFF03,
Any = 0xFFFF
};
enum class Separator {
RoundBracketOpen,
RoundBracketClose,
CurlyBracketOpen,
CurlyBracketClose,
SquareBracketOpen,
SquareBracketClose,
Comma,
Dot,
EndOfExpression,
EndOfProgram
};
struct Identifier {
explicit Identifier(std::string identifier) : m_identifier(std::move(identifier)) { }
[[nodiscard]] const std::string &get() const { return this->m_identifier; }
auto operator<=>(const Identifier &) const = default;
bool operator==(const Identifier &) const = default;
private:
std::string m_identifier;
};
using Literal = std::variant<char, bool, u128, i128, double, std::string, PatternData *>;
using ValueTypes = std::variant<Keyword, Identifier, Operator, Literal, ValueType, Separator>;
Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) {
}
[[nodiscard]] constexpr static inline bool isUnsigned(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x00;
}
[[nodiscard]] constexpr static inline bool isSigned(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x01;
}
[[nodiscard]] constexpr static inline bool isFloatingPoint(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x02;
}
[[nodiscard]] constexpr static inline u32 getTypeSize(const ValueType type) {
return static_cast<u32>(type) >> 4;
}
static u128 literalToUnsigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](const std::string &) -> u128 { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> u128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&result) -> u128 { return result; } },
literal);
}
static i128 literalToSigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](const std::string &) -> i128 { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> i128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&result) -> i128 { return result; } },
literal);
}
static double literalToFloatingPoint(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](const std::string &) -> double { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> double { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&result) -> double { return result; } },
literal);
}
static bool literalToBoolean(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](const std::string &) -> bool { LogConsole::abortEvaluation("expected integral type, got string"); },
[](PatternData *) -> bool { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&result) -> bool { return result != 0; } },
literal);
}
static std::string literalToString(const pl::Token::Literal &literal, bool cast) {
if (!cast && std::get_if<std::string>(&literal) == nullptr)
LogConsole::abortEvaluation("expected string type, got integral");
return std::visit(overloaded {
[](std::string result) -> std::string { return result; },
[](u128 result) -> std::string { return hex::to_string(result); },
[](i128 result) -> std::string { return hex::to_string(result); },
[](bool result) -> std::string { return result ? "true" : "false"; },
[](char result) -> std::string { return { 1, result }; },
[](PatternData *) -> std::string { LogConsole::abortEvaluation("expected integral type, got custom type"); },
[](auto &&result) -> std::string { return std::to_string(result); } },
literal);
}
[[nodiscard]] constexpr static auto getTypeName(const pl::Token::ValueType type) {
switch (type) {
case ValueType::Signed8Bit:
return "s8";
case ValueType::Signed16Bit:
return "s16";
case ValueType::Signed32Bit:
return "s32";
case ValueType::Signed64Bit:
return "s64";
case ValueType::Signed128Bit:
return "s128";
case ValueType::Unsigned8Bit:
return "u8";
case ValueType::Unsigned16Bit:
return "u16";
case ValueType::Unsigned32Bit:
return "u32";
case ValueType::Unsigned64Bit:
return "u64";
case ValueType::Unsigned128Bit:
return "u128";
case ValueType::Float:
return "float";
case ValueType::Double:
return "double";
case ValueType::Character:
return "char";
case ValueType::Character16:
return "char16";
case ValueType::Padding:
return "padding";
case ValueType::String:
return "str";
default:
return "< ??? >";
}
}
bool operator==(const ValueTypes &other) const {
if (this->type == Type::Integer || this->type == Type::Identifier || this->type == Type::String)
return true;
else if (this->type == Type::ValueType) {
auto otherValueType = std::get_if<ValueType>(&other);
auto valueType = std::get_if<ValueType>(&this->value);
if (otherValueType == nullptr) return false;
if (valueType == nullptr) return false;
if (*otherValueType == *valueType)
return true;
else if (*otherValueType == ValueType::Any)
return *valueType != ValueType::CustomType && *valueType != ValueType::Padding;
else if (*otherValueType == ValueType::Unsigned)
return isUnsigned(*valueType);
else if (*otherValueType == ValueType::Signed)
return isSigned(*valueType);
else if (*otherValueType == ValueType::FloatingPoint)
return isFloatingPoint(*valueType);
else if (*otherValueType == ValueType::Integer)
return isUnsigned(*valueType) || isSigned(*valueType);
} else
return other == this->value;
return false;
}
bool operator!=(const ValueTypes &other) const {
return !operator==(other);
}
Type type;
ValueTypes value;
u32 lineNumber;
};
}
#define COMPONENT(type, value) hex::pl::Token::Type::type, hex::pl::Token::type::value
#define KEYWORD_STRUCT COMPONENT(Keyword, Struct)
#define KEYWORD_UNION COMPONENT(Keyword, Union)
#define KEYWORD_USING COMPONENT(Keyword, Using)
#define KEYWORD_ENUM COMPONENT(Keyword, Enum)
#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield)
#define KEYWORD_LE COMPONENT(Keyword, LittleEndian)
#define KEYWORD_BE COMPONENT(Keyword, BigEndian)
#define KEYWORD_IF COMPONENT(Keyword, If)
#define KEYWORD_ELSE COMPONENT(Keyword, Else)
#define KEYWORD_PARENT COMPONENT(Keyword, Parent)
#define KEYWORD_THIS COMPONENT(Keyword, This)
#define KEYWORD_WHILE COMPONENT(Keyword, While)
#define KEYWORD_FOR COMPONENT(Keyword, For)
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
#define KEYWORD_IN COMPONENT(Keyword, In)
#define KEYWORD_OUT COMPONENT(Keyword, Out)
#define KEYWORD_BREAK COMPONENT(Keyword, Break)
#define KEYWORD_CONTINUE COMPONENT(Keyword, Continue)
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""
#define STRING hex::pl::Token::Type::String, hex::pl::Token::Literal("")
#define OPERATOR_ANY COMPONENT(Operator, Any)
#define OPERATOR_AT COMPONENT(Operator, AtDeclaration)
#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment)
#define OPERATOR_INHERIT COMPONENT(Operator, Inherit)
#define OPERATOR_PLUS COMPONENT(Operator, Plus)
#define OPERATOR_MINUS COMPONENT(Operator, Minus)
#define OPERATOR_STAR COMPONENT(Operator, Star)
#define OPERATOR_SLASH COMPONENT(Operator, Slash)
#define OPERATOR_PERCENT COMPONENT(Operator, Percent)
#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft)
#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight)
#define OPERATOR_BITOR COMPONENT(Operator, BitOr)
#define OPERATOR_BITAND COMPONENT(Operator, BitAnd)
#define OPERATOR_BITXOR COMPONENT(Operator, BitXor)
#define OPERATOR_BITNOT COMPONENT(Operator, BitNot)
#define OPERATOR_BOOLEQUALS COMPONENT(Operator, BoolEquals)
#define OPERATOR_BOOLNOTEQUALS COMPONENT(Operator, BoolNotEquals)
#define OPERATOR_BOOLGREATERTHAN COMPONENT(Operator, BoolGreaterThan)
#define OPERATOR_BOOLLESSTHAN COMPONENT(Operator, BoolLessThan)
#define OPERATOR_BOOLGREATERTHANOREQUALS COMPONENT(Operator, BoolGreaterThanOrEquals)
#define OPERATOR_BOOLLESSTHANOREQUALS COMPONENT(Operator, BoolLessThanOrEquals)
#define OPERATOR_BOOLAND COMPONENT(Operator, BoolAnd)
#define OPERATOR_BOOLOR COMPONENT(Operator, BoolOr)
#define OPERATOR_BOOLXOR COMPONENT(Operator, BoolXor)
#define OPERATOR_BOOLNOT COMPONENT(Operator, BoolNot)
#define OPERATOR_TERNARYCONDITIONAL COMPONENT(Operator, TernaryConditional)
#define OPERATOR_DOLLAR COMPONENT(Operator, Dollar)
#define OPERATOR_ADDRESSOF COMPONENT(Operator, AddressOf)
#define OPERATOR_SIZEOF COMPONENT(Operator, SizeOf)
#define OPERATOR_SCOPERESOLUTION COMPONENT(Operator, ScopeResolution)
#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType)
#define VALUETYPE_PADDING COMPONENT(ValueType, Padding)
#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned)
#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed)
#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint)
#define VALUETYPE_AUTO COMPONENT(ValueType, Auto)
#define VALUETYPE_ANY COMPONENT(ValueType, Any)
#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen)
#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose)
#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen)
#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose)
#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen)
#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose)
#define SEPARATOR_COMMA COMPONENT(Separator, Comma)
#define SEPARATOR_DOT COMPONENT(Separator, Dot)
#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression)
#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram)

View File

@@ -1,31 +0,0 @@
#pragma once
#include <hex.hpp>
#include <optional>
#include <string>
#include <vector>
#include <hex/pattern_language/error.hpp>
namespace hex::pl {
class ASTNode;
class Validator {
public:
Validator() = default;
bool validate(const std::vector<ASTNode *> &ast);
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
private:
std::optional<PatternLanguageError> m_error;
[[noreturn]] static void throwValidatorError(const std::string &error, u32 lineNumber) {
throw PatternLanguageError(lineNumber, "Validator: " + error);
}
};
}

View File

@@ -0,0 +1,223 @@
#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; };
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; };
private:
BufferedReader *m_reader;
u64 m_address;
};
Iterator begin() {
return { this, this->m_baseAddress };
}
Iterator end() {
return { this, this->m_baseAddress + 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

@@ -8,7 +8,7 @@ namespace hex::prv {
class Overlay {
public:
Overlay() { }
Overlay() = default;
void setAddress(u64 address) { this->m_address = address; }
[[nodiscard]] u64 getAddress() const { return this->m_address; }

View File

@@ -9,7 +9,11 @@
#include <vector>
#include <hex/providers/overlay.hpp>
#include <hex/pattern_language/pattern_language.hpp>
#include <hex/helpers/fs.hpp>
namespace pl {
class PatternLanguage;
}
namespace hex::prv {
@@ -33,7 +37,7 @@ namespace hex::prv {
virtual void insert(u64 offset, size_t size);
virtual void save();
virtual void saveAs(const fs::path &path);
virtual void saveAs(const std::fs::path &path);
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
@@ -79,7 +83,7 @@ namespace hex::prv {
virtual void drawLoadInterface();
virtual void drawInterface();
pl::PatternLanguage &getPatternLanguageRuntime() { return this->m_patternLanguageRuntime; }
pl::PatternLanguage &getPatternLanguageRuntime() { return *this->m_patternLanguageRuntime; }
std::string &getPatternLanguageSourceCode() { return this->m_patternLanguageSourceCode; }
protected:
@@ -90,7 +94,7 @@ namespace hex::prv {
std::list<std::map<u64, u8>> m_patches;
std::list<Overlay *> m_overlays;
pl::PatternLanguage m_patternLanguageRuntime;
std::unique_ptr<pl::PatternLanguage> m_patternLanguageRuntime;
std::string m_patternLanguageSourceCode;
};

View File

@@ -3,6 +3,7 @@
#include <hex.hpp>
#include <functional>
#include <string>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui.h>
@@ -62,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);
@@ -74,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() {
@@ -117,7 +118,7 @@ namespace ImGui {
}
void TextFormattedCentered(const std::string &fmt, auto &&...args) {
auto text = hex::format(fmt);
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
auto availableSpace = ImGui::GetContentRegionAvail();
auto textSize = ImGui::CalcTextSize(text.c_str(), nullptr, false, availableSpace.x * 0.75F);
@@ -127,4 +128,13 @@ namespace ImGui {
ImGui::TextFormattedWrapped("{}", text);
ImGui::PopTextWrapPos();
}
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), 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

@@ -13,6 +13,7 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/api/localization.hpp>
@@ -38,8 +39,9 @@ namespace hex {
static void showMessagePopup(const std::string &message);
static void showErrorPopup(const std::string &errorMessage);
static void showFatalPopup(const std::string &errorMessage);
static void showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback);
static void showFileChooserPopup(const std::vector<fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(fs::path)> &callback);
static void showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback);
[[nodiscard]] virtual bool hasViewMenuItemEntry() const;
[[nodiscard]] virtual ImVec2 getMinSize() const;
@@ -71,9 +73,11 @@ namespace hex {
static std::string s_popupMessage;
static std::function<void()> s_yesCallback, s_noCallback;
static u32 s_selectableFileIndex;
static std::vector<fs::path> s_selectableFiles;
static std::function<void(fs::path)> s_selectableFileOpenCallback;
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;

View File

@@ -1,6 +1,6 @@
#include <hex/api/content_registry.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/ui/view.hpp>
@@ -16,7 +16,7 @@ namespace hex {
void load() {
bool loaded = false;
for (const auto &dir : hex::getPath(ImHexPath::Config)) {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
std::ifstream settingsFile(dir / "settings.json");
if (settingsFile.good()) {
@@ -31,7 +31,7 @@ namespace hex {
}
void store() {
for (const auto &dir : hex::getPath(ImHexPath::Config)) {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
std::ofstream settingsFile(dir / "settings.json", std::ios::trunc);
if (settingsFile.good()) {
@@ -41,10 +41,23 @@ namespace hex {
}
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback) {
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
auto &entries = getEntries();
const size_t curSlot = entries.size();
auto found = entries.find(Category { unlocalizedCategory });
if (found == entries.end()) {
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
return iter;
}
return found;
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart) {
log::info("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getEntries()[unlocalizedCategory.c_str()].emplace_back(Entry { unlocalizedName.c_str(), callback });
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
@@ -54,10 +67,10 @@ namespace hex {
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback) {
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart) {
log::info("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getEntries()[unlocalizedCategory].emplace_back(Entry { unlocalizedName, callback });
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
@@ -67,6 +80,23 @@ namespace hex {
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart) {
log::info("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_array())
json[unlocalizedCategory][unlocalizedName] = defaultValue;
}
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
}
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
auto &json = getSettingsData();
@@ -141,12 +171,18 @@ namespace hex {
}
std::map<std::string, std::vector<Entry>> &getEntries() {
static std::map<std::string, std::vector<Entry>> entries;
std::map<Category, std::vector<Entry>> &getEntries() {
static std::map<Category, std::vector<Entry>> entries;
return entries;
}
std::map<std::string, std::string> &getCategoryDescriptions() {
static std::map<std::string, std::string> descriptions;
return descriptions;
}
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
auto &settings = getSettingsData();
@@ -184,7 +220,7 @@ namespace hex {
namespace ContentRegistry::PatternLanguage {
static std::string getFunctionName(const Namespace &ns, const std::string &name) {
static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) {
std::string functionName;
for (auto &scope : ns)
functionName += scope + "::";
@@ -194,63 +230,67 @@ namespace hex {
return functionName;
}
void addFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func) {
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider) {
auto runtime = std::make_unique<pl::PatternLanguage>();
runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
provider->read(offset, buffer, size);
}, 0, 0);
runtime->setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude));
for (const auto &func : getFunctions()) {
if (func.dangerous)
runtime->addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
else
runtime->addFunction(func.ns, func.name, func.parameterCount, func.callback);
}
for (const auto &[name, callback] : getPragmas()) {
runtime->addPragma(name, callback);
}
return runtime;
}
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
log::info("Registered new pattern language pragma: {}", name);
getPragmas()[name] = handler;
}
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::info("Registered new pattern language function: {}", getFunctionName(ns, name));
getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, func, false };
getFunctions().push_back({
ns, name,
parameterCount, func,
false
});
}
void addDangerousFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func) {
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::info("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, func, true };
getFunctions().push_back({
ns, name,
parameterCount, func,
true
});
}
std::map<std::string, Function> &getFunctions() {
static std::map<std::string, Function> functions;
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
static std::map<std::string, pl::api::PragmaHandler> pragmas;
return pragmas;
}
std::vector<impl::FunctionDefinition> &getFunctions() {
static std::vector<impl::FunctionDefinition> functions;
return functions;
}
static std::vector<impl::ColorPalette> s_colorPalettes;
static u32 s_colorIndex;
static u32 s_selectedColorPalette;
std::vector<impl::ColorPalette> &getPalettes() {
return s_colorPalettes;
}
void addColorPalette(const std::string &unlocalizedName, const std::vector<u32> &colors) {
s_colorPalettes.push_back({ unlocalizedName,
colors });
}
void setSelectedPalette(u32 index) {
if (index < s_colorPalettes.size())
s_selectedColorPalette = index;
resetPalette();
}
u32 getNextColor() {
if (s_colorPalettes.empty())
return 0x00;
auto &currColors = s_colorPalettes[s_selectedColorPalette].colors;
u32 color = currColors[s_colorIndex];
s_colorIndex++;
s_colorIndex %= currColors.size();
return color;
}
void resetPalette() {
s_colorIndex = 0;
}
}
@@ -297,10 +337,10 @@ namespace hex {
namespace ContentRegistry::DataInspector {
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction function) {
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::info("Registered new data inspector format: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, requiredSize, std::move(function) });
getEntries().push_back({ unlocalizedName, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
std::vector<impl::Entry> &getEntries() {
@@ -314,7 +354,7 @@ namespace hex {
namespace ContentRegistry::DataProcessorNode {
void impl::add(const impl::Entry &entry) {
log::info("Registered new data processor node type: [{}]: ", entry.category, entry.name);
log::info("Registered new data processor node type: [{}]: {}", entry.category, entry.name);
getEntries().push_back(entry);
}
@@ -496,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

@@ -2,9 +2,12 @@
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
#include <utility>
#include <unistd.h>
#include <imgui.h>
namespace hex {
namespace ImHexApi::Common {
@@ -26,17 +29,55 @@ namespace hex {
namespace ImHexApi::HexEditor {
static std::map<u32, ImHexApi::HexEditor::Highlighting> s_highlights;
Highlighting::Highlighting(Region region, color_t color, const std::string &tooltip)
: m_region(region), m_color(color), m_tooltip(tooltip) {
Highlighting::Highlighting(Region region, color_t color)
: m_region(region), m_color(color) {
}
u32 addHighlight(const Region &region, color_t color, std::string tooltip) {
auto id = s_highlights.size();
Tooltip::Tooltip(Region region, std::string value, color_t color) : m_region(region), m_value(std::move(value)), m_color(color) {
s_highlights.insert({
id, Highlighting {region, color, tooltip}
}
namespace impl {
static std::map<u32, Highlighting> s_backgroundHighlights;
std::map<u32, Highlighting> &getBackgroundHighlights() {
return s_backgroundHighlights;
}
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 addBackgroundHighlight(const Region &region, color_t color) {
static u32 id = 0;
id++;
impl::getBackgroundHighlights().insert({
id, Highlighting {region, color}
});
EventManager::post<EventHighlightingChanged>();
@@ -44,23 +85,101 @@ namespace hex {
return id;
}
void removeHighlight(u32 id) {
s_highlights.erase(id);
void removeBackgroundHighlight(u32 id) {
impl::getBackgroundHighlights().erase(id);
EventManager::post<EventHighlightingChanged>();
}
std::map<u32, Highlighting> &getHighlights() {
return s_highlights;
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function) {
static u32 id = 0;
id++;
impl::getBackgroundHighlightingFunctions().insert({ id, function });
EventManager::post<EventHighlightingChanged>();
return id;
}
Region getSelection() {
static Region selectedRegion;
EventManager::subscribe<EventRegionSelected>([](const Region &region) {
selectedRegion = region;
void removeBackgroundHighlightingProvider(u32 id) {
impl::getBackgroundHighlightingFunctions().erase(id);
EventManager::post<EventHighlightingChanged>();
}
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) {
@@ -139,18 +258,20 @@ namespace hex {
namespace ImHexApi::Tasks {
Task createTask(const std::string &unlocalizedName, u64 maxValue) {
return Task(unlocalizedName, maxValue);
return { unlocalizedName, maxValue };
}
std::vector<std::function<void()>> s_deferredCalls;
void doLater(const std::function<void()> &function) {
static std::mutex tasksMutex;
std::scoped_lock lock(tasksMutex);
getDeferredCalls().push_back(function);
}
std::vector<std::function<void()>> &getDeferredCalls() {
return s_deferredCalls;
static std::vector<std::function<void()>> deferredCalls;
return deferredCalls;
}
}
@@ -176,7 +297,7 @@ namespace hex {
}
static float s_globalScale;
static float s_globalScale = 1.0;
void setGlobalScale(float scale) {
s_globalScale = scale;
}
@@ -189,6 +310,11 @@ namespace hex {
s_programArguments.envp = envp;
}
static bool s_borderlessWindowMode;
void setBorderlessWindowMode(bool enabled) {
s_borderlessWindowMode = enabled;
}
}
@@ -225,6 +351,10 @@ namespace hex {
return impl::s_mainDockSpaceId;
}
bool isBorderlessWindowModeEnabled() {
return impl::s_borderlessWindowMode;
}
std::map<std::string, std::string> &getInitArguments() {
static std::map<std::string, std::string> initArgs;

View File

@@ -8,7 +8,7 @@ namespace hex {
std::map<std::string, std::string> LangEntry::s_currStrings;
LanguageDefinition::LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries) {
for (auto pair : entries)
for (const auto &pair : entries)
this->m_entries.insert(pair);
}
@@ -17,7 +17,7 @@ namespace hex {
}
LangEntry::LangEntry(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
LangEntry::LangEntry(const std::string &unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
LangEntry::LangEntry(std::string unlocalizedString) : m_unlocalizedString(std::move(unlocalizedString)) { }
LangEntry::LangEntry(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
LangEntry::operator std::string() const {

View File

@@ -7,7 +7,7 @@
namespace hex {
Plugin::Plugin(const fs::path &path) : m_path(path) {
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
if (this->m_handle == nullptr) {
@@ -15,7 +15,7 @@ namespace hex {
return;
}
auto pluginName = fs::path(path).stem().string();
auto pluginName = std::fs::path(path).stem().string();
this->m_initializePluginFunction = getPluginFunction<InitializePluginFunc>("initializePlugin");
this->m_getPluginNameFunction = getPluginFunction<GetPluginNameFunc>("getPluginName");
@@ -110,7 +110,7 @@ namespace hex {
return false;
}
const fs::path &Plugin::getPath() const {
const std::fs::path &Plugin::getPath() const {
return this->m_path;
}
@@ -124,16 +124,16 @@ namespace hex {
}
fs::path PluginManager::s_pluginFolder;
std::fs::path PluginManager::s_pluginFolder;
std::vector<Plugin> PluginManager::s_plugins;
bool PluginManager::load(const fs::path &pluginFolder) {
bool PluginManager::load(const std::fs::path &pluginFolder) {
if (!fs::exists(pluginFolder))
return false;
PluginManager::s_pluginFolder = pluginFolder;
for (auto &pluginPath : fs::directory_iterator(pluginFolder)) {
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug")
PluginManager::s_plugins.emplace_back(pluginPath.path().string());
}

View File

@@ -34,7 +34,7 @@ namespace hex::dp {
return outputData.value();
}
u64 Node::getIntegerOnInput(u32 index) {
i64 Node::getIntegerOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index);
if (attribute == nullptr)
@@ -54,7 +54,7 @@ namespace hex::dp {
if (outputData->size() < sizeof(u64))
throw std::runtime_error("Not enough data provided for integer");
return *reinterpret_cast<u64 *>(outputData->data());
return *reinterpret_cast<i64 *>(outputData->data());
}
float Node::getFloatOnInput(u32 index) {
@@ -77,10 +77,12 @@ namespace hex::dp {
if (outputData->size() < sizeof(float))
throw std::runtime_error("Not enough data provided for float");
return *reinterpret_cast<float *>(outputData->data());
float result = 0;
std::memcpy(&result, outputData->data(), sizeof(float));
return result;
}
void Node::setBufferOnOutput(u32 index, std::vector<u8> data) {
void Node::setBufferOnOutput(u32 index, const std::vector<u8> &data) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");
@@ -92,7 +94,7 @@ namespace hex::dp {
attribute.getOutputData() = data;
}
void Node::setIntegerOnOutput(u32 index, u64 integer) {
void Node::setIntegerOnOutput(u32 index, i64 integer) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");

View File

@@ -20,6 +20,7 @@
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <bit>
#if MBEDTLS_VERSION_MAJOR <= 2
@@ -82,91 +83,90 @@ namespace hex::crypt {
}
}
template<size_t NumBits> requires (std::has_single_bit(NumBits))
class Crc {
// use reflected algorithm, so we reflect only if refin / refout is FALSE
// mask values, 0b1 << 64 is UB, so use 0b10 << 63
public:
using calc_type = uint64_t;
constexpr Crc(u64 polynomial, u64 init, u64 xorOut, bool reflectInput, bool reflectOutput)
: m_value(0x00), m_init(init & ((0b10ull << (NumBits - 1)) - 1)), m_xorOut(xorOut & ((0b10ull << (NumBits - 1)) - 1)),
m_reflectInput(reflectInput), m_reflectOutput(reflectOutput),
m_table([polynomial]() {
auto reflectedPoly = reflect(polynomial & ((0b10ull << (NumBits - 1)) - 1), NumBits);
std::array<uint64_t, 256> table = { 0 };
Crc(int bits, calc_type polynomial, calc_type init, calc_type xorout, bool refin, bool refout) : m_bits(bits),
m_init(init & ((0b10ull << (bits - 1)) - 1)),
m_xorout(xorout & ((0b10ull << (bits - 1)) - 1)),
m_refin(refin),
m_refout(refout),
table([polynomial, bits]() {
auto reflectedpoly = reflect(polynomial & ((0b10ull << (bits - 1)) - 1), bits);
std::array<uint64_t, 256> table = { 0 };
for (uint32_t i = 0; i < 256; i++) {
uint64_t c = i;
for (std::size_t j = 0; j < 8; j++) {
if (c & 0b1)
c = reflectedPoly ^ (c >> 1);
else
c >>= 1;
}
table[i] = c;
}
for (uint32_t i = 0; i < 256; i++) {
uint64_t c = i;
for (std::size_t j = 0; j < 8; j++) {
if (c & 0b1)
c = reflectedpoly ^ (c >> 1);
else
c >>= 1;
}
table[i] = c;
}
return table;
}()) {
return table;
}()) {
reset();
};
void reset() {
c = reflect(m_init, m_bits);
constexpr void reset() {
this->m_value = reflect(m_init, NumBits);
}
void processBytes(const unsigned char *data, std::size_t size) {
constexpr void processBytes(const unsigned char *data, std::size_t size) {
for (std::size_t i = 0; i < size; i++) {
unsigned char d;
if (m_refin)
d = data[i];
u8 byte;
if (this->m_reflectInput)
byte = data[i];
else
d = reflect(data[i]);
byte = reflect(data[i]);
c = table[(c ^ d) & 0xFFL] ^ (c >> 8);
this->m_value = this->m_table[(this->m_value ^ byte) & 0xFFL] ^ (this->m_value >> 8);
}
}
calc_type checksum() const {
if (m_refout)
return c ^ m_xorout;
[[nodiscard]]
constexpr u64 checksum() const {
if (this->m_reflectOutput)
return this->m_value ^ m_xorOut;
else
return reflect(c, m_bits) ^ m_xorout;
return reflect(this->m_value, NumBits) ^ m_xorOut;
}
private:
const int m_bits;
const calc_type m_init;
const calc_type m_xorout;
const bool m_refin;
const bool m_refout;
const std::array<uint64_t, 256> table;
u64 m_value;
calc_type c;
u64 m_init;
u64 m_xorOut;
bool m_reflectInput;
bool m_reflectOutput;
std::array<uint64_t, 256> m_table;
};
template<int bits>
template<size_t NumBits>
auto calcCrc(prv::Provider *data, u64 offset, std::size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
Crc crc(bits, polynomial, init, xorout, reflectIn, reflectOut);
using Crc = Crc<NumBits>;
Crc crc(polynomial, init, xorout, reflectIn, reflectOut);
processDataByChunks(data, offset, size, std::bind(&Crc::processBytes, &crc, _1, _2));
return crc.checksum();
}
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
return calcCrc<8>(data, offset, size, polynomial, init, xorout, reflectIn, reflectOut);
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
return calcCrc<8>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
}
u16 crc16(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
return calcCrc<16>(data, offset, size, polynomial, init, xorout, reflectIn, reflectOut);
u16 crc16(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
return calcCrc<16>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
}
u32 crc32(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
return calcCrc<32>(data, offset, size, polynomial, init, xorout, reflectIn, reflectOut);
u32 crc32(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
return calcCrc<32>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
}
@@ -414,7 +414,7 @@ namespace hex::crypt {
std::string output(input.size() * 2, '\0');
for (int i = 0; i < input.size(); i++) {
for (size_t i = 0; i < input.size(); i++) {
output[2 * i + 0] = "0123456789ABCDEF"[input[i] / 16];
output[2 * i + 1] = "0123456789ABCDEF"[input[i] % 16];
}
@@ -427,13 +427,15 @@ namespace hex::crypt {
if (input.empty())
return {};
if (key.size() > 256)
return {};
mbedtls_cipher_context_t ctx;
auto cipherInfo = mbedtls_cipher_info_from_type(type);
mbedtls_cipher_setup(&ctx, cipherInfo);
mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
mbedtls_cipher_setkey(&ctx, key.data(), static_cast<int>(key.size() * 8), operation);
std::array<u8, 16> nonceCounter = { 0 };
std::copy(nonce.begin(), nonce.end(), nonceCounter.begin());

View File

@@ -2,16 +2,13 @@
#include <hex/helpers/utils.hpp>
#include <fstream>
namespace hex {
EncodingFile::EncodingFile(Type type, const fs::path &path) {
std::ifstream encodingFile(path.c_str());
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
auto file = fs::File(path, fs::File::Mode::Read);
switch (type) {
case Type::Thingy:
parseThingyFile(encodingFile);
parseThingyFile(file);
break;
default:
return;
@@ -34,22 +31,21 @@ 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)
continue;
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 = " ";
}

View File

@@ -1,9 +1,9 @@
#include <hex/helpers/file.hpp>
#include <unistd.h>
namespace hex {
namespace hex::fs {
File::File(const fs::path &path, Mode mode) noexcept : m_path(path) {
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)
@@ -42,7 +42,7 @@ namespace hex {
void File::close() {
if (isValid()) {
fclose(this->m_file);
std::fclose(this->m_file);
this->m_file = nullptr;
}
}
@@ -57,6 +57,8 @@ namespace hex {
if (!isValid()) return {};
auto size = numBytes ?: getSize();
if (size == 0) return {};
std::vector<u8> bytes(size);
auto bytesRead = fread(bytes.data(), 1, bytes.size(), this->m_file);
@@ -72,25 +74,28 @@ namespace hex {
auto bytes = readBytes(numBytes);
if (bytes.empty())
return "";
return { reinterpret_cast<char *>(bytes.data()), bytes.size() };
}
void File::write(const u8 *buffer, size_t size) {
if (!isValid()) return;
fwrite(buffer, size, 1, this->m_file);
std::fwrite(buffer, size, 1, this->m_file);
}
void File::write(const std::vector<u8> &bytes) {
if (!isValid()) return;
fwrite(bytes.data(), 1, bytes.size(), this->m_file);
std::fwrite(bytes.data(), 1, bytes.size(), this->m_file);
}
void File::write(const std::string &string) {
if (!isValid()) return;
fwrite(string.data(), string.size(), 1, this->m_file);
std::fwrite(string.data(), string.size(), 1, this->m_file);
}
size_t File::getSize() const {
@@ -98,25 +103,35 @@ namespace hex {
auto startPos = ftello64(this->m_file);
fseeko64(this->m_file, 0, SEEK_END);
size_t size = ftello64(this->m_file);
auto size = ftello64(this->m_file);
fseeko64(this->m_file, startPos, SEEK_SET);
if (size < 0)
return 0;
return size;
}
void File::setSize(u64 size) {
if (!isValid()) return;
ftruncate64(fileno(this->m_file), size);
auto result = ftruncate64(fileno(this->m_file), size);
hex::unused(result);
}
void File::flush() {
fflush(this->m_file);
std::fflush(this->m_file);
}
void File::remove() {
bool File::remove() {
this->close();
std::remove(this->m_path.string().c_str());
return std::remove(this->m_path.string().c_str()) == 0;
}
void File::disableBuffering() {
if (!isValid()) return;
std::setvbuf(this->m_file, nullptr, _IONBF, 0);
}
}

View File

@@ -1,5 +1,9 @@
#include <hex/helpers/paths.hpp>
#include <hex/helpers/paths_mac.h>
#include <hex/helpers/fs.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fs_macos.h>
#include <hex/helpers/file.hpp>
#include <hex/helpers/intrinsics.hpp>
#include <xdg.hpp>
@@ -13,37 +17,93 @@
#include <algorithm>
#include <filesystem>
#include <string>
#include <vector>
namespace hex {
namespace hex::fs {
std::string getExecutablePath() {
std::optional<std::fs::path> getExecutablePath() {
#if defined(OS_WINDOWS)
std::string exePath(MAX_PATH, '\0');
GetModuleFileName(nullptr, exePath.data(), exePath.length());
if (GetModuleFileName(nullptr, exePath.data(), exePath.length()) == 0)
return std::nullopt;
return exePath;
#elif defined(OS_LINUX)
std::string exePath(PATH_MAX, '\0');
readlink("/proc/self/exe", exePath.data(), PATH_MAX);
if (readlink("/proc/self/exe", exePath.data(), PATH_MAX) < 0)
return std::nullopt;
return exePath;
#elif defined(OS_MACOS)
return getMacExecutableDirectoryPath();
#else
return "";
return std::nullopt;
#endif
}
std::vector<fs::path> getPath(ImHexPath path, bool listNonExisting) {
std::vector<fs::path> result;
bool isPathWritable(const std::fs::path &path) {
constexpr static auto TestFileName = "__imhex__tmp__";
{
File file(path / TestFileName, File::Mode::Read);
if (file.isValid()) {
if (!file.remove())
return false;
}
}
File file(path / TestFileName, File::Mode::Create);
bool result = file.isValid();
if (!file.remove())
return false;
return result;
}
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;
nfdresult_t result;
switch (mode) {
case DialogMode::Open:
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
break;
case DialogMode::Save:
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
break;
case DialogMode::Folder:
result = NFD::PickFolder(outPath, defaultPath.c_str());
break;
default:
hex::unreachable();
}
if (result == NFD_OKAY) {
callback(reinterpret_cast<const char8_t *>(outPath));
NFD::FreePath(outPath);
}
NFD::Quit();
return result == NFD_OKAY;
}
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> {});
[[maybe_unused]]
auto addUserDirs = [&userDirs](auto &paths) {
std::transform(userDirs.begin(), userDirs.end(), std::back_inserter(paths), [](auto &item) {
return std::move(item);
});
};
#if defined(OS_WINDOWS)
const auto exePath = getExecutablePath();
const auto parentDir = fs::path(exePath).parent_path();
fs::path appDataDir;
std::fs::path appDataDir;
{
LPWSTR wAppDataPath = nullptr;
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath)))
@@ -53,25 +113,32 @@ namespace hex {
CoTaskMemFree(wAppDataPath);
}
std::vector<fs::path> paths = { parentDir, appDataDir / "imhex" };
std::vector<std::fs::path> paths = { appDataDir / "imhex" };
if (exePath)
paths.push_back(exePath->parent_path());
switch (path) {
case ImHexPath::Patterns:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "patterns").string();
});
break;
case ImHexPath::PatternsInclude:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "includes").string();
});
break;
case ImHexPath::Magic:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "magic").string();
});
break;
case ImHexPath::Python:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "python").string();
});
@@ -82,6 +149,7 @@ namespace hex {
});
break;
case ImHexPath::Yara:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "yara").string();
});
@@ -94,11 +162,13 @@ namespace hex {
});
break;
case ImHexPath::Constants:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "constants").string();
});
break;
case ImHexPath::Encodings:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "encodings").string();
});
@@ -109,14 +179,16 @@ namespace hex {
});
break;
default:
__builtin_unreachable();
hex::unreachable();
}
#elif defined(OS_MACOS)
// Get path to special directories
const auto exePath = getExecutablePath();
const fs::path applicationSupportDir(getMacApplicationSupportDirectoryPath());
const std::fs::path applicationSupportDir(getMacApplicationSupportDirectoryPath());
std::vector<fs::path> paths = { exePath, applicationSupportDir };
std::vector<std::fs::path> paths = { applicationSupportDir };
if (exePath)
paths.push_back(exePath->parent_path());
switch (path) {
case ImHexPath::Patterns:
@@ -155,40 +227,43 @@ namespace hex {
result.push_back((applicationSupportDir / "logs").string());
break;
default:
__builtin_unreachable();
hex::unreachable();
}
#else
std::vector<fs::path> configDirs = xdg::ConfigDirs();
std::vector<fs::path> dataDirs = xdg::DataDirs();
std::vector<std::fs::path> configDirs = xdg::ConfigDirs();
std::vector<std::fs::path> dataDirs = xdg::DataDirs();
configDirs.insert(configDirs.begin(), xdg::ConfigHomeDir());
dataDirs.insert(dataDirs.begin(), xdg::DataHomeDir());
configDirs.push_back(xdg::ConfigHomeDir());
dataDirs.push_back(xdg::DataHomeDir());
for (auto &dir : dataDirs)
dir = dir / "imhex";
const auto exePath = getExecutablePath();
if (!exePath.empty())
dataDirs.emplace(dataDirs.begin(), fs::path(exePath.data()).parent_path());
if (exePath && !exePath->empty())
dataDirs.push_back(exePath->parent_path());
switch (path) {
case ImHexPath::Patterns:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "patterns").string(); });
break;
case ImHexPath::PatternsInclude:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "includes").string(); });
break;
case ImHexPath::Magic:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "magic").string(); });
break;
case ImHexPath::Python:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p).string(); });
break;
case ImHexPath::Plugins:
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "plugins").string(); });
break;
case ImHexPath::Yara:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "yara").string(); });
break;
case ImHexPath::Config:
@@ -198,22 +273,25 @@ namespace hex {
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "resources").string(); });
break;
case ImHexPath::Constants:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "constants").string(); });
break;
case ImHexPath::Encodings:
addUserDirs(dataDirs);
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "encodings").string(); });
break;
case ImHexPath::Logs:
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "logs").string(); });
break;
default:
__builtin_unreachable();
hex::unreachable();
}
#endif
if (!listNonExisting) {
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
return !fs::is_directory(path);
return !fs::isDirectory(path);
}),
result.end());
}
@@ -221,4 +299,4 @@ namespace hex {
return result;
}
}
}

View File

@@ -1,5 +1,5 @@
#if defined(OS_MACOS)
#include <hex/helpers/paths_mac.h>
#include <hex/helpers/fs_macos.h>
#include <Foundation/Foundation.h>

View File

@@ -1,10 +1,11 @@
#include <hex/helpers/loader_script_handler.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/paths.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>
@@ -18,10 +19,14 @@ 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;
@@ -47,6 +52,8 @@ namespace hex {
}
PyObject *LoaderScript::Py_addBookmark(PyObject *self, PyObject *args) {
hex::unused(self);
u64 address;
size_t size;
@@ -68,7 +75,12 @@ namespace hex {
Py_RETURN_NONE;
}
static PyObject *createStructureType(std::string keyword, PyObject *args) {
static PyObject *createStructureType(const std::string &keyword, PyObject *args) {
if (args == nullptr) {
PyErr_BadArgument();
return nullptr;
}
auto type = PyTuple_GetItem(args, 0);
if (type == nullptr) {
PyErr_BadArgument();
@@ -112,10 +124,19 @@ namespace hex {
for (Py_ssize_t i = 0; i < PyList_Size(list); i++) {
auto item = PyList_GetItem(list, i);
if (item == nullptr) {
PyErr_SetString(PyExc_TypeError, "failed to get item from list");
return nullptr;
}
auto memberName = PyUnicode_AsUTF8(PyTuple_GetItem(item, 0));
if (memberName == nullptr) {
PyErr_SetString(PyExc_TypeError, "invalid member name");
return nullptr;
}
auto memberType = PyTuple_GetItem(item, 1);
if (memberType == nullptr) {
if (!PyTuple_Check(memberType) || memberType == nullptr) {
PyErr_SetString(PyExc_TypeError, "member needs to have a annotation extending from ImHexType");
return nullptr;
}
@@ -141,12 +162,6 @@ namespace hex {
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) {
@@ -171,18 +186,22 @@ namespace hex {
}
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 fs::path &scriptPath) {
bool LoaderScript::processFile(const std::fs::path &scriptPath) {
Py_SetProgramName(Py_DecodeLocale("ImHex", nullptr));
for (const auto &dir : hex::getPath(ImHexPath::Python)) {
if (fs::exists(fs::path(dir / "lib" / "python" PYTHON_VERSION_MAJOR_MINOR))) {
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;
}
@@ -218,7 +237,7 @@ namespace hex {
PyList_Insert(sysPath, 0, path);
}
File scriptFile(scriptPath, File::Mode::Read);
fs::File scriptFile(scriptPath, fs::File::Mode::Read);
PyRun_SimpleFile(scriptFile.getHandle(), scriptFile.getPath().string().c_str());
Py_Finalize();

View File

@@ -1,13 +1,13 @@
#include <hex/helpers/logger.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/fmt.hpp>
#include <iostream>
namespace hex::log {
static File g_loggerFile;
static fs::File g_loggerFile;
FILE *getDestination() {
if (g_loggerFile.isValid())
@@ -23,8 +23,10 @@ namespace hex::log {
void redirectToFile() {
if (g_loggerFile.isValid()) return;
for (const auto &path : hex::getPath(ImHexPath::Logs)) {
g_loggerFile = File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::now())), File::Mode::Create);
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
fs::createDirectories(path);
g_loggerFile = fs::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::now())), fs::File::Mode::Create);
g_loggerFile.disableBuffering();
if (g_loggerFile.isValid()) break;
}

View File

@@ -1,7 +1,7 @@
#include <hex/helpers/magic.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/providers/provider.hpp>
@@ -24,8 +24,8 @@ namespace hex::magic {
std::string magicFiles;
std::error_code error;
for (const auto &dir : hex::getPath(ImHexPath::Magic)) {
for (const auto &entry : fs::directory_iterator(dir, 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;
}

View File

@@ -38,19 +38,16 @@ namespace hex {
return size * nmemb;
}
static size_t readFromFile(void *contents, size_t size, size_t nmemb, void *userdata) {
FILE *file = static_cast<FILE *>(userdata);
return fread(contents, size, nmemb, file);
}
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) {
FILE *file = static_cast<FILE *>(userdata);
return fwrite(contents, size, nmemb, file);
}
static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userdata) {
[[maybe_unused]]
static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
hex::unused(ctx, userData);
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
static mbedtls_x509_crt crt;
@@ -121,7 +118,7 @@ namespace hex {
std::optional<i32> Net::execute() {
CURLcode result = curl_easy_perform(this->m_ctx);
if (result != CURLE_OK)
log::error("Net request failed with error {}!", curl_easy_strerror(result));
log::error("Net request failed with error {0}: '{1}'", result, curl_easy_strerror(result));
i32 responseCode = 0;
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
@@ -171,7 +168,7 @@ namespace hex {
});
}
std::future<Response<std::string>> Net::uploadFile(const std::string &url, const fs::path &filePath, u32 timeout) {
std::future<Response<std::string>> Net::uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this] {
@@ -179,7 +176,7 @@ namespace hex {
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
File file(filePath.string(), File::Mode::Read);
fs::File file(filePath.string(), fs::File::Mode::Read);
if (!file.isValid())
return Response<std::string> { 400, {} };
@@ -209,7 +206,7 @@ namespace hex {
});
}
std::future<Response<void>> Net::downloadFile(const std::string &url, const fs::path &filePath, u32 timeout) {
std::future<Response<void>> Net::downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this] {
@@ -217,7 +214,7 @@ namespace hex {
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
File file(filePath.string(), File::Mode::Create);
fs::File file(filePath.string(), fs::File::Mode::Create);
if (!file.isValid())
return Response<void> { 400 };

View File

@@ -156,7 +156,7 @@ namespace hex {
ipsOffset += 1;
}
if (std::memcmp(ipsPatch.data(), "EOF", 3))
if (std::memcmp(ipsPatch.data(), "EOF", 3) == 0)
foundEOF = true;
}
@@ -207,7 +207,7 @@ namespace hex {
ipsOffset += 1;
}
if (std::memcmp(ipsPatch.data(), "EEOF", 4))
if (std::memcmp(ipsPatch.data(), "EEOF", 4) == 0)
foundEEOF = true;
}

View File

@@ -9,10 +9,10 @@ using json = nlohmann::json;
namespace hex {
fs::path ProjectFile::s_currProjectFilePath;
std::fs::path ProjectFile::s_currProjectFilePath;
bool ProjectFile::s_hasUnsavedChanged = false;
fs::path ProjectFile::s_filePath;
std::fs::path ProjectFile::s_filePath;
std::string ProjectFile::s_pattern;
Patches ProjectFile::s_patches;
std::list<ImHexApi::Bookmarks::Entry> ProjectFile::s_bookmarks;
@@ -46,7 +46,7 @@ namespace hex {
}
bool ProjectFile::load(const fs::path &filePath) {
bool ProjectFile::load(const std::fs::path &filePath) {
ProjectFile::s_hasUnsavedChanged = false;
json projectFileData;
@@ -55,7 +55,7 @@ namespace hex {
std::ifstream projectFile(filePath.c_str());
projectFile >> projectFileData;
ProjectFile::s_filePath = fs::path(projectFileData["filePath"].get<std::string>());
ProjectFile::s_filePath = std::fs::path(projectFileData["filePath"].get<std::string>());
ProjectFile::s_pattern = projectFileData["pattern"];
ProjectFile::s_patches = projectFileData["patches"].get<Patches>();
ProjectFile::s_dataProcessorContent = projectFileData["dataProcessor"];
@@ -80,7 +80,7 @@ namespace hex {
return true;
}
bool ProjectFile::store(fs::path filePath) {
bool ProjectFile::store(std::fs::path filePath) {
EventManager::post<EventProjectFileStore>();
json projectFileData;
@@ -89,7 +89,7 @@ namespace hex {
filePath = ProjectFile::s_currProjectFilePath;
try {
projectFileData["filePath"] = ProjectFile::s_filePath;
projectFileData["filePath"] = ProjectFile::s_filePath.string();
projectFileData["pattern"] = ProjectFile::s_pattern;
projectFileData["patches"] = ProjectFile::s_patches;
projectFileData["dataProcessor"] = ProjectFile::s_dataProcessorContent;

View File

@@ -20,7 +20,7 @@ namespace hex {
this->connect(address, port);
}
Socket::Socket(Socket &&other) {
Socket::Socket(Socket &&other) noexcept {
this->m_socket = other.m_socket;
this->m_connected = other.m_connected;
@@ -75,7 +75,7 @@ namespace hex {
if (this->m_socket == SOCKET_NONE)
return;
sockaddr_in client = { 0 };
sockaddr_in client = { };
client.sin_family = AF_INET;
client.sin_port = htons(port);

View File

@@ -22,6 +22,9 @@
#include <ApplicationServices/ApplicationServices.h>
#endif
#include <hex/helpers/logger.hpp>
#include <hex/helpers/file.hpp>
namespace hex {
long double operator""_scaled(long double value) {
@@ -46,7 +49,7 @@ namespace hex {
index--;
}
return std::string(data + index + 1);
return { data + index + 1 };
}
std::string to_string(i128 value) {
@@ -63,9 +66,9 @@ namespace hex {
if (value < 0) {
data[index] = '-';
return std::string(data + index);
return { data + index };
} else
return std::string(data + index + 1);
return { data + index + 1 };
}
std::string toByteString(u64 bytes) {
@@ -111,6 +114,18 @@ namespace hex {
return result;
}
std::string makeStringPrintable(const std::string &string) {
std::string result;
for (char c : string) {
if (std::isprint(c))
result += c;
else
result += hex::format("\\x{0:02X}", u8(c));
}
return result;
}
std::string makePrintable(u8 c) {
switch (c) {
case 0:
@@ -189,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);
@@ -234,14 +253,13 @@ namespace hex {
void runCommand(const std::string &command) {
#if defined(OS_WINDOWS)
system(hex::format("start {0}", command).c_str());
auto result = system(hex::format("start {0}", command).c_str());
#elif defined(OS_MACOS)
system(hex::format("open {0}", command).c_str());
auto result = system(hex::format("open {0}", command).c_str());
#elif defined(OS_LINUX)
system(hex::format("xdg-open {0}", command).c_str());
#else
#warning "Unknown OS, can't open webpages"
auto result = system(hex::format("xdg-open {0}", command).c_str());
#endif
hex::unused(result);
}
void openWebpage(std::string url) {
@@ -256,37 +274,128 @@ namespace hex {
LSOpenCFURLRef(urlRef, nullptr);
CFRelease(urlRef);
#elif defined(OS_LINUX)
system(hex::format("xdg-open {0}", url).c_str());
auto result = system(hex::format("xdg-open {0}", url).c_str());
hex::unused(result);
#else
#warning "Unknown OS, can't open webpages"
#endif
}
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(fs::path)> &callback, const std::string &defaultPath) {
NFD::Init();
std::string encodeByteString(const std::vector<u8> &bytes) {
std::string result;
nfdchar_t *outPath;
nfdresult_t result;
switch (mode) {
case DialogMode::Open:
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
break;
case DialogMode::Save:
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
break;
case DialogMode::Folder:
result = NFD::PickFolder(outPath, defaultPath.c_str());
break;
default:
__builtin_unreachable();
for (u8 byte : bytes) {
if (std::isprint(byte) && byte != '\\')
result += char(byte);
else {
switch (byte) {
case '\\':
result += "\\";
break;
case '\a':
result += "\\a";
break;
case '\b':
result += "\\b";
break;
case '\f':
result += "\\f";
break;
case '\n':
result += "\\n";
break;
case '\r':
result += "\\r";
break;
case '\t':
result += "\\t";
break;
case '\v':
result += "\\v";
break;
default:
result += hex::format("\\x{:02X}", byte);
break;
}
}
}
if (result == NFD_OKAY) {
callback(outPath);
NFD::FreePath(outPath);
return result;
}
std::vector<u8> decodeByteString(const std::string &string) {
u32 offset = 0;
std::vector<u8> result;
while (offset < string.length()) {
auto c = [&] { return string[offset]; };
if (c() == '\\') {
if ((offset + 2) >= string.length()) return {};
offset++;
char escapeChar = c();
offset++;
switch (escapeChar) {
case 'a':
result.push_back('\a');
break;
case 'b':
result.push_back('\b');
break;
case 'f':
result.push_back('\f');
break;
case 'n':
result.push_back('\n');
break;
case 'r':
result.push_back('\r');
break;
case 't':
result.push_back('\t');
break;
case 'v':
result.push_back('\v');
break;
case '\\':
result.push_back('\\');
break;
case 'x':
{
u8 byte = 0x00;
if ((offset + 1) >= string.length()) return {};
for (u8 i = 0; i < 2; i++) {
byte <<= 4;
if (c() >= '0' && c() <= '9')
byte |= 0x00 + (c() - '0');
else if (c() >= 'A' && c() <= 'F')
byte |= 0x0A + (c() - 'A');
else if (c() >= 'a' && c() <= 'f')
byte |= 0x0A + (c() - 'a');
else
return {};
offset++;
}
result.push_back(byte);
}
break;
default:
return {};
}
} else {
result.push_back(c());
offset++;
}
}
NFD::Quit();
return result;
}
float float16ToFloat32(u16 float16) {
@@ -294,7 +403,7 @@ namespace hex {
u32 exponent = (float16 >> 10) & 0x1F;
u32 mantissa = float16 & 0x3FF;
u32 result;
u32 result = 0x00;
if (exponent == 0) {
if (mantissa == 0) {
@@ -320,7 +429,10 @@ namespace hex {
result = (sign << 31) | ((exponent + (0x7F - 15)) << 23) | (mantissa << 13);
}
return reinterpret_cast<float &>(result);
float floatResult = 0;
std::memcpy(&floatResult, &result, sizeof(float));
return floatResult;
}
bool isProcessElevated() {
@@ -342,8 +454,17 @@ namespace hex {
return elevated;
#elif defined(OS_LINUX) || defined(OS_MACOS)
return getuid() < 0 || getuid() != geteuid();
return getuid() == 0 || getuid() != geteuid();
#endif
}
std::optional<std::string> getEnvironmentVariable(const std::string &env) {
auto value = std::getenv(env.c_str());
if (value == nullptr)
return std::nullopt;
else
return value;
}
}

View File

@@ -1,234 +0,0 @@
#include <hex/pattern_language/evaluator.hpp>
#include <hex/pattern_language/ast_node.hpp>
#include <hex/pattern_language/pattern_data.hpp>
namespace hex::pl {
void Evaluator::createParameterPack(const std::string &name, const std::vector<Token::Literal> &values) {
this->getScope(0).parameterPack = ParameterPack {
name,
values
};
}
void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value, bool outVariable) {
auto &variables = *this->getScope(0).scope;
for (auto &variable : variables) {
if (variable->getVariableName() == name) {
LogConsole::abortEvaluation(hex::format("variable with name '{}' already exists", name));
}
}
auto startOffset = this->dataOffset();
auto pattern = type == nullptr ? nullptr : type->createPatterns(this).front();
this->dataOffset() = startOffset;
if (pattern == nullptr) {
// Handle auto variables
if (!value.has_value())
LogConsole::abortEvaluation("cannot determine type of auto variable", type);
if (std::get_if<u128>(&value.value()) != nullptr)
pattern = new PatternDataUnsigned(this, 0, sizeof(u128));
else if (std::get_if<i128>(&value.value()) != nullptr)
pattern = new PatternDataSigned(this, 0, sizeof(i128));
else if (std::get_if<double>(&value.value()) != nullptr)
pattern = new PatternDataFloat(this, 0, sizeof(double));
else if (std::get_if<bool>(&value.value()) != nullptr)
pattern = new PatternDataBoolean(this, 0);
else if (std::get_if<char>(&value.value()) != nullptr)
pattern = new PatternDataCharacter(this, 0);
else if (std::get_if<PatternData *>(&value.value()) != nullptr)
pattern = std::get<PatternData *>(value.value())->clone();
else if (std::get_if<std::string>(&value.value()) != nullptr)
pattern = new PatternDataString(this, 0, 1);
else
LogConsole::abortEvaluation("cannot determine type of auto variable", type);
}
pattern->setVariableName(name);
pattern->setLocal(true);
pattern->setOffset(this->getStack().size());
this->getStack().emplace_back();
variables.push_back(pattern);
if (outVariable)
this->m_outVariables[name] = pattern->getOffset();
}
void Evaluator::setVariable(const std::string &name, const Token::Literal &value) {
PatternData *pattern = nullptr;
{
auto &variables = *this->getScope(0).scope;
for (auto &variable : variables) {
if (variable->getVariableName() == name) {
pattern = variable;
break;
}
}
}
if (pattern == nullptr) {
auto &variables = *this->getGlobalScope().scope;
for (auto &variable : variables) {
if (variable->getVariableName() == name) {
if (!variable->isLocal())
LogConsole::abortEvaluation(hex::format("cannot modify global variable '{}' which has been placed in memory", name));
pattern = variable;
break;
}
}
}
if (pattern == nullptr)
LogConsole::abortEvaluation(hex::format("no variable with name '{}' found", name));
Token::Literal castedLiteral = std::visit(overloaded {
[&](double &value) -> Token::Literal {
if (dynamic_cast<PatternDataUnsigned *>(pattern))
return u128(value) & bitmask(pattern->getSize() * 8);
else if (dynamic_cast<PatternDataSigned *>(pattern))
return i128(value) & bitmask(pattern->getSize() * 8);
else if (dynamic_cast<PatternDataFloat *>(pattern))
return pattern->getSize() == sizeof(float) ? double(float(value)) : value;
else
LogConsole::abortEvaluation(hex::format("cannot cast type 'double' to type '{}'", pattern->getTypeName()));
},
[&](const std::string &value) -> Token::Literal {
if (dynamic_cast<PatternDataString *>(pattern))
return value;
else
LogConsole::abortEvaluation(hex::format("cannot cast type 'string' to type '{}'", pattern->getTypeName()));
},
[&](PatternData *const &value) -> Token::Literal {
if (value->getTypeName() == pattern->getTypeName())
return value;
else
LogConsole::abortEvaluation(hex::format("cannot cast type '{}' to type '{}'", value->getTypeName(), pattern->getTypeName()));
},
[&](auto &&value) -> Token::Literal {
if (dynamic_cast<PatternDataUnsigned *>(pattern) || dynamic_cast<PatternDataEnum *>(pattern))
return u128(value) & bitmask(pattern->getSize() * 8);
else if (dynamic_cast<PatternDataSigned *>(pattern))
return i128(value) & bitmask(pattern->getSize() * 8);
else if (dynamic_cast<PatternDataCharacter *>(pattern))
return char(value);
else if (dynamic_cast<PatternDataBoolean *>(pattern))
return bool(value);
else if (dynamic_cast<PatternDataFloat *>(pattern))
return pattern->getSize() == sizeof(float) ? double(float(value)) : value;
else
LogConsole::abortEvaluation(hex::format("cannot cast integer literal to type '{}'", pattern->getTypeName()));
} },
value);
this->getStack()[pattern->getOffset()] = castedLiteral;
}
std::optional<std::vector<PatternData *>> Evaluator::evaluate(const std::vector<ASTNode *> &ast) {
this->m_stack.clear();
this->m_customFunctions.clear();
this->m_scopes.clear();
this->m_mainResult.reset();
this->m_aborted = false;
if (this->m_allowDangerousFunctions == DangerousFunctionPermission::Deny)
this->m_allowDangerousFunctions = DangerousFunctionPermission::Ask;
this->m_dangerousFunctionCalled = false;
ON_SCOPE_EXIT {
this->m_envVariables.clear();
};
this->dataOffset() = 0x00;
this->m_currPatternCount = 0;
for (auto &func : this->m_customFunctionDefinitions)
delete func;
this->m_customFunctionDefinitions.clear();
std::vector<PatternData *> patterns;
try {
this->setCurrentControlFlowStatement(ControlFlowStatement::None);
pushScope(nullptr, patterns);
ON_SCOPE_EXIT {
popScope();
};
for (auto node : ast) {
if (dynamic_cast<ASTNodeTypeDecl *>(node)) {
; // Don't create patterns from type declarations
} else if (dynamic_cast<ASTNodeFunctionCall *>(node)) {
delete node->evaluate(this);
} else if (dynamic_cast<ASTNodeFunctionDefinition *>(node)) {
this->m_customFunctionDefinitions.push_back(node->evaluate(this));
} else if (auto varDeclNode = dynamic_cast<ASTNodeVariableDecl *>(node)) {
auto pattern = node->createPatterns(this).front();
if (varDeclNode->getPlacementOffset() == nullptr) {
auto type = varDeclNode->getType()->evaluate(this);
ON_SCOPE_EXIT { delete type; };
auto &name = pattern->getVariableName();
this->createVariable(name, type, std::nullopt, varDeclNode->isOutVariable());
if (varDeclNode->isInVariable() && this->m_inVariables.contains(name))
this->setVariable(name, this->m_inVariables[name]);
delete pattern;
} else {
patterns.push_back(pattern);
}
} else {
auto newPatterns = node->createPatterns(this);
std::copy(newPatterns.begin(), newPatterns.end(), std::back_inserter(patterns));
}
}
if (this->m_customFunctions.contains("main")) {
auto mainFunction = this->m_customFunctions["main"];
if (mainFunction.parameterCount > 0)
LogConsole::abortEvaluation("main function may not accept any arguments");
this->m_mainResult = mainFunction.func(this, {});
}
} catch (PatternLanguageError &error) {
this->m_console.log(LogConsole::Level::Error, error.what());
if (error.getLineNumber() != 0)
this->m_console.setHardError(error);
for (auto &pattern : patterns)
delete pattern;
patterns.clear();
this->m_currPatternCount = 0;
return std::nullopt;
}
// Remove global local variables
std::erase_if(patterns, [](PatternData *pattern) {
return pattern->isLocal();
});
return patterns;
}
void Evaluator::patternCreated() {
if (this->m_currPatternCount > this->m_patternLimit)
LogConsole::abortEvaluation(hex::format("exceeded maximum number of patterns: {}", this->m_patternLimit));
this->m_currPatternCount++;
}
void Evaluator::patternDestroyed() {
this->m_currPatternCount--;
}
}

View File

@@ -1,535 +0,0 @@
#include <hex/pattern_language/lexer.hpp>
#include <algorithm>
#include <charconv>
#include <functional>
#include <optional>
#include <vector>
namespace hex::pl {
#define TOKEN(type, value) Token::Type::type, Token::type::value, lineNumber
#define VALUE_TOKEN(type, value) Token::Type::type, value, lineNumber
std::string matchTillInvalid(const char *characters, const std::function<bool(char)> &predicate) {
std::string ret;
while (*characters != 0x00) {
ret += *characters;
characters++;
if (!predicate(*characters))
break;
}
return ret;
}
bool isIdentifierCharacter(char c) {
return std::isalnum(c) || c == '_';
}
size_t getIntegerLiteralLength(std::string_view string) {
auto count = string.find_first_not_of("0123456789ABCDEFabcdef'xXoOpP.uU");
if (count == std::string_view::npos)
return string.size();
else
return count;
}
std::optional<Token::Literal> lexIntegerLiteral(std::string_view string) {
bool hasFloatSuffix = string.ends_with('D') || string.ends_with('F') || string.ends_with('d') || string.ends_with('f');
bool isFloat = std::count(string.begin(), string.end(), '.') == 1 ||
!string.starts_with("0x") && hasFloatSuffix;
if (isFloat) {
// Parse double
char suffix = 0x00;
if (hasFloatSuffix) {
suffix = string.back();
string = string.substr(0, string.length() - 1);
}
char *end = nullptr;
double value = std::strtod(string.begin(), &end);
if (end == string.end()) {
switch (suffix) {
case 'd':
case 'D':
return double(value);
case 'f':
case 'F':
return float(value);
default:
return value;
}
}
} else {
bool isUnsigned = false;
if (string.ends_with('U') || string.ends_with('u')) {
isUnsigned = true;
string = string.substr(0, string.length() - 1);
}
u8 prefixOffset = 0;
u8 base = 10;
if (string.starts_with("0x") || string.starts_with("0X")) {
// Parse hexadecimal
prefixOffset = 2;
base = 16;
} else if (string.starts_with("0o") || string.starts_with("0O")) {
// Parse octal
prefixOffset = 2;
base = 8;
} else if (string.starts_with("0b") || string.starts_with("0B")) {
// Parse binary
prefixOffset = 2;
base = 2;
} else {
// Parse decimal
prefixOffset = 0;
base = 10;
}
u128 value = 0x00;
for (char c : string.substr(prefixOffset)) {
value *= base;
value += [&] {
if (c >= '0' && c <= '9') return c - '0';
else if (c >= 'A' && c <= 'F') return 0xA + (c - 'A');
else if (c >= 'a' && c <= 'f') return 0xA + (c - 'a');
else return 0x00;
}();
}
if (isUnsigned)
return value;
else
return i128(value);
}
return std::nullopt;
}
std::optional<Token::Literal> lexIntegerLiteralWithSeparator(std::string_view string) {
if (string.starts_with('\'') || string.ends_with('\''))
return std::nullopt;
else if (string.find('\'') == std::string_view::npos)
return lexIntegerLiteral(string);
else {
auto preprocessedString = std::string(string);
preprocessedString.erase(std::remove(preprocessedString.begin(), preprocessedString.end(), '\''), preprocessedString.end());
return lexIntegerLiteral(preprocessedString);
}
}
std::optional<std::pair<char, size_t>> getCharacter(const std::string &string) {
if (string.length() < 1)
return std::nullopt;
// Escape sequences
if (string[0] == '\\') {
if (string.length() < 2)
return std::nullopt;
// Handle simple escape sequences
switch (string[1]) {
case 'a':
return {
{'\a', 2}
};
case 'b':
return {
{'\b', 2}
};
case 'f':
return {
{'\f', 2}
};
case 'n':
return {
{'\n', 2}
};
case 'r':
return {
{'\r', 2}
};
case 't':
return {
{'\t', 2}
};
case 'v':
return {
{'\v', 2}
};
case '\\':
return {
{'\\', 2}
};
case '\'':
return {
{'\'', 2}
};
case '\"':
return {
{'\"', 2}
};
}
// Hexadecimal number
if (string[1] == 'x') {
if (string.length() != 4)
return std::nullopt;
if (!isxdigit(string[2]) || !isxdigit(string[3]))
return std::nullopt;
return {
{std::strtoul(&string[2], nullptr, 16), 4}
};
}
// Octal number
if (string[1] == 'o') {
if (string.length() != 5)
return {};
if (string[2] < '0' || string[2] > '7' || string[3] < '0' || string[3] > '7' || string[4] < '0' || string[4] > '7')
return {};
return {
{std::strtoul(&string[2], nullptr, 8), 5}
};
}
return std::nullopt;
} else return {
{string[0], 1}
};
}
std::optional<std::pair<std::string, size_t>> getStringLiteral(const std::string &string) {
if (!string.starts_with('\"'))
return {};
size_t size = 1;
std::string result;
while (string[size] != '\"') {
auto character = getCharacter(string.substr(size));
if (!character.has_value())
return {};
auto &[c, charSize] = character.value();
result += c;
size += charSize;
if (size >= string.length())
return {};
}
return {
{result, size + 1}
};
}
std::optional<std::pair<char, size_t>> getCharacterLiteral(const std::string &string) {
if (string.empty())
return {};
if (string[0] != '\'')
return {};
auto character = getCharacter(string.substr(1));
if (!character.has_value())
return {};
auto &[c, charSize] = character.value();
if (string.length() >= charSize + 2 && string[charSize + 1] != '\'')
return {};
return {
{c, charSize + 2}
};
}
std::optional<std::vector<Token>> Lexer::lex(const std::string &code) {
std::vector<Token> tokens;
u32 offset = 0;
u32 lineNumber = 1;
try {
while (offset < code.length()) {
const char &c = code[offset];
if (c == 0x00)
break;
if (std::isblank(c) || std::isspace(c)) {
if (code[offset] == '\n') lineNumber++;
offset += 1;
} else if (c == ';') {
tokens.emplace_back(TOKEN(Separator, EndOfExpression));
offset += 1;
} else if (c == '(') {
tokens.emplace_back(TOKEN(Separator, RoundBracketOpen));
offset += 1;
} else if (c == ')') {
tokens.emplace_back(TOKEN(Separator, RoundBracketClose));
offset += 1;
} else if (c == '{') {
tokens.emplace_back(TOKEN(Separator, CurlyBracketOpen));
offset += 1;
} else if (c == '}') {
tokens.emplace_back(TOKEN(Separator, CurlyBracketClose));
offset += 1;
} else if (c == '[') {
tokens.emplace_back(TOKEN(Separator, SquareBracketOpen));
offset += 1;
} else if (c == ']') {
tokens.emplace_back(TOKEN(Separator, SquareBracketClose));
offset += 1;
} else if (c == ',') {
tokens.emplace_back(TOKEN(Separator, Comma));
offset += 1;
} else if (c == '.') {
tokens.emplace_back(TOKEN(Separator, Dot));
offset += 1;
} else if (code.substr(offset, 2) == "::") {
tokens.emplace_back(TOKEN(Operator, ScopeResolution));
offset += 2;
} else if (c == '@') {
tokens.emplace_back(TOKEN(Operator, AtDeclaration));
offset += 1;
} else if (code.substr(offset, 2) == "==") {
tokens.emplace_back(TOKEN(Operator, BoolEquals));
offset += 2;
} else if (code.substr(offset, 2) == "!=") {
tokens.emplace_back(TOKEN(Operator, BoolNotEquals));
offset += 2;
} else if (code.substr(offset, 2) == ">=") {
tokens.emplace_back(TOKEN(Operator, BoolGreaterThanOrEquals));
offset += 2;
} else if (code.substr(offset, 2) == "<=") {
tokens.emplace_back(TOKEN(Operator, BoolLessThanOrEquals));
offset += 2;
} else if (code.substr(offset, 2) == "&&") {
tokens.emplace_back(TOKEN(Operator, BoolAnd));
offset += 2;
} else if (code.substr(offset, 2) == "||") {
tokens.emplace_back(TOKEN(Operator, BoolOr));
offset += 2;
} else if (code.substr(offset, 2) == "^^") {
tokens.emplace_back(TOKEN(Operator, BoolXor));
offset += 2;
} else if (c == '=') {
tokens.emplace_back(TOKEN(Operator, Assignment));
offset += 1;
} else if (c == ':') {
tokens.emplace_back(TOKEN(Operator, Inherit));
offset += 1;
} else if (c == '+') {
tokens.emplace_back(TOKEN(Operator, Plus));
offset += 1;
} else if (c == '-') {
tokens.emplace_back(TOKEN(Operator, Minus));
offset += 1;
} else if (c == '*') {
tokens.emplace_back(TOKEN(Operator, Star));
offset += 1;
} else if (c == '/') {
tokens.emplace_back(TOKEN(Operator, Slash));
offset += 1;
} else if (c == '%') {
tokens.emplace_back(TOKEN(Operator, Percent));
offset += 1;
} else if (code.substr(offset, 2) == "<<") {
tokens.emplace_back(TOKEN(Operator, ShiftLeft));
offset += 2;
} else if (code.substr(offset, 2) == ">>") {
tokens.emplace_back(TOKEN(Operator, ShiftRight));
offset += 2;
} else if (c == '>') {
tokens.emplace_back(TOKEN(Operator, BoolGreaterThan));
offset += 1;
} else if (c == '<') {
tokens.emplace_back(TOKEN(Operator, BoolLessThan));
offset += 1;
} else if (c == '!') {
tokens.emplace_back(TOKEN(Operator, BoolNot));
offset += 1;
} else if (c == '|') {
tokens.emplace_back(TOKEN(Operator, BitOr));
offset += 1;
} else if (c == '&') {
tokens.emplace_back(TOKEN(Operator, BitAnd));
offset += 1;
} else if (c == '^') {
tokens.emplace_back(TOKEN(Operator, BitXor));
offset += 1;
} else if (c == '~') {
tokens.emplace_back(TOKEN(Operator, BitNot));
offset += 1;
} else if (c == '?') {
tokens.emplace_back(TOKEN(Operator, TernaryConditional));
offset += 1;
} else if (c == '$') {
tokens.emplace_back(TOKEN(Operator, Dollar));
offset += 1;
} else if (code.substr(offset, 9) == "addressof" && !isIdentifierCharacter(code[offset + 9])) {
tokens.emplace_back(TOKEN(Operator, AddressOf));
offset += 9;
} else if (code.substr(offset, 6) == "sizeof" && !isIdentifierCharacter(code[offset + 6])) {
tokens.emplace_back(TOKEN(Operator, SizeOf));
offset += 6;
} else if (c == '\'') {
auto lexedCharacter = getCharacterLiteral(code.substr(offset));
if (!lexedCharacter.has_value())
throwLexerError("invalid character literal", lineNumber);
auto [character, charSize] = lexedCharacter.value();
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(character)));
offset += charSize;
} else if (c == '\"') {
auto string = getStringLiteral(code.substr(offset));
if (!string.has_value())
throwLexerError("invalid string literal", lineNumber);
auto [s, stringSize] = string.value();
tokens.emplace_back(VALUE_TOKEN(String, Token::Literal(s)));
offset += stringSize;
} else if (isIdentifierCharacter(c) && !std::isdigit(c)) {
std::string identifier = matchTillInvalid(&code[offset], isIdentifierCharacter);
// Check for reserved keywords
if (identifier == "struct")
tokens.emplace_back(TOKEN(Keyword, Struct));
else if (identifier == "union")
tokens.emplace_back(TOKEN(Keyword, Union));
else if (identifier == "using")
tokens.emplace_back(TOKEN(Keyword, Using));
else if (identifier == "enum")
tokens.emplace_back(TOKEN(Keyword, Enum));
else if (identifier == "bitfield")
tokens.emplace_back(TOKEN(Keyword, Bitfield));
else if (identifier == "be")
tokens.emplace_back(TOKEN(Keyword, BigEndian));
else if (identifier == "le")
tokens.emplace_back(TOKEN(Keyword, LittleEndian));
else if (identifier == "if")
tokens.emplace_back(TOKEN(Keyword, If));
else if (identifier == "else")
tokens.emplace_back(TOKEN(Keyword, Else));
else if (identifier == "false")
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(false)));
else if (identifier == "true")
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(true)));
else if (identifier == "parent")
tokens.emplace_back(TOKEN(Keyword, Parent));
else if (identifier == "this")
tokens.emplace_back(TOKEN(Keyword, This));
else if (identifier == "while")
tokens.emplace_back(TOKEN(Keyword, While));
else if (identifier == "for")
tokens.emplace_back(TOKEN(Keyword, For));
else if (identifier == "fn")
tokens.emplace_back(TOKEN(Keyword, Function));
else if (identifier == "return")
tokens.emplace_back(TOKEN(Keyword, Return));
else if (identifier == "namespace")
tokens.emplace_back(TOKEN(Keyword, Namespace));
else if (identifier == "in")
tokens.emplace_back(TOKEN(Keyword, In));
else if (identifier == "out")
tokens.emplace_back(TOKEN(Keyword, Out));
else if (identifier == "break")
tokens.emplace_back(TOKEN(Keyword, Break));
else if (identifier == "continue")
tokens.emplace_back(TOKEN(Keyword, Continue));
// Check for built-in types
else if (identifier == "u8")
tokens.emplace_back(TOKEN(ValueType, Unsigned8Bit));
else if (identifier == "s8")
tokens.emplace_back(TOKEN(ValueType, Signed8Bit));
else if (identifier == "u16")
tokens.emplace_back(TOKEN(ValueType, Unsigned16Bit));
else if (identifier == "s16")
tokens.emplace_back(TOKEN(ValueType, Signed16Bit));
else if (identifier == "u32")
tokens.emplace_back(TOKEN(ValueType, Unsigned32Bit));
else if (identifier == "s32")
tokens.emplace_back(TOKEN(ValueType, Signed32Bit));
else if (identifier == "u64")
tokens.emplace_back(TOKEN(ValueType, Unsigned64Bit));
else if (identifier == "s64")
tokens.emplace_back(TOKEN(ValueType, Signed64Bit));
else if (identifier == "u128")
tokens.emplace_back(TOKEN(ValueType, Unsigned128Bit));
else if (identifier == "s128")
tokens.emplace_back(TOKEN(ValueType, Signed128Bit));
else if (identifier == "float")
tokens.emplace_back(TOKEN(ValueType, Float));
else if (identifier == "double")
tokens.emplace_back(TOKEN(ValueType, Double));
else if (identifier == "char")
tokens.emplace_back(TOKEN(ValueType, Character));
else if (identifier == "char16")
tokens.emplace_back(TOKEN(ValueType, Character16));
else if (identifier == "bool")
tokens.emplace_back(TOKEN(ValueType, Boolean));
else if (identifier == "str")
tokens.emplace_back(TOKEN(ValueType, String));
else if (identifier == "padding")
tokens.emplace_back(TOKEN(ValueType, Padding));
else if (identifier == "auto")
tokens.emplace_back(TOKEN(ValueType, Auto));
// If it's not a keyword and a builtin type, it has to be an identifier
else
tokens.emplace_back(VALUE_TOKEN(Identifier, Token::Identifier(identifier)));
offset += identifier.length();
} else if (std::isdigit(c)) {
auto integerLength = getIntegerLiteralLength(&code[offset]);
auto integer = lexIntegerLiteralWithSeparator(std::string_view(&code[offset], integerLength));
if (!integer.has_value())
throwLexerError("invalid integer literal", lineNumber);
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(integer.value())));
offset += integerLength;
} else
throwLexerError("unknown token", lineNumber);
}
tokens.emplace_back(TOKEN(Separator, EndOfProgram));
} catch (PatternLanguageError &e) {
this->m_error = e;
return std::nullopt;
}
return tokens;
}
}

View File

@@ -1,23 +0,0 @@
#include <hex/pattern_language/log_console.hpp>
#include <hex/pattern_language/ast_node.hpp>
namespace hex::pl {
void LogConsole::log(Level level, const std::string &message) {
this->m_consoleLog.emplace_back(level, message);
}
[[noreturn]] void LogConsole::abortEvaluation(const std::string &message, const ASTNode *node) {
if (node == nullptr)
throw PatternLanguageError(0, "Evaluator: " + message);
else
throw PatternLanguageError(node->getLineNumber(), "Evaluator: " + message);
}
void LogConsole::clear() {
this->m_consoleLog.clear();
this->m_lastHardError = {};
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,239 +0,0 @@
#include <hex/pattern_language/pattern_language.hpp>
#include <hex/helpers/file.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/pattern_language/preprocessor.hpp>
#include <hex/pattern_language/lexer.hpp>
#include <hex/pattern_language/parser.hpp>
#include <hex/pattern_language/validator.hpp>
#include <hex/pattern_language/evaluator.hpp>
namespace hex::pl {
class PatternData;
PatternLanguage::PatternLanguage() {
this->m_preprocessor = new Preprocessor();
this->m_lexer = new Lexer();
this->m_parser = new Parser();
this->m_validator = new Validator();
this->m_evaluator = new Evaluator();
this->m_preprocessor->addDefaultPragmaHandlers();
this->m_preprocessor->addPragmaHandler("endian", [this](std::string value) {
if (value == "big") {
this->m_evaluator->setDefaultEndian(std::endian::big);
return true;
} else if (value == "little") {
this->m_evaluator->setDefaultEndian(std::endian::little);
return true;
} else if (value == "native") {
this->m_evaluator->setDefaultEndian(std::endian::native);
return true;
} else
return false;
});
this->m_preprocessor->addPragmaHandler("eval_depth", [this](std::string value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_evaluator->setEvaluationDepth(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("array_limit", [this](const std::string &value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_evaluator->setArrayLimit(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("pattern_limit", [this](const std::string &value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_evaluator->setPatternLimit(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("loop_limit", [this](const std::string &value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_evaluator->setLoopLimit(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("base_address", [](const std::string &value) {
auto baseAddress = strtoull(value.c_str(), nullptr, 0);
ImHexApi::Provider::get()->setBaseAddress(baseAddress);
return true;
});
}
PatternLanguage::~PatternLanguage() {
delete this->m_preprocessor;
delete this->m_lexer;
delete this->m_parser;
delete this->m_validator;
}
std::optional<std::vector<ASTNode *>> PatternLanguage::parseString(const std::string &code) {
auto preprocessedCode = this->m_preprocessor->preprocess(code);
if (!preprocessedCode.has_value()) {
this->m_currError = this->m_preprocessor->getError();
return std::nullopt;
}
auto tokens = this->m_lexer->lex(preprocessedCode.value());
if (!tokens.has_value()) {
this->m_currError = this->m_lexer->getError();
return std::nullopt;
}
auto ast = this->m_parser->parse(tokens.value());
if (!ast.has_value()) {
this->m_currError = this->m_parser->getError();
return std::nullopt;
}
if (!this->m_validator->validate(*ast)) {
this->m_currError = this->m_validator->getError();
for (auto &node : *ast)
delete node;
return std::nullopt;
}
return ast;
}
bool PatternLanguage::executeString(prv::Provider *provider, const std::string &code, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables, bool checkResult) {
this->m_running = true;
ON_SCOPE_EXIT { this->m_running = false; };
this->m_currError.reset();
this->m_evaluator->getConsole().clear();
this->m_evaluator->setProvider(provider);
this->m_evaluator->setDefaultEndian(std::endian::native);
this->m_evaluator->setEvaluationDepth(32);
this->m_evaluator->setArrayLimit(0x1000);
this->m_evaluator->setPatternLimit(0x2000);
this->m_evaluator->setLoopLimit(0x1000);
this->m_evaluator->setInVariables(inVariables);
for (const auto &[name, value] : envVars)
this->m_evaluator->setEnvVariable(name, value);
for (auto &node : this->m_currAST)
delete node;
this->m_currAST.clear();
auto ast = this->parseString(code);
if (!ast)
return false;
this->m_currAST = ast.value();
auto patterns = this->m_evaluator->evaluate(ast.value());
if (!patterns.has_value()) {
this->m_currError = this->m_evaluator->getConsole().getLastHardError();
return false;
}
if (auto mainResult = this->m_evaluator->getMainResult(); checkResult && mainResult.has_value()) {
auto returnCode = Token::literalToSigned(*mainResult);
if (returnCode != 0) {
auto errorMessage = hex::format("non-success value returned from main: {}", returnCode);
this->m_evaluator->getConsole().log(LogConsole::Level::Error, errorMessage);
this->m_currError = PatternLanguageError(0, errorMessage);
return false;
}
}
this->m_patterns = std::move(patterns.value());
return true;
}
bool PatternLanguage::executeFile(prv::Provider *provider, const fs::path &path, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables) {
File file(path, File::Mode::Read);
return this->executeString(provider, file.readString(), envVars, inVariables, true);
}
std::pair<bool, std::optional<Token::Literal>> PatternLanguage::executeFunction(prv::Provider *provider, const std::string &code) {
auto functionContent = hex::format("fn main() {{ {0} }};", code);
auto success = this->executeString(provider, functionContent, {}, {}, false);
auto result = this->m_evaluator->getMainResult();
return { success, result };
}
void PatternLanguage::abort() {
this->m_evaluator->abort();
}
const std::vector<ASTNode *> &PatternLanguage::getCurrentAST() const {
return this->m_currAST;
}
[[nodiscard]] std::map<std::string, Token::Literal> PatternLanguage::getOutVariables() const {
return this->m_evaluator->getOutVariables();
}
const std::vector<std::pair<LogConsole::Level, std::string>> &PatternLanguage::getConsoleLog() {
return this->m_evaluator->getConsole().getLog();
}
const std::optional<PatternLanguageError> &PatternLanguage::getError() {
return this->m_currError;
}
u32 PatternLanguage::getCreatedPatternCount() {
return this->m_evaluator->getPatternCount();
}
u32 PatternLanguage::getMaximumPatternCount() {
return this->m_evaluator->getPatternLimit();
}
void PatternLanguage::allowDangerousFunctions(bool allow) {
this->m_evaluator->allowDangerousFunctions(allow);
}
bool PatternLanguage::hasDangerousFunctionBeenCalled() const {
return this->m_evaluator->hasDangerousFunctionBeenCalled();
}
void PatternLanguage::reset() {
for (auto &pattern : this->m_patterns)
delete pattern;
this->m_patterns.clear();
this->m_currAST.clear();
}
}

View File

@@ -1,258 +0,0 @@
#include <hex/pattern_language/preprocessor.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/file.hpp>
#include <filesystem>
namespace hex::pl {
std::optional<std::string> Preprocessor::preprocess(const std::string &code, bool initialRun) {
u32 offset = 0;
u32 lineNumber = 1;
bool isInString = false;
if (initialRun) {
this->m_defines.clear();
this->m_pragmas.clear();
}
std::string output;
output.reserve(code.length());
try {
bool startOfLine = true;
while (offset < code.length()) {
if (offset > 0 && code[offset - 1] != '\\' && code[offset] == '\"')
isInString = !isInString;
else if (isInString) {
output += code[offset];
offset += 1;
continue;
}
if (code[offset] == '#' && startOfLine) {
offset += 1;
if (code.substr(offset, 7) == "include") {
offset += 7;
while (std::isblank(code[offset]) || std::isspace(code[offset]))
offset += 1;
if (code[offset] != '<' && code[offset] != '"')
throwPreprocessorError("expected '<' or '\"' before file name", lineNumber);
char endChar = code[offset];
if (endChar == '<') endChar = '>';
offset += 1;
std::string includeFile;
while (code[offset] != endChar) {
includeFile += code[offset];
offset += 1;
if (offset >= code.length())
throwPreprocessorError(hex::format("missing terminating '{0}' character", endChar), lineNumber);
}
offset += 1;
fs::path includePath = includeFile;
if (includeFile[0] != '/') {
for (const auto &dir : hex::getPath(ImHexPath::PatternsInclude)) {
fs::path tempPath = dir / includePath;
if (fs::exists(tempPath)) {
includePath = tempPath;
break;
}
}
}
File file(includePath, File::Mode::Read);
if (!file.isValid()) {
if (includePath.parent_path().filename().string() == "std")
throwPreprocessorError(hex::format("{0}: No such file or directory.\n\nThis file might be part of the standard library.\nYou can install the standard library though\nthe Content Store found under Help -> Content Store.", includeFile.c_str()), lineNumber);
else
throwPreprocessorError(hex::format("{0}: No such file or directory", includeFile.c_str()), lineNumber);
}
Preprocessor preprocessor;
preprocessor.addDefaultPragmaHandlers();
preprocessor.m_defines = this->m_defines;
preprocessor.m_onceIncludedFiles = this->m_onceIncludedFiles;
auto preprocessedInclude = preprocessor.preprocess(file.readString(), /*initialRun =*/false);
if (!preprocessedInclude.has_value())
throw *preprocessor.m_error;
if (preprocessor.shouldOnlyIncludeOnce()) {
auto [iter, added] = this->m_onceIncludedFiles.insert(includePath);
if (added) {
auto content = preprocessedInclude.value();
std::replace(content.begin(), content.end(), '\n', ' ');
std::replace(content.begin(), content.end(), '\r', ' ');
output += content;
}
}
this->m_defines = preprocessor.m_defines;
this->m_onceIncludedFiles = preprocessor.m_onceIncludedFiles;
} else if (code.substr(offset, 6) == "define") {
offset += 6;
while (std::isblank(code[offset])) {
offset += 1;
}
std::string defineName;
while (!std::isblank(code[offset])) {
defineName += code[offset];
if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r')
throwPreprocessorError("no value given in #define directive", lineNumber);
offset += 1;
}
while (std::isblank(code[offset])) {
offset += 1;
if (offset >= code.length())
throwPreprocessorError("no value given in #define directive", lineNumber);
}
std::string replaceValue;
while (code[offset] != '\n' && code[offset] != '\r') {
if (offset >= code.length())
throwPreprocessorError("missing new line after #define directive", lineNumber);
replaceValue += code[offset];
offset += 1;
}
if (replaceValue.empty())
throwPreprocessorError("no value given in #define directive", lineNumber);
this->m_defines.emplace(defineName, replaceValue, lineNumber);
} else if (code.substr(offset, 6) == "pragma") {
offset += 6;
while (std::isblank(code[offset])) {
offset += 1;
if (code[offset] == '\n' || code[offset] == '\r')
throwPreprocessorError("no instruction given in #pragma directive", lineNumber);
}
std::string pragmaKey;
while (!std::isblank(code[offset]) && code[offset] != '\n' && code[offset] != '\r') {
pragmaKey += code[offset];
if (offset >= code.length())
throwPreprocessorError("no instruction given in #pragma directive", lineNumber);
offset += 1;
}
while (std::isblank(code[offset]))
offset += 1;
std::string pragmaValue;
while (code[offset] != '\n' && code[offset] != '\r') {
if (offset >= code.length())
throwPreprocessorError("missing new line after #pragma directive", lineNumber);
pragmaValue += code[offset];
offset += 1;
}
this->m_pragmas.emplace(pragmaKey, pragmaValue, lineNumber);
} else
throwPreprocessorError("unknown preprocessor directive", lineNumber);
} else if (code.substr(offset, 2) == "//") {
while (code[offset] != '\n' && offset < code.length())
offset += 1;
} else if (code.substr(offset, 2) == "/*") {
while (code.substr(offset, 2) != "*/" && offset < code.length()) {
if (code[offset] == '\n') {
output += '\n';
lineNumber++;
}
offset += 1;
}
offset += 2;
if (offset >= code.length())
throwPreprocessorError("unterminated comment", lineNumber - 1);
}
if (code[offset] == '\n') {
lineNumber++;
startOfLine = true;
} else if (!std::isspace(code[offset]))
startOfLine = false;
output += code[offset];
offset += 1;
}
// Apply defines
std::vector<std::tuple<std::string, std::string, u32>> sortedDefines;
std::copy(this->m_defines.begin(), this->m_defines.end(), std::back_inserter(sortedDefines));
std::sort(sortedDefines.begin(), sortedDefines.end(), [](const auto &left, const auto &right) {
return std::get<0>(left).size() > std::get<0>(right).size();
});
for (const auto &[define, value, defineLine] : sortedDefines) {
i32 index = 0;
while ((index = output.find(define, index)) != std::string::npos) {
output.replace(index, define.length(), value);
index += value.length();
}
}
// Handle pragmas
for (const auto &[type, value, pragmaLine] : this->m_pragmas) {
if (this->m_pragmaHandlers.contains(type)) {
if (!this->m_pragmaHandlers[type](value))
throwPreprocessorError(hex::format("invalid value provided to '{0}' #pragma directive", type.c_str()), pragmaLine);
} else
throwPreprocessorError(hex::format("no #pragma handler registered for type {0}", type.c_str()), pragmaLine);
}
} catch (PatternLanguageError &e) {
this->m_error = e;
return std::nullopt;
}
return output;
}
void Preprocessor::addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string &)> &function) {
this->m_pragmaHandlers[pragmaType] = function;
}
void Preprocessor::removePragmaHandler(const std::string &pragmaType) {
this->m_pragmaHandlers.erase(pragmaType);
}
void Preprocessor::addDefaultPragmaHandlers() {
this->addPragmaHandler("MIME", [](const std::string &value) {
return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r');
});
this->addPragmaHandler("endian", [](const std::string &value) {
return value == "big" || value == "little" || value == "native";
});
this->addPragmaHandler("once", [this](const std::string &value) {
this->m_onlyIncludeOnce = true;
return value.empty();
});
}
}

View File

@@ -1,51 +0,0 @@
#include <hex/pattern_language/validator.hpp>
#include <hex/pattern_language/ast_node.hpp>
#include <hex/helpers/fmt.hpp>
#include <unordered_set>
#include <string>
namespace hex::pl {
bool Validator::validate(const std::vector<ASTNode *> &ast) {
std::unordered_set<std::string> identifiers;
try {
for (const auto &node : ast) {
if (node == nullptr)
throwValidatorError("nullptr in AST. This is a bug!", 1);
if (auto variableDeclNode = dynamic_cast<ASTNodeVariableDecl *>(node); variableDeclNode != nullptr) {
if (!identifiers.insert(variableDeclNode->getName().data()).second)
throwValidatorError(hex::format("redefinition of identifier '{0}'", variableDeclNode->getName().data()), variableDeclNode->getLineNumber());
this->validate({ variableDeclNode->getType() });
} else if (auto typeDeclNode = dynamic_cast<ASTNodeTypeDecl *>(node); typeDeclNode != nullptr) {
if (!identifiers.insert(typeDeclNode->getName().data()).second)
throwValidatorError(hex::format("redefinition of identifier '{0}'", typeDeclNode->getName().data()), typeDeclNode->getLineNumber());
this->validate({ typeDeclNode->getType() });
} else if (auto structNode = dynamic_cast<ASTNodeStruct *>(node); structNode != nullptr) {
this->validate(structNode->getMembers());
} else if (auto unionNode = dynamic_cast<ASTNodeUnion *>(node); unionNode != nullptr) {
this->validate(unionNode->getMembers());
} else if (auto enumNode = dynamic_cast<ASTNodeEnum *>(node); enumNode != nullptr) {
std::unordered_set<std::string> enumIdentifiers;
for (auto &[name, value] : enumNode->getEntries()) {
if (!enumIdentifiers.insert(name).second)
throwValidatorError(hex::format("redefinition of enum constant '{0}'", name.c_str()), value->getLineNumber());
}
}
}
} catch (PatternLanguageError &e) {
this->m_error = e;
return false;
}
return true;
}
}

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