Compare commits

..

159 Commits

Author SHA1 Message Date
WerWolv
fc105ecc3d build: Bumped version to 1.28.0 2023-04-04 12:04:22 +02:00
WerWolv
649f6c28bf patterns: Updated pattern language 2023-04-04 11:20:09 +02:00
WerWolv
867972b7f5 patterns: Updated pattern language 2023-04-04 10:23:01 +02:00
WerWolv
efe3227ef2 patterns: Updated pattern language 2023-04-04 09:34:50 +02:00
H1X4
aab8c88a96 feat: allow loading and saving pattern code via events (#1004)
Currently there is no way to save the pattern code progamically from a
plugin unless the builtin plugin is modified to add those events. This
pull request will be adding ability to load and save pattern code from
specified file.
2023-04-01 11:18:52 +02:00
Thomas
af18ca011b fix: Modified bytes visually reverting back after saving (#1003)
Fix #988

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

---------

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

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

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

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

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

---------

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

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

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

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

After:  

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

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

---------

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

* update email address
2023-02-13 09:05:52 +01:00
WerWolv
61ce88ba9b build: Fix build on systems that have no backtrace or execinfo
Fixes #932
2023-02-13 08:27:08 +01:00
WerWolv
4b451fd1d3 patterns: Fixed pattern data rows not being selectable when color column is hidden 2023-02-13 08:26:43 +01:00
WerWolv
a87190960f build: Fixed one more missing imhex target name 2023-02-12 22:08:35 +01:00
WerWolv
45558027a6 git: Fixed release workflow 2023-02-12 21:55:22 +01:00
WerWolv
e426606542 build: Fixed flatpak build issues 2023-02-12 21:55:09 +01:00
157 changed files with 7947 additions and 4764 deletions

View File

@@ -70,19 +70,21 @@ jobs:
mkdir -p build
cd build
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
..
mingw32-make -j4 install
cpack
mv imhex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
@@ -179,12 +181,14 @@ jobs:
mkdir build
cd build
cmake \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
cmake \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
..
make -j 4 install
@@ -193,22 +197,24 @@ jobs:
run: |
mkdir -p build
cd build
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.10" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
MACOSX_DEPLOYMENT_TARGET="10.10" \
cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
..
make -j4 package
@@ -260,6 +266,8 @@ jobs:
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
..
make -j 4 install DESTDIR=DebDir
@@ -330,6 +338,8 @@ jobs:
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
-DIMHEX_PLUGINS_IN_SHARE=ON \
-DIMHEX_USE_BUNDLED_CA=ON \
@@ -410,6 +420,8 @@ jobs:
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
-DUSE_SYSTEM_CAPSTONE=OFF \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
..
make -j 4 install DESTDIR=installDir
@@ -456,6 +468,10 @@ jobs:
mock_release: rawhide
release_num: rawhide
mock_config: fedora-rawhide
- name: Fedora
mock_release: f38
release_num: 38
mock_config: fedora-38
- name: Fedora
mock_release: f37
release_num: 37
@@ -515,7 +531,7 @@ jobs:
- name: 🗜️ Create tarball from sources with dependencies
run: tar --exclude-vcs -czf $GITHUB_WORKSPACE/imhex-$IMHEX_VERSION.tar.gz ImHex
- name: "✒️ Modify spec file: set version, use latest pattern language, enable online build"
- name: ✒️ Modify spec file
run: |
sed -i \
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
@@ -546,9 +562,9 @@ jobs:
uses: actions/cache@v3
with:
path: /var/cache/mock
key: ${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
restore-keys: |
${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-mock-
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-
# Fedora cmake build (in imhex.spec)
- name: 📦 Build RPM

View File

@@ -9,9 +9,54 @@ on:
workflow_dispatch:
jobs:
release-common:
release-update-repos:
runs-on: ubuntu-latest
name: Release Common
name: Release Update Repos
steps:
- name: 🎫 Create PatternLanguage release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: PatternLanguage
token: ${{ secrets.RELEASE_TOKEN }}
- name: 🎫 Create ImHex-Patterns release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }}
- name: ✉️ Update C++ Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Cpp-Plugin-Template
event-type: update_submodule
- name: ✉️ Update Rust Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Rust-Plugin-Template
event-type: update_submodule
release-upload-artifacts:
runs-on: ubuntu-latest
name: Release Upload Artifacts
steps:
- name: 🧰 Checkout
@@ -71,15 +116,14 @@ jobs:
- name: ✒️ Prepare PKGBUILD
run: |
cp ImHex/dist/Arch/PKGBUILD .
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst-x86_64 | cut -d ' ' -f 1`
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
sed -i 's/%version%/${{env.IMHEX_VERSION}}/g' PKGBUILD
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
- name: ⬆️ Publish AUR package
# I couldn't make the condition in the env directly for some reason
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
if: "${{ env.AUR_SSH_PRIVATE_KEY != '' }}"
@@ -94,55 +138,15 @@ jobs:
commit_message: Bump to version ${{env.IMHEX_VERSION}}
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
- name: 🎫 Create PatternLanguage release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: PatternLanguage
token: ${{ secrets.RELEASE_TOKEN }}
- name: 🎫 Create ImHex-Patterns release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: ImHex-v${{env.IMHEX_VERSION}}
repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }}
- name: ✉️ Update C++ Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Cpp-Plugin-Template
event_type: update_submodule
- name: ✉️ Update Rust Plugin Template
uses: peter-evans/repository-dispatch@v2
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
token: ${{ secrets.RELEASE_TOKEN }}
repository: WerWolv/ImHex-Rust-Plugin-Template
event_type: update_submodule
release-windows:
name: Release Windows
needs: release-common
runs-on: windows-2022
release-update-winget:
name: Release update winget package
needs: release-upload-artifacts
runs-on: windows-latest
steps:
- name: ⬇️ Download dependencies
shell: pwsh
run: |
iwr https://github.com/microsoft/winget-create/releases/download/v1.1.2.0/wingetcreate.exe -OutFile wingetcreate.exe
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
- name: ⬆️ Update winget manifest
shell: pwsh
env:

3
.gitmodules vendored
View File

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

View File

@@ -9,6 +9,7 @@ option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
# Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23)
@@ -48,7 +49,7 @@ addBundledLibraries()
# Add ImHex sources
add_subdirectory(lib/libimhex)
add_subdirectory(main)
add_custom_target(imhex ALL DEPENDS main libimhex)
add_custom_target(imhex_all ALL DEPENDS main libimhex)
# Add unit tests
enable_testing()

View File

@@ -25,6 +25,9 @@
<a title="Translation" href="https://weblate.werwolv.net/projects/imhex/">
<img alt="Translation" src="https://img.shields.io/weblate/progress/imhex?logo=weblate&logoColor=%23FFFFFF&server=https%3A%2F%2Fweblate.werwolv.net&style=for-the-badge">
</a>
<a title="Documentation" href="https://imhex.werwolv.net/docs">
<img alt="Documentation" src="https://img.shields.io/badge/Docs-Available-green?logo=gitbook&logoColor=%23FFFFFF&style=for-the-badge">
</a>
</p>
## Supporting

View File

@@ -1 +1 @@
1.27.0
1.28.0

View File

@@ -14,13 +14,16 @@ macro(addVersionDefines)
message(FATAL_ERROR "IMHEX_VERSION is not defined")
endif ()
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/.git")
if (DEFINED IMHEX_COMMIT_HASH AND DEFINED IMHEX_COMMIT_BRANCH)
add_compile_definitions(GIT_COMMIT_HASH="${IMHEX_COMMIT_HASH}" GIT_BRANCH="${IMHEX_COMMIT_BRANCH}")
else()
# Get the current working branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_BRANCH
)
# Get the latest abbreviated commit hash of the working branch
@@ -29,9 +32,12 @@ macro(addVersionDefines)
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH
)
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
if (RESULT_BRANCH EQUAL 0 AND RESULT_HASH EQUAL 0)
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
endif ()
endif ()
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
@@ -60,7 +66,9 @@ macro(detectOS)
set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins")
SET(IMHEX_USE_BUNDLED_CA ON)
if (NOT USE_SYSTEM_CURL)
SET(IMHEX_USE_BUNDLED_CA ON)
endif ()
elseif (APPLE)
add_compile_definitions(OS_MACOS)
set(CMAKE_INSTALL_BINDIR ".")
@@ -114,7 +122,7 @@ macro(configurePackingResources)
if (CREATE_PACKAGE)
set(CPACK_GENERATOR "WIX")
set(CPACK_PACKAGE_NAME "imhex")
set(CPACK_PACKAGE_NAME "ImHex")
set(CPACK_PACKAGE_VENDOR "WerWolv")
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
@@ -185,7 +193,7 @@ macro(createPackage)
endif ()
endif ()
add_dependencies(imhex ${plugin})
add_dependencies(imhex_all ${plugin})
endif ()
endforeach()
@@ -256,7 +264,7 @@ macro(createPackage)
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
# 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 "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
@@ -269,7 +277,7 @@ macro(createPackage)
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
# Update library references to make the bundle portable
postprocess_bundle(imhex main)
postprocess_bundle(imhex_all main)
# Enforce DragNDrop packaging.
set(CPACK_GENERATOR "DragNDrop")
@@ -384,7 +392,7 @@ endfunction()
macro(setupCompilerWarnings target)
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow")
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-array-bounds")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
@@ -419,6 +427,13 @@ macro(addBundledLibraries)
add_subdirectory(${EXTERN_LIBS_FOLDER}/intervaltree EXCLUDE_FROM_ALL)
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${EXTERN_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
set(CURL_USE_MBEDTLS ON)
set(BUILD_CURL_EXE OFF)
@@ -515,25 +530,27 @@ macro(addBundledLibraries)
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
endif()
if (WIN32)
message(STATUS "StackWalk enabled!")
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
else ()
find_package(Backtrace)
if (${Backtrace_FOUND})
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
if (NOT IMHEX_DISABLE_STACKTRACE)
if (WIN32)
message(STATUS "StackWalk enabled!")
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
else ()
find_package(Backtrace)
if (${Backtrace_FOUND})
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
if (Backtrace_HEADER STREQUAL "execinfo.h")
set(LIBBACKTRACE_LIBRARIES)
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(HEX_HAS_EXECINFO)
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
set(LIBBACKTRACE_LIBRARIES backtrace)
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(HEX_HAS_BACKTRACE)
endif ()
endif()
if (Backtrace_HEADER STREQUAL "execinfo.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(HEX_HAS_EXECINFO)
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
add_compile_definitions(HEX_HAS_BACKTRACE)
endif ()
endif()
endif ()
endif ()
endmacro()

2
dist/Arch/PKGBUILD vendored
View File

@@ -1,4 +1,4 @@
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
# Maintainer: iTrooz_ <hey at itrooz dot fr>
# Contributor: Morten Linderud <foxboron@archlinux.org>
pkgname=imhex-bin

2
dist/Dockerfile vendored
View File

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

2
dist/rpm/imhex.spec vendored
View File

@@ -131,5 +131,3 @@ cp -a lib/external/xdgpp/LICENSE %{buildroot}%{
%changelog
* Thu Jan 01 1970 ImHex GitHub CI - 0.0.0-0
- Build Package

View File

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

View File

@@ -820,7 +820,12 @@ static void ImGui_ImplGlfw_UpdateMonitors()
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
int monitors_count = 0;
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
platform_io.Monitors.resize(0);
// IMHEX PATCH BEGIN
if (monitors_count > 0)
platform_io.Monitors.resize(0);
// IMHEX PATCH END
for (int n = 0; n < monitors_count; n++)
{
ImGuiPlatformMonitor monitor;

View File

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

1
lib/external/libwolv vendored Submodule

Submodule lib/external/libwolv added at 34d36a2f33

View File

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

View File

@@ -23,10 +23,8 @@ set(LIBIMHEX_SOURCES
source/helpers/fs.cpp
source/helpers/magic.cpp
source/helpers/crypto.cpp
source/helpers/net.cpp
source/helpers/http_requests.cpp
source/helpers/opengl.cpp
source/helpers/file.cpp
source/helpers/socket.cpp
source/helpers/patches.cpp
source/helpers/encoding_file.cpp
source/helpers/logger.cpp
@@ -49,9 +47,7 @@ if (APPLE)
endif ()
endif ()
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
source/helpers/fs_macos.m
source/helpers/utils_macos.m)
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_macos.m)
endif ()
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
@@ -72,4 +68,4 @@ elseif (APPLE)
endif ()
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl intervaltree ${MINIAUDIO_LIBRARIES})
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl intervaltree ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash)

View File

@@ -41,87 +41,206 @@ namespace hex {
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
namespace Settings {
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
struct Entry {
std::string name;
bool requiresRestart;
Callback callback;
};
namespace impl {
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
struct Category {
std::string name;
size_t slot = 0;
struct Entry {
std::string name;
bool requiresRestart;
Callback callback;
};
bool operator<(const Category &other) const {
return name < other.name;
}
struct Category {
std::string name;
size_t slot = 0;
explicit operator const std::string &() const {
return name;
}
};
bool operator<(const Category &other) const {
return name < other.name;
}
void load();
void store();
void clear();
explicit operator const std::string &() const {
return name;
}
};
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart = false);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart = false);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart = false);
void load();
void store();
void clear();
std::map<Category, std::vector<Entry>> &getEntries();
std::map<std::string, std::string> &getCategoryDescriptions();
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
nlohmann::json &getSettingsData();
}
/**
* @brief Adds a new integer setting entry
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @param callback The callback that will be called when the settings item in the preferences window is rendered
* @param requiresRestart Whether the setting requires a restart to take effect
*/
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart = false);
/**
* @brief Adds a new string setting entry
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @param callback The callback that will be called when the settings item in the preferences window is rendered
* @param requiresRestart Whether the setting requires a restart to take effect
*/
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
/**
* @brief Adds a new string list setting entry
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @param callback The callback that will be called when the settings item in the preferences window is rendered
* @param requiresRestart Whether the setting requires a restart to take effect
*/
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
/**
* @brief Adds a description to a given category
* @param unlocalizedCategory The name of the category
* @param unlocalizedCategoryDescription The description of the category
*/
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription);
/**
* @brief Writes a integer value to the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param value The value to write
*/
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value);
/**
* @brief Writes a string value to the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param value The value to write
*/
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
/**
* @brief Writes a string list value to the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param value The value to write
*/
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value);
/**
* @brief Reads an integer value from the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @return The value of the setting
*/
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue);
/**
* @brief Reads a string value from the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @return The value of the setting
*/
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
/**
* @brief Reads a string list value from the settings file
* @param unlocalizedCategory The category of the setting
* @param unlocalizedName The name of the setting
* @param defaultValue The default value of the setting
* @return The value of the setting
*/
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue = {});
std::map<Category, std::vector<Entry>> &getEntries();
std::map<std::string, std::string> &getCategoryDescriptions();
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
nlohmann::json &getSettingsData();
}
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
namespace CommandPaletteCommands {
enum class Type : u32
{
enum class Type : u32 {
SymbolCommand,
KeywordCommand
};
using DisplayCallback = std::function<std::string(std::string)>;
using ExecuteCallback = std::function<void(std::string)>;
namespace impl {
struct Entry {
Type type;
std::string command;
std::string unlocalizedDescription;
DisplayCallback displayCallback;
ExecuteCallback executeCallback;
};
struct QueryResult {
std::string name;
std::function<void(std::string)> callback;
};
using DisplayCallback = std::function<std::string(std::string)>;
using ExecuteCallback = std::function<void(std::string)>;
using QueryCallback = std::function<std::vector<QueryResult>(std::string)>;
struct Entry {
Type type;
std::string command;
std::string unlocalizedDescription;
DisplayCallback displayCallback;
ExecuteCallback executeCallback;
};
struct Handler {
Type type;
std::string command;
QueryCallback queryCallback;
DisplayCallback displayCallback;
};
std::vector<impl::Entry> &getEntries();
std::vector<impl::Handler> &getHandlers();
}
/**
* @brief Adds a new command to the command palette
* @param type The type of the command
* @param command The command to add
* @param unlocalizedDescription The description of the command
* @param displayCallback The callback that will be called when the command is displayed in the command palette
* @param executeCallback The callback that will be called when the command is executed
*/
void add(
Type type,
const std::string &command,
const std::string &unlocalizedDescription,
const DisplayCallback &displayCallback,
const ExecuteCallback &executeCallback = [](auto) {});
std::vector<Entry> &getEntries();
const impl::DisplayCallback &displayCallback,
const impl::ExecuteCallback &executeCallback = [](auto) {});
/**
* @brief Adds a new command handler to the command palette
* @param type The type of the command
* @param command The command to add
* @param unlocalizedDescription The description of the command
* @param queryCallback The callback that will be called when the command palette wants to load the name and callback items
* @param displayCallback The callback that will be called when the command is displayed in the command palette
*/
void addHandler(
Type type,
const std::string &command,
const impl::QueryCallback &queryCallback,
const impl::DisplayCallback &displayCallback);
}
/* Pattern Language Function Registry. Allows adding of new functions that may be used inside the pattern language */
namespace PatternLanguage {
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::Iteratable&, bool, std::span<const pl::core::Token::Literal>)>;
namespace impl {
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::Iteratable&, bool, std::span<const pl::core::Token::Literal>)>;
struct FunctionDefinition {
pl::api::Namespace ns;
std::string name;
@@ -138,20 +257,52 @@ namespace hex {
};
std::map<std::string, Visualizer> &getVisualizers();
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
std::vector<impl::FunctionDefinition> &getFunctions();
}
/**
* @brief Configures the pattern language runtime using ImHex's default settings
* @param runtime The pattern language runtime to configure
* @param provider The provider to use for data access
*/
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider);
/**
* @brief Adds a new pragma to the pattern language
* @param name The name of the pragma
* @param handler The handler that will be called when the pragma is encountered
*/
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
/**
* @brief Adds a new function to the pattern language
* @param ns The namespace of the function
* @param name The name of the function
* @param parameterCount The amount of parameters the function takes
* @param func The function callback
*/
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
/**
* @brief Adds a new dangerous function to the pattern language
* @note Dangerous functions are functions that require the user to explicitly allow them to be used
* @param ns The namespace of the function
* @param name The name of the function
* @param parameterCount The amount of parameters the function takes
* @param func The function callback
*/
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
void addVisualizer(const std::string &name, const VisualizerFunctionCallback &func, u32 parameterCount);
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
std::vector<impl::FunctionDefinition> &getFunctions();
/**
* @brief Adds a new visualizer to the pattern language
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
* @param name The name of the visualizer
* @param func The function callback
* @param parameterCount The amount of parameters the function takes
*/
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &func, u32 parameterCount);
}
@@ -161,18 +312,27 @@ namespace hex {
namespace impl {
void add(View *view);
std::map<std::string, View *> &getEntries();
}
/**
* @brief Adds a new view to ImHex
* @tparam T The custom view class that extends View
* @tparam Args Arguments types
* @param args Arguments passed to the constructor of the view
*/
template<std::derived_from<View> T, typename... Args>
void add(Args &&...args) {
return impl::add(new T(std::forward<Args>(args)...));
}
std::map<std::string, View *> &getEntries();
/**
* @brief Gets a view by its unlocalized name
* @param unlocalizedName The unlocalized name of the view
* @return The view if it exists, nullptr otherwise
*/
View *getViewByName(const std::string &unlocalizedName);
}
/* Tools Registry. Allows adding new entries to the tools window */
@@ -188,11 +348,16 @@ namespace hex {
bool detached;
};
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new tool to the tools window
* @param unlocalizedName The unlocalized name of the tool
* @param function The function that will be called to draw the tool
*/
void add(const std::string &unlocalizedName, const impl::Callback &function);
std::vector<impl::Entry> &getEntries();
}
/* Data Inspector Registry. Allows adding of new types to the data inspector */
@@ -219,12 +384,28 @@ namespace hex {
std::optional<impl::EditingFunction> editingFunction;
};
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new entry to the data inspector
* @param unlocalizedName The unlocalized name of the entry
* @param requiredSize The minimum required number of bytes available for the entry to appear
* @param displayGeneratorFunction The function that will be called to generate the display function
* @param editingFunction The function that will be called to edit the data
*/
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
std::vector<impl::Entry> &getEntries();
/**
* @brief Adds a new entry to the data inspector
* @param unlocalizedName The unlocalized name of the entry
* @param requiredSize The minimum required number of bytes available for the entry to appear
* @param maxSize The maximum number of bytes to read from the data
* @param displayGeneratorFunction The function that will be called to generate the display function
* @param editingFunction The function that will be called to edit the data
*/
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
}
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
@@ -242,9 +423,18 @@ namespace hex {
void add(const Entry &entry);
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new node to the data processor
* @tparam T The custom node class that extends dp::Node
* @tparam Args Arguments types
* @param unlocalizedCategory The unlocalized category name of the node
* @param unlocalizedName The unlocalized name of the node
* @param args Arguments passed to the constructor of the node
*/
template<std::derived_from<dp::Node> T, typename... Args>
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
add(impl::Entry {
@@ -258,18 +448,29 @@ namespace hex {
});
}
/**
* @brief Adds a separator to the data processor right click menu
*/
void addSeparator();
std::vector<impl::Entry> &getEntries();
}
/* Language Registry. Allows together with the LangEntry class and the _lang user defined literal to add new languages */
namespace Language {
/**
* @brief Loads localization information from json data
* @param data The language data
*/
void addLocalization(const nlohmann::json &data);
std::map<std::string, std::string> &getLanguages();
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
namespace impl {
std::map<std::string, std::string> &getLanguages();
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
}
}
/* Interface Registry. Allows adding new items to various interfaces */
@@ -277,9 +478,11 @@ namespace hex {
namespace impl {
using DrawCallback = std::function<void()>;
using LayoutFunction = std::function<void(u32)>;
using ClickCallback = std::function<void()>;
using DrawCallback = std::function<void()>;
using MenuCallback = std::function<void()>;
using EnabledCallback = std::function<bool()>;
using LayoutFunction = std::function<void(u32)>;
using ClickCallback = std::function<void()>;
struct Layout {
std::string unlocalizedName;
@@ -291,8 +494,10 @@ namespace hex {
};
struct MenuItem {
std::string unlocalizedName;
DrawCallback callback;
std::vector<std::string> unlocalizedNames;
Shortcut shortcut;
MenuCallback callback;
EnabledCallback enabledCallback;
};
struct SidebarItem {
@@ -306,29 +511,99 @@ namespace hex {
ClickCallback callback;
};
constexpr static auto SeparatorValue = "$SEPARATOR$";
constexpr static auto SubMenuValue = "$SUBMENU$";
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems();
std::multimap<u32, impl::MenuItem> &getMenuItems();
std::vector<impl::DrawCallback> &getWelcomeScreenEntries();
std::vector<impl::DrawCallback> &getFooterItems();
std::vector<impl::DrawCallback> &getToolbarItems();
std::vector<impl::SidebarItem> &getSidebarItems();
std::vector<impl::TitleBarButton> &getTitleBarButtons();
std::vector<impl::Layout> &getLayouts();
}
/**
* @brief Adds a new top-level main menu entry
* @param unlocalizedName The unlocalized name of the entry
* @param priority The priority of the entry. Lower values are displayed first
*/
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority);
void addMenuItem(const std::string &unlocalizedMainMenuName, u32 priority, const impl::DrawCallback &function);
/**
* @brief Adds a new main menu entry
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
* @param priority The priority of the entry. Lower values are displayed first
* @param shortcut The shortcut to use for the entry
* @param function The function to call when the entry is clicked
* @param enabledCallback The function to call to determine if the entry is enabled
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
*/
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; }, View *view = nullptr);
/**
* @brief Adds a new main menu sub-menu entry
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
* @param priority The priority of the entry. Lower values are displayed first
* @param function The function to call when the entry is clicked
* @param enabledCallback The function to call to determine if the entry is enabled
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
*/
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; });
/**
* @brief Adds a new main menu separator
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
* @param priority The priority of the entry. Lower values are displayed first
*/
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority);
/**
* @brief Adds a new welcome screen entry
* @param function The function to call to draw the entry
*/
void addWelcomeScreenEntry(const impl::DrawCallback &function);
/**
* @brief Adds a new footer item
* @param function The function to call to draw the item
*/
void addFooterItem(const impl::DrawCallback &function);
/**
* @brief Adds a new toolbar item
* @param function The function to call to draw the item
*/
void addToolbarItem(const impl::DrawCallback &function);
/**
* @brief Adds a new sidebar item
* @param icon The icon to use for the item
* @param function The function to call to draw the item
*/
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function);
/**
* @brief Adds a new title bar button
* @param icon The icon to use for the button
* @param unlocalizedTooltip The unlocalized tooltip to use for the button
* @param function The function to call when the button is clicked
*/
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function);
/**
* @brief Adds a new layout definition to the Layout menu
* @param unlocalizedName The unlocalized name of the layout
* @param function The function to call to setup the layout
*/
void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function);
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems();
std::multimap<u32, impl::MenuItem> &getMenuItems();
std::vector<impl::DrawCallback> &getWelcomeScreenEntries();
std::vector<impl::DrawCallback> &getFooterItems();
std::vector<impl::DrawCallback> &getToolbarItems();
std::vector<impl::SidebarItem> &getSidebarItems();
std::vector<impl::TitleBarButton> &getTitleBarButtons();
std::vector<impl::Layout> &getLayouts();
}
/* Provider Registry. Allows adding new data providers to be created from the UI */
@@ -338,8 +613,15 @@ namespace hex {
void addProviderName(const std::string &unlocalizedName);
std::vector<std::string> &getEntries();
}
/**
* @brief Adds a new provider to the list of providers
* @tparam T The provider type that extends hex::prv::Provider
* @param addToList Whether to display the provider in the Other Providers list in the welcome screen and File menu
*/
template<std::derived_from<hex::prv::Provider> T>
void add(bool addToList = true) {
auto typeName = T().getTypeName();
@@ -359,10 +641,9 @@ namespace hex {
impl::addProviderName(typeName);
}
std::vector<std::string> &getEntries();
}
/* Data Formatter Registry. Allows adding formatters that are used in the Copy-As menu for example */
namespace DataFormatter {
namespace impl {
@@ -373,32 +654,45 @@ namespace hex {
Callback callback;
};
std::vector<impl::Entry> &getEntries();
}
void add(const std::string &unlocalizedName, const impl::Callback &callback);
std::vector<impl::Entry> &getEntries();
/**
* @brief Adds a new data formatter
* @param unlocalizedName The unlocalized name of the formatter
* @param callback The function to call to format the data
*/
void add(const std::string &unlocalizedName, const impl::Callback &callback);
}
/* File Handler Registry. Allows adding handlers for opening files specific file types */
namespace FileHandler {
namespace impl {
using Callback = std::function<bool(std::filesystem::path)>;
using Callback = std::function<bool(std::fs::path)>;
struct Entry {
std::vector<std::string> extensions;
Callback callback;
};
std::vector<impl::Entry> &getEntries();
}
/**
* @brief Adds a new file handler
* @param extensions The file extensions to handle
* @param callback The function to call to handle the file
*/
void add(const std::vector<std::string> &extensions, const impl::Callback &callback);
std::vector<impl::Entry> &getEntries();
}
/* Hex Editor Registry. Allows adding new functionality to the hex editor */
namespace HexEditor {
class DataVisualizer {
@@ -417,7 +711,8 @@ namespace hex {
protected:
const static int TextInputFlags;
bool drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
bool drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
bool drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const;
private:
u16 m_bytesPerCell;
u16 m_maxCharsPerCell;
@@ -431,6 +726,12 @@ namespace hex {
}
/**
* @brief Adds a new cell data visualizer
* @tparam T The data visualizer type that extends hex::DataVisualizer
* @param unlocalizedName The unlocalized name of the data visualizer
* @param args The arguments to pass to the constructor of the data visualizer
*/
template<std::derived_from<DataVisualizer> T, typename... Args>
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
@@ -438,6 +739,7 @@ namespace hex {
}
/* Hash Registry. Allows adding new hashes to the Hash view */
namespace Hashes {
class Hash {
@@ -503,6 +805,12 @@ namespace hex {
void add(Hash* hash);
}
/**
* @brief Adds a new hash
* @tparam T The hash type that extends hex::Hash
* @param args The arguments to pass to the constructor of the hash
*/
template<typename T, typename ... Args>
void add(Args && ... args) {
impl::add(new T(std::forward<Args>(args)...));

View File

@@ -10,68 +10,98 @@
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/fs.hpp>
#define EVENT_DEF(event_name, ...) \
struct event_name final : public hex::Event<__VA_ARGS__> { \
constexpr static auto id = [] { return hex::EventId(); }(); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
#define EVENT_DEF(event_name, ...) \
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
constexpr static auto id = [] { return hex::impl::EventId(); }(); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
}
struct GLFWwindow;
namespace hex {
class EventId {
public:
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
this->m_hash = line ^ 987654321;
for (auto c : std::string_view(func)) {
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
this->m_hash ^= c;
namespace impl {
class EventId {
public:
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
this->m_hash = line ^ 987654321;
for (auto c : std::string_view(func)) {
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
this->m_hash ^= c;
}
}
}
constexpr bool operator==(const EventId &rhs) const = default;
constexpr bool operator==(const EventId &rhs) const = default;
private:
u32 m_hash;
};
private:
u32 m_hash;
};
struct EventBase {
EventBase() noexcept = default;
};
struct EventBase {
EventBase() noexcept = default;
};
template<typename... Params>
struct Event : public EventBase {
using Callback = std::function<void(Params...)>;
template<typename... Params>
struct Event : public EventBase {
using Callback = std::function<void(Params...)>;
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
void operator()(Params... params) const noexcept {
this->m_func(params...);
}
void operator()(Params... params) const noexcept {
this->m_func(params...);
}
private:
Callback m_func;
};
private:
Callback m_func;
};
}
/**
* @brief The EventManager allows subscribing to and posting events to different parts of the program.
* To create a new event, use the EVENT_DEF macro. This will create a new event type with the given name and parameters
*/
class EventManager {
public:
using EventList = std::list<std::pair<EventId, EventBase *>>;
using EventList = std::list<std::pair<impl::EventId, impl::EventBase *>>;
/**
* @brief Subscribes to an event
* @tparam E Event
* @param function Function to call when the event is posted
* @return Token to unsubscribe from the event
*/
template<typename E>
static EventList::iterator subscribe(typename E::Callback function) {
return s_events.insert(s_events.end(), std::make_pair(E::id, new E(function)));
}
/**
* @brief Subscribes to an event
* @tparam E Event
* @param token Unique token to register the event to. Later required to unsubscribe again
* @param function Function to call when the event is posted
*/
template<typename E>
static void subscribe(void *token, typename E::Callback function) {
s_tokenStore.insert(std::make_pair(token, subscribe<E>(function)));
}
static void unsubscribe(EventList::iterator iter) noexcept {
s_events.remove(*iter);
/**
* @brief Unsubscribes from an event
* @param token Token returned by subscribe
*/
static void unsubscribe(const EventList::iterator &token) noexcept {
s_events.remove(*token);
}
/**
* @brief Unsubscribes from an event
* @tparam E Event
* @param token Token passed to subscribe
*/
template<typename E>
static void unsubscribe(void *token) noexcept {
auto iter = std::find_if(s_tokenStore.begin(), s_tokenStore.end(), [&](auto &item) {
@@ -85,6 +115,11 @@ namespace hex {
}
/**
* @brief Posts an event to all subscribers of it
* @tparam E Event
* @param args Arguments to pass to the event
*/
template<typename E>
static void post(auto &&...args) noexcept {
for (const auto &[id, event] : s_events) {
@@ -93,6 +128,9 @@ namespace hex {
}
}
/**
* @brief Unsubscribe all subscribers from all events
*/
static void clear() noexcept {
s_events.clear();
s_tokenStore.clear();
@@ -127,6 +165,8 @@ namespace hex {
EVENT_DEF(RequestSelectionChange, Region);
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t);
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
EVENT_DEF(RequestUpdateWindowTitle);
EVENT_DEF(RequestCloseImHex, bool);
EVENT_DEF(RequestRestartImHex);
@@ -134,6 +174,7 @@ namespace hex {
EVENT_DEF(RequestChangeTheme, std::string);
EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);
EVENT_DEF(RequestInitThemeHandlers);
EVENT_DEF(RequestShowInfoPopup, std::string);
EVENT_DEF(RequestShowErrorPopup, std::string);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,7 @@
#include <hex/data_processor/attribute.hpp>
#include <set>
#include <span>
#include <string_view>
#include <vector>
@@ -77,7 +78,7 @@ namespace hex::dp {
const i128& getIntegerOnInput(u32 index);
const long double& getFloatOnInput(u32 index);
void setBufferOnOutput(u32 index, const std::vector<u8> &data);
void setBufferOnOutput(u32 index, std::span<const u8> data);
void setIntegerOnOutput(u32 index, i128 integer);
void setFloatOnOutput(u32 index, long double floatingPoint);

View File

@@ -20,10 +20,16 @@ namespace hex {
TMS320C64X,
M680X,
EVM,
MOS65XX,
WASM,
#if defined(CS_MODE_RISCV32)
RISCV,
#endif
#if defined(CS_MODE_MOS65XX_6502)
MOS65XX,
#endif
#if defined(CS_MODE_BPF_CLASSIC)
BPF,
RISCV,
#endif
MAX,
MIN = ARM

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -75,6 +75,13 @@ namespace hex::gl {
return copy;
}
auto operator==(const Vector<T, Size>& other) {
for (size_t i = 0; i < Size; i++)
if (this->m_data[i] != other[i])
return false;
return true;
}
private:
std::array<T, Size> m_data;
};

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,6 +16,9 @@
namespace hex::prv {
/**
* @brief Represent the data source for a tab
*/
class Provider {
public:
constexpr static size_t PageSize = 0x1000'0000;
@@ -29,7 +32,21 @@ namespace hex::prv {
[[nodiscard]] virtual bool isResizable() const = 0;
[[nodiscard]] virtual bool isSavable() const = 0;
/**
* @brief Read data from this provider, applying overlays and patches
* @param offset offset to start reading the data
* @param buffer buffer to write read data
* @param size number of bytes to read
* @param overlays apply overlays and patches is true. Same as readRaw() if false
*/
virtual void read(u64 offset, void *buffer, size_t size, bool overlays = true);
/**
* @brief Write data to the patches of this provider. Will not directly modify provider.
* @param offset offset to start writing the data
* @param buffer buffer to take data to write from
* @param size number of bytes to write
*/
virtual void write(u64 offset, const void *buffer, size_t size);
virtual void resize(size_t newSize);
@@ -39,7 +56,19 @@ namespace hex::prv {
virtual void save();
virtual void saveAs(const std::fs::path &path);
/**
* @brief Read data from this provider, without applying overlays and patches
* @param offset offset to start reading the data
* @param buffer buffer to write read data
* @param size number of bytes to read
*/
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
/**
* @brief Write data directly to this provider
* @param offset offset to start writing the data
* @param buffer buffer to take data to write from
* @param size number of bytes to write
*/
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
[[nodiscard]] virtual size_t getActualSize() const = 0;
@@ -84,7 +113,7 @@ namespace hex::prv {
[[nodiscard]] virtual bool hasLoadInterface() const;
[[nodiscard]] virtual bool hasInterface() const;
virtual void drawLoadInterface();
virtual bool drawLoadInterface();
virtual void drawInterface();
[[nodiscard]] u32 getID() const;
@@ -103,6 +132,9 @@ namespace hex::prv {
void skipLoadInterface() { this->m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
void setErrorMessage(const std::string &errorMessage) { this->m_errorMessage = errorMessage; }
[[nodiscard]] const std::string& getErrorMessage() const { return this->m_errorMessage; }
protected:
u32 m_currPage = 0;
u64 m_baseAddress = 0;
@@ -116,6 +148,8 @@ namespace hex::prv {
bool m_dirty = false;
bool m_skipLoadInterface = false;
std::string m_errorMessage;
private:
static u32 s_idCounter;
};

View File

@@ -1,17 +1,16 @@
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/ui/view.hpp>
#include <hex/data_processor/node.hpp>
#include <filesystem>
#include <fstream>
#include <nlohmann/json.hpp>
#include <hex/data_processor/node.hpp>
#include <wolv/io/file.hpp>
namespace hex {
@@ -19,58 +18,89 @@ namespace hex {
constexpr auto SettingsFile = "settings.json";
void load() {
bool loaded = false;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
fs::File file(dir / SettingsFile, fs::File::Mode::Read);
namespace impl {
if (file.isValid()) {
getSettingsData() = nlohmann::json::parse(file.readString());
loaded = true;
break;
std::map<Category, std::vector<Entry>> &getEntries() {
static std::map<Category, std::vector<Entry>> entries;
return entries;
}
std::map<std::string, std::string> &getCategoryDescriptions() {
static std::map<std::string, std::string> descriptions;
return descriptions;
}
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
auto &settings = getSettingsData();
if (!settings.contains(unlocalizedCategory)) return {};
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
return settings[unlocalizedCategory][unlocalizedName];
}
nlohmann::json &getSettingsData() {
static nlohmann::json settings;
return settings;
}
void load() {
bool loaded = false;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
if (file.isValid()) {
getSettingsData() = nlohmann::json::parse(file.readString());
loaded = true;
break;
}
}
if (!loaded)
store();
}
void store() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
if (file.isValid()) {
file.writeString(getSettingsData().dump(4));
break;
}
}
}
if (!loaded)
store();
}
void store() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
fs::File file(dir / SettingsFile, fs::File::Mode::Create);
if (file.isValid()) {
file.write(getSettingsData().dump(4));
break;
void clear() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::fs::remove(dir / SettingsFile);
}
}
}
void clear() {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
hex::fs::remove(dir / SettingsFile);
}
}
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
auto &entries = getEntries();
const size_t curSlot = entries.size();
auto found = entries.find(Category { unlocalizedCategory });
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
auto &entries = getEntries();
const size_t curSlot = entries.size();
auto found = entries.find(Category { unlocalizedCategory });
if (found == entries.end()) {
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
return iter;
}
if (found == entries.end()) {
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
return iter;
return found;
}
return found;
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart) {
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart) {
log::debug("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -78,12 +108,12 @@ namespace hex {
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart) {
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart) {
log::debug("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -91,12 +121,12 @@ namespace hex {
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
}
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart) {
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart) {
log::debug("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -105,11 +135,11 @@ namespace hex {
}
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
impl::getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
}
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -118,7 +148,7 @@ namespace hex {
}
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -127,7 +157,7 @@ namespace hex {
}
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
json[unlocalizedCategory] = nlohmann::json::object();
@@ -137,7 +167,7 @@ namespace hex {
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
return defaultValue;
@@ -151,7 +181,7 @@ namespace hex {
}
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
return defaultValue;
@@ -165,7 +195,7 @@ namespace hex {
}
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue) {
auto &json = getSettingsData();
auto &json = impl::getSettingsData();
if (!json.contains(unlocalizedCategory))
return defaultValue;
@@ -181,49 +211,37 @@ namespace hex {
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
}
std::map<Category, std::vector<Entry>> &getEntries() {
static std::map<Category, std::vector<Entry>> entries;
return entries;
}
std::map<std::string, std::string> &getCategoryDescriptions() {
static std::map<std::string, std::string> descriptions;
return descriptions;
}
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
auto &settings = getSettingsData();
if (!settings.contains(unlocalizedCategory)) return {};
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
return settings[unlocalizedCategory][unlocalizedName];
}
nlohmann::json &getSettingsData() {
static nlohmann::json settings;
return settings;
}
}
namespace ContentRegistry::CommandPaletteCommands {
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const DisplayCallback &displayCallback, const ExecuteCallback &executeCallback) {
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
log::debug("Registered new command palette command: {}", command);
getEntries().push_back(ContentRegistry::CommandPaletteCommands::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
impl::getEntries().push_back(ContentRegistry::CommandPaletteCommands::impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
}
std::vector<Entry> &getEntries() {
static std::vector<Entry> commands;
void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) {
log::debug("Registered new command palette command handler: {}", command);
impl::getHandlers().push_back(ContentRegistry::CommandPaletteCommands::impl::Handler { type, command, queryCallback, displayCallback });
}
namespace impl {
std::vector<Entry> &getEntries() {
static std::vector<Entry> commands;
return commands;
}
std::vector<Handler> &getHandlers() {
static std::vector<Handler> commands;
return commands;
}
return commands;
}
}
@@ -258,14 +276,14 @@ namespace hex {
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
for (const auto &func : getFunctions()) {
for (const auto &func : impl::getFunctions()) {
if (func.dangerous)
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
else
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
}
for (const auto &[name, callback] : getPragmas()) {
for (const auto &[name, callback] : impl::getPragmas()) {
runtime.addPragma(name, callback);
}
@@ -276,13 +294,13 @@ namespace hex {
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
log::debug("Registered new pattern language pragma: {}", name);
getPragmas()[name] = handler;
impl::getPragmas()[name] = handler;
}
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::debug("Registered new pattern language function: {}", getFunctionName(ns, name));
getFunctions().push_back({
impl::getFunctions().push_back({
ns, name,
parameterCount, func,
false
@@ -292,7 +310,7 @@ namespace hex {
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
getFunctions().push_back({
impl::getFunctions().push_back({
ns, name,
parameterCount, func,
true
@@ -300,48 +318,58 @@ namespace hex {
}
std::map<std::string, impl::Visualizer> &impl::getVisualizers() {
static std::map<std::string, impl::Visualizer> visualizers;
return visualizers;
}
void addVisualizer(const std::string &name, const VisualizerFunctionCallback &function, u32 parameterCount) {
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
log::debug("Registered new pattern visualizer function: {}", name);
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
}
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
static std::map<std::string, pl::api::PragmaHandler> pragmas;
return pragmas;
namespace impl {
std::map<std::string, impl::Visualizer> &getVisualizers() {
static std::map<std::string, impl::Visualizer> visualizers;
return visualizers;
}
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
static std::map<std::string, pl::api::PragmaHandler> pragmas;
return pragmas;
}
std::vector<impl::FunctionDefinition> &getFunctions() {
static std::vector<impl::FunctionDefinition> functions;
return functions;
}
}
std::vector<impl::FunctionDefinition> &getFunctions() {
static std::vector<impl::FunctionDefinition> functions;
return functions;
}
}
namespace ContentRegistry::Views {
namespace impl {
std::map<std::string, View *> &getEntries() {
static std::map<std::string, View *> views;
return views;
}
}
void impl::add(View *view) {
log::debug("Registered new view: {}", view->getUnlocalizedName());
getEntries().insert({ view->getUnlocalizedName(), view });
}
std::map<std::string, View *> &getEntries() {
static std::map<std::string, View *> views;
return views;
impl::getEntries().insert({ view->getUnlocalizedName(), view });
}
View *getViewByName(const std::string &unlocalizedName) {
auto &views = getEntries();
auto &views = impl::getEntries();
if (views.contains(unlocalizedName))
return views[unlocalizedName];
@@ -356,13 +384,17 @@ namespace hex {
void add(const std::string &unlocalizedName, const impl::Callback &function) {
log::debug("Registered new tool: {}", unlocalizedName);
getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
impl::getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<Entry> &getEntries() {
static std::vector<Entry> tools;
return tools;
}
return entries;
}
}
@@ -372,21 +404,26 @@ namespace hex {
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
impl::getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
impl::getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
return entries;
}
return entries;
}
}
namespace ContentRegistry::DataProcessorNode {
@@ -398,13 +435,17 @@ namespace hex {
}
void addSeparator() {
getEntries().push_back({ "", "", [] { return nullptr; } });
impl::getEntries().push_back({ "", "", [] { return nullptr; } });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> nodes;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> nodes;
return nodes;
}
return nodes;
}
}
@@ -437,7 +478,7 @@ namespace hex {
LangEntry::setFallbackLanguage(code.get<std::string>());
}
getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
impl::getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
std::map<std::string, std::string> translationDefinitions;
for (auto &[key, value] : translations.items()) {
@@ -449,20 +490,25 @@ namespace hex {
translationDefinitions[key] = value.get<std::string>();
}
getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
impl::getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
}
std::map<std::string, std::string> &getLanguages() {
static std::map<std::string, std::string> languages;
namespace impl {
std::map<std::string, std::string> &getLanguages() {
static std::map<std::string, std::string> languages;
return languages;
}
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
return definitions;
}
return languages;
}
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
return definitions;
}
}
@@ -471,85 +517,109 @@ namespace hex {
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) {
log::debug("Registered new main menu item: {}", unlocalizedName);
getMainMenuItems().insert({ priority, { unlocalizedName } });
impl::getMainMenuItems().insert({ priority, { unlocalizedName } });
}
void addMenuItem(const std::string &unlocalizedMainMenuName, u32 priority, const impl::DrawCallback &function) {
log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuName, priority);
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
log::debug("Added new menu item to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
getMenuItems().insert({
priority, {unlocalizedMainMenuName, function}
impl::getMenuItems().insert({
priority, { unlocalizedMainMenuNames, shortcut, function, enabledCallback }
});
if (shortcut.isLocal() && view != nullptr)
ShortcutManager::addShortcut(view, shortcut, function);
else
ShortcutManager::addGlobalShortcut(shortcut, function);
}
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
log::debug("Added new menu item sub menu to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
impl::getMenuItems().insert({
priority, { unlocalizedMainMenuNames, {}, function, enabledCallback }
});
}
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority) {
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
impl::getMenuItems().insert({
priority, { unlocalizedMainMenuNames, {}, []{}, []{ return true; } }
});
}
void addWelcomeScreenEntry(const impl::DrawCallback &function) {
getWelcomeScreenEntries().push_back(function);
impl::getWelcomeScreenEntries().push_back(function);
}
void addFooterItem(const impl::DrawCallback &function) {
getFooterItems().push_back(function);
impl::getFooterItems().push_back(function);
}
void addToolbarItem(const impl::DrawCallback &function) {
getToolbarItems().push_back(function);
impl::getToolbarItems().push_back(function);
}
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function) {
getSidebarItems().push_back({ icon, function });
impl::getSidebarItems().push_back({ icon, function });
}
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) {
getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
impl::getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
}
void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function) {
log::debug("Added new layout: {}", unlocalizedName);
getLayouts().push_back({ unlocalizedName, function });
impl::getLayouts().push_back({ unlocalizedName, function });
}
namespace impl {
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
static std::multimap<u32, impl::MainMenuItem> items;
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
static std::multimap<u32, impl::MainMenuItem> items;
return items;
}
std::multimap<u32, impl::MenuItem> &getMenuItems() {
static std::multimap<u32, impl::MenuItem> items;
return items;
}
std::multimap<u32, impl::MenuItem> &getMenuItems() {
static std::multimap<u32, impl::MenuItem> items;
return items;
}
return items;
}
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
static std::vector<impl::DrawCallback> entries;
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
static std::vector<impl::DrawCallback> entries;
return entries;
}
std::vector<impl::DrawCallback> &getFooterItems() {
static std::vector<impl::DrawCallback> items;
return entries;
}
std::vector<impl::DrawCallback> &getFooterItems() {
static std::vector<impl::DrawCallback> items;
return items;
}
std::vector<impl::DrawCallback> &getToolbarItems() {
static std::vector<impl::DrawCallback> items;
return items;
}
std::vector<impl::DrawCallback> &getToolbarItems() {
static std::vector<impl::DrawCallback> items;
return items;
}
std::vector<impl::SidebarItem> &getSidebarItems() {
static std::vector<impl::SidebarItem> items;
return items;
}
std::vector<impl::SidebarItem> &getSidebarItems() {
static std::vector<impl::SidebarItem> items;
return items;
}
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
static std::vector<impl::TitleBarButton> buttons;
return items;
}
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
static std::vector<impl::TitleBarButton> buttons;
return buttons;
}
return buttons;
}
std::vector<impl::Layout> &getLayouts() {
static std::vector<impl::Layout> layouts;
std::vector<impl::Layout> &getLayouts() {
static std::vector<impl::Layout> layouts;
return layouts;
}
return layouts;
}
}
@@ -562,12 +632,18 @@ namespace hex {
getEntries().push_back(unlocalizedName);
}
std::vector<std::string> &getEntries() {
static std::vector<std::string> providerNames;
return providerNames;
namespace impl {
std::vector<std::string> &getEntries() {
static std::vector<std::string> providerNames;
return providerNames;
}
}
}
namespace ContentRegistry::DataFormatter {
@@ -575,13 +651,17 @@ namespace hex {
void add(const std::string &unlocalizedName, const impl::Callback &callback) {
log::debug("Registered new data formatter: {}", unlocalizedName);
getEntries().push_back({ unlocalizedName, callback });
impl::getEntries().push_back({ unlocalizedName, callback });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
return entries;
}
return entries;
}
}
@@ -592,13 +672,17 @@ namespace hex {
for (const auto &extension : extensions)
log::debug("Registered new data handler for extensions: {}", extension);
getEntries().push_back({ extensions, callback });
impl::getEntries().push_back({ extensions, callback });
}
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
namespace impl {
std::vector<impl::Entry> &getEntries() {
static std::vector<impl::Entry> entries;
return entries;
}
return entries;
}
}
@@ -607,7 +691,7 @@ namespace hex {
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
bool DataVisualizer::drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
struct UserData {
u8 *data;
i32 maxChars;
@@ -636,29 +720,69 @@ namespace hex {
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
}
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
getVisualizers().insert({ unlocalizedName, visualizer });
bool DataVisualizer::drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const {
struct UserData {
std::string *data;
i32 maxChars;
bool editingDone;
};
UserData userData = {
.data = &data,
.maxChars = this->getMaxCharsPerCell(),
.editingDone = false
};
ImGui::PushID(reinterpret_cast<void*>(address));
ImGui::InputText("##editing_input", data.data(), data.size() + 1, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
userData.data->resize(data->BufSize);
if (data->BufTextLen >= userData.maxChars)
userData.editingDone = true;
return 0;
}, &userData);
ImGui::PopID();
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
}
namespace impl {
void addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
getVisualizers().insert({ unlocalizedName, visualizer });
}
std::map<std::string, DataVisualizer*> &getVisualizers() {
static std::map<std::string, DataVisualizer*> visualizers;
return visualizers;
}
}
std::map<std::string, DataVisualizer*> &impl::getVisualizers() {
static std::map<std::string, DataVisualizer*> visualizers;
return visualizers;
}
}
namespace ContentRegistry::Hashes {
std::vector<Hash *> &impl::getHashes() {
static std::vector<Hash *> hashes;
namespace impl {
return hashes;
}
std::vector<Hash *> &getHashes() {
static std::vector<Hash *> hashes;
return hashes;
}
void add(Hash *hash) {
getHashes().push_back(hash);
}
void impl::add(Hash *hash) {
getHashes().push_back(hash);
}
}

View File

@@ -19,19 +19,6 @@
namespace hex {
namespace ImHexApi::Common {
void closeImHex(bool noQuestions) {
EventManager::post<RequestCloseImHex>(noQuestions);
}
void restartImHex() {
EventManager::post<RequestRestartImHex>();
EventManager::post<RequestCloseImHex>(false);
}
}
namespace ImHexApi::HexEditor {
@@ -408,6 +395,14 @@ namespace hex {
}
void closeImHex(bool noQuestions) {
EventManager::post<RequestCloseImHex>(noQuestions);
}
void restartImHex() {
EventManager::post<RequestRestartImHex>();
EventManager::post<RequestCloseImHex>(false);
}
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress) {
EventManager::post<EventSetTaskBarIconState>(u32(state), u32(type), progress);

View File

@@ -76,7 +76,7 @@ namespace hex {
void LangEntry::loadLanguage(const std::string &language) {
LangEntry::s_currStrings.clear();
auto &definitions = ContentRegistry::Language::getLanguageDefinitions();
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
if (!definitions.contains(language))
return;
@@ -92,7 +92,7 @@ namespace hex {
}
const std::map<std::string, std::string> &LangEntry::getSupportedLanguages() {
return ContentRegistry::Language::getLanguages();
return ContentRegistry::Language::impl::getLanguages();
}
void LangEntry::setFallbackLanguage(const std::string &language) {

View File

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

View File

@@ -6,6 +6,9 @@
#include <hex/providers/provider.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/io/fs.hpp>
namespace hex {
constexpr static auto MetadataHeaderMagic = "HEX";
@@ -24,7 +27,7 @@ namespace hex {
ProjectFile::s_currProjectPath = originalPath;
};
if (!fs::exists(filePath) || !fs::isRegularFile(filePath))
if (!wolv::io::fs::exists(filePath) || !wolv::io::fs::isRegularFile(filePath))
return false;
if (filePath.extension() != ".hexproj")
return false;
@@ -37,7 +40,7 @@ namespace hex {
return false;
{
const auto metadataContent = tar.read(MetadataPath);
const auto metadataContent = tar.readVector(MetadataPath);
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
return false;
@@ -128,7 +131,7 @@ namespace hex {
{
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
tar.write(MetadataPath, metadataContent);
tar.writeString(MetadataPath, metadataContent);
}
ImHexApi::Provider::resetDirty();

View File

@@ -47,7 +47,7 @@ namespace hex {
void Task::update(u64 value) {
this->m_currValue = value;
if (this->m_shouldInterrupt)
if (this->m_shouldInterrupt) [[unlikely]]
throw TaskInterruptor();
}

View File

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

View File

@@ -86,7 +86,7 @@ namespace hex::dp {
return *reinterpret_cast<long double *>(outputData.data());
}
void Node::setBufferOnOutput(u32 index, const std::vector<u8> &data) {
void Node::setBufferOnOutput(u32 index, std::span<const u8> data) {
if (index >= this->getAttributes().size())
throwNodeError("Attribute index out of bounds!");
@@ -95,7 +95,7 @@ namespace hex::dp {
if (attribute.getIOType() != Attribute::IOType::Out)
throwNodeError("Tried to set output data of an input attribute!");
attribute.getOutputData() = data;
attribute.getOutputData() = { data.begin(), data.end() };
}
void Node::setIntegerOnOutput(u32 index, i128 integer) {

View File

@@ -1,8 +1,8 @@
#include <hex/helpers/crypto.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/concepts.hpp>
#include <wolv/utils/guards.hpp>
#include <mbedtls/version.h>
#include <mbedtls/base64.h>
@@ -11,13 +11,10 @@
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/sha512.h>
#include <mbedtls/aes.h>
#include <mbedtls/cipher.h>
#include <array>
#include <span>
#include <functional>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <bit>

View File

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

View File

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

View File

@@ -2,11 +2,7 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/project_file_manager.hpp>
#include <hex/helpers/fs_macos.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/intrinsics.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <xdg.hpp>
@@ -21,68 +17,25 @@
#include <algorithm>
#include <filesystem>
#include <wolv/io/file.hpp>
#include <wolv/io/fs.hpp>
namespace hex::fs {
std::optional<std::fs::path> getExecutablePath() {
#if defined(OS_WINDOWS)
std::wstring exePath(MAX_PATH, '\0');
if (GetModuleFileNameW(nullptr, exePath.data(), exePath.length()) == 0)
return std::nullopt;
hex::trim(exePath);
return exePath;
#elif defined(OS_LINUX)
std::string exePath(PATH_MAX, '\0');
if (readlink("/proc/self/exe", exePath.data(), PATH_MAX) < 0)
return std::nullopt;
hex::trim(exePath);
return exePath;
#elif defined(OS_MACOS)
std::string exePath;
{
auto string = getMacExecutableDirectoryPath();
exePath = string;
macFree(string);
}
hex::trim(exePath);
return exePath;
#else
return std::nullopt;
#endif
}
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;
}
static std::function<void()> s_fileBrowserErrorCallback;
void setFileBrowserErrorCallback(const std::function<void()> &callback) {
static std::function<void(const std::string&)> s_fileBrowserErrorCallback;
void setFileBrowserErrorCallback(const std::function<void(const std::string&)> &callback) {
s_fileBrowserErrorCallback = callback;
}
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath, bool multiple) {
NFD::Init();
NFD::ClearError();
if (NFD::Init() != NFD_OKAY) {
log::error("NFD init returned an error: {}", NFD::GetError());
if (s_fileBrowserErrorCallback != nullptr)
s_fileBrowserErrorCallback(NFD::GetError() ? NFD::GetError() : "No details");
return false;
}
NFD::UniquePathU8 outPath;
NFD::UniquePathSet outPaths;
@@ -119,8 +72,9 @@ namespace hex::fs {
}
}
} else if (result == NFD_ERROR) {
log::error("Requested file dialog returned an error: {}", NFD::GetError());
if (s_fileBrowserErrorCallback != nullptr)
s_fileBrowserErrorCallback();
s_fileBrowserErrorCallback(NFD::GetError() ? NFD::GetError() : "No details");
}
NFD::Quit();
@@ -128,7 +82,7 @@ namespace hex::fs {
return result == NFD_OKAY;
}
static std::vector<std::fs::path> getDataPaths() {
std::vector<std::fs::path> getDataPaths() {
std::vector<std::fs::path> paths;
#if defined(OS_WINDOWS)
@@ -143,14 +97,7 @@ namespace hex::fs {
#elif defined(OS_MACOS)
std::fs::path applicationSupportDirPath;
{
auto string = getMacApplicationSupportDirectoryPath();
applicationSupportDirPath = std::string(string);
macFree(string);
}
paths.push_back(applicationSupportDirPath);
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
#elif defined(OS_LINUX)
@@ -166,12 +113,12 @@ namespace hex::fs {
#if defined(OS_MACOS)
if (auto executablePath = fs::getExecutablePath(); executablePath.has_value())
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(*executablePath);
#else
if (auto executablePath = fs::getExecutablePath(); executablePath.has_value())
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(executablePath->parent_path());
#endif
@@ -193,17 +140,7 @@ namespace hex::fs {
#elif defined(OS_MACOS)
return getDataPaths();
#elif defined(OS_LINUX)
std::vector<std::fs::path> paths;
paths.push_back(xdg::DataHomeDir());
auto dataDirs = xdg::DataDirs();
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
for (auto &path : paths)
path = path / "imhex";
return paths;
return {xdg::ConfigHomeDir() / "imhex"};
#endif
}
@@ -239,7 +176,7 @@ namespace hex::fs {
result = appendPath(getDataPaths(), "encodings");
break;
case ImHexPath::Logs:
result = appendPath(getConfigPaths(), "logs");
result = appendPath(getDataPaths(), "logs");
break;
case ImHexPath::Plugins:
result = appendPath(getPluginPaths(), "plugins");
@@ -281,13 +218,31 @@ namespace hex::fs {
if (!listNonExisting) {
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
return !fs::isDirectory(path);
return !wolv::io::fs::isDirectory(path);
}), result.end());
}
return result;
}
bool isPathWritable(const std::fs::path &path) {
constexpr static auto TestFileName = "__imhex__tmp__";
{
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Read);
if (file.isValid()) {
if (!file.remove())
return false;
}
}
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Create);
bool result = file.isValid();
if (!file.remove())
return false;
return result;
}
std::fs::path toShortPath(const std::fs::path &path) {
#if defined(OS_WINDOWS)
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0);

View File

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

View File

@@ -0,0 +1,81 @@
#include <hex/helpers/http_requests.hpp>
namespace hex {
std::string HttpRequest::s_caCertData;
std::string HttpRequest::s_proxyUrl;
void HttpRequest::setDefaultConfig() {
curl_easy_setopt(this->m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(this->m_curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_easy_setopt(this->m_curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(this->m_curl, CURLOPT_USERAGENT, "ImHex/1.0");
curl_easy_setopt(this->m_curl, CURLOPT_DEFAULT_PROTOCOL, "https");
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(this->m_curl, CURLOPT_TIMEOUT_MS, 0L);
curl_easy_setopt(this->m_curl, CURLOPT_CONNECTTIMEOUT_MS, this->m_timeout);
curl_easy_setopt(this->m_curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(this->m_curl, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
curl_easy_setopt(this->m_curl, CURLOPT_PROXY, s_proxyUrl.c_str());
#if defined(IMHEX_USE_BUNDLED_CA)
curl_easy_setopt(this->m_curl, CURLOPT_CAINFO, nullptr);
curl_easy_setopt(this->m_curl, CURLOPT_CAPATH, nullptr);
curl_easy_setopt(this->m_curl, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(this->m_curl, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
this->m_caCert = std::make_unique<mbedtls_x509_crt>();
curl_easy_setopt(this->m_curl, CURLOPT_SSL_CTX_DATA, this->m_caCert.get());
#endif
}
CURLcode HttpRequest::sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
hex::unused(ctx, userData);
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
auto crt = static_cast<mbedtls_x509_crt*>(userData);
mbedtls_x509_crt_init(crt);
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(HttpRequest::s_caCertData.data()), HttpRequest::s_caCertData.size());
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
return CURLE_OK;
}
size_t HttpRequest::writeToVector(void *contents, size_t size, size_t nmemb, void *userdata) {
auto &response = *reinterpret_cast<std::vector<u8>*>(userdata);
auto startSize = response.size();
response.resize(startSize + size * nmemb);
std::memcpy(response.data() + startSize, contents, size * nmemb);
return size * nmemb;
}
size_t HttpRequest::writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) {
auto &file = *reinterpret_cast<wolv::io::File*>(userdata);
file.writeBuffer(reinterpret_cast<const u8*>(contents), size * nmemb);
return size * nmemb;
}
int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
auto &request = *static_cast<HttpRequest *>(contents);
if (dlTotal > 0)
request.m_progress = float(dlNow) / dlTotal;
else if (ulTotal > 0)
request.m_progress = float(ulNow) / ulTotal;
else
request.m_progress = 0.0F;
return request.m_canceled ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
}
}

View File

@@ -1,13 +1,12 @@
#include <hex/helpers/logger.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/fmt.hpp>
#include <iostream>
#include <wolv/io/file.hpp>
namespace hex::log {
static fs::File g_loggerFile;
static wolv::io::File g_loggerFile;
FILE *getDestination() {
if (g_loggerFile.isValid())
@@ -24,8 +23,8 @@ namespace hex::log {
if (g_loggerFile.isValid()) return;
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);
wolv::io::fs::createDirectories(path);
g_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::now())), wolv::io::File::Mode::Create);
g_loggerFile.disableBuffering();
if (g_loggerFile.isValid()) break;

View File

@@ -3,6 +3,9 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp>
#include <wolv/utils/guards.hpp>
#include <wolv/utils/string.hpp>
#include <hex/providers/provider.hpp>
#include <filesystem>
@@ -25,9 +28,9 @@ namespace hex::magic {
std::error_code error;
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
for (const auto &entry : std::fs::recursive_directory_iterator(dir, error)) {
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc"))) {
magicFiles += hex::toUTF8String(fs::toShortPath(entry.path())) + MAGIC_PATH_SEPARATOR;
magicFiles += wolv::util::toUTF8String(wolv::io::fs::toShortPath(entry.path())) + MAGIC_PATH_SEPARATOR;
}
}
}

View File

@@ -1,304 +0,0 @@
#include <hex/helpers/net.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/api/content_registry.hpp>
#include <filesystem>
#include <cstdio>
#include <nlohmann/json.hpp>
namespace hex {
Net::Net() {
FIRST_TIME {
curl_global_sslset(CURLSSLBACKEND_MBEDTLS, nullptr, nullptr);
curl_global_init(CURL_GLOBAL_ALL);
};
FINAL_CLEANUP {
curl_global_cleanup();
};
this->m_ctx = curl_easy_init();
}
Net::~Net() {
curl_easy_cleanup(this->m_ctx);
}
static size_t writeToString(void *contents, size_t size, size_t nmemb, void *userdata) {
static_cast<std::string *>(userdata)->append((char *)contents, size * nmemb);
return size * nmemb;
}
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);
}
[[maybe_unused]]
CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
hex::unused(ctx, userData);
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
auto crt = static_cast<mbedtls_x509_crt*>(userData);
mbedtls_x509_crt_init(crt);
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(Net::s_caCert.data()), Net::s_caCert.size());
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
return CURLE_OK;
}
int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
auto &net = *static_cast<Net *>(contents);
if (dlTotal > 0)
net.m_progress = float(dlNow) / dlTotal;
else if (ulTotal > 0)
net.m_progress = float(ulNow) / ulTotal;
else
net.m_progress = 0.0F;
return net.m_shouldCancel ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
}
void Net::setCommonSettings(std::string &response, const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
this->m_headers = curl_slist_append(this->m_headers, "Cache-Control: no-cache");
if (!extraHeaders.empty())
for (const auto &[key, value] : extraHeaders) {
std::string entry = key;
entry += ": ";
entry += value;
this->m_headers = curl_slist_append(this->m_headers, entry.c_str());
}
if (!body.empty())
curl_easy_setopt(this->m_ctx, CURLOPT_POSTFIELDS, body.c_str());
curl_easy_setopt(this->m_ctx, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(this->m_ctx, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
curl_easy_setopt(this->m_ctx, CURLOPT_URL, url.c_str());
curl_easy_setopt(this->m_ctx, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(this->m_ctx, CURLOPT_HTTPHEADER, this->m_headers);
curl_easy_setopt(this->m_ctx, CURLOPT_USERAGENT, "ImHex/1.0");
curl_easy_setopt(this->m_ctx, CURLOPT_DEFAULT_PROTOCOL, "https");
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToString);
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(this->m_ctx, CURLOPT_TIMEOUT_MS, 0L);
curl_easy_setopt(this->m_ctx, CURLOPT_CONNECTTIMEOUT_MS, timeout);
curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFODATA, this);
curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFOFUNCTION, progressCallback);
curl_easy_setopt(this->m_ctx, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(this->m_ctx, CURLOPT_NOPROGRESS, 0L);
#if defined(IMHEX_USE_BUNDLED_CA)
curl_easy_setopt(this->m_ctx, CURLOPT_CAINFO, nullptr);
curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr);
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_DATA, &this->m_caCert);
#endif
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
}
std::optional<i32> Net::execute() {
CURLcode result = curl_easy_perform(this->m_ctx);
if (result != CURLE_OK){
char *url = nullptr;
curl_easy_getinfo(this->m_ctx, CURLINFO_EFFECTIVE_URL, &url);
log::error("Net request '{0}' failed with error {1}: '{2}'", url, u32(result), curl_easy_strerror(result));
if(!Net::s_proxyUrl.empty()){
log::info("A custom proxy '{}' is in use. Is it working correctly?", Net::s_proxyUrl);
}
}
long responseCode = 0;
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
curl_slist_free_all(this->m_headers);
this->m_headers = nullptr;
this->m_progress = 0.0F;
this->m_shouldCancel = false;
if (result != CURLE_OK)
return std::nullopt;
else
return i32(responseCode);
}
std::future<Response<std::string>> Net::getString(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this] {
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
setCommonSettings(response, url, timeout, extraHeaders, body);
auto responseCode = execute();
return Response<std::string> { responseCode.value_or(0), response };
});
}
std::future<Response<nlohmann::json>> Net::getJson(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this] {
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
setCommonSettings(response, url, timeout, extraHeaders, body);
auto responseCode = execute();
if (!responseCode.has_value())
return Response<nlohmann::json> { 0, { } };
else
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
});
}
std::future<Response<nlohmann::json>> Net::postJson(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
this->m_transmissionActive.lock();
return std::async(std::launch::async, [=, this] {
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "POST");
setCommonSettings(response, url, timeout, extraHeaders, body);
auto responseCode = execute();
if (!responseCode.has_value())
return Response<nlohmann::json> { 0, { } };
else
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
});
}
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] {
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
fs::File file(filePath, fs::File::Mode::Read);
if (!file.isValid())
return Response<std::string> { 400, {} };
curl_mime *mime = curl_mime_init(this->m_ctx);
curl_mimepart *part = curl_mime_addpart(mime);
auto fileName = hex::toUTF8String(filePath.filename());
curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto file = static_cast<FILE*>(arg);
return fread(buffer, size, nitems, file);
},
[](void *arg, curl_off_t offset, int origin) -> int {
auto file = static_cast<FILE*>(arg);
if (fseek(file, offset, origin) != 0)
return CURL_SEEKFUNC_CANTSEEK;
else
return CURL_SEEKFUNC_OK;
},
[](void *arg) {
auto file = static_cast<FILE*>(arg);
fclose(file);
},
file.getHandle());
curl_mime_filename(part, fileName.c_str());
curl_mime_name(part, "file");
setCommonSettings(response, url, timeout);
curl_easy_setopt(this->m_ctx, CURLOPT_MIMEPOST, mime);
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "POST");
auto responseCode = execute();
return Response<std::string> { responseCode.value_or(0), response };
});
}
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] {
std::string response;
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
fs::File file(filePath, fs::File::Mode::Create);
if (!file.isValid())
return Response<void> { 400 };
setCommonSettings(response, url, timeout);
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToFile);
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, file.getHandle());
auto responseCode = execute();
return Response<void> { responseCode.value_or(0) };
});
}
std::string Net::encode(const std::string &input) {
auto escapedString = curl_easy_escape(this->m_ctx, input.c_str(), std::strlen(input.c_str()));
if (escapedString != nullptr) {
std::string output = escapedString;
curl_free(escapedString);
return output;
}
return {};
}
std::string Net::decode(const std::string &input) {
auto unescapedString = curl_easy_unescape(this->m_ctx, input.c_str(), std::strlen(input.c_str()), nullptr);
if (unescapedString != nullptr) {
std::string output = unescapedString;
curl_free(unescapedString);
return output;
}
return {};
}
std::string Net::s_proxyUrl;
void Net::setProxy(const std::string &url) {
Net::s_proxyUrl = url;
}
std::string Net::s_caCert;
void Net::setCACert(const std::string &content) {
Net::s_caCert = content;
}
}

View File

@@ -3,6 +3,8 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <wolv/utils/guards.hpp>
namespace hex::gl {
Shader::Shader(std::string_view vertexSource, std::string_view fragmentSource) {

View File

@@ -1,104 +0,0 @@
#include <hex/helpers/socket.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
namespace hex {
Socket::Socket(const std::string &address, u16 port) {
#if defined(OS_WINDOWS)
FIRST_TIME {
WSAData wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
};
FINAL_CLEANUP {
WSACleanup();
};
#endif
this->connect(address, port);
}
Socket::Socket(Socket &&other) noexcept {
this->m_socket = other.m_socket;
this->m_connected = other.m_connected;
other.m_socket = SOCKET_NONE;
}
Socket::~Socket() {
this->disconnect();
}
void Socket::writeBytes(const std::vector<u8> &bytes) const {
if (!this->isConnected()) return;
::send(this->m_socket, reinterpret_cast<const char *>(bytes.data()), bytes.size(), 0);
}
void Socket::writeString(const std::string &string) const {
if (!this->isConnected()) return;
::send(this->m_socket, string.c_str(), string.length(), 0);
}
std::vector<u8> Socket::readBytes(size_t size) const {
std::vector<u8> data;
data.resize(size);
auto receivedSize = ::recv(this->m_socket, reinterpret_cast<char *>(data.data()), size, 0);
if (receivedSize < 0)
return {};
data.resize(receivedSize);
return data;
}
std::string Socket::readString(size_t size) const {
auto bytes = readBytes(size);
std::string result;
std::copy(bytes.begin(), bytes.end(), std::back_inserter(result));
return result;
}
bool Socket::isConnected() const {
return this->m_connected;
}
void Socket::connect(const std::string &address, u16 port) {
this->m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (this->m_socket == SOCKET_NONE)
return;
sockaddr_in client = { };
client.sin_family = AF_INET;
client.sin_port = htons(port);
#if defined(OS_WINDOWS)
client.sin_addr.S_un.S_addr = ::inet_addr(address.c_str());
#else
client.sin_addr.s_addr = ::inet_addr(address.c_str());
#endif
this->m_connected = ::connect(this->m_socket, reinterpret_cast<sockaddr *>(&client), sizeof(client)) == 0;
}
void Socket::disconnect() {
if (this->m_socket != SOCKET_NONE) {
#if defined(OS_WINDOWS)
closesocket(this->m_socket);
#else
close(this->m_socket);
#endif
}
this->m_connected = false;
}
}

View File

@@ -94,75 +94,82 @@
}
#elif defined(HEX_HAS_EXECINFO) && __has_include(BACKTRACE_HEADER)
#elif defined(HEX_HAS_EXECINFO)
#include BACKTRACE_HEADER
#include <llvm/Demangle/Demangle.h>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
#if __has_include(BACKTRACE_HEADER)
namespace hex::stacktrace {
#include BACKTRACE_HEADER
#include <llvm/Demangle/Demangle.h>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
void initialize() {
namespace hex::stacktrace {
}
std::vector<StackFrame> getStackTrace() {
static std::vector<StackFrame> result;
std::array<void*, 128> addresses;
auto count = backtrace(addresses.data(), addresses.size());
auto functions = backtrace_symbols(addresses.data(), count);
for (i32 i = 0; i < count; i++)
result.push_back(StackFrame { "", functions[i], 0 });
return result;
}
}
#elif defined(HEX_HAS_BACKTRACE) && __has_include(BACKTRACE_HEADER)
#include BACKTRACE_HEADER
#include <llvm/Demangle/Demangle.h>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
namespace hex::stacktrace {
static struct backtrace_state *s_backtraceState;
void initialize() {
if (auto executablePath = fs::getExecutablePath(); executablePath.has_value()) {
static std::string path = executablePath->string();
s_backtraceState = backtrace_create_state(path.c_str(), 1, [](void *, const char *msg, int) { log::error("{}", msg); }, nullptr);
}
}
std::vector<StackFrame> getStackTrace() {
static std::vector<StackFrame> result;
result.clear();
if (s_backtraceState != nullptr) {
backtrace_full(s_backtraceState, 0, [](void *, uintptr_t, const char *fileName, int lineNumber, const char *function) -> int {
if (fileName == nullptr)
fileName = "??";
if (function == nullptr)
function = "??";
result.push_back(StackFrame { std::fs::path(fileName).filename().string(), llvm::demangle(function), u32(lineNumber) });
return 0;
}, nullptr, nullptr);
void initialize() {
}
return result;
std::vector<StackFrame> getStackTrace() {
static std::vector<StackFrame> result;
std::array<void*, 128> addresses;
auto count = backtrace(addresses.data(), addresses.size());
auto functions = backtrace_symbols(addresses.data(), count);
for (i32 i = 0; i < count; i++)
result.push_back(StackFrame { "", functions[i], 0 });
return result;
}
}
#endif
#elif defined(HEX_HAS_BACKTRACE)
#if __has_include(BACKTRACE_HEADER)
#include BACKTRACE_HEADER
#include <llvm/Demangle/Demangle.h>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
namespace hex::stacktrace {
static struct backtrace_state *s_backtraceState;
void initialize() {
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
static std::string path = executablePath->string();
s_backtraceState = backtrace_create_state(path.c_str(), 1, [](void *, const char *msg, int) { log::error("{}", msg); }, nullptr);
}
}
std::vector<StackFrame> getStackTrace() {
static std::vector<StackFrame> result;
result.clear();
if (s_backtraceState != nullptr) {
backtrace_full(s_backtraceState, 0, [](void *, uintptr_t, const char *fileName, int lineNumber, const char *function) -> int {
if (fileName == nullptr)
fileName = "??";
if (function == nullptr)
function = "??";
result.push_back(StackFrame { std::fs::path(fileName).filename().string(), llvm::demangle(function), u32(lineNumber) });
return 0;
}, nullptr, nullptr);
}
return result;
}
}
}
#endif
#else

View File

@@ -1,8 +1,9 @@
#include <hex/helpers/tar.hpp>
#include <hex/helpers/literals.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/fs.hpp>
#include <wolv/io/file.hpp>
namespace hex {
using namespace hex::literals;
@@ -12,11 +13,11 @@ namespace hex {
// Explicitly create file so a short path gets generated
if (mode == Mode::Create) {
fs::File file(path, fs::File::Mode::Create);
wolv::io::File file(path, wolv::io::File::Mode::Create);
file.flush();
}
auto shortPath = hex::fs::toShortPath(path);
auto shortPath = wolv::io::fs::toShortPath(path);
if (mode == Tar::Mode::Read)
error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "r");
else if (mode == Tar::Mode::Write)
@@ -58,7 +59,7 @@ namespace hex {
mtar_header_t header;
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
std::fs::path path = header.name;
if (header.name != PaxHeaderName && fs::isSubPath(basePath, path)) {
if (header.name != PaxHeaderName && wolv::io::fs::isSubPath(basePath, path)) {
result.emplace_back(header.name);
}
@@ -83,7 +84,7 @@ namespace hex {
this->m_valid = false;
}
std::vector<u8> Tar::read(const std::fs::path &path) {
std::vector<u8> Tar::readVector(const std::fs::path &path) {
mtar_header_t header;
auto fixedPath = path.string();
@@ -99,11 +100,11 @@ namespace hex {
}
std::string Tar::readString(const std::fs::path &path) {
auto result = this->read(path);
auto result = this->readVector(path);
return { result.begin(), result.end() };
}
void Tar::write(const std::fs::path &path, const std::vector<u8> &data) {
void Tar::writeVector(const std::fs::path &path, const std::vector<u8> &data) {
if (path.has_parent_path()) {
std::fs::path pathPart;
for (const auto &part : path.parent_path()) {
@@ -125,21 +126,21 @@ namespace hex {
mtar_write_data(&this->m_ctx, data.data(), data.size());
}
void Tar::write(const std::fs::path &path, const std::string &data) {
this->write(path, std::vector<u8>(data.begin(), data.end()));
void Tar::writeString(const std::fs::path &path, const std::string &data) {
this->writeVector(path, { data.begin(), data.end() });
}
static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) {
constexpr static u64 BufferSize = 1_MiB;
fs::File outputFile(path, fs::File::Mode::Create);
wolv::io::File outputFile(path, wolv::io::File::Mode::Create);
std::vector<u8> buffer;
for (u64 offset = 0; offset < header->size; offset += BufferSize) {
buffer.resize(std::min<u64>(BufferSize, header->size - offset));
mtar_read_data(ctx, buffer.data(), buffer.size());
outputFile.write(buffer);
outputFile.writeVector(buffer);
}
}

View File

@@ -66,6 +66,25 @@ namespace hex {
return { data + index + 1 };
}
std::optional<u8> parseBinaryString(const std::string &string) {
if (string.empty())
return std::nullopt;
u8 byte = 0x00;
for (char c : string) {
byte <<= 1;
if (c == '1')
byte |= 0b01;
else if (c == '0')
byte |= 0b00;
else
return std::nullopt;
}
return byte;
}
std::string toByteString(u64 bytes) {
double value = bytes;
u8 unitIndex = 0;

View File

@@ -9,6 +9,7 @@
#include <optional>
#include <hex/helpers/magic.hpp>
#include <wolv/io/file.hpp>
namespace hex::prv {
@@ -36,7 +37,28 @@ namespace hex::prv {
void Provider::save() { }
void Provider::saveAs(const std::fs::path &path) {
hex::unused(path);
wolv::io::File file(path, wolv::io::File::Mode::Create);
if (file.isValid()) {
std::vector<u8> buffer(std::min<size_t>(0xFF'FFFF, this->getActualSize()), 0x00);
size_t bufferSize = 0;
for (u64 offset = 0; offset < this->getActualSize(); offset += bufferSize) {
bufferSize = buffer.size();
auto [region, valid] = this->getRegionValidity(offset + this->getBaseAddress());
if (!valid)
offset = region.getEndAddress() + 1;
auto [newRegion, newValid] = this->getRegionValidity(offset + this->getBaseAddress());
bufferSize = std::min<size_t>(bufferSize, (newRegion.getEndAddress() - offset) + 1);
bufferSize = std::min<size_t>(bufferSize, this->getActualSize() - offset);
this->read(offset + this->getBaseAddress(), buffer.data(), bufferSize, true);
file.writeBuffer(buffer.data(), bufferSize);
}
}
}
void Provider::resize(size_t newSize) {
@@ -114,6 +136,10 @@ namespace hex::prv {
for (auto &[patchAddress, patch] : getPatches()) {
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
}
if (!this->isWritable())
return;
this->markDirty();
this->m_patches.emplace_back();
@@ -239,7 +265,8 @@ namespace hex::prv {
return false;
}
void Provider::drawLoadInterface() {
bool Provider::drawLoadInterface() {
return true;
}
void Provider::drawInterface() {

View File

@@ -40,9 +40,7 @@ namespace hex {
void exitGLFW();
void exitImGui();
friend void *ImHexSettingsHandler_ReadOpenFn(ImGuiContext *ctx, ImGuiSettingsHandler *, const char *);
friend void ImHexSettingsHandler_ReadLine(ImGuiContext *, ImGuiSettingsHandler *handler, void *, const char *line);
friend void ImHexSettingsHandler_WriteAll(ImGuiContext *ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf);
void registerEventHandlers();
GLFWwindow *m_window = nullptr;

View File

@@ -14,9 +14,12 @@
#include <hex/ui/imgui_imhex_extensions.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
#include <imgui_impl_opengl3_loader.h>
#include <fonts/fontawesome_font.h>
#include <GLFW/glfw3.h>
#include <wolv/utils/guards.hpp>
#include <unistd.h>
#include <chrono>
@@ -90,29 +93,34 @@ namespace hex::init {
}
bool WindowSplash::loop() {
// Load splash screen image from romfs
auto splash = romfs::get("splash.png");
ImGui::Texture splashTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
// If the image couldn't be loaded correctly, something went wrong during the build process
// Close the application since this would lead to errors later on anyway.
if (!splashTexture.isValid()) {
log::fatal("Could not load splash screen image!");
exit(EXIT_FAILURE);
}
// Launch init tasks in background
auto tasksSucceeded = processTasksAsync();
auto scale = ImHexApi::System::getGlobalScale();
// Splash window rendering loop
while (!glfwWindowShouldClose(this->m_window)) {
glfwPollEvents();
// Start a new ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Draw the splash screen background
auto drawList = ImGui::GetForegroundDrawList();
{
std::lock_guard guard(this->m_progressMutex);
auto drawList = ImGui::GetForegroundDrawList();
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.getSize() * scale);
@@ -123,11 +131,16 @@ namespace hex::init {
#else
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
#endif
}
// Draw the task progress bar
{
std::lock_guard guard(this->m_progressMutex);
drawList->AddRectFilled(ImVec2(0, splashTexture.getSize().y - 5) * scale, ImVec2(splashTexture.getSize().x * this->m_progress, splashTexture.getSize().y) * scale, 0xFFFFFFFF);
drawList->AddText(ImVec2(15, splashTexture.getSize().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}...", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
}
// Render the frame
ImGui::Render();
int displayWidth, displayHeight;
glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight);
@@ -138,6 +151,7 @@ namespace hex::init {
glfwSwapBuffers(this->m_window);
// Check if all background tasks have finished so the splash screen can be closed
if (tasksSucceeded.wait_for(0s) == std::future_status::ready) {
return tasksSucceeded.get();
}
@@ -147,20 +161,25 @@ namespace hex::init {
}
static void centerWindow(GLFWwindow *window) {
// Get the primary monitor
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
if (!monitor)
return;
// Get information about the monitor
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
if (!mode)
return;
// Get the position of the monitor's viewport on the virtual screen
int monitorX, monitorY;
glfwGetMonitorPos(monitor, &monitorX, &monitorY);
// Get the window size
int windowWidth, windowHeight;
glfwGetWindowSize(window, &windowWidth, &windowHeight);
// Center the splash screen on the monitor
glfwSetWindowPos(window, monitorX + (mode->width - windowWidth) / 2, monitorY + (mode->height - windowHeight) / 2);
}
@@ -174,22 +193,25 @@ namespace hex::init {
exit(EXIT_FAILURE);
}
// Configure used OpenGL version
#if defined(OS_MACOS)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
#else
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
#endif
// Make splash screen non-resizable, undecorated and transparent
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
// Create the splash screen window
this->m_window = glfwCreateWindow(1, 400, "Starting ImHex...", nullptr, nullptr);
if (this->m_window == nullptr) {
log::fatal("Failed to create GLFW window!");
@@ -223,6 +245,7 @@ namespace hex::init {
}
void WindowSplash::initImGui() {
// Initialize ImGui
IMGUI_CHECKVERSION();
GImGui = ImGui::CreateContext();
ImGui::StyleColorsDark();
@@ -239,31 +262,36 @@ namespace hex::init {
ImGui::GetStyle().ScaleAllSizes(ImHexApi::System::getGlobalScale());
io.Fonts->Clear();
// Load fonts necessary for the splash screen
{
io.Fonts->Clear();
ImFontConfig cfg;
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
cfg.SizePixels = 13.0_scaled;
io.Fonts->AddFontDefault(&cfg);
ImFontConfig cfg;
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
cfg.SizePixels = 13.0_scaled;
io.Fonts->AddFontDefault(&cfg);
cfg.MergeMode = true;
cfg.MergeMode = true;
ImWchar fontAwesomeRange[] = {
ICON_MIN_FA, ICON_MAX_FA, 0
};
std::uint8_t *px;
int w, h;
io.Fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 11.0_scaled, &cfg, fontAwesomeRange);
io.Fonts->GetTexDataAsRGBA32(&px, &w, &h);
ImWchar fontAwesomeRange[] = {
ICON_MIN_FA, ICON_MAX_FA, 0
};
std::uint8_t *px;
int w, h;
io.Fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 11.0_scaled, &cfg, fontAwesomeRange);
io.Fonts->GetTexDataAsAlpha8(&px, &w, &h);
// Create new font atlas
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA8, GL_UNSIGNED_INT, px);
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(tex));
// Create new font atlas
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, px);
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(tex));
}
// Don't save window settings for the splash screen
io.IniFilename = nullptr;
}

View File

@@ -8,7 +8,7 @@
#include <hex/api/project_file_manager.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/net.hpp>
#include <hex/helpers/http_requests.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
@@ -22,28 +22,46 @@
#include <nlohmann/json.hpp>
#include <wolv/io/fs.hpp>
#include <wolv/io/file.hpp>
namespace hex::init {
using namespace std::literals::string_literals;
static bool checkForUpdates() {
// documentation of the value above the setting definition
int showCheckForUpdates = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 2);
// Check if we should check for updates
if (showCheckForUpdates == 1){
hex::Net net;
HttpRequest request("GET", GitHubApiURL + "/releases/latest"s);
request.setTimeout(2000);
auto releases = net.getJson(GitHubApiURL + "/releases/latest"s, 2000).get();
if (releases.code != 200)
// Query the GitHub API for the latest release version
auto response = request.execute().get();
if (response.getStatusCode() != 200)
return false;
if (!releases.body.contains("tag_name") || !releases.body["tag_name"].is_string())
nlohmann::json releases;
try {
releases = nlohmann::json::parse(response.getData());
} catch (std::exception &e) {
return false;
}
// Check if the response is valid
if (!releases.contains("tag_name") || !releases["tag_name"].is_string())
return false;
// Convert the current version string to a format that can be compared to the latest release
auto versionString = std::string(IMHEX_VERSION);
size_t versionLength = std::min(versionString.find_first_of('-'), versionString.length());
auto currVersion = "v" + versionString.substr(0, versionLength);
auto latestVersion = releases.body["tag_name"].get<std::string_view>();
// Get the latest release version string
auto latestVersion = releases["tag_name"].get<std::string_view>();
// Check if the latest release is different from the current version
if (latestVersion != currVersion)
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
@@ -54,7 +72,28 @@ namespace hex::init {
bool setupEnvironment() {
hex::log::debug("Using romfs: '{}'", romfs::name());
Net::setCACert(std::string(romfs::get("cacert.pem").string()));
// Load the SSL certificate
constexpr static auto CaCertFileName = "cacert.pem";
// Look for a custom certificate in the config folder
std::fs::path caCertPath;
for (const auto &folder : fs::getDefaultPaths(fs::ImHexPath::Config)) {
for (const auto &file : std::fs::directory_iterator(folder)) {
if (file.path().filename() == CaCertFileName) {
caCertPath = file.path();
break;
}
}
}
// If a custom certificate was found, use it, otherwise use the one from the romfs
std::string caCertData;
if (!caCertPath.empty())
caCertData = wolv::io::File(caCertPath, wolv::io::File::Mode::Read).readString();
else
caCertData = std::string(romfs::get(CaCertFileName).string());
HttpRequest::setCACert(caCertData);
return true;
}
@@ -64,13 +103,13 @@ namespace hex::init {
using enum fs::ImHexPath;
// Create all folders
// Try to create all default directories
for (u32 path = 0; path < u32(fs::ImHexPath::END); path++) {
for (auto &folder : fs::getDefaultPaths(static_cast<fs::ImHexPath>(path), true)) {
try {
fs::createDirectories(folder);
wolv::io::fs::createDirectories(folder);
} catch (...) {
log::error("Failed to create folder {}!", hex::toUTF8String(folder));
log::error("Failed to create folder {}!", wolv::util::toUTF8String(folder));
result = false;
}
}
@@ -82,68 +121,132 @@ namespace hex::init {
return result;
}
bool migrateConfig(){
// check if there is a new config in folder
auto configPaths = hex::fs::getDefaultPaths(hex::fs::ImHexPath::Config, false);
// There should always be exactly one config path on Linux
std::fs::path newConfigPath = configPaths[0];
wolv::io::File newConfigFile(newConfigPath / "settings.json", wolv::io::File::Mode::Read);
if (!newConfigFile.isValid()) {
// find an old config
std::fs::path oldConfigPath;
for(auto dir : hex::fs::appendPath(hex::fs::getDataPaths(), "config")) {
wolv::io::File oldConfigFile(dir / "settings.json", wolv::io::File::Mode::Read);
if (oldConfigFile.isValid()) {
oldConfigPath = dir;
break;
}
}
if (!oldConfigPath.empty()) {
// move it to new location
auto configPaths = hex::fs::getDefaultPaths(hex::fs::ImHexPath::Config, false);
// There should always be exactly one config path on Linux
std::fs::path newConfigPath = configPaths[0];
log::info("Found config file in {} ! Migrating to {}", oldConfigPath.string(), newConfigPath.string());
std::fs::rename(oldConfigPath / "settings.json", newConfigPath / "settings.json");
wolv::io::File oldIniFile(oldConfigPath / "interface.ini", wolv::io::File::Mode::Read);
if (oldIniFile.isValid()) {
std::fs::rename(oldConfigPath / "interface.ini", newConfigPath / "interface.ini");
}
std::fs::remove(oldConfigPath);
}
}
return true;
}
static bool loadFontsImpl(bool loadUnicode) {
float fontSize = ImHexApi::System::getFontSize();
const auto &fontFile = ImHexApi::System::getCustomFontPath();
// Setup basic font configuration
auto fonts = IM_NEW(ImFontAtlas)();
ImFontConfig cfg = {};
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
cfg.OversampleH = cfg.OversampleV = 2, cfg.PixelSnapH = true;
cfg.SizePixels = fontSize;
fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
// Configure font glyph ranges that should be loaded from the default font and unifont
ImVector<ImWchar> ranges;
{
ImFontGlyphRangesBuilder glyphRangesBuilder;
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesDefault());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesJapanese());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesChineseFull());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesCyrillic());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesKorean());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesThai());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesVietnamese());
{
constexpr static ImWchar controlCodeRange[] = { 0x0000, 0x001F, 0 };
constexpr static ImWchar controlCodeRange[] = { 0x0001, 0x001F, 0 };
constexpr static ImWchar extendedAsciiRange[] = { 0x007F, 0x00FF, 0 };
glyphRangesBuilder.AddRanges(controlCodeRange);
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesDefault());
glyphRangesBuilder.AddRanges(extendedAsciiRange);
}
if (loadUnicode) {
constexpr static ImWchar fullRange[] = { 0x0100, 0xFFEF, 0 };
glyphRangesBuilder.AddRanges(fullRange);
} else {
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesJapanese());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesChineseFull());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesCyrillic());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesKorean());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesThai());
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesVietnamese());
}
glyphRangesBuilder.BuildRanges(&ranges);
}
// Glyph range for font awesome icons
ImWchar fontAwesomeRange[] = {
ICON_MIN_FA, ICON_MAX_FA, 0
};
// Glyph range for codicons icons
ImWchar codiconsRange[] = {
ICON_MIN_VS, ICON_MAX_VS, 0
};
// Load main font
// If a custom font has been specified, load it, otherwise load the default ImGui font
if (fontFile.empty()) {
// Load default font if no custom one has been specified
fonts->Clear();
fonts->AddFontDefault(&cfg);
} else {
// Load custom font
fonts->AddFontFromFileTTF(hex::toUTF8String(fontFile).c_str(), 0, &cfg, ranges.Data);
fonts->AddFontFromFileTTF(wolv::util::toUTF8String(fontFile).c_str(), 0, &cfg, ranges.Data);
}
// Merge all fonts into one big font atlas
cfg.MergeMode = true;
// Add font awesome and codicons icons to font atlas
fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 0, &cfg, fontAwesomeRange);
fonts->AddFontFromMemoryCompressedTTF(codicons_compressed_data, codicons_compressed_size, 0, &cfg, codiconsRange);
// Add unifont if unicode support is enabled
if (loadUnicode)
fonts->AddFontFromMemoryCompressedTTF(unifont_compressed_data, unifont_compressed_size, 0, &cfg, ranges.Data);
// Try to build the font atlas
if (!fonts->Build()) {
// The main reason the font atlas failed to build is that the font is too big for the GPU to handle
// If unicode support is enabled, therefor try to load the font atlas without unicode support
// If that still didn't work, there's probably something else going on with the graphics drivers
// Especially Intel GPU drivers are known to have various bugs
if (loadUnicode) {
log::error("Failed to build font atlas! Disabling Unicode support.");
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.enable_unicode", false);
IM_DELETE(fonts);
// Disable unicode support in settings
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.enable_unicode", false);
// Try to load the font atlas again
return loadFontsImpl(false);
} else {
log::error("Failed to build font atlas! Check your Graphics driver!");
@@ -151,6 +254,7 @@ namespace hex::init {
}
}
// Configure ImGui to use the font atlas
View::setFontAtlas(fonts);
View::setFontConfig(cfg);
@@ -162,11 +266,15 @@ namespace hex::init {
}
bool deleteSharedData() {
// This function is called when ImHex is closed. It deletes all shared data that was created by plugins
// This is a bit of a hack but necessary because when ImHex gets closed, all plugins are unloaded in order for
// destructors to be called correctly. To prevent crashes when ImHex exits, we need to delete all shared data
EventManager::clear();
while (ImHexApi::Provider::isValid())
ImHexApi::Provider::remove(ImHexApi::Provider::get());
ContentRegistry::Provider::getEntries().clear();
ContentRegistry::Provider::impl::getEntries().clear();
ImHexApi::System::getInitArguments().clear();
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
@@ -176,50 +284,51 @@ namespace hex::init {
ImHexApi::HexEditor::impl::getTooltips().clear();
ImHexApi::HexEditor::impl::getTooltipFunctions().clear();
ContentRegistry::Settings::getEntries().clear();
ContentRegistry::Settings::getSettingsData().clear();
ContentRegistry::Settings::impl::getEntries().clear();
ContentRegistry::Settings::impl::getSettingsData().clear();
ContentRegistry::CommandPaletteCommands::getEntries().clear();
ContentRegistry::CommandPaletteCommands::impl::getEntries().clear();
ContentRegistry::CommandPaletteCommands::impl::getHandlers().clear();
ContentRegistry::PatternLanguage::getFunctions().clear();
ContentRegistry::PatternLanguage::getPragmas().clear();
ContentRegistry::PatternLanguage::impl::getFunctions().clear();
ContentRegistry::PatternLanguage::impl::getPragmas().clear();
ContentRegistry::PatternLanguage::impl::getVisualizers().clear();
{
auto &views = ContentRegistry::Views::getEntries();
auto &views = ContentRegistry::Views::impl::getEntries();
for (auto &[name, view] : views)
delete view;
views.clear();
}
ContentRegistry::Tools::getEntries().clear();
ContentRegistry::DataInspector::getEntries().clear();
ContentRegistry::Tools::impl::getEntries().clear();
ContentRegistry::DataInspector::impl::getEntries().clear();
ContentRegistry::Language::getLanguages().clear();
ContentRegistry::Language::getLanguageDefinitions().clear();
ContentRegistry::Language::impl::getLanguages().clear();
ContentRegistry::Language::impl::getLanguageDefinitions().clear();
LangEntry::resetLanguageStrings();
ContentRegistry::Interface::getWelcomeScreenEntries().clear();
ContentRegistry::Interface::getFooterItems().clear();
ContentRegistry::Interface::getToolbarItems().clear();
ContentRegistry::Interface::getMainMenuItems().clear();
ContentRegistry::Interface::getMenuItems().clear();
ContentRegistry::Interface::getSidebarItems().clear();
ContentRegistry::Interface::getTitleBarButtons().clear();
ContentRegistry::Interface::getLayouts().clear();
ContentRegistry::Interface::impl::getWelcomeScreenEntries().clear();
ContentRegistry::Interface::impl::getFooterItems().clear();
ContentRegistry::Interface::impl::getToolbarItems().clear();
ContentRegistry::Interface::impl::getMainMenuItems().clear();
ContentRegistry::Interface::impl::getMenuItems().clear();
ContentRegistry::Interface::impl::getSidebarItems().clear();
ContentRegistry::Interface::impl::getTitleBarButtons().clear();
ContentRegistry::Interface::impl::getLayouts().clear();
ShortcutManager::clearShortcuts();
TaskManager::getRunningTasks().clear();
ContentRegistry::DataProcessorNode::getEntries().clear();
ContentRegistry::DataProcessorNode::impl::getEntries().clear();
ContentRegistry::DataFormatter::getEntries().clear();
ContentRegistry::FileHandler::getEntries().clear();
ContentRegistry::DataFormatter::impl::getEntries().clear();
ContentRegistry::FileHandler::impl::getEntries().clear();
ContentRegistry::Hashes::impl::getHashes().clear();
api::ThemeManager::reset();
ThemeManager::reset();
{
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
@@ -237,12 +346,15 @@ namespace hex::init {
}
bool loadPlugins() {
// Load plugins
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) {
PluginManager::load(dir);
}
// Get loaded plugins
auto &plugins = PluginManager::getPlugins();
// If no plugins were loaded, ImHex wasn't installed properly. This will trigger an error popup later on
if (plugins.empty()) {
log::error("No plugins found!");
@@ -250,7 +362,8 @@ namespace hex::init {
return false;
}
const auto shouldLoadPlugin = [executablePath = hex::fs::getExecutablePath()](const Plugin &plugin) {
const auto shouldLoadPlugin = [executablePath = wolv::io::fs::getExecutablePath()](const Plugin &plugin) {
// In debug builds, ignore all plugins that are not part of the executable directory
#if !defined(DEBUG)
return true;
#endif
@@ -258,12 +371,14 @@ namespace hex::init {
if (!executablePath.has_value())
return true;
// In debug builds, ignore all plugins that are not part of the executable directory
// Check if the plugin is somewhere in the same directory tree as the executable
return !std::fs::relative(plugin.getPath(), executablePath->parent_path()).string().starts_with("..");
};
u32 builtinPlugins = 0;
u32 loadErrors = 0;
// Load the builtin plugin first, so it can initialize everything that's necessary for ImHex to work
for (const auto &plugin : plugins) {
if (!plugin.isBuiltinPlugin()) continue;
@@ -272,15 +387,18 @@ namespace hex::init {
continue;
}
// Make sure there's only one built-in plugin
builtinPlugins++;
if (builtinPlugins > 1) continue;
// Initialize the plugin
if (!plugin.initializePlugin()) {
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
log::error("Failed to initialize plugin {}", wolv::util::toUTF8String(plugin.getPath().filename()));
loadErrors++;
}
}
// Load all other plugins
for (const auto &plugin : plugins) {
if (plugin.isBuiltinPlugin()) continue;
@@ -289,18 +407,22 @@ namespace hex::init {
continue;
}
// Initialize the plugin
if (!plugin.initializePlugin()) {
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
log::error("Failed to initialize plugin {}", wolv::util::toUTF8String(plugin.getPath().filename()));
loadErrors++;
}
}
// If no plugins were loaded successfully, ImHex wasn't installed properly. This will trigger an error popup later on
if (loadErrors == plugins.size()) {
log::error("No plugins loaded successfully!");
ImHexApi::System::impl::addInitArgument("no-plugins");
return false;
}
// ImHex requires exactly one built-in plugin
// If no built-in plugin or more than one was found, something's wrong and we can't continue
if (builtinPlugins == 0) {
log::error("Built-in plugin not found!");
ImHexApi::System::impl::addInitArgument("no-builtin-plugin");
@@ -322,12 +444,15 @@ namespace hex::init {
bool loadSettings() {
try {
ContentRegistry::Settings::load();
// Try to load settings from file
ContentRegistry::Settings::impl::load();
} catch (std::exception &e) {
// If that fails, create a new settings file
log::error("Failed to load configuration! {}", e.what());
ContentRegistry::Settings::clear();
ContentRegistry::Settings::store();
ContentRegistry::Settings::impl::clear();
ContentRegistry::Settings::impl::store();
return false;
}
@@ -337,7 +462,7 @@ namespace hex::init {
bool storeSettings() {
try {
ContentRegistry::Settings::store();
ContentRegistry::Settings::impl::store();
} catch (std::exception &e) {
log::error("Failed to store configuration! {}", e.what());
return false;
@@ -349,6 +474,9 @@ namespace hex::init {
return {
{ "Setting up environment", setupEnvironment, false },
{ "Creating directories", createDirectories, false },
#if defined(OS_LINUX)
{ "Migrate config to .config", migrateConfig, false },
#endif
{ "Loading settings", loadSettings, false },
{ "Loading plugins", loadPlugins, false },
{ "Checking for updates", checkForUpdates, true },

View File

@@ -1,6 +1,5 @@
#include <hex.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include "window.hpp"
@@ -10,23 +9,26 @@
#include <hex/api/project_file_manager.hpp>
#include <wolv/io/fs.hpp>
#include <wolv/utils/guards.hpp>
int main(int argc, char **argv, char **envp) {
using namespace hex;
ImHexApi::System::impl::setProgramArguments(argc, argv, envp);
bool shouldRestart = false;
// Check if ImHex is installed in portable mode
{
if (const auto executablePath = fs::getExecutablePath(); executablePath.has_value()) {
if (const auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
const auto flagFile = executablePath->parent_path() / "PORTABLE";
if (fs::exists(flagFile) && fs::isRegularFile(flagFile))
if (wolv::io::fs::exists(flagFile) && wolv::io::fs::isRegularFile(flagFile))
ImHexApi::System::impl::setPortableVersion(true);
}
}
bool shouldRestart = false;
do {
// Register a event to handle restarting of ImHex
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
shouldRestart = false;
@@ -38,15 +40,17 @@ int main(int argc, char **argv, char **envp) {
init::WindowSplash splashWindow;
// Add initialization tasks to run
TaskManager::init();
for (const auto &[name, task, async] : init::getInitTasks())
splashWindow.addStartupTask(name, task, async);
// Draw the splash window while tasks are running
if (!splashWindow.loop())
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
}
// Clean up
// Clean up everything after the main window is closed
ON_SCOPE_EXIT {
for (const auto &[name, task, async] : init::getExitTasks())
task();
@@ -65,7 +69,7 @@ int main(int argc, char **argv, char **envp) {
}
}
// Render the main window
window.loop();
}

View File

@@ -9,7 +9,10 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <wolv/utils/core.hpp>
#include <nlohmann/json.hpp>
#include <cstdio>
#include <sys/wait.h>
#include <unistd.h>
@@ -24,6 +27,12 @@ namespace hex {
setenv("LD_LIBRARY_PATH", hex::format("{};{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true);
}
// Various libraries sadly directly print to stderr with no way to disable it
// We redirect stderr to /dev/null to prevent this
wolv::util::unused(freopen("/dev/null", "w", stderr));
setvbuf(stderr, nullptr, _IONBF, 0);
// Redirect stdout to log file if we're not running in a terminal
if (!isatty(STDOUT_FILENO)) {
log::redirectToFile();
}
@@ -39,6 +48,7 @@ namespace hex {
std::array<char, 128> buffer = { 0 };
std::string result;
// Ask GNOME for the current theme
// TODO: In the future maybe support more DEs instead of just GNOME
FILE *pipe = popen("gsettings get org.gnome.desktop.interface gtk-theme 2>&1", "r");
if (pipe == nullptr) return;

View File

@@ -10,6 +10,7 @@
#include <hex/helpers/logger.hpp>
#include <nlohmann/json.hpp>
#include <cstdio>
#include <unistd.h>
#include <imgui_impl_glfw.h>
@@ -23,6 +24,12 @@ namespace hex {
setenv("LD_LIBRARY_PATH", hex::format("{};{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true);
}
// Various libraries sadly directly print to stderr with no way to disable it
// We redirect stderr to /dev/null to prevent this
freopen("/dev/null", "w", stderr);
setvbuf(stderr, nullptr, _IONBF, 0);
// Redirect stdout to log file if we're not running in a terminal
if (!isatty(STDOUT_FILENO)) {
log::redirectToFile();
}

View File

@@ -24,6 +24,7 @@
#include <wrl/client.h>
#include <csignal>
#include <cstdio>
#include <imgui_impl_glfw.h>
@@ -34,10 +35,12 @@ namespace hex {
static ImGuiMouseCursor g_mouseCursorIcon;
static Microsoft::WRL::ComPtr<ITaskbarList4> g_taskbarList;
// Custom Window procedure for receiving OS events
static LRESULT commonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_COPYDATA:
{
case WM_COPYDATA: {
// Handle opening files in existing instance
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
if (message == nullptr) break;
@@ -45,12 +48,12 @@ namespace hex {
if (data == nullptr) break;
std::fs::path path = data;
log::info("Opening file in existing instance: {}", hex::toUTF8String(path));
log::info("Opening file in existing instance: {}", wolv::util::toUTF8String(path));
EventManager::post<RequestOpenFile>(path);
break;
}
case WM_SETTINGCHANGE:
{
case WM_SETTINGCHANGE: {
// Handle Windows theme changes
if (lParam == 0) break;
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
@@ -66,120 +69,124 @@ namespace hex {
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
}
// Custom window procedure for borderless window
static LRESULT borderlessWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_NCACTIVATE:
case WM_NCPAINT:
// Handle Windows Aero Snap
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
case WM_NCCALCSIZE:
{
RECT &rect = *reinterpret_cast<RECT *>(lParam);
RECT client = rect;
case WM_NCCALCSIZE: {
// Handle window resizing
CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
RECT &rect = *reinterpret_cast<RECT *>(lParam);
RECT client = rect;
if (IsMaximized(hwnd)) {
WINDOWINFO windowInfo = { };
windowInfo.cbSize = sizeof(WINDOWINFO);
CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
GetWindowInfo(hwnd, &windowInfo);
rect = RECT {
.left = static_cast<LONG>(client.left + windowInfo.cyWindowBorders),
.top = static_cast<LONG>(client.top + windowInfo.cyWindowBorders),
.right = static_cast<LONG>(client.right - windowInfo.cyWindowBorders),
.bottom = static_cast<LONG>(client.bottom - windowInfo.cyWindowBorders) + 1
};
} else {
rect = client;
}
if (IsMaximized(hwnd)) {
WINDOWINFO windowInfo = { };
windowInfo.cbSize = sizeof(WINDOWINFO);
return 0;
}
case WM_SETCURSOR:
{
auto cursorPos = LOWORD(lParam);
switch (cursorPos) {
case HTRIGHT:
case HTLEFT:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeEW;
break;
case HTTOP:
case HTBOTTOM:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNS;
break;
case HTTOPLEFT:
case HTBOTTOMRIGHT:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNWSE;
break;
case HTTOPRIGHT:
case HTBOTTOMLEFT:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNESW;
break;
case HTCAPTION:
case HTCLIENT:
g_mouseCursorIcon = ImGuiMouseCursor_None;
break;
default:
break;
}
return TRUE;
}
case WM_NCHITTEST:
{
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
const POINT border {
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale() / 1.5F),
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale() / 1.5F)
GetWindowInfo(hwnd, &windowInfo);
rect = RECT {
.left = static_cast<LONG>(client.left + windowInfo.cyWindowBorders),
.top = static_cast<LONG>(client.top + windowInfo.cyWindowBorders),
.right = static_cast<LONG>(client.right - windowInfo.cyWindowBorders),
.bottom = static_cast<LONG>(client.bottom - windowInfo.cyWindowBorders) + 1
};
RECT window;
if (!::GetWindowRect(hwnd, &window)) {
return HTNOWHERE;
}
constexpr static auto RegionClient = 0b0000;
constexpr static auto RegionLeft = 0b0001;
constexpr static auto RegionRight = 0b0010;
constexpr static auto RegionTop = 0b0100;
constexpr static auto RegionBottom = 0b1000;
const auto result =
RegionLeft * (cursor.x < (window.left + border.x)) |
RegionRight * (cursor.x >= (window.right - border.x)) |
RegionTop * (cursor.y < (window.top + border.y)) |
RegionBottom * (cursor.y >= (window.bottom - border.y));
if (result != 0 && (ImGui::IsItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
break;
switch (result) {
case RegionLeft:
return HTLEFT;
case RegionRight:
return HTRIGHT;
case RegionTop:
return HTTOP;
case RegionBottom:
return HTBOTTOM;
case RegionTop | RegionLeft:
return HTTOPLEFT;
case RegionTop | RegionRight:
return HTTOPRIGHT;
case RegionBottom | RegionLeft:
return HTBOTTOMLEFT;
case RegionBottom | RegionRight:
return HTBOTTOMRIGHT;
case RegionClient:
default:
if ((cursor.y < (window.top + g_titleBarHeight * 2)) && !(ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
return HTCAPTION;
else break;
}
break;
} else {
rect = client;
}
return 0;
}
case WM_SETCURSOR: {
// Handle mouse cursor icon
auto cursorPos = LOWORD(lParam);
switch (cursorPos) {
case HTRIGHT:
case HTLEFT:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeEW;
break;
case HTTOP:
case HTBOTTOM:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNS;
break;
case HTTOPLEFT:
case HTBOTTOMRIGHT:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNWSE;
break;
case HTTOPRIGHT:
case HTBOTTOMLEFT:
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNESW;
break;
case HTCAPTION:
case HTCLIENT:
g_mouseCursorIcon = ImGuiMouseCursor_None;
break;
default:
break;
}
return TRUE;
}
case WM_NCHITTEST: {
// Handle window resizing and moving
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
const POINT border {
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale() / 1.5F),
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale() / 1.5F)
};
RECT window;
if (!::GetWindowRect(hwnd, &window)) {
return HTNOWHERE;
}
constexpr static auto RegionClient = 0b0000;
constexpr static auto RegionLeft = 0b0001;
constexpr static auto RegionRight = 0b0010;
constexpr static auto RegionTop = 0b0100;
constexpr static auto RegionBottom = 0b1000;
const auto result =
RegionLeft * (cursor.x < (window.left + border.x)) |
RegionRight * (cursor.x >= (window.right - border.x)) |
RegionTop * (cursor.y < (window.top + border.y)) |
RegionBottom * (cursor.y >= (window.bottom - border.y));
if (result != 0 && (ImGui::IsItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
break;
switch (result) {
case RegionLeft:
return HTLEFT;
case RegionRight:
return HTRIGHT;
case RegionTop:
return HTTOP;
case RegionBottom:
return HTBOTTOM;
case RegionTop | RegionLeft:
return HTTOPLEFT;
case RegionTop | RegionRight:
return HTTOPRIGHT;
case RegionBottom | RegionLeft:
return HTBOTTOMLEFT;
case RegionBottom | RegionRight:
return HTBOTTOMRIGHT;
case RegionClient:
default:
if ((cursor.y < (window.top + g_titleBarHeight * 2)) && !(ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
return HTCAPTION;
else break;
}
break;
}
default:
break;
}
@@ -197,16 +204,18 @@ namespace hex {
AddDllDirectory(path.c_str());
}
// Various libraries sadly directly print to stderr with no way to disable it
// We redirect stderr to NUL to prevent this
freopen("NUL:", "w", stderr);
setvbuf(stderr, nullptr, _IONBF, 0);
// Attach to parent console if one exists
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
// Redirect cin, cout and cerr to that console
// Redirect stdin and stdout to that new console
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
setvbuf(stdin, nullptr, _IONBF, 0);
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
fmt::print("\n");
@@ -230,24 +239,32 @@ namespace hex {
HANDLE globalMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, UniqueMutexId);
if (!globalMutex) {
// If no ImHex instance is running, create a new global mutex
globalMutex = CreateMutex(nullptr, FALSE, UniqueMutexId);
} else {
// If an ImHex instance is already running, send the file path to it and exit
if (ImHexApi::System::getProgramArguments().argc > 1) {
// Find the ImHex Window and send the file path as a message to it
::EnumWindows([](HWND hWnd, LPARAM) -> BOOL {
auto &programArgs = ImHexApi::System::getProgramArguments();
// Get the window name
auto length = ::GetWindowTextLength(hWnd);
std::string windowName(length + 1, '\x00');
::GetWindowText(hWnd, windowName.data(), windowName.size());
// Check if the window is visible and if it's an ImHex window
if (::IsWindowVisible(hWnd) && length != 0) {
if (windowName.starts_with("ImHex")) {
// Create the message
COPYDATASTRUCT message = {
.dwData = 0,
.cbData = static_cast<DWORD>(std::strlen(programArgs.argv[1])) + 1,
.lpData = programArgs.argv[1]
};
// Send the message
SendMessage(hWnd, WM_COPYDATA, reinterpret_cast<WPARAM>(hWnd), reinterpret_cast<LPARAM>(&message));
return FALSE;
@@ -255,8 +272,7 @@ namespace hex {
}
return TRUE;
},
0);
}, 0);
std::exit(0);
}
@@ -271,7 +287,7 @@ namespace hex {
ImGui_ImplGlfw_SetBorderlessWindowMode(borderlessWindowMode);
// Set up the correct window procedure based on the borderless window mode state
if (borderlessWindowMode) {
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)borderlessWindowProc);
@@ -287,7 +303,7 @@ namespace hex {
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)commonWindowProc);
}
// Catch heap corruption
// Add a custom exception handler to detect heap corruptions
{
::AddVectoredExceptionHandler(TRUE, [](PEXCEPTION_POINTERS exception) -> LONG {
if ((exception->ExceptionRecord->ExceptionCode & 0xF000'0000) == 0xC000'0000) {
@@ -302,40 +318,42 @@ namespace hex {
});
}
if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) {
CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList4, &g_taskbarList);
// Set up a taskbar progress handler
{
if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) {
CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList4, &g_taskbarList);
}
EventManager::subscribe<EventSetTaskBarIconState>([hwnd](u32 state, u32 type, u32 progress){
using enum ImHexApi::System::TaskProgressState;
switch (ImHexApi::System::TaskProgressState(state)) {
case Reset:
g_taskbarList->SetProgressState(hwnd, TBPF_NOPROGRESS);
g_taskbarList->SetProgressValue(hwnd, 0, 0);
break;
case Flash:
FlashWindow(hwnd, true);
break;
case Progress:
g_taskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE);
g_taskbarList->SetProgressValue(hwnd, progress, 100);
break;
}
using enum ImHexApi::System::TaskProgressType;
switch (ImHexApi::System::TaskProgressType(type)) {
case Normal:
g_taskbarList->SetProgressState(hwnd, TBPF_NORMAL);
break;
case Warning:
g_taskbarList->SetProgressState(hwnd, TBPF_PAUSED);
break;
case Error:
g_taskbarList->SetProgressState(hwnd, TBPF_ERROR);
break;
}
});
}
EventManager::subscribe<EventSetTaskBarIconState>([hwnd](u32 state, u32 type, u32 progress){
using enum ImHexApi::System::TaskProgressState;
switch (ImHexApi::System::TaskProgressState(state)) {
case Reset:
g_taskbarList->SetProgressState(hwnd, TBPF_NOPROGRESS);
g_taskbarList->SetProgressValue(hwnd, 0, 0);
break;
case Flash:
FlashWindow(hwnd, true);
break;
case Progress:
g_taskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE);
g_taskbarList->SetProgressValue(hwnd, progress, 100);
break;
}
using enum ImHexApi::System::TaskProgressType;
switch (ImHexApi::System::TaskProgressType(type)) {
case Normal:
g_taskbarList->SetProgressState(hwnd, TBPF_NORMAL);
break;
case Warning:
g_taskbarList->SetProgressState(hwnd, TBPF_PAUSED);
break;
case Error:
g_taskbarList->SetProgressState(hwnd, TBPF_ERROR);
break;
}
});
}
void Window::beginNativeWindowFrame() {
@@ -350,6 +368,7 @@ namespace hex {
ImGui::SetMouseCursor(g_mouseCursorIcon);
}
// Translate ImGui mouse cursors to Win32 mouse cursors
switch (ImGui::GetMouseCursor()) {
case ImGuiMouseCursor_Arrow:
SetCursor(LoadCursor(nullptr, IDC_ARROW));
@@ -386,6 +405,8 @@ namespace hex {
}
void Window::drawTitleBar() {
// In borderless window mode, we draw our own title bar
if (!ImHexApi::System::isBorderlessWindowModeEnabled()) return;
auto startX = ImGui::GetCursorPosX();
@@ -397,8 +418,9 @@ namespace hex {
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered));
auto &titleBarButtons = ContentRegistry::Interface::getTitleBarButtons();
auto &titleBarButtons = ContentRegistry::Interface::impl::getTitleBarButtons();
// Draw custom title bar buttons
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * (4 + titleBarButtons.size()));
for (const auto &[icon, tooltip, callback] : titleBarButtons) {
if (ImGui::TitleBarButton(icon.c_str(), buttonSize)) {
@@ -407,6 +429,7 @@ namespace hex {
ImGui::InfoTooltip(LangEntry(tooltip));
}
// Draw minimize, restore and maximize buttons
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3);
if (ImGui::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize))
glfwIconifyWindow(this->m_window);
@@ -421,9 +444,9 @@ namespace hex {
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8);
// Draw close button
if (ImGui::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) {
ImHexApi::Common::closeImHex();
ImHexApi::System::closeImHex();
}
ImGui::PopStyleColor(5);

View File

@@ -41,45 +41,22 @@ namespace hex {
using namespace std::literals::chrono_literals;
void *ImHexSettingsHandler_ReadOpenFn(ImGuiContext *ctx, ImGuiSettingsHandler *, const char *) {
return ctx; // Unused, but the return value has to be non-null
}
void ImHexSettingsHandler_ReadLine(ImGuiContext *, ImGuiSettingsHandler *, void *, const char *line) {
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
std::string format = view->getUnlocalizedName() + "=%d";
sscanf(line, format.c_str(), &view->getWindowOpenState());
}
for (auto &[name, function, detached] : ContentRegistry::Tools::getEntries()) {
std::string format = name + "=%d";
sscanf(line, format.c_str(), &detached);
}
}
void ImHexSettingsHandler_WriteAll(ImGuiContext *, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf) {
buf->appendf("[%s][General]\n", handler->TypeName);
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
buf->appendf("%s=%d\n", name.c_str(), view->getWindowOpenState());
}
for (auto &[name, function, detached] : ContentRegistry::Tools::getEntries()) {
buf->appendf("%s=%d\n", name.c_str(), detached);
}
buf->append("\n");
}
static void signalHandler(int signalNumber, std::string signalName) {
// Custom signal handler to print various information and a stacktrace when the application crashes
static void signalHandler(int signalNumber, const std::string &signalName) {
log::fatal("Terminating with signal '{}' ({})", signalName, signalNumber);
// Trigger an event so that plugins can handle crashes
EventManager::post<EventAbnormalTermination>(signalNumber);
// Detect if the crash was due to an uncaught exception
if (std::uncaught_exceptions() > 0) {
log::fatal("Uncaught exception thrown!");
}
// Reset the signal handler to the default handler
std::signal(signalNumber, SIG_DFL);
// Print stack trace
for (const auto &stackFrame : stacktrace::getStackTrace()) {
if (stackFrame.line == 0)
log::fatal(" {}", stackFrame.function);
@@ -87,7 +64,7 @@ namespace hex {
log::fatal(" ({}:{}) | {}", stackFrame.file, stackFrame.line, stackFrame.function);
}
// Trigger a breakpoint if we're in a debug build or raise the signal again for the default handler to handle it
#if defined(DEBUG)
assert(!"Debug build, triggering breakpoint");
#else
@@ -107,6 +84,7 @@ namespace hex {
});
};
// Handle fatal error popups for errors detected during initialization
{
for (const auto &[argument, value] : ImHexApi::System::getInitArguments()) {
if (argument == "no-plugins") {
@@ -119,13 +97,36 @@ namespace hex {
}
}
// Initialize the window
this->initGLFW();
this->initImGui();
this->setupNativeWindow();
this->registerEventHandlers();
auto logoData = romfs::get("logo.png");
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logoData.data()), logoData.size());
ContentRegistry::Settings::impl::store();
EventManager::post<EventSettingsChanged>();
EventManager::post<EventWindowInitialized>();
}
Window::~Window() {
EventManager::unsubscribe<EventProviderDeleted>(this);
EventManager::unsubscribe<RequestCloseImHex>(this);
EventManager::unsubscribe<RequestUpdateWindowTitle>(this);
EventManager::unsubscribe<EventAbnormalTermination>(this);
EventManager::unsubscribe<RequestOpenPopup>(this);
this->exitImGui();
this->exitGLFW();
}
void Window::registerEventHandlers() {
// Initialize default theme
EventManager::post<RequestChangeTheme>("Dark");
// Handle the close window request by telling GLFW to shut down
EventManager::subscribe<RequestCloseImHex>(this, [this](bool noQuestions) {
glfwSetWindowShouldClose(this->m_window, GLFW_TRUE);
@@ -133,10 +134,13 @@ namespace hex {
EventManager::post<EventWindowClosing>(this->m_window);
});
// Handle updating the window title
EventManager::subscribe<RequestUpdateWindowTitle>(this, [this]() {
std::string title = "ImHex";
if (ProjectFile::hasPath()) {
// If a project is open, show the project name instead of the file name
title += " - Project " + hex::limitStringLength(ProjectFile::getPath().stem().string(), 32);
if (ImHexApi::Provider::isDirty())
@@ -161,8 +165,9 @@ namespace hex {
constexpr static auto CrashBackupFileName = "crash_backup.hexproj";
// Save a backup project when the application crashes
EventManager::subscribe<EventAbnormalTermination>(this, [this](int) {
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
ImGui::SaveIniSettingsToDisk(wolv::util::toUTF8String(this->m_imguiSettingsPath).c_str());
if (!ImHexApi::Provider::isDirty())
return;
@@ -173,21 +178,28 @@ namespace hex {
}
});
// Handle opening popups
EventManager::subscribe<RequestOpenPopup>(this, [this](auto name) {
std::scoped_lock lock(this->m_popupMutex);
this->m_popupsToOpen.push_back(name);
});
#define HANDLE_SIGNAL(name) \
std::signal(name, [](int signalNumber){ \
signalHandler(signalNumber, #name); \
});
HANDLE_SIGNAL(SIGSEGV)
HANDLE_SIGNAL(SIGILL)
HANDLE_SIGNAL(SIGABRT)
HANDLE_SIGNAL(SIGFPE)
#undef HANDLE_SIGNAL
// Register signal handlers
{
#define HANDLE_SIGNAL(name) \
std::signal(name, [](int signalNumber){ \
signalHandler(signalNumber, #name); \
});
HANDLE_SIGNAL(SIGSEGV)
HANDLE_SIGNAL(SIGILL)
HANDLE_SIGNAL(SIGABRT)
HANDLE_SIGNAL(SIGFPE)
#undef HANDLE_SIGNAL
}
std::set_terminate([]{
try {
std::rethrow_exception(std::current_exception());
@@ -200,56 +212,55 @@ namespace hex {
}
EventManager::post<EventAbnormalTermination>(0);
});
auto logoData = romfs::get("logo.png");
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logoData.data()), logoData.size());
ContentRegistry::Settings::store();
EventManager::post<EventSettingsChanged>();
EventManager::post<EventWindowInitialized>();
}
Window::~Window() {
EventManager::unsubscribe<EventProviderDeleted>(this);
EventManager::unsubscribe<RequestCloseImHex>(this);
EventManager::unsubscribe<RequestUpdateWindowTitle>(this);
EventManager::unsubscribe<EventAbnormalTermination>(this);
EventManager::unsubscribe<RequestOpenPopup>(this);
this->exitImGui();
this->exitGLFW();
}
void Window::loop() {
this->m_lastFrameTime = glfwGetTime();
while (!glfwWindowShouldClose(this->m_window)) {
if (!glfwGetWindowAttrib(this->m_window, GLFW_VISIBLE) || glfwGetWindowAttrib(this->m_window, GLFW_ICONIFIED)) {
// If the application is minimized or not visible, don't render anything
glfwWaitEvents();
} else {
glfwPollEvents();
bool frameRateUnlocked = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || TaskManager::getRunningTaskCount() > 0 || this->m_mouseButtonDown || this->m_hadEvent || !this->m_pressedKeys.empty();
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime));
this->m_hadEvent = false;
// If no events have been received in a while, lower the frame rate
{
// If the mouse is down, the mouse is moving or a popup is open, we don't want to lower the frame rate
bool frameRateUnlocked =
ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) ||
TaskManager::getRunningTaskCount() > 0 ||
this->m_mouseButtonDown ||
this->m_hadEvent ||
!this->m_pressedKeys.empty();
if ((this->m_lastFrameTime - this->m_frameRateUnlockTime) > 5 && this->m_frameRateTemporarilyUnlocked && !frameRateUnlocked) {
this->m_frameRateTemporarilyUnlocked = false;
}
// Calculate the time until the next frame
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime));
if (frameRateUnlocked || this->m_frameRateTemporarilyUnlocked) {
if (!this->m_frameRateTemporarilyUnlocked) {
this->m_frameRateTemporarilyUnlocked = true;
this->m_frameRateUnlockTime = this->m_lastFrameTime;
// If the frame rate has been unlocked for 5 seconds, lock it again
if ((this->m_lastFrameTime - this->m_frameRateUnlockTime) > 5 && this->m_frameRateTemporarilyUnlocked && !frameRateUnlocked) {
this->m_frameRateTemporarilyUnlocked = false;
}
} else {
glfwWaitEventsTimeout(timeout);
// If the frame rate is locked, wait for events with a timeout
if (frameRateUnlocked || this->m_frameRateTemporarilyUnlocked) {
if (!this->m_frameRateTemporarilyUnlocked) {
this->m_frameRateTemporarilyUnlocked = true;
this->m_frameRateUnlockTime = this->m_lastFrameTime;
}
} else {
glfwWaitEventsTimeout(timeout);
}
this->m_hadEvent = false;
}
}
// Render frame
this->frameBegin();
this->frame();
this->frameEnd();
// Limit frame rate
const auto targetFps = ImHexApi::System::getTargetFPS();
if (targetFps <= 200) {
auto leftoverFrameTime = i64((this->m_lastFrameTime + 1 / targetFps - glfwGetTime()) * 1000);
@@ -261,12 +272,34 @@ namespace hex {
}
}
void Window::frameBegin() {
static void createNestedMenu(std::span<const std::string> menuItems, const Shortcut &shortcut, const std::function<void()> &callback, const std::function<bool()> &enabledCallback) {
const auto &name = menuItems.front();
if (name == ContentRegistry::Interface::impl::SeparatorValue) {
ImGui::Separator();
return;
}
if (name == ContentRegistry::Interface::impl::SubMenuValue) {
callback();
} else if (menuItems.size() == 1) {
if (ImGui::MenuItem(LangEntry(name), shortcut.toString().c_str(), false, enabledCallback()))
callback();
} else {
if (ImGui::BeginMenu(LangEntry(name))) {
createNestedMenu({ menuItems.begin() + 1, menuItems.end() }, shortcut, callback, enabledCallback);
ImGui::EndMenu();
}
}
}
void Window::frameBegin() {
// Start new ImGui Frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Handle all undocked floating windows
ImGuiViewport *viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(ImHexApi::System::getMainWindowSize() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing()));
@@ -279,44 +312,50 @@ namespace hex {
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
// Render main dock space
if (ImGui::Begin("ImHexDockSpace", nullptr, windowFlags)) {
auto drawList = ImGui::GetWindowDrawList();
ImGui::PopStyleVar();
auto sidebarPos = ImGui::GetCursorPos();
auto sidebarWidth = ContentRegistry::Interface::getSidebarItems().empty() ? 0 : 30_scaled;
auto sidebarWidth = ContentRegistry::Interface::impl::getSidebarItems().empty() ? 0 : 30_scaled;
ImGui::SetCursorPosX(sidebarWidth);
auto footerHeight = ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().FramePadding.y * 2 + 1_scaled;
auto dockSpaceSize = ImVec2(ImHexApi::System::getMainWindowSize().x - sidebarWidth, ImGui::GetContentRegionAvail().y - footerHeight);
auto dockId = ImGui::DockSpace(ImGui::GetID("ImHexMainDock"), dockSpaceSize);
ImHexApi::System::impl::setMainDockSpaceId(dockId);
// Render footer
{
drawList->AddRectFilled(ImGui::GetWindowPos(), ImGui::GetWindowPos() + ImGui::GetWindowSize() - ImVec2(dockSpaceSize.x, footerHeight - ImGui::GetStyle().FramePadding.y - 1_scaled), ImGui::GetColorU32(ImGuiCol_MenuBarBg));
auto dockId = ImGui::DockSpace(ImGui::GetID("ImHexMainDock"), dockSpaceSize);
ImHexApi::System::impl::setMainDockSpaceId(dockId);
ImGui::Separator();
ImGui::SetCursorPosX(8);
for (const auto &callback : ContentRegistry::Interface::getFooterItems()) {
auto prevIdx = drawList->_VtxCurrentIdx;
callback();
auto currIdx = drawList->_VtxCurrentIdx;
drawList->AddRectFilled(ImGui::GetWindowPos(), ImGui::GetWindowPos() + ImGui::GetWindowSize() - ImVec2(dockSpaceSize.x, footerHeight - ImGui::GetStyle().FramePadding.y - 1_scaled), ImGui::GetColorU32(ImGuiCol_MenuBarBg));
// Only draw separator if something was actually drawn
if (prevIdx != currIdx) {
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
ImGui::Separator();
ImGui::SetCursorPosX(8);
for (const auto &callback : ContentRegistry::Interface::impl::getFooterItems()) {
auto prevIdx = drawList->_VtxCurrentIdx;
callback();
auto currIdx = drawList->_VtxCurrentIdx;
// Only draw separator if something was actually drawn
if (prevIdx != currIdx) {
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
}
}
}
// Render sidebar
{
ImGui::SetCursorPos(sidebarPos);
static i32 openWindow = -1;
u32 index = 0;
ImGui::PushID("SideBarWindows");
for (const auto &[icon, callback] : ContentRegistry::Interface::getSidebarItems()) {
for (const auto &[icon, callback] : ContentRegistry::Interface::impl::getSidebarItems()) {
ImGui::SetCursorPosY(sidebarPos.y + sidebarWidth * index);
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetColorU32(ImGuiCol_MenuBarBg));
@@ -355,6 +394,7 @@ namespace hex {
ImGui::PopID();
}
// Render main menu
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
if (ImGui::BeginMainMenuBar()) {
@@ -364,22 +404,15 @@ namespace hex {
ImGui::Image(this->m_logoTexture, ImVec2(menuBarHeight, menuBarHeight));
}
for (const auto &[priority, menuItem] : ContentRegistry::Interface::getMainMenuItems()) {
for (const auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMainMenuItems()) {
if (ImGui::BeginMenu(LangEntry(menuItem.unlocalizedName))) {
ImGui::EndMenu();
}
}
std::set<std::string> encounteredMenus;
for (auto &[priority, menuItem] : ContentRegistry::Interface::getMenuItems()) {
if (ImGui::BeginMenu(LangEntry(menuItem.unlocalizedName))) {
auto [iter, inserted] = encounteredMenus.insert(menuItem.unlocalizedName);
if (!inserted)
ImGui::Separator();
menuItem.callback();
ImGui::EndMenu();
}
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
const auto &[unlocalizedNames, shortcut, callback, enabledCallback] = menuItem;
createNestedMenu(unlocalizedNames, shortcut, callback, enabledCallback);
}
this->drawTitleBar();
@@ -388,10 +421,10 @@ namespace hex {
}
ImGui::PopStyleVar();
// Draw toolbar
// Render toolbar
if (ImGui::BeginMenuBar()) {
for (const auto &callback : ContentRegistry::Interface::getToolbarItems()) {
for (const auto &callback : ContentRegistry::Interface::impl::getToolbarItems()) {
callback();
ImGui::SameLine();
}
@@ -422,14 +455,15 @@ namespace hex {
const auto filePath = path / "builtin.hexplug";
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(hex::toUTF8String(filePath).c_str());
ImGui::TextUnformatted(wolv::util::toUTF8String(filePath).c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
ImGui::TextUnformatted(wolv::io::fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
}
ImGui::EndTable();
}
};
// No plugins error popup
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
if (ImGui::BeginPopupModal("No Plugins", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) {
ImGui::TextUnformatted("No ImHex plugins loaded (including the built-in plugin)!");
@@ -443,6 +477,7 @@ namespace hex {
ImGui::EndPopup();
}
// No built-in plugin error popup
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
if (ImGui::BeginPopupModal("No Builtin Plugin", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) {
ImGui::TextUnformatted("The ImHex built-in plugins could not be loaded!");
@@ -456,6 +491,7 @@ namespace hex {
ImGui::EndPopup();
}
// Multiple built-in plugins error popup
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
if (ImGui::BeginPopupModal("Multiple Builtin Plugins", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) {
ImGui::TextUnformatted("ImHex found and attempted to load multiple built-in plugins!");
@@ -470,6 +506,8 @@ namespace hex {
ImGui::EndPopup();
}
}
// Open popups when plugins requested it
{
std::scoped_lock lock(this->m_popupMutex);
this->m_popupsToOpen.remove_if([](const auto &name) {
@@ -482,33 +520,51 @@ namespace hex {
});
}
// Run all deferred calls
TaskManager::runDeferredCalls();
// Draw main menu popups
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
const auto &[unlocalizedNames, shortcut, callback, enabledCallback] = menuItem;
if (ImGui::BeginPopup(unlocalizedNames.front().c_str())) {
createNestedMenu({ unlocalizedNames.begin() + 1, unlocalizedNames.end() }, shortcut, callback, enabledCallback);
ImGui::EndPopup();
}
}
EventManager::post<EventFrameBegin>();
}
void Window::frame() {
auto &io = ImGui::GetIO();
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
const bool popupOpen = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId);
// Loop through all views and draw them
for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) {
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
// Draw always visible views
view->drawAlwaysVisible();
// Skip views that shouldn't be processed currently
if (!view->shouldProcess())
continue;
// Draw view
if (view->isAvailable()) {
float fontScaling = std::max(1.0F, ImHexApi::System::getFontSize() / ImHexApi::System::DefaultFontSize) * ImHexApi::System::getGlobalScale();
ImGui::SetNextWindowSizeConstraints(view->getMinSize() * fontScaling, view->getMaxSize() * fontScaling);
ImGui::SetNextWindowSizeConstraints(scaled(view->getMinSize()), scaled(view->getMaxSize()));
view->drawContent();
}
if (view->getWindowOpenState()) {
// Handle per-view shortcuts
if (view->getWindowOpenState() && !popupOpen) {
auto window = ImGui::FindWindowByName(view->getName().c_str());
bool hasWindow = window != nullptr;
bool focused = false;
// Get the currently focused view
if (hasWindow && !(window->Flags & ImGuiWindowFlags_Popup)) {
ImGui::Begin(View::toWindowName(name).c_str());
@@ -516,14 +572,18 @@ namespace hex {
ImGui::End();
}
// Pass on currently pressed keys to the shortcut handler
for (const auto &key : this->m_pressedKeys) {
ShortcutManager::process(view, io.KeyCtrl, io.KeyAlt, io.KeyShift, io.KeySuper, focused, key);
}
}
}
for (const auto &key : this->m_pressedKeys) {
ShortcutManager::processGlobals(io.KeyCtrl, io.KeyAlt, io.KeyShift, io.KeySuper, key);
// Handle global shortcuts
if (!popupOpen) {
for (const auto &key : this->m_pressedKeys) {
ShortcutManager::processGlobals(io.KeyCtrl, io.KeyAlt, io.KeyShift, io.KeySuper, key);
}
}
this->m_pressedKeys.clear();
@@ -532,9 +592,12 @@ namespace hex {
void Window::frameEnd() {
EventManager::post<EventFrameEnd>();
// Clean up all tasks that are done
TaskManager::collectGarbage();
this->endNativeWindowFrame();
// Render UI
ImGui::Render();
int displayWidth, displayHeight;
@@ -562,6 +625,7 @@ namespace hex {
std::abort();
}
// Set up used OpenGL version
#if defined(OS_MACOS)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
@@ -576,6 +640,7 @@ namespace hex {
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
// Create window
this->m_windowTitle = "ImHex";
this->m_window = glfwCreateWindow(1280_scaled, 720_scaled, this->m_windowTitle.c_str(), nullptr, nullptr);
@@ -589,6 +654,7 @@ namespace hex {
glfwMakeContextCurrent(this->m_window);
glfwSwapInterval(1);
// Center window
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
if (monitor != nullptr) {
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
@@ -603,6 +669,7 @@ namespace hex {
}
}
// Set up initial window position
{
int x = 0, y = 0;
glfwGetWindowPos(this->m_window, &x, &y);
@@ -610,6 +677,7 @@ namespace hex {
ImHexApi::System::impl::setMainWindowPosition(x, y);
}
// Set up initial window size
{
int width = 0, height = 0;
glfwGetWindowSize(this->m_window, &width, &height);
@@ -617,6 +685,7 @@ namespace hex {
ImHexApi::System::impl::setMainWindowSize(width, height);
}
// Register window move callback
glfwSetWindowPosCallback(this->m_window, [](GLFWwindow *window, int x, int y) {
ImHexApi::System::impl::setMainWindowPosition(x, y);
@@ -629,6 +698,7 @@ namespace hex {
win->processEvent();
});
// Register window resize callback
glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) {
if (!glfwGetWindowAttrib(window, GLFW_ICONIFIED))
ImHexApi::System::impl::setMainWindowSize(width, height);
@@ -642,6 +712,7 @@ namespace hex {
win->processEvent();
});
// Register mouse handling callback
glfwSetMouseButtonCallback(this->m_window, [](GLFWwindow *window, int button, int action, int mods) {
hex::unused(button, mods);
@@ -654,6 +725,15 @@ namespace hex {
win->processEvent();
});
// Register scrolling callback
glfwSetScrollCallback(this->m_window, [](GLFWwindow *window, double xOffset, double yOffset) {
hex::unused(xOffset, yOffset);
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
win->processEvent();
});
// Register key press callback
glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) {
hex::unused(mods);
@@ -669,28 +749,7 @@ namespace hex {
win->processEvent();
});
glfwSetDropCallback(this->m_window, [](GLFWwindow *, int count, const char **paths) {
for (int i = 0; i < count; i++) {
auto path = std::fs::path(reinterpret_cast<const char8_t *>(paths[i]));
bool handled = false;
for (const auto &[extensions, handler] : ContentRegistry::FileHandler::getEntries()) {
for (const auto &extension : extensions) {
if (path.extension() == extension) {
if (!handler(path))
log::error("Handler for extensions '{}' failed to process file!", extension);
handled = true;
break;
}
}
}
if (!handled)
EventManager::post<RequestOpenFile>(path);
}
});
// Register cursor position callback
glfwSetCursorPosCallback(this->m_window, [](GLFWwindow *window, double x, double y) {
hex::unused(x, y);
@@ -698,10 +757,39 @@ namespace hex {
win->processEvent();
});
// Register window close callback
glfwSetWindowCloseCallback(this->m_window, [](GLFWwindow *window) {
EventManager::post<EventWindowClosing>(window);
});
// Register file drop callback
glfwSetDropCallback(this->m_window, [](GLFWwindow *, int count, const char **paths) {
// Loop over all dropped files
for (int i = 0; i < count; i++) {
auto path = std::fs::path(reinterpret_cast<const char8_t *>(paths[i]));
// Check if a custom file handler can handle the file
bool handled = false;
for (const auto &[extensions, handler] : ContentRegistry::FileHandler::impl::getEntries()) {
for (const auto &extension : extensions) {
if (path.extension() == extension) {
// Pass the file to the handler and check if it was successful
if (!handler(path)) {
log::error("Handler for extensions '{}' failed to process file!", extension);
break;
}
handled = true;
}
}
}
// If no custom handler was found, just open the file regularly
if (!handled)
EventManager::post<RequestOpenFile>(path);
}
});
glfwSetWindowSizeLimits(this->m_window, 720_scaled, 480_scaled, GLFW_DONT_CARE, GLFW_DONT_CARE);
glfwShowWindow(this->m_window);
@@ -712,6 +800,7 @@ namespace hex {
auto fonts = View::getFontAtlas();
// Initialize ImGui and all other ImGui extensions
GImGui = ImGui::CreateContext(fonts);
GImPlot = ImPlot::CreateContext();
GImNodes = ImNodes::CreateContext();
@@ -719,6 +808,7 @@ namespace hex {
ImGuiIO &io = ImGui::GetIO();
ImGuiStyle &style = ImGui::GetStyle();
// Configure window alpha and rounding to make them not stand out when detached
style.Alpha = 1.0F;
style.WindowRounding = 0.0F;
@@ -726,9 +816,9 @@ namespace hex {
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigWindowsMoveFromTitleBarOnly = true;
io.FontGlobalScale = 1.0F;
io.FontGlobalScale = ImHexApi::System::getGlobalScale();
// Disable multi-window support on Wayland since it doesn't support it
if (glfwGetPrimaryMonitor() != nullptr) {
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", 1) != 0;
@@ -745,8 +835,9 @@ namespace hex {
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkCreationOnSnap);
// Allow ImNodes links to always be detached without holding down any button
{
static bool always = true;
static bool always = true;
ImNodes::GetIO().LinkDetachWithModifierClick.Modifier = &always;
}
@@ -755,46 +846,58 @@ namespace hex {
auto scale = ImHexApi::System::getGlobalScale();
style.ScaleAllSizes(scale);
io.DisplayFramebufferScale = ImVec2(scale, scale);
{
GLsizei width, height;
u8 *fontData;
io.Fonts->GetTexDataAsRGBA32(&fontData, &width, &height);
// Create new font atlas
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA8, GL_UNSIGNED_INT, fontData);
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(tex));
}
io.Fonts->SetTexID(fonts->TexID);
style.WindowMenuButtonPosition = ImGuiDir_None;
style.IndentSpacing = 10.0F;
style.DisplaySafeAreaPadding = ImVec2(0.0F, 0.0F);
// Install custom settings handler
ImGuiSettingsHandler handler;
handler.TypeName = "ImHex";
handler.TypeHash = ImHashStr("ImHex");
handler.ReadOpenFn = ImHexSettingsHandler_ReadOpenFn;
handler.ReadLineFn = ImHexSettingsHandler_ReadLine;
handler.WriteAllFn = ImHexSettingsHandler_WriteAll;
handler.UserData = this;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(handler);
{
ImGuiSettingsHandler handler;
handler.TypeName = "ImHex";
handler.TypeHash = ImHashStr("ImHex");
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
if (std::fs::exists(dir) && fs::isPathWritable(dir)) {
this->m_imguiSettingsPath = dir / "interface.ini";
io.IniFilename = nullptr;
break;
handler.ReadOpenFn = [](ImGuiContext *ctx, ImGuiSettingsHandler *, const char *) -> void* { return ctx; };
handler.ReadLineFn = [](ImGuiContext *, ImGuiSettingsHandler *, void *, const char *line) {
for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) {
std::string format = view->getUnlocalizedName() + "=%d";
sscanf(line, format.c_str(), &view->getWindowOpenState());
}
for (auto &[name, function, detached] : ContentRegistry::Tools::impl::getEntries()) {
std::string format = name + "=%d";
sscanf(line, format.c_str(), &detached);
}
};
handler.WriteAllFn = [](ImGuiContext *, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf) {
buf->appendf("[%s][General]\n", handler->TypeName);
for (auto &[name, view] : ContentRegistry::Views::impl::getEntries()) {
buf->appendf("%s=%d\n", name.c_str(), view->getWindowOpenState());
}
for (auto &[name, function, detached] : ContentRegistry::Tools::impl::getEntries()) {
buf->appendf("%s=%d\n", name.c_str(), detached);
}
buf->append("\n");
};
handler.UserData = this;
ImGui::GetCurrentContext()->SettingsHandlers.push_back(handler);
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
if (std::fs::exists(dir) && fs::isPathWritable(dir)) {
this->m_imguiSettingsPath = dir / "interface.ini";
io.IniFilename = nullptr;
break;
}
}
}
if (!this->m_imguiSettingsPath.empty() && fs::exists(this->m_imguiSettingsPath))
ImGui::LoadIniSettingsFromDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
if (!this->m_imguiSettingsPath.empty() && wolv::io::fs::exists(this->m_imguiSettingsPath))
ImGui::LoadIniSettingsFromDisk(wolv::util::toUTF8String(this->m_imguiSettingsPath).c_str());
}
ImGui_ImplGlfw_InitForOpenGL(this->m_window, true);
@@ -806,6 +909,8 @@ namespace hex {
for (const auto &plugin : PluginManager::getPlugins())
plugin.setImGuiContext(ImGui::GetCurrentContext());
EventManager::post<RequestInitThemeHandlers>();
}
void Window::exitGLFW() {
@@ -816,7 +921,7 @@ namespace hex {
void Window::exitImGui() {
delete static_cast<ImGui::ImHexCustomData *>(ImGui::GetIO().UserData);
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
ImGui::SaveIniSettingsToDisk(wolv::util::toUTF8String(this->m_imguiSettingsPath).c_str());
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();

View File

@@ -55,6 +55,7 @@ add_library(${PROJECT_NAME} SHARED
source/content/views/view_diff.cpp
source/content/views/view_provider_settings.cpp
source/content/views/view_find.cpp
source/content/views/view_theme_manager.cpp
source/content/helpers/math_evaluator.cpp

View File

@@ -3,9 +3,15 @@
#include <hex.hpp>
#include <imgui.h>
#include <implot.h>
#include <hex/providers/provider.hpp>
#include <hex/providers/buffered_reader.hpp>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <hex/helpers/logger.hpp>
#include <random>
namespace hex {
@@ -130,6 +136,28 @@ namespace hex {
this->m_processing = false;
}
void reset(u64 size) {
this->m_processing = true;
this->m_buffer.clear();
this->m_buffer.resize(size);
this->m_byteCount = 0;
this->m_fileSize = size;
}
void update(u8 byte) {
// Check if there is some space left
if (this->m_byteCount < this->m_fileSize) {
this->m_buffer[this->m_byteCount] = byte;
++this->m_byteCount;
if (this->m_byteCount == this->m_fileSize) {
this->m_buffer = getSampleSelection(this->m_buffer, this->m_sampleSize);
processImpl();
this->m_processing = false;
}
}
}
private:
void processImpl() {
this->m_glowBuffer.resize(this->m_buffer.size());
@@ -142,7 +170,7 @@ namespace hex {
}
for (size_t i = 0; i < (this->m_buffer.empty() ? 0 : this->m_buffer.size() - 1); i++) {
this->m_glowBuffer[i] = std::min(0.2F + (float(heatMap[this->m_buffer[i] << 8 | this->m_buffer[i + 1]]) / float(this->m_highestCount / 1000)), 1.0F);
this->m_glowBuffer[i] = std::min<float>(0.2F + (float(heatMap[this->m_buffer[i] << 8 | this->m_buffer[i + 1]]) / float(this->m_highestCount / 1000)), 1.0F);
}
this->m_opacity = (log10(float(this->m_sampleSize)) / log10(float(m_highestCount))) / 10.0F;
@@ -151,6 +179,10 @@ namespace hex {
private:
size_t m_sampleSize;
// The number of byte processed and the size of
// the file to analyze (useful for iterative analysis)
u64 m_byteCount;
u64 m_fileSize;
std::vector<u8> m_buffer;
std::vector<float> m_glowBuffer;
float m_opacity = 0.0F;
@@ -158,7 +190,6 @@ namespace hex {
std::atomic<bool> m_processing = false;
};
class DiagramLayeredDistribution {
public:
DiagramLayeredDistribution(size_t sampleSize = 0x9000) : m_sampleSize(sampleSize) { }
@@ -200,6 +231,27 @@ namespace hex {
this->m_processing = false;
}
void reset(u64 size) {
this->m_processing = true;
this->m_buffer.clear();
this->m_buffer.resize(size);
this->m_byteCount = 0;
this->m_fileSize = size;
}
void update(u8 byte) {
// Check if there is some space left
if (this->m_byteCount < this->m_fileSize) {
this->m_buffer[this->m_byteCount] = byte;
++this->m_byteCount;
if (this->m_byteCount == this->m_fileSize) {
this->m_buffer = getSampleSelection(this->m_buffer, this->m_sampleSize);
processImpl();
this->m_processing = false;
}
}
}
private:
void processImpl() {
this->m_glowBuffer.resize(this->m_buffer.size());
@@ -212,13 +264,18 @@ namespace hex {
}
for (size_t i = 0; i < (this->m_buffer.empty() ? 0 : this->m_buffer.size() - 1); i++) {
this->m_glowBuffer[i] = std::min(0.2F + (float(heatMap[this->m_buffer[i] << 8 | this->m_buffer[i + 1]]) / float(this->m_highestCount / 1000)), 1.0F);
this->m_glowBuffer[i] = std::min<float>(0.2F + (float(heatMap[this->m_buffer[i] << 8 | this->m_buffer[i + 1]]) / float(this->m_highestCount / 1000)), 1.0F);
}
this->m_opacity = (log10(float(this->m_sampleSize)) / log10(float(m_highestCount))) / 10.0F;
}
private:
size_t m_sampleSize;
// The number of byte processed and the size of
// the file to analyze (useful for iterative analysis)
u64 m_byteCount;
u64 m_fileSize;
std::vector<u8> m_buffer;
std::vector<float> m_glowBuffer;
@@ -227,4 +284,643 @@ namespace hex {
std::atomic<bool> m_processing = false;
};
}
class DiagramChunkBasedEntropyAnalysis {
public:
DiagramChunkBasedEntropyAnalysis(u64 blockSize = 256, size_t sampleSize = 0x1000) : m_blockSize(blockSize), m_sampleSize(sampleSize) { }
void draw(ImVec2 size, ImPlotFlags flags, bool updateHandle = false) {
if (!this->m_processing && ImPlot::BeginPlot("##ChunkBasedAnalysis", size, flags)) {
ImPlot::SetupAxes("hex.builtin.common.address"_lang, "hex.builtin.view.information.entropy"_lang, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock);
// Set the axis limit to [first block : last block]
ImPlot::SetupAxesLimits(
this->m_startAddress / this->m_blockSize,
this->m_endAddress / this->m_blockSize,
-0.1F, 1.1F, ImGuiCond_Always
);
// Draw the plot
ImPlot::PlotLine("##ChunkBasedAnalysisLine", this->m_xBlockEntropy.data(), this->m_yBlockEntropy.data(), this->m_blockCount);
// The parameter updateHandle is used when using the pattern language since we don't have a provider
// but just a set of bytes we won't be able to use the drag bar correctly.
if (updateHandle) {
// Set a draggable line on the plot
if (ImPlot::DragLineX(1, &this->m_handlePosition, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
// The line was dragged, update the position in the hex editor
// Clamp the value between the start/end of the region to analyze
this->m_handlePosition = std::clamp<double>(
this->m_handlePosition,
std::ceil(this->m_startAddress / double(this->m_blockSize)),
std::floor(this->m_endAddress / double(this->m_blockSize)));
// Compute the position inside hex editor
u64 address = u64(std::max<double>(this->m_handlePosition * this->m_blockSize, 0)) + this->m_baseAddress;
address = std::min<u64>(address, this->m_baseAddress + this->m_fileSize - 1);
ImHexApi::HexEditor::setSelection(address, 1);
}
}
ImPlot::EndPlot();
}
}
void process(prv::Provider *provider, u64 chunkSize, u64 startAddress, u64 endAddress) {
this->m_processing = true;
// Update attributes
this->m_chunkSize = chunkSize;
this->m_startAddress = startAddress;
this->m_endAddress = endAddress;
this->m_baseAddress = provider->getBaseAddress();
this->m_fileSize = provider->getSize();
// Get a file reader
auto reader = prv::ProviderReader(provider);
std::vector<u8> bytes = reader.read(this->m_startAddress, this->m_endAddress - this->m_startAddress);
this->processImpl(bytes);
// Set the diagram handle position to the start of the plot
this->m_handlePosition = this->m_startAddress / double(this->m_blockSize);
this->m_processing = false;
}
void process(std::vector<u8> buffer, u64 chunkSize) {
this->m_processing = true;
// Update attributes (use buffer size as end address)
this->m_chunkSize = chunkSize;
this->m_startAddress = 0;
this->m_endAddress = buffer.size();
this->m_baseAddress = 0;
this->m_fileSize = buffer.size();
this->processImpl(buffer);
// Set the diagram handle position to the start of the plot
this->m_handlePosition = this->m_startAddress / double(this->m_blockSize);
this->m_processing = false;
}
// Reset the entropy analysis
void reset(u64 chunkSize, u64 startAddress, u64 endAddress, u64 baseAddress, u64 size) {
this->m_processing = true;
// Update attributes
this->m_chunkSize = chunkSize;
this->m_startAddress = startAddress;
this->m_endAddress = endAddress;
this->m_baseAddress = baseAddress;
this->m_fileSize = size;
this->m_blockValueCounts = { 0 };
// Reset and resize the array
this->m_yBlockEntropy.clear();
this->m_yBlockEntropy.resize(((this->m_endAddress - this->m_startAddress) / this->m_chunkSize) + 1);
this->m_byteCount = 0;
this->m_blockCount = 0;
// Set the diagram handle position to the start of the plot
this->m_handlePosition = this->m_startAddress / double(this->m_blockSize);
}
// Process one byte at the time
void update(u8 byte) {
u64 totalBlock = std::ceil((this->m_endAddress - this->m_startAddress) / this->m_chunkSize);
// Check if there is still some
if (this->m_blockCount < totalBlock) {
// Increment the occurrence of the current byte
this->m_blockValueCounts[byte]++;
this->m_byteCount++;
// Check if we processed one complete chunk, if so compute the entropy and start analysing the next chunk
if (((this->m_byteCount % this->m_chunkSize) == 0) || this->m_byteCount == (this->m_endAddress - this->m_startAddress)) [[unlikely]] {
this->m_yBlockEntropy[this->m_blockCount] = calculateEntropy(this->m_blockValueCounts, this->m_chunkSize);
this->m_blockCount += 1;
this->m_blockValueCounts = { 0 };
}
// Check if we processed the last block, if so setup the X axis part of the data
if (this->m_blockCount == totalBlock) {
processFinalize();
this->m_processing = false;
}
}
}
// Method used to compute the entropy of a block of size `blockSize`
// using the bytes occurrences from `valueCounts` array.
double calculateEntropy(std::array<ImU64, 256> &valueCounts, size_t blockSize) {
double entropy = 0;
for (auto count : valueCounts) {
if (count == 0) [[unlikely]]
continue;
double probability = static_cast<double>(count) / blockSize;
entropy += probability * std::log2(probability);
}
return std::min<double>(1.0, (-entropy) / 8); // log2(256) = 8
}
// Return the highest entropy value among all of the blocks
double getHighestEntropyBlockValue() {
double result = 0.0f;
if (!this->m_yBlockEntropy.empty())
result = *std::max_element(this->m_yBlockEntropy.begin(), this->m_yBlockEntropy.end());
return result;
}
// Return the highest entropy value among all of the blocks
u64 getHighestEntropyBlockAddress() {
u64 address = 0x00;
if (!this->m_yBlockEntropy.empty())
address = (std::max_element(this->m_yBlockEntropy.begin(), this->m_yBlockEntropy.end()) - this->m_yBlockEntropy.begin()) * this->m_blockSize;
return address;
}
// Return the highest entropy value among all of the blocks
double getLowestEntropyBlockValue() {
double result = 0.0f;
if (!this->m_yBlockEntropy.empty())
result = *std::min_element(this->m_yBlockEntropy.begin(), this->m_yBlockEntropy.end());
return result;
}
// Return the highest entropy value among all of the blocks
u64 getLowestEntropyBlockAddress() {
u64 address = 0x00;
if (!this->m_yBlockEntropy.empty())
address = (std::min_element(this->m_yBlockEntropy.begin(), this->m_yBlockEntropy.end()) - this->m_yBlockEntropy.begin()) * this->m_blockSize;
return address;
}
// Return the number of blocks that have been processed
u64 getSize() {
return this->m_yBlockEntropy.size();
}
// Return the size of the chunk used for this analysis
u64 getChunkSize() {
return this->m_chunkSize;
}
void setHandlePosition(u64 filePosition) {
this->m_handlePosition = filePosition / double(this->m_blockSize);
}
private:
// Private method used to factorize the process public method
void processImpl(std::vector<u8> bytes) {
this->m_blockValueCounts = { 0 };
// Reset and resize the array
this->m_yBlockEntropy.clear();
this->m_yBlockEntropy.resize(std::ceil((this->m_endAddress - this->m_startAddress) / this->m_chunkSize));
this->m_byteCount = 0;
this->m_blockCount = 0;
// Loop over each byte of the file (or a part of it)
for (u8 byte: bytes) {
// Increment the occurrence of the current byte
this->m_blockValueCounts[byte]++;
this->m_byteCount++;
// Check if we processed one complete chunk, if so compute the entropy and start analysing the next chunk
if (((this->m_byteCount % this->m_chunkSize) == 0) || this->m_byteCount == bytes.size() * 8) [[unlikely]] {
this->m_yBlockEntropy[this->m_blockCount] = calculateEntropy(this->m_blockValueCounts, this->m_chunkSize);
this->m_blockCount += 1;
this->m_blockValueCounts = { 0 };
}
}
processFinalize();
}
void processFinalize() {
// Only save at most m_sampleSize elements of the result
this->m_yBlockEntropy = sampleData(this->m_yBlockEntropy, std::min<size_t>(this->m_blockCount, this->m_sampleSize));
size_t stride = std::max(1.0, double(
std::ceil((this->m_endAddress - this->m_startAddress) / this->m_blockSize) / this->m_yBlockEntropy.size())) + 1;
this->m_blockCount = this->m_yBlockEntropy.size();
// The m_xBlockEntropy attribute is used to specify the position of entropy values
// in the plot when the Y axis doesn't start at 0
this->m_xBlockEntropy.clear();
this->m_xBlockEntropy.resize(this->m_blockCount);
for (u64 i = 0; i < this->m_blockCount; ++i)
this->m_xBlockEntropy[i] = (this->m_startAddress / this->m_blockSize) + stride*i;
--this->m_blockCount;
}
private:
// Variables used to store the parameters to process
// Chunk's size for entropy analysis
u64 m_chunkSize;
u64 m_startAddress;
u64 m_endAddress;
// Start / size of the file
u64 m_baseAddress;
u64 m_fileSize;
// The size of the blocks (for diagram drawing)
u64 m_blockSize;
// Position of the handle inside the plot
double m_handlePosition = 0.0;
// Hold the number of block that have been processed
// during the chunk based entropy analysis
u64 m_blockCount;
// Hold the number of bytes that have been processed
// during the analysis (useful for the iterative analysis)
u64 m_byteCount;
// Array used to hold the occurrences of each byte
// (useful for the iterative analysis)
std::array<ImU64, 256> m_blockValueCounts;
// Variable to hold the result of the chunk based
// entropy analysis
std::vector<double> m_xBlockEntropy;
std::vector<double> m_yBlockEntropy;
// Sampling size, number of elements displayed in the plot,
// avoid showing to many data because it decreased the frame rate
size_t m_sampleSize;
std::atomic<bool> m_processing = false;
};
class DiagramByteDistribution {
public:
void draw(ImVec2 size, ImPlotFlags flags) {
if (!this->m_processing && ImPlot::BeginPlot("##distribution", size, flags)) {
ImPlot::SetupAxes("hex.builtin.common.value"_lang, "hex.builtin.common.count"_lang, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock | ImPlotAxisFlags_LogScale);
ImPlot::SetupAxesLimits(0, 256, 1, double(*std::max_element(this->m_valueCounts.begin(), this->m_valueCounts.end())) * 1.1F, ImGuiCond_Always);
constexpr static auto x = [] {
std::array<ImU64, 256> result { 0 };
std::iota(result.begin(), result.end(), 0);
return result;
}();
ImPlot::PlotBars<ImU64>("##bytes", x.data(), this->m_valueCounts.data(), x.size(), 1.0);
ImPlot::EndPlot();
}
}
void process(prv::Provider *provider, u64 startAddress, u64 endAddress) {
this->m_processing = true;
// Update attributes
this->m_startAddress = startAddress;
this->m_endAddress = endAddress;
// Get a file reader
auto reader = prv::ProviderReader(provider);
std::vector<u8> bytes = reader.read(this->m_startAddress, this->m_endAddress - this->m_startAddress);
this->processImpl(bytes);
this->m_processing = false;
}
void process(std::vector<u8> buffer) {
this->m_processing = true;
// Update attributes
this->m_startAddress = 0;
this->m_endAddress = buffer.size();
this->processImpl(buffer);
this->m_processing = false;
}
// Reset the byte distribution array
void reset() {
this->m_processing = true;
this->m_valueCounts.fill(0);
this->m_processing = false;
}
// Process one byte at the time
void update(u8 byte) {
this->m_processing = true;
this->m_valueCounts[byte]++;
this->m_processing = false;
}
// Return byte distribution array in it's current state
std::array<ImU64, 256> & get() {
return this->m_valueCounts;
}
private:
// Private method used to factorize the process public method
void processImpl(std::vector<u8> bytes) {
// Reset the array
this->m_valueCounts.fill(0);
// Loop over each byte of the file (or a part of it)
// Increment the occurrence of the current byte
for (u8 byte : bytes)
this->m_valueCounts[byte]++;
}
private:
// Variables used to store the parameters to process
u64 m_startAddress;
u64 m_endAddress;
// Hold the result of the byte distribution analysis
std::array<ImU64, 256> m_valueCounts;
std::atomic<bool> m_processing = false;
};
class DiagramByteTypesDistribution {
public:
DiagramByteTypesDistribution(u64 blockSize = 256, size_t sampleSize = 0x1000) : m_blockSize(blockSize), m_sampleSize(sampleSize){ }
void draw(ImVec2 size, ImPlotFlags flags, bool updateHandle = false) {
// Draw the result of the analysis
if (!this->m_processing && ImPlot::BeginPlot("##byte_types", size, flags)) {
ImPlot::SetupAxes("hex.builtin.common.address"_lang, "hex.builtin.common.percentage"_lang, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock);
ImPlot::SetupAxesLimits(this->m_startAddress / this->m_blockSize, this->m_endAddress / this->m_blockSize, -0.1F, 100.1F, ImGuiCond_Always);
ImPlot::SetupLegend(ImPlotLocation_South, ImPlotLegendFlags_Horizontal | ImPlotLegendFlags_Outside);
constexpr static std::array Names = { "iscntrl", "isprint", "isspace", "isblank",
"isgraph", "ispunct", "isalnum", "isalpha",
"isupper", "islower", "isdigit", "isxdigit"
};
for (u32 i = 0; i < Names.size(); i++) {
ImPlot::PlotLine(Names[i], this->m_xBlockTypeDistributions.data(), this->m_yBlockTypeDistributions[i].data(), this->m_blockCount);
}
// The parameter updateHandle is used when using the pattern language since we don't have a provider
// but just a set of bytes we won't be able to use the drag bar correctly.
if (updateHandle) {
// Set a draggable line on the plot
if (ImPlot::DragLineX(1, &this->m_handlePosition, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
// The line was dragged, update the position in the hex editor
// Clamp the value between the start/end of the region to analyze
this->m_handlePosition = std::clamp<double>(
this->m_handlePosition,
std::ceil(this->m_startAddress / double(this->m_blockSize)),
std::floor(this->m_endAddress / double(this->m_blockSize)));
// Compute the position inside hex editor
u64 address = u64(std::max<double>(this->m_handlePosition * this->m_blockSize, 0)) + this->m_baseAddress;
address = std::min<u64>(address, this->m_baseAddress + this->m_fileSize - 1);
ImHexApi::HexEditor::setSelection(address, 1);
}
}
ImPlot::EndPlot();
}
}
void process(prv::Provider *provider, u64 startAddress, u64 endAddress) {
this->m_processing = true;
// Update attributes
this->m_startAddress = startAddress;
this->m_endAddress = endAddress;
this->m_baseAddress = provider->getBaseAddress();
this->m_fileSize = provider->getSize();
// Get a file reader
auto reader = prv::ProviderReader(provider);
std::vector<u8> bytes = reader.read(this->m_startAddress, this->m_endAddress - this->m_startAddress);
this->processImpl(bytes);
// Set the diagram handle position to the start of the plot
this->m_handlePosition = this->m_startAddress / double(this->m_blockSize);
this->m_processing = false;
}
void process(std::vector<u8> buffer, u64 baseAddress, u64 fileSize) {
this->m_processing = true;
// Update attributes
this->m_startAddress = 0;
this->m_endAddress = buffer.size();
this->m_baseAddress = baseAddress;
this->m_fileSize = fileSize;
this->processImpl(buffer);
// Set the diagram handle position to the start of the plot
this->m_handlePosition = this->m_startAddress / double(this->m_blockSize);
this->m_processing = false;
}
// Reset the byte type distribution analysis
void reset(u64 startAddress, u64 endAddress, u64 baseAddress, u64 size) {
this->m_processing = true;
// Update attributes
this->m_startAddress = startAddress;
this->m_endAddress = endAddress;
this->m_baseAddress = baseAddress;
this->m_fileSize = size;
this->m_byteCount = 0;
this->m_blockCount = 0;
this->m_blockValueCounts = { 0 };
// Reset and resize the array
this->m_yBlockTypeDistributions.fill({});
for (auto &blockDistribution : this->m_yBlockTypeDistributions)
blockDistribution.resize(((this->m_endAddress - this->m_startAddress) / this->m_blockSize) + 1);
// Set the diagram handle position to the start of the plot
this->m_handlePosition = this->m_startAddress / double(this->m_blockSize);
}
// Process one byte at the time
void update(u8 byte) {
u64 totalBlock = std::ceil((this->m_endAddress - this->m_startAddress) / this->m_blockSize);
// Check if there is still some block to process
if (this->m_blockCount < totalBlock) {
this->m_blockValueCounts[byte]++;
this->m_byteCount++;
if (((this->m_byteCount % this->m_blockSize) == 0) || this->m_byteCount == (this->m_endAddress - this->m_startAddress)) [[unlikely]] {
auto typeDist = calculateTypeDistribution(this->m_blockValueCounts, this->m_blockSize);
for (u8 i = 0; i < typeDist.size(); i++)
this->m_yBlockTypeDistributions[i][this->m_blockCount] = typeDist[i] * 100;
this->m_blockCount += 1;
this->m_blockValueCounts = { 0 };
}
// Check if we processed the last block, if so setup the X axis part of the data
if (this->m_blockCount == totalBlock) {
processFinalize();
this->m_processing = false;
}
}
}
// Return the percentage of plain text character inside the analyzed region
double getPlainTextCharacterPercentage() {
double plainTextPercentage = std::reduce(this->m_yBlockTypeDistributions[2].begin(), this->m_yBlockTypeDistributions[2].end()) / this->m_yBlockTypeDistributions[2].size();
return plainTextPercentage + std::reduce(this->m_yBlockTypeDistributions[4].begin(), this->m_yBlockTypeDistributions[4].end()) / this->m_yBlockTypeDistributions[4].size();
}
void setHandlePosition(u64 filePosition) {
this->m_handlePosition = filePosition / double(this->m_blockSize);
}
private:
std::array<float, 12> calculateTypeDistribution(std::array<ImU64, 256> &valueCounts, size_t blockSize) {
std::array<ImU64, 12> counts = {};
for (u16 value = 0x00; value < u16(valueCounts.size()); value++) {
const auto &count = valueCounts[value];
if (count == 0) [[unlikely]]
continue;
if (std::iscntrl(value))
counts[0] += count;
if (std::isprint(value))
counts[1] += count;
if (std::isspace(value))
counts[2] += count;
if (std::isblank(value))
counts[3] += count;
if (std::isgraph(value))
counts[4] += count;
if (std::ispunct(value))
counts[5] += count;
if (std::isalnum(value))
counts[6] += count;
if (std::isalpha(value))
counts[7] += count;
if (std::isupper(value))
counts[8] += count;
if (std::islower(value))
counts[9] += count;
if (std::isdigit(value))
counts[10] += count;
if (std::isxdigit(value))
counts[11] += count;
}
std::array<float, 12> distribution = {};
for (u32 i = 0; i < distribution.size(); i++)
distribution[i] = static_cast<float>(counts[i]) / blockSize;
return distribution;
}
// Private method used to factorize the process public method
void processImpl(std::vector<u8> bytes) {
this->m_blockValueCounts = { 0 };
this->m_yBlockTypeDistributions.fill({});
for (auto &blockDistribution : this->m_yBlockTypeDistributions)
blockDistribution.resize(((this->m_endAddress - this->m_startAddress) / this->m_blockSize) + 1);
this->m_byteCount = 0;
this->m_blockCount = 0;
// Loop over each byte of the file (or a part of it)
for (u8 byte : bytes) {
this->m_blockValueCounts[byte]++;
this->m_byteCount++;
if (((this->m_byteCount % this->m_blockSize) == 0) || this->m_byteCount == (this->m_endAddress - this->m_startAddress)) [[unlikely]] {
auto typeDist = calculateTypeDistribution(this->m_blockValueCounts, this->m_blockSize);
for (u8 i = 0; i < typeDist.size(); i++)
this->m_yBlockTypeDistributions[i][this->m_blockCount] = typeDist[i] * 100;
this->m_blockCount += 1;
this->m_blockValueCounts = { 0 };
}
}
processFinalize();
}
void processFinalize() {
// Only save at most m_sampleSize elements of the result
for (u8 i = 0; i < this->m_yBlockTypeDistributions.size(); ++i)
this->m_yBlockTypeDistributions[i] = sampleData(this->m_yBlockTypeDistributions[i], std::min<size_t>(this->m_blockCount, this->m_sampleSize));
size_t stride = std::max(1.0, double(this->m_blockCount / this->m_yBlockTypeDistributions[0].size())) + 1;
this->m_blockCount = this->m_yBlockTypeDistributions[0].size();
// The m_xBlockTypeDistributions attribute is used to specify the position of entropy
// values in the plot when the Y axis doesn't start at 0
this->m_xBlockTypeDistributions.clear();
this->m_xBlockTypeDistributions.resize(this->m_blockCount);
for (u64 i = 0; i < this->m_blockCount; ++i)
this->m_xBlockTypeDistributions[i] = (this->m_startAddress / this->m_blockSize) + stride*i;
--this->m_blockCount;
}
private:
// Variables used to store the parameters to process
// The size of the block we are considering for the analysis
u64 m_blockSize;
u64 m_startAddress;
u64 m_endAddress;
// Start / size of the file
u64 m_baseAddress;
u64 m_fileSize;
// Position of the handle inside the plot
double m_handlePosition = 0.0;
// Hold the number of block that have been processed
// during the chunk based entropy analysis
u64 m_blockCount;
// Hold the number of bytes that have been processed
// during the analysis (useful for the iterative analysis)
u64 m_byteCount;
// Sampling size, number of elements displayed in the plot,
// avoid showing to many data because it decreased the frame rate
size_t m_sampleSize;
// Array used to hold the occurrences of each byte
// (useful for the iterative analysis)
std::array<ImU64, 256> m_blockValueCounts;
// The m_xBlockTypeDistributions attributes is used to specify the position of
// the values in the plot when the Y axis doesn't start at 0
std::vector<float> m_xBlockTypeDistributions;
// Hold the result of the byte distribution analysis
std::array<std::vector<float>, 12> m_yBlockTypeDistributions;
std::atomic<bool> m_processing = false;
};
}

View File

@@ -110,6 +110,7 @@ namespace hex::plugin::builtin {
std::vector<std::pair<std::fs::path, std::fs::path>> rules;
std::vector<YaraMatch> matches;
std::vector<YaraMatch*> sortedMatches;
} yara;
};

View File

@@ -37,7 +37,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataDescription() const override;
[[nodiscard]] bool hasLoadInterface() const override { return true; }
void drawLoadInterface() override;
bool drawLoadInterface() override;
void loadSettings(const nlohmann::json &settings) override;
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings = { }) const override;

View File

@@ -2,23 +2,11 @@
#include <hex/providers/provider.hpp>
#include <wolv/io/file.hpp>
#include <mutex>
#include <string_view>
#include <sys/stat.h>
#if defined(OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(OS_MACOS)
#include <sys/mman.h>
#include <unistd.h>
#include <sys/fcntl.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#endif
namespace hex::plugin::builtin {
class FileProvider : public hex::prv::Provider {
@@ -41,6 +29,11 @@ namespace hex::plugin::builtin {
void readRaw(u64 offset, void *buffer, size_t size) override;
void writeRaw(u64 offset, const void *buffer, size_t size) override;
/**
* @brief closes the file streams used to read the file.
* Need to be called on file write, see https://github.com/WerWolv/ImHex/issues/988
*/
void invalidateFiles();
[[nodiscard]] size_t getActualSize() const override;
void save() override;
@@ -67,16 +60,20 @@ namespace hex::plugin::builtin {
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
private:
wolv::io::File& getFile();
protected:
std::fs::path m_path;
void *m_mappedFile = nullptr;
size_t m_fileSize = 0;
struct stat m_fileStats = { };
bool m_fileStatsValid = false;
bool m_emptyFile = false;
wolv::io::File m_sizeFile;
std::map<std::thread::id, wolv::io::File> m_files;
std::optional<struct stat> m_fileStats;
bool m_readable = false, m_writable = false;
std::mutex m_fileAccessMutex, m_writeMutex;
};
}

View File

@@ -1,8 +1,9 @@
#pragma once
#include <hex/helpers/socket.hpp>
#include <hex/providers/provider.hpp>
#include <wolv/utils/socket.hpp>
#include <array>
#include <mutex>
#include <string_view>
@@ -29,7 +30,6 @@ namespace hex::plugin::builtin {
[[nodiscard]] size_t getActualSize() const override;
void save() override;
void saveAs(const std::fs::path &path) override;
[[nodiscard]] std::string getName() const override;
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataDescription() const override;
@@ -40,7 +40,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool isConnected() const;
[[nodiscard]] bool hasLoadInterface() const override { return true; }
void drawLoadInterface() override;
bool drawLoadInterface() override;
void loadSettings(const nlohmann::json &settings) override;
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override;
@@ -53,14 +53,14 @@ namespace hex::plugin::builtin {
std::variant<std::string, i128> queryInformation(const std::string &category, const std::string &argument) override;
protected:
hex::Socket m_socket;
wolv::util::Socket m_socket;
std::string m_ipAddress;
int m_port = 0;
u64 m_size = 0;
constexpr static size_t CacheLineSize = 0x1000;
constexpr static size_t CacheLineSize = 0x10;
struct CacheLine {
u64 address;
@@ -69,6 +69,7 @@ namespace hex::plugin::builtin {
};
std::list<CacheLine> m_cache;
std::atomic<bool> m_resetCache = false;
std::thread m_cacheUpdateThread;
std::mutex m_cacheLock;

View File

@@ -28,7 +28,6 @@ namespace hex::plugin::builtin {
void remove(u64 offset, size_t size) override;
void save() override;
void saveAs(const std::fs::path &path) override;
[[nodiscard]] std::string getName() const override { return LangEntry("hex.builtin.provider.mem_file.unsaved"); }
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataDescription() const override { return { }; }

View File

@@ -44,7 +44,7 @@ namespace hex::plugin::builtin {
bool m_justOpened = false;
bool m_focusInputTextBox = false;
std::vector<char> m_commandBuffer;
std::string m_commandBuffer;
std::vector<CommandResult> m_lastResults;
std::string m_exactResult;

View File

@@ -27,7 +27,7 @@ namespace hex::plugin::builtin {
bool m_shouldInvalidate = true;
std::endian m_endian = std::endian::native;
std::endian m_endian = std::endian::native;
ContentRegistry::DataInspector::NumberDisplayStyle m_numberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle::Decimal;
bool m_invert = false;
@@ -38,7 +38,9 @@ namespace hex::plugin::builtin {
std::vector<InspectorCacheEntry> m_cachedData, m_workData;
TaskHolder m_updateTask;
std::string m_editingValue;
std::string m_editingValue = "";
pl::PatternLanguage m_runtime;
};
}

View File

@@ -4,11 +4,16 @@
#include <imgui.h>
#include <hex/ui/view.hpp>
#include <hex/api/task.hpp>
#include <array>
#include <string>
#include <vector>
#include "ui/hex_editor.hpp"
#include <IntervalTree.h>
namespace hex::plugin::builtin {
class ViewDiff : public View {
@@ -18,14 +23,30 @@ namespace hex::plugin::builtin {
void drawContent() override;
public:
struct Column {
ui::HexEditor hexEditor;
int provider = -1;
i32 scrollLock = 0;
};
enum class DifferenceType : u8 {
Added,
Removed,
Modified
};
struct Diff {
Region region;
DifferenceType type;
};
private:
void drawDiffLine(const std::array<int, 2> &providerIds, u64 row) const;
std::array<Column, 2> m_columns;
int m_providerA = -1, m_providerB = -1;
bool m_greyedOutZeros = true;
bool m_upperCaseHex = true;
u32 m_columnCount = 16;
std::vector<Diff> m_diffs;
TaskHolder m_diffTask;
std::atomic<bool> m_analyzed = false;
};
}

View File

@@ -43,18 +43,20 @@ namespace hex::plugin::builtin {
Value
} mode = Mode::Strings;
enum class StringType : int { ASCII = 0, UTF16LE = 1, UTF16BE = 2, ASCII_UTF16LE = 3, ASCII_UTF16BE = 4 };
struct Strings {
int minLength = 5;
enum class Type : int { ASCII = 0, UTF16LE = 1, UTF16BE = 2, ASCII_UTF16LE = 3, ASCII_UTF16BE = 4 } type = Type::ASCII;
bool nullTermination = false;
StringType type = StringType::ASCII;
bool m_lowerCaseLetters = true;
bool m_upperCaseLetters = true;
bool m_numbers = true;
bool m_underscores = true;
bool m_symbols = true;
bool m_spaces = true;
bool m_lineFeeds = false;
bool lowerCaseLetters = true;
bool upperCaseLetters = true;
bool numbers = true;
bool underscores = true;
bool symbols = true;
bool spaces = true;
bool lineFeeds = false;
} strings;
struct Sequence {
@@ -62,6 +64,10 @@ namespace hex::plugin::builtin {
} bytes;
struct Regex {
int minLength = 5;
bool nullTermination = false;
StringType type = StringType::ASCII;
std::string pattern;
bool fullMatch = true;
} regex;
@@ -90,7 +96,7 @@ namespace hex::plugin::builtin {
std::map<prv::Provider*, OccurrenceTree> m_occurrenceTree;
std::map<prv::Provider*, std::string> m_currFilter;
TaskHolder m_searchTask;
TaskHolder m_searchTask, m_filterTask;
bool m_settingsValid = false;
private:
@@ -104,7 +110,7 @@ namespace hex::plugin::builtin {
static std::tuple<bool, std::variant<u64, i64, float, double>, size_t> parseNumericValueInput(const std::string &input, SearchSettings::Value::Type type);
void runSearch();
std::string decodeValue(prv::Provider *provider, Occurrence occurrence) const;
std::string decodeValue(prv::Provider *provider, Occurrence occurrence, size_t maxBytes = 0xFFFF'FFFF) const;
};
}

View File

@@ -21,18 +21,17 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
bool m_dataValid = false;
u32 m_blockSize = 0;
double m_averageEntropy = -1.0;
bool m_dataValid = false;
u32 m_blockSize = 0;
double m_averageEntropy = -1.0;
double m_highestBlockEntropy = -1.0;
u64 m_highestBlockEntropyAddress = 0x00;
double m_lowestBlockEntropy = -1.0;
u64 m_lowestBlockEntropyAddress = 0x00;
double m_plainTextCharacterPercentage = -1.0;
std::vector<double> m_blockEntropy;
std::array<std::vector<float>, 12> m_blockTypeDistributions;
std::atomic<u64> m_processedBlockCount = 0;
double m_diagramHandlePosition = 0.0;
std::array<ImU64, 256> m_valueCounts = { 0 };
TaskHolder m_analyzerTask;
Region m_analyzedRegion = { 0, 0 };
@@ -42,8 +41,16 @@ namespace hex::plugin::builtin {
DiagramDigram m_digram;
DiagramLayeredDistribution m_layeredDistribution;
DiagramByteDistribution m_byteDistribution;
DiagramByteTypesDistribution m_byteTypesDistribution;
DiagramChunkBasedEntropyAnalysis m_chunkBasedEntropy;
void analyze();
// User controlled input (referenced by ImgGui)
int m_inputChunkSize = 0;
u64 m_inputStartAddress = 0;
u64 m_inputEndAddress = 0;
};
}
}

View File

@@ -66,6 +66,9 @@ namespace hex::plugin::builtin {
bool m_autoLoadPatterns = true;
std::map<prv::Provider*, std::move_only_function<void()>> m_sectionWindowDrawer;
ui::HexEditor m_sectionHexEditor;
private:
void drawConsole(ImVec2 size, const std::vector<std::pair<pl::core::LogConsole::Level, std::string>> &console);
void drawEnvVars(ImVec2 size, std::list<PlData::EnvVar> &envVars);

View File

@@ -3,7 +3,7 @@
#include <hex.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/net.hpp>
#include <hex/helpers/http_requests.hpp>
#include <hex/helpers/fs.hpp>
#include <array>
@@ -17,7 +17,7 @@ namespace hex::plugin::builtin {
NotAttempted,
InProgress,
Failed,
Succeded,
Succeeded,
};
struct StoreEntry {
@@ -45,16 +45,16 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool hasViewMenuItemEntry() const override { return false; }
[[nodiscard]] ImVec2 getMinSize() const override { return { 600, 400 }; }
[[nodiscard]] ImVec2 getMaxSize() const override { return { 800, 600 }; }
[[nodiscard]] ImVec2 getMaxSize() const override { return { 900, 700 }; }
private:
Net m_net;
std::future<Response<std::string>> m_apiRequest;
std::future<Response<void>> m_download;
HttpRequest m_httpRequest = HttpRequest("GET", "");
std::future<HttpRequest::Result<std::string>> m_apiRequest;
std::future<HttpRequest::Result<std::string>> m_download;
std::fs::path m_downloadPath;
RequestStatus m_requestStatus = RequestStatus::NotAttempted;
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants, m_yara, m_encodings;
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants, m_yara, m_encodings, m_nodes, m_themes;
void drawStore();

View File

@@ -0,0 +1,28 @@
#pragma once
#include <hex.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
#include <array>
#include <string>
namespace hex::plugin::builtin {
class ViewThemeManager : public View {
public:
ViewThemeManager();
~ViewThemeManager() override = default;
void drawContent() override;
[[nodiscard]] bool isAvailable() const override { return true; }
[[nodiscard]] bool hasViewMenuItemEntry() const override { return false; }
private:
std::string m_themeName;
bool m_viewOpen = false;
};
}

View File

@@ -25,7 +25,11 @@ namespace hex::plugin::builtin::ui {
~HexEditor();
void draw(float height = ImGui::GetContentRegionAvail().y);
void setProvider(prv::Provider *provider) { this->m_provider = provider; }
void setProvider(prv::Provider *provider) {
this->m_provider = provider;
this->m_currValidRegion = { Region::Invalid(), false };
}
void setUnknownDataCharacter(char character) { this->m_unknownDataCharacter = character; }
private:
enum class CellType { None, Hex, ASCII };
@@ -42,6 +46,7 @@ namespace hex::plugin::builtin::ui {
void setSelectionUnchecked(std::optional<u64> start, std::optional<u64> end) {
this->m_selectionStart = start;
this->m_selectionEnd = end;
this->m_cursorPosition = end;
}
void setSelection(const Region &region) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
void setSelection(u128 start, u128 end) {
@@ -54,6 +59,7 @@ namespace hex::plugin::builtin::ui {
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
this->m_cursorPosition = this->m_selectionEnd;
if (this->m_selectionChanged) {
auto selection = this->getSelection();
@@ -73,6 +79,14 @@ namespace hex::plugin::builtin::ui {
return { start, size };
}
[[nodiscard]] std::optional<u64> getCursorPosition() const {
return this->m_cursorPosition;
}
void setCursorPosition(u64 cursorPosition) {
this->m_cursorPosition = cursorPosition;
}
[[nodiscard]] bool isSelectionValid() const {
return this->m_selectionStart.has_value() && this->m_selectionEnd.has_value();
}
@@ -136,8 +150,14 @@ namespace hex::plugin::builtin::ui {
return this->m_currCustomEncoding;
}
void setCustomEncoding(EncodingFile encoding) {
void setCustomEncoding(const EncodingFile &encoding) {
this->m_currCustomEncoding = encoding;
this->m_encodingLineStartAddresses.clear();
}
void setCustomEncoding(EncodingFile &&encoding) {
this->m_currCustomEncoding = std::move(encoding);
this->m_encodingLineStartAddresses.clear();
}
void forceUpdateScrollPosition() {
@@ -169,11 +189,13 @@ namespace hex::plugin::builtin::ui {
std::optional<u64> m_selectionStart;
std::optional<u64> m_selectionEnd;
std::optional<u64> m_cursorPosition;
float m_scrollPosition = 0;
u16 m_bytesPerRow = 16;
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
u32 m_grayZeroHighlighter = 0;
char m_unknownDataCharacter = '?';
bool m_shouldJumpToSelection = false;
bool m_centerOnJump = false;
@@ -196,10 +218,12 @@ namespace hex::plugin::builtin::ui {
bool m_upperCaseHex = true;
bool m_grayOutZero = true;
bool m_showAscii = true;
bool m_showCustomEncoding = true;
bool m_syncScrolling = false;
u32 m_byteCellPadding = 0, m_characterCellPadding = 0;
std::optional<EncodingFile> m_currCustomEncoding;
std::vector<u64> m_encodingLineStartAddresses;
std::pair<Region, bool> m_currValidRegion = { Region::Invalid(), false };

View File

@@ -19,6 +19,7 @@ namespace hex::plugin::builtin::ui {
};
void setTreeStyle(TreeStyle style) { this->m_treeStyle = style; }
void setSelectionCallback(std::function<void(Region)> callback) { this->m_selectionCallback = std::move(callback); }
void reset();
private:
@@ -28,6 +29,7 @@ namespace hex::plugin::builtin::ui {
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
void visit(pl::ptrn::PatternBitfieldArray& pattern) override;
void visit(pl::ptrn::PatternBitfield& pattern) override;
void visit(pl::ptrn::PatternBoolean& pattern) override;
void visit(pl::ptrn::PatternCharacter& pattern) override;
@@ -74,5 +76,7 @@ namespace hex::plugin::builtin::ui {
std::set<pl::ptrn::Pattern*> m_visualizedPatterns;
std::string m_lastVisualizerError;
std::function<void(Region)> m_selectionCallback = [](Region) { };
};
}

View File

@@ -73,6 +73,9 @@
"hex.builtin.hash.crc.xor_out",
"hex.builtin.hash.crc16",
"hex.builtin.hash.crc32",
"hex.builtin.hash.crc32c",
"hex.builtin.hash.crc32mpeg",
"hex.builtin.hash.crc32posix",
"hex.builtin.hash.crc8",
"hex.builtin.hash.md5",
"hex.builtin.hash.sha1",
@@ -154,7 +157,7 @@
"hex.builtin.menu.file.open_project",
"hex.builtin.menu.file.open_recent",
"hex.builtin.menu.file.quit",
"hex.builtin.menu.file.reload_file",
"hex.builtin.menu.file.reload_provider",
"hex.builtin.menu.file.save_project",
"hex.builtin.menu.file.save_project_as",
"hex.builtin.menu.help",
@@ -335,6 +338,8 @@
"hex.builtin.provider.disk.reload",
"hex.builtin.provider.disk.sector_size",
"hex.builtin.provider.disk.selected_disk",
"hex.builtin.provider.disk.error.read_ro",
"hex.builtin.provider.disk.error.read_rw",
"hex.builtin.provider.file",
"hex.builtin.provider.file.access",
"hex.builtin.provider.file.creation",
@@ -590,7 +595,6 @@
"hex.builtin.view.disassembler.ppc.spe",
"hex.builtin.view.disassembler.region",
"hex.builtin.view.disassembler.riscv.compressed",
"hex.builtin.view.disassembler.settings.header",
"hex.builtin.view.disassembler.settings.mode",
"hex.builtin.view.disassembler.sparc.v9",
"hex.builtin.view.find.binary_pattern",
@@ -743,6 +747,7 @@
"hex.builtin.view.pattern_editor.sections",
"hex.builtin.view.pattern_editor.settings",
"hex.builtin.view.provider_settings.load_error",
"hex.builtin.view.provider_settings.load_error_details",
"hex.builtin.view.provider_settings.load_popup",
"hex.builtin.view.provider_settings.name",
"hex.builtin.view.settings.name",

View File

@@ -9,6 +9,7 @@
"hex.builtin.command.web.desc": "Webseite nachschlagen",
"hex.builtin.command.web.result": "'{0}' nachschlagen",
"hex.builtin.common.address": "Adresse",
"hex.builtin.common.begin": "",
"hex.builtin.common.big": "Big",
"hex.builtin.common.big_endian": "Big Endian",
"hex.builtin.common.browse": "Durchsuchen...",
@@ -24,6 +25,7 @@
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
"hex.builtin.common.encoding.utf16le": "UTF-16LE",
"hex.builtin.common.encoding.utf8": "UTF-8",
"hex.builtin.common.end": "",
"hex.builtin.common.endian": "Endian",
"hex.builtin.common.error": "Fehler",
"hex.builtin.common.fatal": "Fataler Fehler",
@@ -51,7 +53,9 @@
"hex.builtin.common.range.entire_data": "Gesamte Daten",
"hex.builtin.common.range.selection": "Auswahl",
"hex.builtin.common.region": "Region",
"hex.builtin.common.reset": "",
"hex.builtin.common.set": "Setzen",
"hex.builtin.common.settings": "Einstellungen",
"hex.builtin.common.size": "Länge",
"hex.builtin.common.type": "Typ",
"hex.builtin.common.type.f32": "float",
@@ -137,6 +141,8 @@
"hex.builtin.menu.file.export": "Exportieren...",
"hex.builtin.menu.file.export.base64": "Base64",
"hex.builtin.menu.file.export.base64.popup.export_error": "Erstellen der Base64 Datei fehlgeschlagen!",
"hex.builtin.menu.file.export.bookmark": "",
"hex.builtin.menu.file.export.data_processor": "",
"hex.builtin.menu.file.export.ips": "IPS Patch",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "Ein Patch hat versucht eine Adresse zu patchen, welche nicht vorhanden ist!",
"hex.builtin.menu.file.export.ips.popup.export_error": "Erstellen der IPS Datei fehlgeschlagen!",
@@ -145,22 +151,29 @@
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "Fehlender IPS EOF Eintrag!",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "Ein Patch war grösser als die maximal erlaubte Grösse!",
"hex.builtin.menu.file.export.ips32": "IPS32 Patch",
"hex.builtin.menu.file.export.pattern": "",
"hex.builtin.menu.file.export.popup.create": "Daten konnten nicht exportiert werden. Datei konnte nicht erstellt werden!",
"hex.builtin.menu.file.export.title": "Datei exportieren",
"hex.builtin.menu.file.import": "Importieren...",
"hex.builtin.menu.file.import.base64": "Base64 Datei",
"hex.builtin.menu.file.import.base64.popup.import_error": "Datei hat kein gültiges Base64 Format!",
"hex.builtin.menu.file.import.base64.popup.open_error": "Öffnen der Datei fehlgeschlagen!",
"hex.builtin.menu.file.import.bookmark": "",
"hex.builtin.menu.file.import.custom_encoding": "",
"hex.builtin.menu.file.import.data_processor": "",
"hex.builtin.menu.file.import.ips": "IPS Patch",
"hex.builtin.menu.file.import.ips32": "IPS32 Patch",
"hex.builtin.menu.file.import.modified_file": "",
"hex.builtin.menu.file.import.pattern": "",
"hex.builtin.menu.file.open_file": "Datei öffnen...",
"hex.builtin.menu.file.open_other": "Provider öffnen...",
"hex.builtin.menu.file.open_project": "Projekt öffnen...",
"hex.builtin.menu.file.open_recent": "Zuletzt geöffnete Dateien",
"hex.builtin.menu.file.project": "",
"hex.builtin.menu.file.project.open": "",
"hex.builtin.menu.file.project.save": "",
"hex.builtin.menu.file.project.save_as": "",
"hex.builtin.menu.file.quit": "ImHex beenden",
"hex.builtin.menu.file.reload_file": "Datei neu laden",
"hex.builtin.menu.file.save_project": "Projekt speichern",
"hex.builtin.menu.file.save_project_as": "Projekt speichern unter...",
"hex.builtin.menu.file.reload_provider": "Provider neu laden",
"hex.builtin.menu.help": "Hilfe",
"hex.builtin.menu.layout": "Layout",
"hex.builtin.menu.view": "Ansicht",
@@ -171,17 +184,25 @@
"hex.builtin.nodes.arithmetic.add.header": "Plus",
"hex.builtin.nodes.arithmetic.average": "Durchschnitt",
"hex.builtin.nodes.arithmetic.average.header": "Durchschnitt",
"hex.builtin.nodes.arithmetic.ceil": "",
"hex.builtin.nodes.arithmetic.ceil.header": "",
"hex.builtin.nodes.arithmetic.div": "Division",
"hex.builtin.nodes.arithmetic.div.header": "Durch",
"hex.builtin.nodes.arithmetic.floor": "",
"hex.builtin.nodes.arithmetic.floor.header": "",
"hex.builtin.nodes.arithmetic.median": "Median",
"hex.builtin.nodes.arithmetic.median.header": "Median",
"hex.builtin.nodes.arithmetic.mod": "Modulus",
"hex.builtin.nodes.arithmetic.mod.header": "Modulo",
"hex.builtin.nodes.arithmetic.mul": "Multiplikation",
"hex.builtin.nodes.arithmetic.mul.header": "Mal",
"hex.builtin.nodes.arithmetic.round": "",
"hex.builtin.nodes.arithmetic.round.header": "",
"hex.builtin.nodes.arithmetic.sub": "Subtraktion",
"hex.builtin.nodes.arithmetic.sub.header": "Minus",
"hex.builtin.nodes.bitwise": "Bitweise Operationen",
"hex.builtin.nodes.bitwise.add": "",
"hex.builtin.nodes.bitwise.add.header": "",
"hex.builtin.nodes.bitwise.and": "UND",
"hex.builtin.nodes.bitwise.and.header": "Bitweise UND",
"hex.builtin.nodes.bitwise.not": "NICHT",
@@ -200,6 +221,9 @@
"hex.builtin.nodes.buffer.repeat.header": "Buffer wiederholen",
"hex.builtin.nodes.buffer.repeat.input.buffer": "Input",
"hex.builtin.nodes.buffer.repeat.input.count": "Anzahl",
"hex.builtin.nodes.buffer.size": "",
"hex.builtin.nodes.buffer.size.header": "",
"hex.builtin.nodes.buffer.size.output": "",
"hex.builtin.nodes.buffer.slice": "Zerschneiden",
"hex.builtin.nodes.buffer.slice.header": "Buffer zerschneiden",
"hex.builtin.nodes.buffer.slice.input.buffer": "Input",
@@ -266,6 +290,15 @@
"hex.builtin.nodes.crypto.aes.key_length": "Schlüssellänge",
"hex.builtin.nodes.crypto.aes.mode": "Modus",
"hex.builtin.nodes.crypto.aes.nonce": "Nonce",
"hex.builtin.nodes.custom": "",
"hex.builtin.nodes.custom.custom": "",
"hex.builtin.nodes.custom.custom.edit": "",
"hex.builtin.nodes.custom.custom.edit_hint": "",
"hex.builtin.nodes.custom.custom.header": "",
"hex.builtin.nodes.custom.input": "",
"hex.builtin.nodes.custom.input.header": "",
"hex.builtin.nodes.custom.output": "",
"hex.builtin.nodes.custom.output.header": "",
"hex.builtin.nodes.data_access": "Datenzugriff",
"hex.builtin.nodes.data_access.read": "Lesen",
"hex.builtin.nodes.data_access.read.address": "Adresse",
@@ -320,6 +353,8 @@
"hex.builtin.pattern_drawer.var_name": "Name",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "Falsche anzahl Parameter",
"hex.builtin.pattern_drawer.visualizer.unknown": "Unbekannter Visualizer",
"hex.builtin.pl_visualizer.3d.rotation": "",
"hex.builtin.pl_visualizer.3d.scale": "",
"hex.builtin.popup.close_provider.desc": "Es wurden ungespeicherte Änderungen an diesem Provider vorgenommen.\nBist du sicher, dass du ihn schliessen willst?",
"hex.builtin.popup.close_provider.title": "Provider schliessen?",
"hex.builtin.popup.error.create": "Erstellen der neuen Datei fehlgeschlagen!",
@@ -332,6 +367,8 @@
"hex.builtin.popup.error.task_exception": "Fehler in Task '{}':\n\n{}",
"hex.builtin.popup.exit_application.desc": "Es sind nicht gespeicherte Änderungen in diesem Projekt vorhanden.\nBist du sicher, dass du ImHex schliessen willst?",
"hex.builtin.popup.exit_application.title": "Applikation verlassen?",
"hex.builtin.popup.waiting_for_tasks.desc": "Einige Tasks laufen immer noch im Hintergrund.\nImHex wird geschlossen, nachdem diese Abgeschlossen wurden.",
"hex.builtin.popup.waiting_for_tasks.title": "Warten auf Tasks",
"hex.builtin.provider.disk": "Datenträger Provider",
"hex.builtin.provider.disk.disk_size": "Datenträgergrösse",
"hex.builtin.provider.disk.reload": "Neu laden",
@@ -366,6 +403,7 @@
"hex.builtin.setting.general.auto_load_patterns": "Automatisches Laden unterstützter Pattern",
"hex.builtin.setting.general.check_for_updates": "Automatisch nach Updates beim Start suchen",
"hex.builtin.setting.general.enable_unicode": "Alle Unicode Zeichen laden",
"hex.builtin.setting.general.save_recent_providers": "",
"hex.builtin.setting.general.show_tips": "Tipps beim Start anzeigen",
"hex.builtin.setting.general.sync_pattern_source": "Pattern Source Code zwischen Providern synchronisieren",
"hex.builtin.setting.hex_editor": "Hex Editor",
@@ -397,8 +435,6 @@
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "Wikipedia Sprache",
"hex.builtin.setting.proxy": "Proxy",
"hex.builtin.setting.proxy.description": "Proxy wird bei allen Netzwerkverbindungen angewendet.",
@@ -412,6 +448,7 @@
"hex.builtin.tools.base_converter.dec": "DEC",
"hex.builtin.tools.base_converter.hex": "HEX",
"hex.builtin.tools.base_converter.oct": "OCT",
"hex.builtin.tools.byte_swapper": "",
"hex.builtin.tools.calc": "Rechner",
"hex.builtin.tools.color": "Farbwähler",
"hex.builtin.tools.demangler": "LLVM Demangler",
@@ -492,6 +529,7 @@
"hex.builtin.tools.invariant_multiplication.description": "Division durch invariante Multiplikation ist eine Technik, welche häuffig von Compilern verwendet wird um divisionen durch konstante Ganzzahlen in eine Multiplikation und ein Bitshift zu optimieren. Der Grund dafür ist, dass Divisionen meistens viel mehr Clock Zyklen benötigen als Multiplikationen.\n\nDieses Tool kann benutzt werden um diese Divisionen in Multiplikationen umzuwandeln und umgekehrt.",
"hex.builtin.tools.invariant_multiplication.num_bits": "Anzahl Bits",
"hex.builtin.tools.name": "Name",
"hex.builtin.tools.output": "",
"hex.builtin.tools.permissions": "UNIX Berechtigungsrechner",
"hex.builtin.tools.permissions.absolute": "Absolute Notation",
"hex.builtin.tools.permissions.perm_bits": "Berechtigungsbits",
@@ -509,7 +547,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "Ungültige Antwort von Wikipedia!",
"hex.builtin.tools.wiki_explain.results": "Resultate",
"hex.builtin.tools.wiki_explain.search": "Suchen",
"hex.builtin.view.bookmarks.address": "0x{0:X} : 0x{1:X} ({2} Bytes)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "Gehe zu",
"hex.builtin.view.bookmarks.button.remove": "Entfernen",
"hex.builtin.view.bookmarks.default_title": "Lesezeichen [0x{0:X} - 0x{1:X}]",
@@ -536,8 +574,14 @@
"hex.builtin.view.data_processor.menu.remove_link": "Link entfernen",
"hex.builtin.view.data_processor.menu.remove_node": "Knoten entfernen",
"hex.builtin.view.data_processor.menu.remove_selection": "Auswahl entfernen",
"hex.builtin.view.data_processor.menu.save_node": "",
"hex.builtin.view.data_processor.name": "Datenprozessor",
"hex.builtin.view.diff.added": "",
"hex.builtin.view.diff.modified": "",
"hex.builtin.view.diff.name": "Diffing",
"hex.builtin.view.diff.provider_a": "",
"hex.builtin.view.diff.provider_b": "",
"hex.builtin.view.diff.removed": "",
"hex.builtin.view.disassembler.16bit": "16-bit",
"hex.builtin.view.disassembler.32bit": "32-bit",
"hex.builtin.view.disassembler.64bit": "64-bit",
@@ -592,7 +636,6 @@
"hex.builtin.view.disassembler.ppc.spe": "Signal Processing Engine",
"hex.builtin.view.disassembler.region": "Code Region",
"hex.builtin.view.disassembler.riscv.compressed": "Komprimiert",
"hex.builtin.view.disassembler.settings.header": "Einstellungen",
"hex.builtin.view.disassembler.settings.mode": "Modus",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "Binärpattern",
@@ -652,8 +695,9 @@
"hex.builtin.view.hex_editor.copy.cpp": "C++ Array",
"hex.builtin.view.hex_editor.copy.crystal": "Crystal Array",
"hex.builtin.view.hex_editor.copy.csharp": "C# Array",
"hex.builtin.view.hex_editor.copy.custom_encoding": "Benutzerdefinierte Codierung",
"hex.builtin.view.hex_editor.copy.go": "Go Array",
"hex.builtin.view.hex_editor.copy.ascuu": "Hex String",
"hex.builtin.view.hex_editor.copy.hex_view": "Hex View",
"hex.builtin.view.hex_editor.copy.html": "HTML",
"hex.builtin.view.hex_editor.copy.java": "Java Array",
"hex.builtin.view.hex_editor.copy.js": "JavaScript Array",
@@ -703,16 +747,18 @@
"hex.builtin.view.information.distribution": "Byte Verteilung",
"hex.builtin.view.information.encrypted": "Diese Daten sind vermutlich verschlüsselt oder komprimiert!",
"hex.builtin.view.information.entropy": "Entropie",
"hex.builtin.view.information.file_entropy": "Dateientropie",
"hex.builtin.view.information.file_entropy": "Gesammtentropie",
"hex.builtin.view.information.highest_entropy": "Höchste Blockentropie",
"hex.builtin.view.information.info_analysis": "Informationsanalyse",
"hex.builtin.view.information.layered_distribution": "Schichtverteilung",
"hex.builtin.view.information.lowest_entropy": "",
"hex.builtin.view.information.magic": "Magic Informationen",
"hex.builtin.view.information.magic_db_added": "Magic Datenbank hinzugefügt!",
"hex.builtin.view.information.mime": "MIME Typ:",
"hex.builtin.view.information.name": "Dateninformationen",
"hex.builtin.view.information.plain_text": "Diese Daten sind vermutlich einfacher Text.",
"hex.builtin.view.information.plain_text_percentage": "Klartext Prozentanteil",
"hex.builtin.view.information.provider_information": "Provider Informationen",
"hex.builtin.view.information.region": "Analysierte Region",
"hex.builtin.view.patches.name": "Patches",
"hex.builtin.view.patches.offset": "Offset",
@@ -762,9 +808,17 @@
"hex.builtin.view.store.tab.encodings": "Encodings",
"hex.builtin.view.store.tab.libraries": "Libraries",
"hex.builtin.view.store.tab.magics": "Magic Files",
"hex.builtin.view.store.tab.nodes": "",
"hex.builtin.view.store.tab.patterns": "Patterns",
"hex.builtin.view.store.tab.themes": "",
"hex.builtin.view.store.tab.yara": "Yara Regeln",
"hex.builtin.view.store.update": "Update",
"hex.builtin.view.theme_manager.colors": "",
"hex.builtin.view.theme_manager.export": "",
"hex.builtin.view.theme_manager.export.name": "",
"hex.builtin.view.theme_manager.name": "",
"hex.builtin.view.theme_manager.save_theme": "",
"hex.builtin.view.theme_manager.styles": "",
"hex.builtin.view.tools.name": "Werkzeuge",
"hex.builtin.view.yara.error": "Yara Kompilerfehler: ",
"hex.builtin.view.yara.header.matches": "Treffer",
@@ -779,6 +833,7 @@
"hex.builtin.view.yara.reset": "Zurücksetzen",
"hex.builtin.view.yara.rule_added": "Yara Regel hinzugefügt!",
"hex.builtin.view.yara.whole_data": "Gesamte Daten Übereinstimmung!",
"hex.builtin.visualizer.binary": "",
"hex.builtin.visualizer.decimal.signed.16bit": "Dezimal Signed (16 bits)",
"hex.builtin.visualizer.decimal.signed.32bit": "Dezimal Signed (32 bits)",
"hex.builtin.visualizer.decimal.signed.64bit": "Dezimal Signed (64 bits)",
@@ -837,10 +892,6 @@
"hex.builtin.welcome.tip_of_the_day": "Tipp des Tages",
"hex.builtin.welcome.update.desc": "ImHex {0} wurde gerade released! Downloade die neue Version hier",
"hex.builtin.welcome.update.link": "https://github.com/WerWolv/ImHex/releases/latest",
"hex.builtin.welcome.update.title": "Neues Update verfügbar!",
"hex.builtin.popup.waiting_for_tasks.title": "Warten auf Tasks",
"hex.builtin.popup.waiting_for_tasks.desc": "Einige Tasks laufen immer noch im Hintergrund.\nImHex wird geschlossen, nachdem diese Abgeschlossen wurden.",
"hex.builtin.view.hex_editor.copy.custom_encoding": "Benutzerdefinierte Codierung",
"hex.builtin.view.hex_editor.copy.hex_view": "Hex View"
"hex.builtin.welcome.update.title": "Neues Update verfügbar!"
}
}
}

View File

@@ -10,6 +10,7 @@
"hex.builtin.command.web.desc": "Website lookup",
"hex.builtin.command.web.result": "Navigate to '{0}'",
"hex.builtin.common.address": "Address",
"hex.builtin.common.begin": "Begin",
"hex.builtin.common.big": "Big",
"hex.builtin.common.big_endian": "Big Endian",
"hex.builtin.common.browse": "Browse...",
@@ -25,6 +26,7 @@
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
"hex.builtin.common.encoding.utf16le": "UTF-16LE",
"hex.builtin.common.encoding.utf8": "UTF-8",
"hex.builtin.common.end": "End",
"hex.builtin.common.endian": "Endian",
"hex.builtin.common.error": "Error",
"hex.builtin.common.fatal": "Fatal Error",
@@ -52,7 +54,9 @@
"hex.builtin.common.range.entire_data": "Entire Data",
"hex.builtin.common.range.selection": "Selection",
"hex.builtin.common.region": "Region",
"hex.builtin.common.reset": "Reset",
"hex.builtin.common.set": "Set",
"hex.builtin.common.settings": "Settings",
"hex.builtin.common.size": "Size",
"hex.builtin.common.type": "Type",
"hex.builtin.common.type.f32": "float",
@@ -76,9 +80,12 @@
"hex.builtin.hash.crc.refl_in": "Reflect In",
"hex.builtin.hash.crc.refl_out": "Reflect Out",
"hex.builtin.hash.crc.xor_out": "XOR Out",
"hex.builtin.hash.crc16": "CRC16",
"hex.builtin.hash.crc32": "CRC32",
"hex.builtin.hash.crc8": "CRC8",
"hex.builtin.hash.crc16": "CRC-16",
"hex.builtin.hash.crc32": "CRC-32",
"hex.builtin.hash.crc32c": "CRC-32C",
"hex.builtin.hash.crc32mpeg": "CRC-32/MPEG",
"hex.builtin.hash.crc32posix": "CRC-32/POSIX",
"hex.builtin.hash.crc8": "CRC-8",
"hex.builtin.hash.md5": "MD5",
"hex.builtin.hash.sha1": "SHA1",
"hex.builtin.hash.sha224": "SHA224",
@@ -146,6 +153,9 @@
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "Missing IPS EOF record!",
"hex.builtin.menu.file.export.ips": "IPS Patch",
"hex.builtin.menu.file.export.ips32": "IPS32 Patch",
"hex.builtin.menu.file.export.bookmark": "Bookmark",
"hex.builtin.menu.file.export.pattern": "Pattern File",
"hex.builtin.menu.file.export.data_processor": "Data Processor Workspace",
"hex.builtin.menu.file.export.popup.create": "Cannot export data. Failed to create file!",
"hex.builtin.menu.file.export.title": "Export File",
"hex.builtin.menu.file.import": "Import...",
@@ -155,14 +165,19 @@
"hex.builtin.menu.file.import.ips": "IPS Patch",
"hex.builtin.menu.file.import.ips32": "IPS32 Patch",
"hex.builtin.menu.file.import.modified_file": "Modified File",
"hex.builtin.menu.file.import.bookmark": "Bookmark",
"hex.builtin.menu.file.import.pattern": "Pattern File",
"hex.builtin.menu.file.import.data_processor": "Data Processor Workspace",
"hex.builtin.menu.file.import.custom_encoding": "Custom Encoding File",
"hex.builtin.menu.file.open_file": "Open File...",
"hex.builtin.menu.file.open_other": "Open Other...",
"hex.builtin.menu.file.open_project": "Open Project...",
"hex.builtin.menu.file.project": "Project",
"hex.builtin.menu.file.project.open": "Open Project...",
"hex.builtin.menu.file.project.save": "Save Project",
"hex.builtin.menu.file.project.save_as": "Save Project As...",
"hex.builtin.menu.file.open_recent": "Open Recent",
"hex.builtin.menu.file.quit": "Quit ImHex",
"hex.builtin.menu.file.reload_file": "Reload File",
"hex.builtin.menu.file.save_project": "Save Project",
"hex.builtin.menu.file.save_project_as": "Save Project As...",
"hex.builtin.menu.file.reload_provider": "Reload Provider",
"hex.builtin.menu.help": "Help",
"hex.builtin.menu.layout": "Layout",
"hex.builtin.menu.view": "View",
@@ -342,11 +357,13 @@
"hex.builtin.pattern_drawer.var_name": "Name",
"hex.builtin.pattern_drawer.visualizer.unknown": "Unknown visualizer",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "Invalid parameter count",
"hex.builtin.pl_visualizer.3d.rotation": "Rotation",
"hex.builtin.pl_visualizer.3d.scale": "Scale",
"hex.builtin.popup.close_provider.desc": "There are unsaved changes made to this Provider\nthat haven't been saved to a Project yet.\n\nAre you sure you want to close it?",
"hex.builtin.popup.close_provider.title": "Close Provider?",
"hex.builtin.popup.error.create": "Failed to create new file!",
"hex.builtin.popup.error.file_dialog.common": "An error occurred while opening the file browser!",
"hex.builtin.popup.error.file_dialog.portal": "There was an error while opening the file browser.\nThis might be caused by your system not having a xdg-desktop-portal backend installed correctly.\n\nOn KDE, it's xdg-desktop-portal-kde.\nOn Gnome it's xdg-desktop-portal-gnome.\nOn wlroots it's xdg-desktop-portal-wlr.\nOtherwise, you can try to use xdg-desktop-portal-gtk.\n\nReboot your system after installing it.\n\nIf the file browser still doesn't work after this, submit an issue at https://github.com/WerWolv/ImHex/issues\n\nIn the meantime files can still be opened by dragging them onto the ImHex window!",
"hex.builtin.popup.error.file_dialog.common": "An error occurred while opening the file browser: {}",
"hex.builtin.popup.error.file_dialog.portal": "There was an error while opening the file browser: {}.\nThis might be caused by your system not having a xdg-desktop-portal backend installed correctly.\n\nOn KDE, it's xdg-desktop-portal-kde.\nOn Gnome it's xdg-desktop-portal-gnome.\nOn wlroots it's xdg-desktop-portal-wlr.\nOtherwise, you can try to use xdg-desktop-portal-gtk.\n\nReboot your system after installing it.\n\nIf the file browser still doesn't work after this, submit an issue at https://github.com/WerWolv/ImHex/issues\n\nIn the meantime files can still be opened by dragging them onto the ImHex window!",
"hex.builtin.popup.error.open": "Failed to open file!",
"hex.builtin.popup.error.project.load": "Failed to load project!",
"hex.builtin.popup.error.project.save": "Failed to save project!",
@@ -361,6 +378,8 @@
"hex.builtin.provider.disk.reload": "Reload",
"hex.builtin.provider.disk.sector_size": "Sector Size",
"hex.builtin.provider.disk.selected_disk": "Disk",
"hex.builtin.provider.disk.error.read_ro": "Failed to open disk {} in read/write: {}",
"hex.builtin.provider.disk.error.read_rw": "Failed to open disk {} in read/write: {}",
"hex.builtin.provider.file": "File Provider",
"hex.builtin.provider.file.access": "Last access time",
"hex.builtin.provider.file.creation": "Creation time",
@@ -386,10 +405,12 @@
"hex.builtin.setting.font": "Font",
"hex.builtin.setting.font.font_path": "Custom Font Path",
"hex.builtin.setting.font.font_size": "Font Size",
"hex.builtin.setting.font.font_size.tooltip": "The font size can only be adjusted when a custom font has been selected above.\n\nThis is because ImHex uses a pixel-perfect bitmap font by default. Scaling it by any non-integer factor will only cause it to become blurry.",
"hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_load_patterns": "Auto-load supported pattern",
"hex.builtin.setting.general.check_for_updates": "Check for updates on startup",
"hex.builtin.setting.general.enable_unicode": "Load all unicode characters",
"hex.builtin.setting.general.save_recent_providers": "Save recently used providers",
"hex.builtin.setting.general.show_tips": "Show tips on startup",
"hex.builtin.setting.general.sync_pattern_source": "Sync pattern source code between providers",
"hex.builtin.setting.hex_editor": "Hex Editor",
@@ -421,8 +442,6 @@
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "Wikipedia Language",
"hex.builtin.setting.proxy": "Proxy",
"hex.builtin.setting.proxy.description": "Proxy will take effect on store, wikipedia or any other plugin immediately.",
@@ -436,6 +455,7 @@
"hex.builtin.tools.base_converter.dec": "DEC",
"hex.builtin.tools.base_converter.hex": "HEX",
"hex.builtin.tools.base_converter.oct": "OCT",
"hex.builtin.tools.byte_swapper": "Byte Swapper",
"hex.builtin.tools.calc": "Calculator",
"hex.builtin.tools.color": "Color picker",
"hex.builtin.tools.demangler": "LLVM Demangler",
@@ -515,6 +535,7 @@
"hex.builtin.tools.invariant_multiplication.description": "Division by invariant multiplication is a technique often used by compilers to optimize integer division by a constant into a multiplication followed by a shift. The reason for this is that divisions often take many times more clock cycles than multiplications do.\n\nThis tool can be used to calculate the multiplier from the divisor or the divisor from the multiplier.",
"hex.builtin.tools.invariant_multiplication.num_bits": "Number of Bits",
"hex.builtin.tools.input": "Input",
"hex.builtin.tools.output": "Output",
"hex.builtin.tools.name": "Name",
"hex.builtin.tools.permissions": "UNIX Permissions Calculator",
"hex.builtin.tools.permissions.absolute": "Absolute Notation",
@@ -533,7 +554,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "Invalid response from Wikipedia!",
"hex.builtin.tools.wiki_explain.results": "Results",
"hex.builtin.tools.wiki_explain.search": "Search",
"hex.builtin.view.bookmarks.address": "0x{0:X} : 0x{1:X} ({2} bytes)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "Jump to",
"hex.builtin.view.bookmarks.button.remove": "Remove",
"hex.builtin.view.bookmarks.default_title": "Bookmark [0x{0:X} - 0x{1:X}]",
@@ -563,6 +584,11 @@
"hex.builtin.view.data_processor.menu.save_node": "Save Node",
"hex.builtin.view.data_processor.name": "Data Processor",
"hex.builtin.view.diff.name": "Diffing",
"hex.builtin.view.diff.added": "Added",
"hex.builtin.view.diff.modified": "Modified",
"hex.builtin.view.diff.provider_a": "Provider A",
"hex.builtin.view.diff.provider_b": "Provider B",
"hex.builtin.view.diff.removed": "Removed",
"hex.builtin.view.disassembler.16bit": "16-bit",
"hex.builtin.view.disassembler.32bit": "32-bit",
"hex.builtin.view.disassembler.64bit": "64-bit",
@@ -617,7 +643,6 @@
"hex.builtin.view.disassembler.ppc.spe": "Signal Processing Engine",
"hex.builtin.view.disassembler.region": "Code region",
"hex.builtin.view.disassembler.riscv.compressed": "Compressed",
"hex.builtin.view.disassembler.settings.header": "Settings",
"hex.builtin.view.disassembler.settings.mode": "Mode",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "Binary Pattern",
@@ -729,8 +754,9 @@
"hex.builtin.view.information.distribution": "Byte distribution",
"hex.builtin.view.information.encrypted": "This data is most likely encrypted or compressed!",
"hex.builtin.view.information.entropy": "Entropy",
"hex.builtin.view.information.file_entropy": "File entropy",
"hex.builtin.view.information.highest_entropy": "Highest entropy block",
"hex.builtin.view.information.file_entropy": "Overall entropy",
"hex.builtin.view.information.highest_entropy": "Highest block entropy",
"hex.builtin.view.information.lowest_entropy": "Lowest block entropy",
"hex.builtin.view.information.info_analysis": "Information analysis",
"hex.builtin.view.information.layered_distribution": "Layered distribution",
"hex.builtin.view.information.magic": "Magic information",
@@ -740,6 +766,7 @@
"hex.builtin.view.information.region": "Analyzed region",
"hex.builtin.view.information.plain_text": "This data is most likely plain text.",
"hex.builtin.view.information.plain_text_percentage": "Plain text percentage",
"hex.builtin.view.information.provider_information": "Provider Information",
"hex.builtin.view.patches.name": "Patches",
"hex.builtin.view.patches.offset": "Offset",
"hex.builtin.view.patches.orig": "Original value",
@@ -770,6 +797,7 @@
"hex.builtin.view.pattern_editor.sections": "Sections",
"hex.builtin.view.pattern_editor.settings": "Settings",
"hex.builtin.view.provider_settings.load_error": "An error occurred while trying to open this provider!",
"hex.builtin.view.provider_settings.load_error_details": "An error occurred while trying to open this provider!\nDetails: {}",
"hex.builtin.view.provider_settings.load_popup": "Open Provider",
"hex.builtin.view.provider_settings.name": "Provider Settings",
"hex.builtin.view.settings.name": "Settings",
@@ -788,9 +816,17 @@
"hex.builtin.view.store.tab.encodings": "Encodings",
"hex.builtin.view.store.tab.libraries": "Libraries",
"hex.builtin.view.store.tab.magics": "Magic Files",
"hex.builtin.view.store.tab.nodes": "Nodes",
"hex.builtin.view.store.tab.patterns": "Patterns",
"hex.builtin.view.store.tab.themes": "Themes",
"hex.builtin.view.store.tab.yara": "Yara Rules",
"hex.builtin.view.store.update": "Update",
"hex.builtin.view.theme_manager.name": "Theme Manager",
"hex.builtin.view.theme_manager.colors": "Colors",
"hex.builtin.view.theme_manager.export": "Export",
"hex.builtin.view.theme_manager.export.name": "Theme name",
"hex.builtin.view.theme_manager.save_theme": "Save Theme",
"hex.builtin.view.theme_manager.styles": "Styles",
"hex.builtin.view.tools.name": "Tools",
"hex.builtin.view.yara.error": "Yara Compiler error: ",
"hex.builtin.view.yara.header.matches": "Matches",
@@ -805,6 +841,7 @@
"hex.builtin.view.yara.reset": "Reset",
"hex.builtin.view.yara.rule_added": "Yara rule added!",
"hex.builtin.view.yara.whole_data": "Whole file matches!",
"hex.builtin.visualizer.binary": "Binary",
"hex.builtin.visualizer.decimal.signed.16bit": "Decimal Signed (16 bits)",
"hex.builtin.visualizer.decimal.signed.32bit": "Decimal Signed (32 bits)",
"hex.builtin.visualizer.decimal.signed.64bit": "Decimal Signed (64 bits)",

View File

@@ -9,6 +9,7 @@
"hex.builtin.command.web.desc": "Consulta il Web",
"hex.builtin.command.web.result": "Naviga a '{0}'",
"hex.builtin.common.address": "Indirizzo",
"hex.builtin.common.begin": "",
"hex.builtin.common.big": "Big",
"hex.builtin.common.big_endian": "Big Endian",
"hex.builtin.common.browse": "Esplora...",
@@ -24,6 +25,7 @@
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
"hex.builtin.common.encoding.utf16le": "UTF-16LE",
"hex.builtin.common.encoding.utf8": "UTF-8",
"hex.builtin.common.end": "",
"hex.builtin.common.endian": "Endian",
"hex.builtin.common.error": "Errore",
"hex.builtin.common.fatal": "Errore Fatale",
@@ -51,7 +53,9 @@
"hex.builtin.common.range.entire_data": "",
"hex.builtin.common.range.selection": "",
"hex.builtin.common.region": "Regione",
"hex.builtin.common.reset": "",
"hex.builtin.common.set": "Imposta",
"hex.builtin.common.settings": "Impostazioni",
"hex.builtin.common.size": "Dimensione",
"hex.builtin.common.type": "",
"hex.builtin.common.type.f32": "float",
@@ -137,6 +141,8 @@
"hex.builtin.menu.file.export": "Esporta...",
"hex.builtin.menu.file.export.base64": "",
"hex.builtin.menu.file.export.base64.popup.export_error": "",
"hex.builtin.menu.file.export.bookmark": "",
"hex.builtin.menu.file.export.data_processor": "",
"hex.builtin.menu.file.export.ips": "IPS Patch",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "",
"hex.builtin.menu.file.export.ips.popup.export_error": "",
@@ -145,22 +151,29 @@
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "",
"hex.builtin.menu.file.export.ips32": "IPS32 Patch",
"hex.builtin.menu.file.export.pattern": "",
"hex.builtin.menu.file.export.popup.create": "",
"hex.builtin.menu.file.export.title": "Esporta File",
"hex.builtin.menu.file.import": "Importa...",
"hex.builtin.menu.file.import.base64": "Base64 File",
"hex.builtin.menu.file.import.base64.popup.import_error": "",
"hex.builtin.menu.file.import.base64.popup.open_error": "",
"hex.builtin.menu.file.import.bookmark": "",
"hex.builtin.menu.file.import.custom_encoding": "",
"hex.builtin.menu.file.import.data_processor": "",
"hex.builtin.menu.file.import.ips": "IPS Patch",
"hex.builtin.menu.file.import.ips32": "IPS32 Patch",
"hex.builtin.menu.file.import.modified_file": "",
"hex.builtin.menu.file.import.pattern": "",
"hex.builtin.menu.file.open_file": "Apri File...",
"hex.builtin.menu.file.open_other": "Apri altro...",
"hex.builtin.menu.file.open_project": "Apri un Progetto...",
"hex.builtin.menu.file.open_recent": "File recenti",
"hex.builtin.menu.file.project": "",
"hex.builtin.menu.file.project.open": "",
"hex.builtin.menu.file.project.save": "",
"hex.builtin.menu.file.project.save_as": "",
"hex.builtin.menu.file.quit": "Uscita ImHex",
"hex.builtin.menu.file.reload_file": "",
"hex.builtin.menu.file.save_project": "Salva Progetto",
"hex.builtin.menu.file.save_project_as": "",
"hex.builtin.menu.file.reload_provider": "",
"hex.builtin.menu.help": "Aiuto",
"hex.builtin.menu.layout": "Layout",
"hex.builtin.menu.view": "Vista",
@@ -171,17 +184,25 @@
"hex.builtin.nodes.arithmetic.add.header": "Aggiungi",
"hex.builtin.nodes.arithmetic.average": "",
"hex.builtin.nodes.arithmetic.average.header": "",
"hex.builtin.nodes.arithmetic.ceil": "",
"hex.builtin.nodes.arithmetic.ceil.header": "",
"hex.builtin.nodes.arithmetic.div": "Divisione",
"hex.builtin.nodes.arithmetic.div.header": "Dividi",
"hex.builtin.nodes.arithmetic.floor": "",
"hex.builtin.nodes.arithmetic.floor.header": "",
"hex.builtin.nodes.arithmetic.median": "",
"hex.builtin.nodes.arithmetic.median.header": "",
"hex.builtin.nodes.arithmetic.mod": "Modulo",
"hex.builtin.nodes.arithmetic.mod.header": "Modulo",
"hex.builtin.nodes.arithmetic.mul": "Moltiplicazione",
"hex.builtin.nodes.arithmetic.mul.header": "Moltiplica",
"hex.builtin.nodes.arithmetic.round": "",
"hex.builtin.nodes.arithmetic.round.header": "",
"hex.builtin.nodes.arithmetic.sub": "Sottrazione",
"hex.builtin.nodes.arithmetic.sub.header": "Sottrai",
"hex.builtin.nodes.bitwise": "Operazioni di Bitwise",
"hex.builtin.nodes.bitwise.add": "",
"hex.builtin.nodes.bitwise.add.header": "",
"hex.builtin.nodes.bitwise.and": "E",
"hex.builtin.nodes.bitwise.and.header": "Bitwise E",
"hex.builtin.nodes.bitwise.not": "NON",
@@ -200,6 +221,9 @@
"hex.builtin.nodes.buffer.repeat.header": "Ripeti buffer",
"hex.builtin.nodes.buffer.repeat.input.buffer": "Input",
"hex.builtin.nodes.buffer.repeat.input.count": "Conta",
"hex.builtin.nodes.buffer.size": "",
"hex.builtin.nodes.buffer.size.header": "",
"hex.builtin.nodes.buffer.size.output": "",
"hex.builtin.nodes.buffer.slice": "Affetta",
"hex.builtin.nodes.buffer.slice.header": "Affetta buffer",
"hex.builtin.nodes.buffer.slice.input.buffer": "Input",
@@ -266,6 +290,15 @@
"hex.builtin.nodes.crypto.aes.key_length": "Lunghezza Chiave",
"hex.builtin.nodes.crypto.aes.mode": "Modalità",
"hex.builtin.nodes.crypto.aes.nonce": "Nonce",
"hex.builtin.nodes.custom": "",
"hex.builtin.nodes.custom.custom": "",
"hex.builtin.nodes.custom.custom.edit": "",
"hex.builtin.nodes.custom.custom.edit_hint": "",
"hex.builtin.nodes.custom.custom.header": "",
"hex.builtin.nodes.custom.input": "",
"hex.builtin.nodes.custom.input.header": "",
"hex.builtin.nodes.custom.output": "",
"hex.builtin.nodes.custom.output.header": "",
"hex.builtin.nodes.data_access": "Accesso ai Dati",
"hex.builtin.nodes.data_access.read": "Leggi",
"hex.builtin.nodes.data_access.read.address": "Indirizzo",
@@ -320,6 +353,8 @@
"hex.builtin.pattern_drawer.var_name": "",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "",
"hex.builtin.pattern_drawer.visualizer.unknown": "",
"hex.builtin.pl_visualizer.3d.rotation": "",
"hex.builtin.pl_visualizer.3d.scale": "",
"hex.builtin.popup.close_provider.desc": "",
"hex.builtin.popup.close_provider.title": "",
"hex.builtin.popup.error.create": "Impossibile creare il nuovo File!",
@@ -332,6 +367,8 @@
"hex.builtin.popup.error.task_exception": "",
"hex.builtin.popup.exit_application.desc": "Hai delle modifiche non salvate nel tuo progetto.\nSei sicuro di voler uscire?",
"hex.builtin.popup.exit_application.title": "Uscire dall'applicazione?",
"hex.builtin.popup.waiting_for_tasks.desc": "",
"hex.builtin.popup.waiting_for_tasks.title": "",
"hex.builtin.provider.disk": "Provider di dischi raw",
"hex.builtin.provider.disk.disk_size": "Dimensione disco",
"hex.builtin.provider.disk.reload": "Ricarica",
@@ -366,6 +403,7 @@
"hex.builtin.setting.general.auto_load_patterns": "Auto-caricamento del pattern supportato",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.save_recent_providers": "",
"hex.builtin.setting.general.show_tips": "Mostra consigli all'avvio",
"hex.builtin.setting.general.sync_pattern_source": "",
"hex.builtin.setting.hex_editor": "Hex Editor",
@@ -397,8 +435,6 @@
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "",
"hex.builtin.setting.proxy": "",
"hex.builtin.setting.proxy.description": "",
@@ -412,6 +448,7 @@
"hex.builtin.tools.base_converter.dec": "DEC",
"hex.builtin.tools.base_converter.hex": "HEX",
"hex.builtin.tools.base_converter.oct": "OCT",
"hex.builtin.tools.byte_swapper": "",
"hex.builtin.tools.calc": "Calcolatrice",
"hex.builtin.tools.color": "Selettore di Colore",
"hex.builtin.tools.demangler": "LLVM Demangler",
@@ -492,6 +529,7 @@
"hex.builtin.tools.invariant_multiplication.description": "",
"hex.builtin.tools.invariant_multiplication.num_bits": "",
"hex.builtin.tools.name": "Nome",
"hex.builtin.tools.output": "",
"hex.builtin.tools.permissions": "Calcolatrice dei permessi UNIX",
"hex.builtin.tools.permissions.absolute": "Notazione assoluta",
"hex.builtin.tools.permissions.perm_bits": "Bit di autorizzazione",
@@ -509,7 +547,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "Risposta non valida da Wikipedia!",
"hex.builtin.tools.wiki_explain.results": "Risultati",
"hex.builtin.tools.wiki_explain.search": "Cerca",
"hex.builtin.view.bookmarks.address": "0x{0:X} : 0x{1:X} ({2} bytes)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "Vai a",
"hex.builtin.view.bookmarks.button.remove": "Rimuovi",
"hex.builtin.view.bookmarks.default_title": "Segnalibro [0x{0:X} - 0x{1:X}]",
@@ -536,8 +574,14 @@
"hex.builtin.view.data_processor.menu.remove_link": "Rimuovi Link",
"hex.builtin.view.data_processor.menu.remove_node": "Rimuovi Nodo",
"hex.builtin.view.data_processor.menu.remove_selection": "Rimuovi i selezionati",
"hex.builtin.view.data_processor.menu.save_node": "",
"hex.builtin.view.data_processor.name": "Processa Dati",
"hex.builtin.view.diff.added": "",
"hex.builtin.view.diff.modified": "",
"hex.builtin.view.diff.name": "Diffing",
"hex.builtin.view.diff.provider_a": "",
"hex.builtin.view.diff.provider_b": "",
"hex.builtin.view.diff.removed": "",
"hex.builtin.view.disassembler.16bit": "16-bit",
"hex.builtin.view.disassembler.32bit": "32-bit",
"hex.builtin.view.disassembler.64bit": "64-bit",
@@ -592,7 +636,6 @@
"hex.builtin.view.disassembler.ppc.spe": "Signal Processing Engine",
"hex.builtin.view.disassembler.region": "Regione del Codice",
"hex.builtin.view.disassembler.riscv.compressed": "Compresso",
"hex.builtin.view.disassembler.settings.header": "Impostazioni",
"hex.builtin.view.disassembler.settings.mode": "",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "",
@@ -646,12 +689,15 @@
"hex.builtin.view.help.name": "Aiuto",
"hex.builtin.view.help.pattern_cheat_sheet": "Pattern Language Cheat Sheet",
"hex.builtin.view.hex_editor.copy.address": "",
"hex.builtin.view.hex_editor.copy.ascii": "",
"hex.builtin.view.hex_editor.copy.base64": "Base64",
"hex.builtin.view.hex_editor.copy.c": "C Array",
"hex.builtin.view.hex_editor.copy.cpp": "C++ Array",
"hex.builtin.view.hex_editor.copy.crystal": "Crystal Array",
"hex.builtin.view.hex_editor.copy.csharp": "C# Array",
"hex.builtin.view.hex_editor.copy.custom_encoding": "",
"hex.builtin.view.hex_editor.copy.go": "Go Array",
"hex.builtin.view.hex_editor.copy.hex_view": "",
"hex.builtin.view.hex_editor.copy.html": "HTML",
"hex.builtin.view.hex_editor.copy.java": "Java Array",
"hex.builtin.view.hex_editor.copy.js": "JavaScript Array",
@@ -701,16 +747,18 @@
"hex.builtin.view.information.distribution": "Distribuzione dei Byte",
"hex.builtin.view.information.encrypted": "Questi dati sono probabilmente codificati o compressi!",
"hex.builtin.view.information.entropy": "Entropia",
"hex.builtin.view.information.file_entropy": "Entropia dei File",
"hex.builtin.view.information.highest_entropy": "Highest entropy block",
"hex.builtin.view.information.file_entropy": "",
"hex.builtin.view.information.highest_entropy": "Highest block entropy",
"hex.builtin.view.information.info_analysis": "Informazioni dell'analisi",
"hex.builtin.view.information.layered_distribution": "",
"hex.builtin.view.information.lowest_entropy": "",
"hex.builtin.view.information.magic": "Informazione Magica",
"hex.builtin.view.information.magic_db_added": "Database magico aggiunto!",
"hex.builtin.view.information.mime": "Tipo di MIME:",
"hex.builtin.view.information.name": "Informazione sui Dati",
"hex.builtin.view.information.plain_text": "",
"hex.builtin.view.information.plain_text_percentage": "",
"hex.builtin.view.information.provider_information": "",
"hex.builtin.view.information.region": "Regione Analizzata",
"hex.builtin.view.patches.name": "Patches",
"hex.builtin.view.patches.offset": "Offset",
@@ -760,9 +808,17 @@
"hex.builtin.view.store.tab.encodings": "Encodings",
"hex.builtin.view.store.tab.libraries": "Librerie",
"hex.builtin.view.store.tab.magics": "File Magici",
"hex.builtin.view.store.tab.nodes": "",
"hex.builtin.view.store.tab.patterns": "Modelli",
"hex.builtin.view.store.tab.themes": "",
"hex.builtin.view.store.tab.yara": "Regole di Yara",
"hex.builtin.view.store.update": "Aggiorna",
"hex.builtin.view.theme_manager.colors": "",
"hex.builtin.view.theme_manager.export": "",
"hex.builtin.view.theme_manager.export.name": "",
"hex.builtin.view.theme_manager.name": "",
"hex.builtin.view.theme_manager.save_theme": "",
"hex.builtin.view.theme_manager.styles": "",
"hex.builtin.view.tools.name": "Strumenti",
"hex.builtin.view.yara.error": "Errore compilazione Yara: ",
"hex.builtin.view.yara.header.matches": "Abbinamenti",
@@ -777,6 +833,7 @@
"hex.builtin.view.yara.reset": "",
"hex.builtin.view.yara.rule_added": "Regola di Yara aggiunta!",
"hex.builtin.view.yara.whole_data": "Tutti i file combaciano!",
"hex.builtin.visualizer.binary": "",
"hex.builtin.visualizer.decimal.signed.16bit": "",
"hex.builtin.visualizer.decimal.signed.32bit": "",
"hex.builtin.visualizer.decimal.signed.64bit": "",

View File

@@ -9,6 +9,7 @@
"hex.builtin.command.web.desc": "ウェブサイト参照",
"hex.builtin.command.web.result": "'{0}' を開く",
"hex.builtin.common.address": "アドレス",
"hex.builtin.common.begin": "",
"hex.builtin.common.big": "ビッグ",
"hex.builtin.common.big_endian": "ビッグエンディアン",
"hex.builtin.common.browse": "ファイルを参照…",
@@ -24,6 +25,7 @@
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
"hex.builtin.common.encoding.utf16le": "UTF-16LE",
"hex.builtin.common.encoding.utf8": "UTF-8",
"hex.builtin.common.end": "",
"hex.builtin.common.endian": "エンディアン",
"hex.builtin.common.error": "エラー",
"hex.builtin.common.fatal": "深刻なエラー",
@@ -51,7 +53,9 @@
"hex.builtin.common.range.entire_data": "データ全体",
"hex.builtin.common.range.selection": "選択範囲",
"hex.builtin.common.region": "領域",
"hex.builtin.common.reset": "",
"hex.builtin.common.set": "セット",
"hex.builtin.common.settings": "設定",
"hex.builtin.common.size": "サイズ",
"hex.builtin.common.type": "",
"hex.builtin.common.type.f32": "float",
@@ -137,6 +141,8 @@
"hex.builtin.menu.file.export": "エクスポート…",
"hex.builtin.menu.file.export.base64": "",
"hex.builtin.menu.file.export.base64.popup.export_error": "",
"hex.builtin.menu.file.export.bookmark": "",
"hex.builtin.menu.file.export.data_processor": "",
"hex.builtin.menu.file.export.ips": "IPSパッチ",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "",
"hex.builtin.menu.file.export.ips.popup.export_error": "",
@@ -145,22 +151,29 @@
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "",
"hex.builtin.menu.file.export.ips32": "IPS32パッチ",
"hex.builtin.menu.file.export.pattern": "",
"hex.builtin.menu.file.export.popup.create": "データをエクスポートできません。\nファイルの作成に失敗しました。",
"hex.builtin.menu.file.export.title": "ファイルをエクスポート",
"hex.builtin.menu.file.import": "インポート…",
"hex.builtin.menu.file.import.base64": "Base64ファイル",
"hex.builtin.menu.file.import.base64.popup.import_error": "有効なBase64形式ではありません。",
"hex.builtin.menu.file.import.base64.popup.open_error": "ファイルを開けません。",
"hex.builtin.menu.file.import.bookmark": "",
"hex.builtin.menu.file.import.custom_encoding": "",
"hex.builtin.menu.file.import.data_processor": "",
"hex.builtin.menu.file.import.ips": "IPSパッチ",
"hex.builtin.menu.file.import.ips32": "IPS32パッチ",
"hex.builtin.menu.file.import.modified_file": "",
"hex.builtin.menu.file.import.pattern": "",
"hex.builtin.menu.file.open_file": "ファイルを開く…",
"hex.builtin.menu.file.open_other": "その他の開くオプション…",
"hex.builtin.menu.file.open_project": "プロジェクトを開く…",
"hex.builtin.menu.file.open_recent": "最近使用したファイル",
"hex.builtin.menu.file.project": "",
"hex.builtin.menu.file.project.open": "",
"hex.builtin.menu.file.project.save": "",
"hex.builtin.menu.file.project.save_as": "",
"hex.builtin.menu.file.quit": "ImHexを終了",
"hex.builtin.menu.file.reload_file": "",
"hex.builtin.menu.file.save_project": "プロジェクトを保存",
"hex.builtin.menu.file.save_project_as": "",
"hex.builtin.menu.file.reload_provider": "",
"hex.builtin.menu.help": "ヘルプ",
"hex.builtin.menu.layout": "レイアウト",
"hex.builtin.menu.view": "表示",
@@ -171,17 +184,25 @@
"hex.builtin.nodes.arithmetic.add.header": "加算",
"hex.builtin.nodes.arithmetic.average": "",
"hex.builtin.nodes.arithmetic.average.header": "",
"hex.builtin.nodes.arithmetic.ceil": "",
"hex.builtin.nodes.arithmetic.ceil.header": "",
"hex.builtin.nodes.arithmetic.div": "除算÷",
"hex.builtin.nodes.arithmetic.div.header": "除算",
"hex.builtin.nodes.arithmetic.floor": "",
"hex.builtin.nodes.arithmetic.floor.header": "",
"hex.builtin.nodes.arithmetic.median": "",
"hex.builtin.nodes.arithmetic.median.header": "",
"hex.builtin.nodes.arithmetic.mod": "剰余(余り)",
"hex.builtin.nodes.arithmetic.mod.header": "剰余",
"hex.builtin.nodes.arithmetic.mul": "乗算×",
"hex.builtin.nodes.arithmetic.mul.header": "乗算",
"hex.builtin.nodes.arithmetic.round": "",
"hex.builtin.nodes.arithmetic.round.header": "",
"hex.builtin.nodes.arithmetic.sub": "減算-",
"hex.builtin.nodes.arithmetic.sub.header": "減算",
"hex.builtin.nodes.bitwise": "Bitwise operations",
"hex.builtin.nodes.bitwise.add": "",
"hex.builtin.nodes.bitwise.add.header": "",
"hex.builtin.nodes.bitwise.and": "AND",
"hex.builtin.nodes.bitwise.and.header": "Bitwise AND",
"hex.builtin.nodes.bitwise.not": "NOT",
@@ -200,6 +221,9 @@
"hex.builtin.nodes.buffer.repeat.header": "バッファを繰り返し",
"hex.builtin.nodes.buffer.repeat.input.buffer": "",
"hex.builtin.nodes.buffer.repeat.input.count": "カウント",
"hex.builtin.nodes.buffer.size": "",
"hex.builtin.nodes.buffer.size.header": "",
"hex.builtin.nodes.buffer.size.output": "",
"hex.builtin.nodes.buffer.slice": "スライス",
"hex.builtin.nodes.buffer.slice.header": "バッファをスライス",
"hex.builtin.nodes.buffer.slice.input.buffer": "",
@@ -266,6 +290,15 @@
"hex.builtin.nodes.crypto.aes.key_length": "キー長",
"hex.builtin.nodes.crypto.aes.mode": "モード",
"hex.builtin.nodes.crypto.aes.nonce": "Nonce",
"hex.builtin.nodes.custom": "",
"hex.builtin.nodes.custom.custom": "",
"hex.builtin.nodes.custom.custom.edit": "",
"hex.builtin.nodes.custom.custom.edit_hint": "",
"hex.builtin.nodes.custom.custom.header": "",
"hex.builtin.nodes.custom.input": "",
"hex.builtin.nodes.custom.input.header": "",
"hex.builtin.nodes.custom.output": "",
"hex.builtin.nodes.custom.output.header": "",
"hex.builtin.nodes.data_access": "データアクセス",
"hex.builtin.nodes.data_access.read": "読み込み",
"hex.builtin.nodes.data_access.read.address": "アドレス",
@@ -320,6 +353,8 @@
"hex.builtin.pattern_drawer.var_name": "名前",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "",
"hex.builtin.pattern_drawer.visualizer.unknown": "",
"hex.builtin.pl_visualizer.3d.rotation": "",
"hex.builtin.pl_visualizer.3d.scale": "",
"hex.builtin.popup.close_provider.desc": "変更がプロジェクトとして保存されていません。\nファイルを閉じてもよろしいですか",
"hex.builtin.popup.close_provider.title": "タブを閉じますか?",
"hex.builtin.popup.error.create": "新しいファイルを作成できませんでした。",
@@ -332,6 +367,8 @@
"hex.builtin.popup.error.task_exception": "",
"hex.builtin.popup.exit_application.desc": "変更がプロジェクトとして保存されていません。\n終了してもよろしいですか",
"hex.builtin.popup.exit_application.title": "アプリケーションを終了しますか?",
"hex.builtin.popup.waiting_for_tasks.desc": "",
"hex.builtin.popup.waiting_for_tasks.title": "",
"hex.builtin.provider.disk": "ディスクイメージ",
"hex.builtin.provider.disk.disk_size": "ディスクサイズ",
"hex.builtin.provider.disk.reload": "リロード",
@@ -366,6 +403,7 @@
"hex.builtin.setting.general.auto_load_patterns": "対応するパターンを自動で読み込む",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.save_recent_providers": "",
"hex.builtin.setting.general.show_tips": "起動時に豆知識を表示",
"hex.builtin.setting.general.sync_pattern_source": "ファイル間のパターンソースコードを同期",
"hex.builtin.setting.hex_editor": "Hexエディタ",
@@ -397,8 +435,6 @@
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "",
"hex.builtin.setting.proxy": "プロキシ",
"hex.builtin.setting.proxy.description": "",
@@ -412,6 +448,7 @@
"hex.builtin.tools.base_converter.dec": "10進法",
"hex.builtin.tools.base_converter.hex": "16進法",
"hex.builtin.tools.base_converter.oct": "8進法",
"hex.builtin.tools.byte_swapper": "",
"hex.builtin.tools.calc": "電卓",
"hex.builtin.tools.color": "カラーピッカー",
"hex.builtin.tools.demangler": "LLVMデマングラー",
@@ -492,6 +529,7 @@
"hex.builtin.tools.invariant_multiplication.description": "",
"hex.builtin.tools.invariant_multiplication.num_bits": "",
"hex.builtin.tools.name": "名前",
"hex.builtin.tools.output": "",
"hex.builtin.tools.permissions": "UNIXパーミッション計算機",
"hex.builtin.tools.permissions.absolute": "数値表記",
"hex.builtin.tools.permissions.perm_bits": "アクセス権",
@@ -509,7 +547,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "Wikipediaからのレスポンスが無効です。",
"hex.builtin.tools.wiki_explain.results": "結果",
"hex.builtin.tools.wiki_explain.search": "検索",
"hex.builtin.view.bookmarks.address": "0x{0:X} : 0x{1:X} ({2} バイト)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "移動",
"hex.builtin.view.bookmarks.button.remove": "削除",
"hex.builtin.view.bookmarks.default_title": "ブックマーク [0x{0:X} - 0x{1:X}]",
@@ -536,8 +574,14 @@
"hex.builtin.view.data_processor.menu.remove_link": "リンクを削除",
"hex.builtin.view.data_processor.menu.remove_node": "ノードを削除",
"hex.builtin.view.data_processor.menu.remove_selection": "選択部分を削除",
"hex.builtin.view.data_processor.menu.save_node": "",
"hex.builtin.view.data_processor.name": "データプロセッサ",
"hex.builtin.view.diff.added": "",
"hex.builtin.view.diff.modified": "",
"hex.builtin.view.diff.name": "比較",
"hex.builtin.view.diff.provider_a": "",
"hex.builtin.view.diff.provider_b": "",
"hex.builtin.view.diff.removed": "",
"hex.builtin.view.disassembler.16bit": "16-bit",
"hex.builtin.view.disassembler.32bit": "32-bit",
"hex.builtin.view.disassembler.64bit": "64-bit",
@@ -592,7 +636,6 @@
"hex.builtin.view.disassembler.ppc.spe": "信号処理エンジン",
"hex.builtin.view.disassembler.region": "コード領域",
"hex.builtin.view.disassembler.riscv.compressed": "圧縮済み",
"hex.builtin.view.disassembler.settings.header": "設定",
"hex.builtin.view.disassembler.settings.mode": "モード",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "16進数",
@@ -646,12 +689,15 @@
"hex.builtin.view.help.name": "ヘルプ",
"hex.builtin.view.help.pattern_cheat_sheet": "パターン言語リファレンス",
"hex.builtin.view.hex_editor.copy.address": "",
"hex.builtin.view.hex_editor.copy.ascii": "",
"hex.builtin.view.hex_editor.copy.base64": "Base64",
"hex.builtin.view.hex_editor.copy.c": "C 配列",
"hex.builtin.view.hex_editor.copy.cpp": "C++ 配列",
"hex.builtin.view.hex_editor.copy.crystal": "Crystal 配列",
"hex.builtin.view.hex_editor.copy.csharp": "C# 配列",
"hex.builtin.view.hex_editor.copy.custom_encoding": "",
"hex.builtin.view.hex_editor.copy.go": "Go 配列",
"hex.builtin.view.hex_editor.copy.hex_view": "",
"hex.builtin.view.hex_editor.copy.html": "HTML",
"hex.builtin.view.hex_editor.copy.java": "Java 配列",
"hex.builtin.view.hex_editor.copy.js": "JavaScript 配列",
@@ -701,16 +747,18 @@
"hex.builtin.view.information.distribution": "バイト分布",
"hex.builtin.view.information.encrypted": "暗号化や圧縮を経たデータと推測されます。",
"hex.builtin.view.information.entropy": "エントロピー",
"hex.builtin.view.information.file_entropy": "ファイルのエントロピー",
"hex.builtin.view.information.file_entropy": "",
"hex.builtin.view.information.highest_entropy": "最大エントロピーブロック",
"hex.builtin.view.information.info_analysis": "情報の分析",
"hex.builtin.view.information.layered_distribution": "",
"hex.builtin.view.information.lowest_entropy": "",
"hex.builtin.view.information.magic": "Magic情報",
"hex.builtin.view.information.magic_db_added": "Magicデータベースが追加されました。",
"hex.builtin.view.information.mime": "MIMEタイプ:",
"hex.builtin.view.information.name": "データ解析",
"hex.builtin.view.information.plain_text": "",
"hex.builtin.view.information.plain_text_percentage": "",
"hex.builtin.view.information.provider_information": "",
"hex.builtin.view.information.region": "解析する領域",
"hex.builtin.view.patches.name": "パッチ",
"hex.builtin.view.patches.offset": "オフセット",
@@ -760,9 +808,17 @@
"hex.builtin.view.store.tab.encodings": "エンコード",
"hex.builtin.view.store.tab.libraries": "ライブラリ",
"hex.builtin.view.store.tab.magics": "Magicファイル",
"hex.builtin.view.store.tab.nodes": "",
"hex.builtin.view.store.tab.patterns": "パターン",
"hex.builtin.view.store.tab.themes": "",
"hex.builtin.view.store.tab.yara": "Yaraルール",
"hex.builtin.view.store.update": "アップデート",
"hex.builtin.view.theme_manager.colors": "",
"hex.builtin.view.theme_manager.export": "",
"hex.builtin.view.theme_manager.export.name": "",
"hex.builtin.view.theme_manager.name": "",
"hex.builtin.view.theme_manager.save_theme": "",
"hex.builtin.view.theme_manager.styles": "",
"hex.builtin.view.tools.name": "ツール",
"hex.builtin.view.yara.error": "Yaraコンパイルエラー: ",
"hex.builtin.view.yara.header.matches": "マッチ結果",
@@ -777,6 +833,7 @@
"hex.builtin.view.yara.reset": "",
"hex.builtin.view.yara.rule_added": "Yaraルールが追加されました。",
"hex.builtin.view.yara.whole_data": "ファイル全体が一致します。",
"hex.builtin.visualizer.binary": "",
"hex.builtin.visualizer.decimal.signed.16bit": "符号付き整数型 (16 bits)",
"hex.builtin.visualizer.decimal.signed.32bit": "符号付き整数型 (32 bits)",
"hex.builtin.visualizer.decimal.signed.64bit": "符号付き整数型 (64 bits)",

View File

@@ -9,6 +9,7 @@
"hex.builtin.command.web.desc": "웹사이트 탐색",
"hex.builtin.command.web.result": "웹사이트 이동 '{0}'",
"hex.builtin.common.address": "주소",
"hex.builtin.common.begin": "",
"hex.builtin.common.big": "빅",
"hex.builtin.common.big_endian": "빅 엔디안",
"hex.builtin.common.browse": "찾아보기...",
@@ -24,6 +25,7 @@
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
"hex.builtin.common.encoding.utf16le": "UTF-16LE",
"hex.builtin.common.encoding.utf8": "UTF-8",
"hex.builtin.common.end": "",
"hex.builtin.common.endian": "엔디안",
"hex.builtin.common.error": "에러",
"hex.builtin.common.fatal": "치명적 에러",
@@ -51,7 +53,9 @@
"hex.builtin.common.range.entire_data": "전체 데이터",
"hex.builtin.common.range.selection": "선택",
"hex.builtin.common.region": "지역",
"hex.builtin.common.reset": "",
"hex.builtin.common.set": "설정",
"hex.builtin.common.settings": "설정",
"hex.builtin.common.size": "크기",
"hex.builtin.common.type": "타입",
"hex.builtin.common.type.f32": "float",
@@ -137,6 +141,8 @@
"hex.builtin.menu.file.export": "내보내기...",
"hex.builtin.menu.file.export.base64": "",
"hex.builtin.menu.file.export.base64.popup.export_error": "",
"hex.builtin.menu.file.export.bookmark": "",
"hex.builtin.menu.file.export.data_processor": "",
"hex.builtin.menu.file.export.ips": "IPS 패치",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "",
"hex.builtin.menu.file.export.ips.popup.export_error": "",
@@ -145,22 +151,29 @@
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "",
"hex.builtin.menu.file.export.ips32": "IPS32 패치",
"hex.builtin.menu.file.export.pattern": "",
"hex.builtin.menu.file.export.popup.create": "데이터를 내보낼 수 없습니다. 파일을 만드는 데 실패했습니다!",
"hex.builtin.menu.file.export.title": "파일 내보내기",
"hex.builtin.menu.file.import": "가져오기...",
"hex.builtin.menu.file.import.base64": "Base64 파일",
"hex.builtin.menu.file.import.base64.popup.import_error": "파일이 올바른 Base64 형식이 아닙니다!",
"hex.builtin.menu.file.import.base64.popup.open_error": "파일을 여는 데 실패했습니다!",
"hex.builtin.menu.file.import.bookmark": "",
"hex.builtin.menu.file.import.custom_encoding": "",
"hex.builtin.menu.file.import.data_processor": "",
"hex.builtin.menu.file.import.ips": "IPS 패치",
"hex.builtin.menu.file.import.ips32": "IPS32 패치",
"hex.builtin.menu.file.import.modified_file": "",
"hex.builtin.menu.file.import.pattern": "",
"hex.builtin.menu.file.open_file": "파일 열기...",
"hex.builtin.menu.file.open_other": "다른 공급자 열기...",
"hex.builtin.menu.file.open_project": "프로젝트 열기...",
"hex.builtin.menu.file.open_recent": "최근 파일",
"hex.builtin.menu.file.project": "",
"hex.builtin.menu.file.project.open": "",
"hex.builtin.menu.file.project.save": "",
"hex.builtin.menu.file.project.save_as": "",
"hex.builtin.menu.file.quit": "ImHex 종료하기",
"hex.builtin.menu.file.reload_file": "",
"hex.builtin.menu.file.save_project": "프로젝트 저장",
"hex.builtin.menu.file.save_project_as": "",
"hex.builtin.menu.file.reload_provider": "",
"hex.builtin.menu.help": "도움말",
"hex.builtin.menu.layout": "레이아웃",
"hex.builtin.menu.view": "뷰",
@@ -171,17 +184,25 @@
"hex.builtin.nodes.arithmetic.add.header": "덧셈",
"hex.builtin.nodes.arithmetic.average": "",
"hex.builtin.nodes.arithmetic.average.header": "",
"hex.builtin.nodes.arithmetic.ceil": "",
"hex.builtin.nodes.arithmetic.ceil.header": "",
"hex.builtin.nodes.arithmetic.div": "나눗셈",
"hex.builtin.nodes.arithmetic.div.header": "나눗셈",
"hex.builtin.nodes.arithmetic.floor": "",
"hex.builtin.nodes.arithmetic.floor.header": "",
"hex.builtin.nodes.arithmetic.median": "",
"hex.builtin.nodes.arithmetic.median.header": "",
"hex.builtin.nodes.arithmetic.mod": "나머지",
"hex.builtin.nodes.arithmetic.mod.header": "나머지",
"hex.builtin.nodes.arithmetic.mul": "곱셈",
"hex.builtin.nodes.arithmetic.mul.header": "곱셈",
"hex.builtin.nodes.arithmetic.round": "",
"hex.builtin.nodes.arithmetic.round.header": "",
"hex.builtin.nodes.arithmetic.sub": "뺄셈",
"hex.builtin.nodes.arithmetic.sub.header": "뺄셈",
"hex.builtin.nodes.bitwise": "비트 연산",
"hex.builtin.nodes.bitwise.add": "",
"hex.builtin.nodes.bitwise.add.header": "",
"hex.builtin.nodes.bitwise.and": "AND",
"hex.builtin.nodes.bitwise.and.header": "논리 AND",
"hex.builtin.nodes.bitwise.not": "NOT",
@@ -200,6 +221,9 @@
"hex.builtin.nodes.buffer.repeat.header": "버퍼 반복",
"hex.builtin.nodes.buffer.repeat.input.buffer": "",
"hex.builtin.nodes.buffer.repeat.input.count": "개수",
"hex.builtin.nodes.buffer.size": "",
"hex.builtin.nodes.buffer.size.header": "",
"hex.builtin.nodes.buffer.size.output": "",
"hex.builtin.nodes.buffer.slice": "자르기",
"hex.builtin.nodes.buffer.slice.header": "버퍼 자르기",
"hex.builtin.nodes.buffer.slice.input.buffer": "입력",
@@ -266,6 +290,15 @@
"hex.builtin.nodes.crypto.aes.key_length": "Key 길이",
"hex.builtin.nodes.crypto.aes.mode": "모드",
"hex.builtin.nodes.crypto.aes.nonce": "논스",
"hex.builtin.nodes.custom": "",
"hex.builtin.nodes.custom.custom": "",
"hex.builtin.nodes.custom.custom.edit": "",
"hex.builtin.nodes.custom.custom.edit_hint": "",
"hex.builtin.nodes.custom.custom.header": "",
"hex.builtin.nodes.custom.input": "",
"hex.builtin.nodes.custom.input.header": "",
"hex.builtin.nodes.custom.output": "",
"hex.builtin.nodes.custom.output.header": "",
"hex.builtin.nodes.data_access": "데이터 접근",
"hex.builtin.nodes.data_access.read": "읽기",
"hex.builtin.nodes.data_access.read.address": "주소",
@@ -320,6 +353,8 @@
"hex.builtin.pattern_drawer.var_name": "이름",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "",
"hex.builtin.pattern_drawer.visualizer.unknown": "",
"hex.builtin.pl_visualizer.3d.rotation": "",
"hex.builtin.pl_visualizer.3d.scale": "",
"hex.builtin.popup.close_provider.desc": "공급자에 저장하지 않은 내용이 있습니다.\n정말로 종료하시겠습니까?",
"hex.builtin.popup.close_provider.title": "공급자를 종료하시겠습니까?",
"hex.builtin.popup.error.create": "새 파일을 만드는데 실패했습니다!",
@@ -332,6 +367,8 @@
"hex.builtin.popup.error.task_exception": "",
"hex.builtin.popup.exit_application.desc": "프로젝트에 저장하지 않은 내용이 있습니다.\n정말로 종료하시겠습니까?",
"hex.builtin.popup.exit_application.title": "프로그램을 종료하시겠습니까?",
"hex.builtin.popup.waiting_for_tasks.desc": "",
"hex.builtin.popup.waiting_for_tasks.title": "",
"hex.builtin.provider.disk": "Raw 디스크 공급자",
"hex.builtin.provider.disk.disk_size": "디스크 크기",
"hex.builtin.provider.disk.reload": "새로 고침",
@@ -366,6 +403,7 @@
"hex.builtin.setting.general.auto_load_patterns": "지원하는 패턴 자동으로 로드",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.save_recent_providers": "",
"hex.builtin.setting.general.show_tips": "시작 시 팁 표시",
"hex.builtin.setting.general.sync_pattern_source": "공급자 간 패턴 소스 코드 동기화",
"hex.builtin.setting.hex_editor": "헥스 편집기",
@@ -397,8 +435,6 @@
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "Wikipedia 언어",
"hex.builtin.setting.proxy": "프록시",
"hex.builtin.setting.proxy.description": "프록시는 스토어, wikipedia, 그리고 추가적인 플러그인에 즉시 적용이 됩니다.",
@@ -412,6 +448,7 @@
"hex.builtin.tools.base_converter.dec": "DEC",
"hex.builtin.tools.base_converter.hex": "HEX",
"hex.builtin.tools.base_converter.oct": "OCT",
"hex.builtin.tools.byte_swapper": "",
"hex.builtin.tools.calc": "계산기",
"hex.builtin.tools.color": "컬러 피커",
"hex.builtin.tools.demangler": "LLVM Demangler",
@@ -492,6 +529,7 @@
"hex.builtin.tools.invariant_multiplication.description": "",
"hex.builtin.tools.invariant_multiplication.num_bits": "",
"hex.builtin.tools.name": "이름",
"hex.builtin.tools.output": "",
"hex.builtin.tools.permissions": "UNIX 권한 계산기",
"hex.builtin.tools.permissions.absolute": "절대값",
"hex.builtin.tools.permissions.perm_bits": "권한 비트",
@@ -509,7 +547,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "Wikipedia에서 잘못된 응답이 왔습니다!",
"hex.builtin.tools.wiki_explain.results": "결과",
"hex.builtin.tools.wiki_explain.search": "검색",
"hex.builtin.view.bookmarks.address": "0x{0:X} : 0x{1:X} ({2} bytes)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "이동하기",
"hex.builtin.view.bookmarks.button.remove": "지우기",
"hex.builtin.view.bookmarks.default_title": "북마크 [0x{0:X} - 0x{1:X}]",
@@ -536,8 +574,14 @@
"hex.builtin.view.data_processor.menu.remove_link": "링크 삭제",
"hex.builtin.view.data_processor.menu.remove_node": "노드 삭제",
"hex.builtin.view.data_processor.menu.remove_selection": "선택 영역 삭제",
"hex.builtin.view.data_processor.menu.save_node": "",
"hex.builtin.view.data_processor.name": "데이터 프로세서",
"hex.builtin.view.diff.added": "",
"hex.builtin.view.diff.modified": "",
"hex.builtin.view.diff.name": "파일 비교",
"hex.builtin.view.diff.provider_a": "",
"hex.builtin.view.diff.provider_b": "",
"hex.builtin.view.diff.removed": "",
"hex.builtin.view.disassembler.16bit": "16-bit",
"hex.builtin.view.disassembler.32bit": "32-bit",
"hex.builtin.view.disassembler.64bit": "64-bit",
@@ -592,7 +636,6 @@
"hex.builtin.view.disassembler.ppc.spe": "Signal Processing Engine",
"hex.builtin.view.disassembler.region": "코드 영역",
"hex.builtin.view.disassembler.riscv.compressed": "Compressed",
"hex.builtin.view.disassembler.settings.header": "설정",
"hex.builtin.view.disassembler.settings.mode": "모드",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "바이너리 패턴",
@@ -646,12 +689,15 @@
"hex.builtin.view.help.name": "도움말",
"hex.builtin.view.help.pattern_cheat_sheet": "패턴 언어 치트시트",
"hex.builtin.view.hex_editor.copy.address": "",
"hex.builtin.view.hex_editor.copy.ascii": "",
"hex.builtin.view.hex_editor.copy.base64": "Base64",
"hex.builtin.view.hex_editor.copy.c": "C 배열",
"hex.builtin.view.hex_editor.copy.cpp": "C++ 배열",
"hex.builtin.view.hex_editor.copy.crystal": "Crystal 배열",
"hex.builtin.view.hex_editor.copy.csharp": "C# 배열",
"hex.builtin.view.hex_editor.copy.custom_encoding": "",
"hex.builtin.view.hex_editor.copy.go": "Go 배열",
"hex.builtin.view.hex_editor.copy.hex_view": "",
"hex.builtin.view.hex_editor.copy.html": "HTML",
"hex.builtin.view.hex_editor.copy.java": "Java 배열",
"hex.builtin.view.hex_editor.copy.js": "JavaScript 배열",
@@ -701,16 +747,18 @@
"hex.builtin.view.information.distribution": "바이트 분포",
"hex.builtin.view.information.encrypted": "이 데이터는 아마 암호화 혹은 압축되었을 가능성이 높습니다!",
"hex.builtin.view.information.entropy": "엔트로피",
"hex.builtin.view.information.file_entropy": "파일 엔트로피",
"hex.builtin.view.information.file_entropy": "",
"hex.builtin.view.information.highest_entropy": "최대 엔트로피 블록",
"hex.builtin.view.information.info_analysis": "정보 분석",
"hex.builtin.view.information.layered_distribution": "",
"hex.builtin.view.information.lowest_entropy": "",
"hex.builtin.view.information.magic": "Magic 정보",
"hex.builtin.view.information.magic_db_added": "Magic 데이터베이스 추가됨!",
"hex.builtin.view.information.mime": "MIME 타입:",
"hex.builtin.view.information.name": "데이터 정보",
"hex.builtin.view.information.plain_text": "",
"hex.builtin.view.information.plain_text_percentage": "",
"hex.builtin.view.information.provider_information": "",
"hex.builtin.view.information.region": "분석한 영역",
"hex.builtin.view.patches.name": "패치",
"hex.builtin.view.patches.offset": "오프셋",
@@ -760,9 +808,17 @@
"hex.builtin.view.store.tab.encodings": "인코딩",
"hex.builtin.view.store.tab.libraries": "라이브러리",
"hex.builtin.view.store.tab.magics": "Magic 파일",
"hex.builtin.view.store.tab.nodes": "",
"hex.builtin.view.store.tab.patterns": "패턴",
"hex.builtin.view.store.tab.themes": "",
"hex.builtin.view.store.tab.yara": "Yara 규칙",
"hex.builtin.view.store.update": "업데이트",
"hex.builtin.view.theme_manager.colors": "",
"hex.builtin.view.theme_manager.export": "",
"hex.builtin.view.theme_manager.export.name": "",
"hex.builtin.view.theme_manager.name": "",
"hex.builtin.view.theme_manager.save_theme": "",
"hex.builtin.view.theme_manager.styles": "",
"hex.builtin.view.tools.name": "도구",
"hex.builtin.view.yara.error": "Yara 컴파일러 에러: ",
"hex.builtin.view.yara.header.matches": "규칙",
@@ -777,6 +833,7 @@
"hex.builtin.view.yara.reset": "",
"hex.builtin.view.yara.rule_added": "Yara 규칙 추가됨!",
"hex.builtin.view.yara.whole_data": "모든 파일을 검색했습니다!",
"hex.builtin.visualizer.binary": "",
"hex.builtin.visualizer.decimal.signed.16bit": "부호 있는 10진수 (16 비트)",
"hex.builtin.visualizer.decimal.signed.32bit": "부호 있는 10진수 (32 비트)",
"hex.builtin.visualizer.decimal.signed.64bit": "부호 있는 10진수 (64 비트)",

View File

@@ -9,6 +9,7 @@
"hex.builtin.command.web.desc": "Website lookup",
"hex.builtin.command.web.result": "Navegar para '{0}'",
"hex.builtin.common.address": "Address",
"hex.builtin.common.begin": "",
"hex.builtin.common.big": "Big",
"hex.builtin.common.big_endian": "Big Endian",
"hex.builtin.common.browse": "Navegar...",
@@ -24,6 +25,7 @@
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
"hex.builtin.common.encoding.utf16le": "UTF-16LE",
"hex.builtin.common.encoding.utf8": "UTF-8",
"hex.builtin.common.end": "",
"hex.builtin.common.endian": "Endian",
"hex.builtin.common.error": "Erro",
"hex.builtin.common.fatal": "Erro Fatal",
@@ -51,7 +53,9 @@
"hex.builtin.common.range.entire_data": "",
"hex.builtin.common.range.selection": "",
"hex.builtin.common.region": "Region",
"hex.builtin.common.reset": "",
"hex.builtin.common.set": "Colocar",
"hex.builtin.common.settings": "Configurações",
"hex.builtin.common.size": "Tamanho",
"hex.builtin.common.type": "",
"hex.builtin.common.type.f32": "float",
@@ -137,6 +141,8 @@
"hex.builtin.menu.file.export": "Exportar...",
"hex.builtin.menu.file.export.base64": "",
"hex.builtin.menu.file.export.base64.popup.export_error": "",
"hex.builtin.menu.file.export.bookmark": "",
"hex.builtin.menu.file.export.data_processor": "",
"hex.builtin.menu.file.export.ips": "IPS Patch",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "",
"hex.builtin.menu.file.export.ips.popup.export_error": "",
@@ -145,22 +151,29 @@
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "",
"hex.builtin.menu.file.export.ips32": "IPS32 Patch",
"hex.builtin.menu.file.export.pattern": "",
"hex.builtin.menu.file.export.popup.create": "Não é possível exportar os dados. Falha ao criar arquivo!",
"hex.builtin.menu.file.export.title": "Exportar Arquivo",
"hex.builtin.menu.file.import": "Importar...",
"hex.builtin.menu.file.import.base64": "Arquivo Base64",
"hex.builtin.menu.file.import.base64.popup.import_error": "Esse arquivo não é baseado em um formato Base64 valido!",
"hex.builtin.menu.file.import.base64.popup.open_error": "Falha ao abrir o arquivo!",
"hex.builtin.menu.file.import.bookmark": "",
"hex.builtin.menu.file.import.custom_encoding": "",
"hex.builtin.menu.file.import.data_processor": "",
"hex.builtin.menu.file.import.ips": "IPS Patch",
"hex.builtin.menu.file.import.ips32": "IPS32 Patch",
"hex.builtin.menu.file.import.modified_file": "",
"hex.builtin.menu.file.import.pattern": "",
"hex.builtin.menu.file.open_file": "Abrir Arquivo...",
"hex.builtin.menu.file.open_other": "Abrir outro...",
"hex.builtin.menu.file.open_project": "Abrir Projeto...",
"hex.builtin.menu.file.open_recent": "Abrir Recentes",
"hex.builtin.menu.file.project": "",
"hex.builtin.menu.file.project.open": "",
"hex.builtin.menu.file.project.save": "",
"hex.builtin.menu.file.project.save_as": "",
"hex.builtin.menu.file.quit": "Sair do ImHex",
"hex.builtin.menu.file.reload_file": "",
"hex.builtin.menu.file.save_project": "Salvar Projeto",
"hex.builtin.menu.file.save_project_as": "",
"hex.builtin.menu.file.reload_provider": "",
"hex.builtin.menu.help": "Ajuda",
"hex.builtin.menu.layout": "Layout",
"hex.builtin.menu.view": "Exibir",
@@ -171,17 +184,25 @@
"hex.builtin.nodes.arithmetic.add.header": "Adicionar",
"hex.builtin.nodes.arithmetic.average": "",
"hex.builtin.nodes.arithmetic.average.header": "",
"hex.builtin.nodes.arithmetic.ceil": "",
"hex.builtin.nodes.arithmetic.ceil.header": "",
"hex.builtin.nodes.arithmetic.div": "Divisão",
"hex.builtin.nodes.arithmetic.div.header": "Dividir",
"hex.builtin.nodes.arithmetic.floor": "",
"hex.builtin.nodes.arithmetic.floor.header": "",
"hex.builtin.nodes.arithmetic.median": "",
"hex.builtin.nodes.arithmetic.median.header": "",
"hex.builtin.nodes.arithmetic.mod": "Módulos",
"hex.builtin.nodes.arithmetic.mod.header": "Módulo",
"hex.builtin.nodes.arithmetic.mul": "Multiplição",
"hex.builtin.nodes.arithmetic.mul.header": "Multiplicar",
"hex.builtin.nodes.arithmetic.round": "",
"hex.builtin.nodes.arithmetic.round.header": "",
"hex.builtin.nodes.arithmetic.sub": "Subtração",
"hex.builtin.nodes.arithmetic.sub.header": "Subtrair",
"hex.builtin.nodes.bitwise": "Bitwise operations",
"hex.builtin.nodes.bitwise.add": "",
"hex.builtin.nodes.bitwise.add.header": "",
"hex.builtin.nodes.bitwise.and": "AND",
"hex.builtin.nodes.bitwise.and.header": "Bitwise AND",
"hex.builtin.nodes.bitwise.not": "NOT",
@@ -200,6 +221,9 @@
"hex.builtin.nodes.buffer.repeat.header": "Repetir buffer",
"hex.builtin.nodes.buffer.repeat.input.buffer": "",
"hex.builtin.nodes.buffer.repeat.input.count": "Contar",
"hex.builtin.nodes.buffer.size": "",
"hex.builtin.nodes.buffer.size.header": "",
"hex.builtin.nodes.buffer.size.output": "",
"hex.builtin.nodes.buffer.slice": "Slice",
"hex.builtin.nodes.buffer.slice.header": "Slice buffer",
"hex.builtin.nodes.buffer.slice.input.buffer": "Entrada",
@@ -266,6 +290,15 @@
"hex.builtin.nodes.crypto.aes.key_length": "Key length",
"hex.builtin.nodes.crypto.aes.mode": "Mode",
"hex.builtin.nodes.crypto.aes.nonce": "Nonce",
"hex.builtin.nodes.custom": "",
"hex.builtin.nodes.custom.custom": "",
"hex.builtin.nodes.custom.custom.edit": "",
"hex.builtin.nodes.custom.custom.edit_hint": "",
"hex.builtin.nodes.custom.custom.header": "",
"hex.builtin.nodes.custom.input": "",
"hex.builtin.nodes.custom.input.header": "",
"hex.builtin.nodes.custom.output": "",
"hex.builtin.nodes.custom.output.header": "",
"hex.builtin.nodes.data_access": "Acesso de dados",
"hex.builtin.nodes.data_access.read": "Ler",
"hex.builtin.nodes.data_access.read.address": "Caminho",
@@ -320,6 +353,8 @@
"hex.builtin.pattern_drawer.var_name": "Nome",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "",
"hex.builtin.pattern_drawer.visualizer.unknown": "",
"hex.builtin.pl_visualizer.3d.rotation": "",
"hex.builtin.pl_visualizer.3d.scale": "",
"hex.builtin.popup.close_provider.desc": "",
"hex.builtin.popup.close_provider.title": "",
"hex.builtin.popup.error.create": "Falha ao criar um novo arquivo!",
@@ -332,6 +367,8 @@
"hex.builtin.popup.error.task_exception": "",
"hex.builtin.popup.exit_application.desc": "Você tem alterações não salvas feitas em seu projeto.\nVocê tem certeza que quer sair?",
"hex.builtin.popup.exit_application.title": "Sair da aplicação?",
"hex.builtin.popup.waiting_for_tasks.desc": "",
"hex.builtin.popup.waiting_for_tasks.title": "",
"hex.builtin.provider.disk": "Provedor de disco bruto",
"hex.builtin.provider.disk.disk_size": "Tamanho do Disco",
"hex.builtin.provider.disk.reload": "Recarregar",
@@ -366,6 +403,7 @@
"hex.builtin.setting.general.auto_load_patterns": "Padrão compatível com carregamento automático",
"hex.builtin.setting.general.check_for_updates": "",
"hex.builtin.setting.general.enable_unicode": "",
"hex.builtin.setting.general.save_recent_providers": "",
"hex.builtin.setting.general.show_tips": "Mostrar dicas na inicialização",
"hex.builtin.setting.general.sync_pattern_source": "",
"hex.builtin.setting.hex_editor": "Hex Editor",
@@ -397,8 +435,6 @@
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "Idioma do Wikipedia",
"hex.builtin.setting.proxy": "",
"hex.builtin.setting.proxy.description": "",
@@ -412,6 +448,7 @@
"hex.builtin.tools.base_converter.dec": "DEC",
"hex.builtin.tools.base_converter.hex": "HEX",
"hex.builtin.tools.base_converter.oct": "OCT",
"hex.builtin.tools.byte_swapper": "",
"hex.builtin.tools.calc": "Calculadora",
"hex.builtin.tools.color": "Color picker",
"hex.builtin.tools.demangler": "LLVM Demangler",
@@ -492,6 +529,7 @@
"hex.builtin.tools.invariant_multiplication.description": "",
"hex.builtin.tools.invariant_multiplication.num_bits": "",
"hex.builtin.tools.name": "Nome",
"hex.builtin.tools.output": "",
"hex.builtin.tools.permissions": "Calculadora de Permissões UNIX",
"hex.builtin.tools.permissions.absolute": "Absolute Notation",
"hex.builtin.tools.permissions.perm_bits": "Permission bits",
@@ -509,7 +547,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "Resposta inválida da Wikipedia!",
"hex.builtin.tools.wiki_explain.results": "Resultados",
"hex.builtin.tools.wiki_explain.search": "Procurar",
"hex.builtin.view.bookmarks.address": "0x{0:X} : 0x{1:X} ({2} bytes)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "Pular para",
"hex.builtin.view.bookmarks.button.remove": "Remover",
"hex.builtin.view.bookmarks.default_title": "Favorito [0x{0:X} - 0x{1:X}]",
@@ -536,8 +574,14 @@
"hex.builtin.view.data_processor.menu.remove_link": "Remover Link",
"hex.builtin.view.data_processor.menu.remove_node": "Remover Node",
"hex.builtin.view.data_processor.menu.remove_selection": "Remover Selecionado",
"hex.builtin.view.data_processor.menu.save_node": "",
"hex.builtin.view.data_processor.name": "Data Processor",
"hex.builtin.view.diff.added": "",
"hex.builtin.view.diff.modified": "",
"hex.builtin.view.diff.name": "Diferenciando",
"hex.builtin.view.diff.provider_a": "",
"hex.builtin.view.diff.provider_b": "",
"hex.builtin.view.diff.removed": "",
"hex.builtin.view.disassembler.16bit": "16-bit",
"hex.builtin.view.disassembler.32bit": "32-bit",
"hex.builtin.view.disassembler.64bit": "64-bit",
@@ -592,7 +636,6 @@
"hex.builtin.view.disassembler.ppc.spe": "Signal Processing Engine",
"hex.builtin.view.disassembler.region": "Região do código",
"hex.builtin.view.disassembler.riscv.compressed": "Compressed",
"hex.builtin.view.disassembler.settings.header": "Configurações",
"hex.builtin.view.disassembler.settings.mode": "Modo",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "",
@@ -646,12 +689,15 @@
"hex.builtin.view.help.name": "Ajuda",
"hex.builtin.view.help.pattern_cheat_sheet": "Pattern Language Cheat Sheet",
"hex.builtin.view.hex_editor.copy.address": "",
"hex.builtin.view.hex_editor.copy.ascii": "",
"hex.builtin.view.hex_editor.copy.base64": "Base64",
"hex.builtin.view.hex_editor.copy.c": "C Array",
"hex.builtin.view.hex_editor.copy.cpp": "C++ Array",
"hex.builtin.view.hex_editor.copy.crystal": "Crystal Array",
"hex.builtin.view.hex_editor.copy.csharp": "C# Array",
"hex.builtin.view.hex_editor.copy.custom_encoding": "",
"hex.builtin.view.hex_editor.copy.go": "Go Array",
"hex.builtin.view.hex_editor.copy.hex_view": "",
"hex.builtin.view.hex_editor.copy.html": "HTML",
"hex.builtin.view.hex_editor.copy.java": "Java Array",
"hex.builtin.view.hex_editor.copy.js": "JavaScript Array",
@@ -701,16 +747,18 @@
"hex.builtin.view.information.distribution": "Byte distribution",
"hex.builtin.view.information.encrypted": "Esses dados provavelmente estão criptografados ou compactados!",
"hex.builtin.view.information.entropy": "Entropy",
"hex.builtin.view.information.file_entropy": "File entropy",
"hex.builtin.view.information.highest_entropy": "Highest entropy block",
"hex.builtin.view.information.file_entropy": "",
"hex.builtin.view.information.highest_entropy": "Highest block entropy",
"hex.builtin.view.information.info_analysis": "Análise de Informações",
"hex.builtin.view.information.layered_distribution": "",
"hex.builtin.view.information.lowest_entropy": "",
"hex.builtin.view.information.magic": "Informação Mágica",
"hex.builtin.view.information.magic_db_added": "Magic database added!",
"hex.builtin.view.information.mime": "MIME Type:",
"hex.builtin.view.information.name": "Data Information",
"hex.builtin.view.information.plain_text": "",
"hex.builtin.view.information.plain_text_percentage": "",
"hex.builtin.view.information.provider_information": "",
"hex.builtin.view.information.region": "Região analizada",
"hex.builtin.view.patches.name": "Patches",
"hex.builtin.view.patches.offset": "Desvio",
@@ -760,9 +808,17 @@
"hex.builtin.view.store.tab.encodings": "Codificações",
"hex.builtin.view.store.tab.libraries": "Bibliotecas",
"hex.builtin.view.store.tab.magics": "Arquivos Mágicos",
"hex.builtin.view.store.tab.nodes": "",
"hex.builtin.view.store.tab.patterns": "Padrões",
"hex.builtin.view.store.tab.themes": "",
"hex.builtin.view.store.tab.yara": "Regras Yara",
"hex.builtin.view.store.update": "Atualizar",
"hex.builtin.view.theme_manager.colors": "",
"hex.builtin.view.theme_manager.export": "",
"hex.builtin.view.theme_manager.export.name": "",
"hex.builtin.view.theme_manager.name": "",
"hex.builtin.view.theme_manager.save_theme": "",
"hex.builtin.view.theme_manager.styles": "",
"hex.builtin.view.tools.name": "Ferramentas",
"hex.builtin.view.yara.error": "Erro do compilador Yara: ",
"hex.builtin.view.yara.header.matches": "Combinações",
@@ -777,6 +833,7 @@
"hex.builtin.view.yara.reset": "",
"hex.builtin.view.yara.rule_added": "Regra Yara Adicionada!",
"hex.builtin.view.yara.whole_data": "O arquivo inteiro corresponde!",
"hex.builtin.visualizer.binary": "",
"hex.builtin.visualizer.decimal.signed.16bit": "Decimal Signed (16 bits)",
"hex.builtin.visualizer.decimal.signed.32bit": "Decimal Signed (32 bits)",
"hex.builtin.visualizer.decimal.signed.64bit": "Decimal Signed (64 bits)",

View File

@@ -12,7 +12,7 @@
"hex.builtin.common.big": "大",
"hex.builtin.common.big_endian": "大端序",
"hex.builtin.common.browse": "浏览...",
"hex.builtin.common.bytes": "",
"hex.builtin.common.bytes": "字节",
"hex.builtin.common.cancel": "取消",
"hex.builtin.common.choose_file": "选择文件",
"hex.builtin.common.close": "关闭",
@@ -31,7 +31,7 @@
"hex.builtin.common.filter": "过滤器",
"hex.builtin.common.hexadecimal": "十六进制",
"hex.builtin.common.info": "信息",
"hex.builtin.common.instruction": "",
"hex.builtin.common.instruction": "指示",
"hex.builtin.common.link": "链接",
"hex.builtin.common.little": "小",
"hex.builtin.common.little_endian": "小端序",
@@ -44,7 +44,7 @@
"hex.builtin.common.offset": "偏移",
"hex.builtin.common.okay": "好的",
"hex.builtin.common.open": "打开",
"hex.builtin.common.percentage": "",
"hex.builtin.common.percentage": "百分比",
"hex.builtin.common.processing": "处理",
"hex.builtin.common.question": "问题",
"hex.builtin.common.range": "范围",
@@ -52,6 +52,7 @@
"hex.builtin.common.range.selection": "选区",
"hex.builtin.common.region": "区域",
"hex.builtin.common.set": "设置",
"hex.builtin.common.settings": "设置",
"hex.builtin.common.size": "大小",
"hex.builtin.common.type": "类型",
"hex.builtin.common.type.f32": "float",
@@ -135,32 +136,40 @@
"hex.builtin.menu.file.close": "关闭",
"hex.builtin.menu.file.create_file": "新建文件...",
"hex.builtin.menu.file.export": "导出...",
"hex.builtin.menu.file.export.base64": "",
"hex.builtin.menu.file.export.base64.popup.export_error": "",
"hex.builtin.menu.file.export.base64": "Base64",
"hex.builtin.menu.file.export.base64.popup.export_error": "创建新的Base64文件失败",
"hex.builtin.menu.file.export.bookmark": "",
"hex.builtin.menu.file.export.data_processor": "",
"hex.builtin.menu.file.export.ips": "IPS 补丁",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "",
"hex.builtin.menu.file.export.ips.popup.export_error": "",
"hex.builtin.menu.file.export.ips.popup.invalid_patch_format_error": "",
"hex.builtin.menu.file.export.ips.popup.invalid_patch_header_error": "",
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "补丁尝试修补范围之外的地址!",
"hex.builtin.menu.file.export.ips.popup.export_error": "创建新的 IPS 文件失败!",
"hex.builtin.menu.file.export.ips.popup.invalid_patch_format_error": "无效 IPS 补丁格式!",
"hex.builtin.menu.file.export.ips.popup.invalid_patch_header_error": "无效 IPS 补丁头!",
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "缺少 IPS EOF 记录!",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "补丁大于最大允许大小!",
"hex.builtin.menu.file.export.ips32": "IPS32 补丁",
"hex.builtin.menu.file.export.pattern": "",
"hex.builtin.menu.file.export.popup.create": "无法导出文件。文件创建失败!",
"hex.builtin.menu.file.export.title": "导出文件",
"hex.builtin.menu.file.import": "导入...",
"hex.builtin.menu.file.import.base64": "Base64 文件",
"hex.builtin.menu.file.import.base64.popup.import_error": "文件不是有效的 Base64 格式!",
"hex.builtin.menu.file.import.base64.popup.open_error": "打开文件失败!",
"hex.builtin.menu.file.import.bookmark": "",
"hex.builtin.menu.file.import.custom_encoding": "",
"hex.builtin.menu.file.import.data_processor": "",
"hex.builtin.menu.file.import.ips": "IPS 补丁",
"hex.builtin.menu.file.import.ips32": "IPS32 补丁",
"hex.builtin.menu.file.import.pattern": "",
"hex.builtin.menu.file.open_file": "打开文件...",
"hex.builtin.menu.file.open_other": "打开其他...",
"hex.builtin.menu.file.open_project": "打开项目...",
"hex.builtin.menu.file.open_recent": "最近打开",
"hex.builtin.menu.file.project": "",
"hex.builtin.menu.file.project.open": "",
"hex.builtin.menu.file.project.save": "",
"hex.builtin.menu.file.project.save_as": "",
"hex.builtin.menu.file.quit": "退出 ImHex",
"hex.builtin.menu.file.reload_file": "重新加载文件",
"hex.builtin.menu.file.save_project": "保存项目",
"hex.builtin.menu.file.save_project_as": "另存项目为...",
"hex.builtin.menu.file.reload_provider": "",
"hex.builtin.menu.help": "帮助",
"hex.builtin.menu.layout": "布局",
"hex.builtin.menu.view": "视图",
@@ -318,8 +327,8 @@
"hex.builtin.pattern_drawer.type": "类型",
"hex.builtin.pattern_drawer.value": "值",
"hex.builtin.pattern_drawer.var_name": "名称",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "",
"hex.builtin.pattern_drawer.visualizer.unknown": "",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "无效参数数",
"hex.builtin.pattern_drawer.visualizer.unknown": "未知可视化器",
"hex.builtin.popup.close_provider.desc": "有对此提供器做出的未保存的更改。\n你确定要关闭吗",
"hex.builtin.popup.close_provider.title": "关闭提供器?",
"hex.builtin.popup.error.create": "创建新文件失败!",
@@ -366,6 +375,7 @@
"hex.builtin.setting.general.auto_load_patterns": "自动加载支持的模式",
"hex.builtin.setting.general.check_for_updates": "启动时检查更新",
"hex.builtin.setting.general.enable_unicode": "加载所有 Unicode 字符",
"hex.builtin.setting.general.save_recent_providers": "",
"hex.builtin.setting.general.show_tips": "在启动时显示每日提示",
"hex.builtin.setting.general.sync_pattern_source": "在提供器间同步模式源码",
"hex.builtin.setting.hex_editor": "Hex 编辑器",
@@ -382,23 +392,21 @@
"hex.builtin.setting.imhex": "ImHex",
"hex.builtin.setting.imhex.recent_files": "最近文件",
"hex.builtin.setting.interface": "界面",
"hex.builtin.setting.interface.color": "",
"hex.builtin.setting.interface.color": "颜色主题",
"hex.builtin.setting.interface.fps": "FPS 限制",
"hex.builtin.setting.interface.fps.unlocked": "无限制",
"hex.builtin.setting.interface.language": "语言",
"hex.builtin.setting.interface.multi_windows": "启用多窗口支持",
"hex.builtin.setting.interface.pattern_tree_style": "",
"hex.builtin.setting.interface.pattern_tree_style.auto_expanded": "",
"hex.builtin.setting.interface.pattern_tree_style.flattened": "",
"hex.builtin.setting.interface.pattern_tree_style.tree": "",
"hex.builtin.setting.interface.pattern_tree_style": "模式树样式",
"hex.builtin.setting.interface.pattern_tree_style.auto_expanded": "自动展开树",
"hex.builtin.setting.interface.pattern_tree_style.flattened": "扁平化",
"hex.builtin.setting.interface.pattern_tree_style.tree": "",
"hex.builtin.setting.interface.scaling": "缩放",
"hex.builtin.setting.interface.scaling.native": "本地默认",
"hex.builtin.setting.interface.scaling.x0_5": "x0.5",
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "维基百科使用语言",
"hex.builtin.setting.proxy": "网络代理",
"hex.builtin.setting.proxy.description": "代理设置会立即在可下载内容、维基百科查询上生效。",
@@ -412,6 +420,7 @@
"hex.builtin.tools.base_converter.dec": "DEC",
"hex.builtin.tools.base_converter.hex": "HEX",
"hex.builtin.tools.base_converter.oct": "OCT",
"hex.builtin.tools.byte_swapper": "",
"hex.builtin.tools.calc": "计算器",
"hex.builtin.tools.color": "颜色选择器",
"hex.builtin.tools.demangler": "LLVM 名还原",
@@ -426,7 +435,7 @@
"hex.builtin.tools.file_tools.combiner.combine": "合并",
"hex.builtin.tools.file_tools.combiner.combining": "合并中...",
"hex.builtin.tools.file_tools.combiner.delete": "删除",
"hex.builtin.tools.file_tools.combiner.error.open_output": "创建输出文件失败",
"hex.builtin.tools.file_tools.combiner.error.open_output": "创建输出文件失败",
"hex.builtin.tools.file_tools.combiner.open_input": "打开输入文件 {0} 失败",
"hex.builtin.tools.file_tools.combiner.output": "输出文件 ",
"hex.builtin.tools.file_tools.combiner.output.picker": "选择输出路径",
@@ -443,7 +452,7 @@
"hex.builtin.tools.file_tools.splitter": "分割",
"hex.builtin.tools.file_tools.splitter.input": "目标文件 ",
"hex.builtin.tools.file_tools.splitter.output": "输出路径 ",
"hex.builtin.tools.file_tools.splitter.picker.error.create": "创建分块文件 {0} 失败",
"hex.builtin.tools.file_tools.splitter.picker.error.create": "创建分块文件 {0} 失败",
"hex.builtin.tools.file_tools.splitter.picker.error.open": "打开选择的文件失败!",
"hex.builtin.tools.file_tools.splitter.picker.error.size": "文件小于单分块大小",
"hex.builtin.tools.file_tools.splitter.picker.input": "打开文件以分割",
@@ -473,7 +482,7 @@
"hex.builtin.tools.format.standard": "标准",
"hex.builtin.tools.history": "历史",
"hex.builtin.tools.ieee754": "IEEE 754 浮点数测试器",
"hex.builtin.tools.ieee754.description": "",
"hex.builtin.tools.ieee754.description": "IEEE754 是大多数现代 CPU 使用的表示浮点数的标准。\n\n此工具可视化浮点数的内部表示并允许解码具有非标准数量的尾数或指数位的数字。",
"hex.builtin.tools.ieee754.double_precision": "双精度浮点数",
"hex.builtin.tools.ieee754.exponent": "指数",
"hex.builtin.tools.ieee754.exponent_size": "指数位数",
@@ -488,10 +497,11 @@
"hex.builtin.tools.ieee754.singe_precision": "单精度浮点数",
"hex.builtin.tools.ieee754.type": "部分",
"hex.builtin.tools.input": "输入",
"hex.builtin.tools.invariant_multiplication": "",
"hex.builtin.tools.invariant_multiplication.description": "",
"hex.builtin.tools.invariant_multiplication.num_bits": "",
"hex.builtin.tools.invariant_multiplication": "通过乘法除以常量",
"hex.builtin.tools.invariant_multiplication.description": "通过乘法除以常量是编译器经常使用的一种技术,用于将整数除以常数优化为乘法并位移。这样做的原因是除法通常比乘法花费多倍的时钟周期。\n\n此工具可用于从除数计算乘数或从乘数计算除数。",
"hex.builtin.tools.invariant_multiplication.num_bits": "位数量",
"hex.builtin.tools.name": "名称",
"hex.builtin.tools.output": "",
"hex.builtin.tools.permissions": "UNIX 权限计算器",
"hex.builtin.tools.permissions.absolute": "绝对符号",
"hex.builtin.tools.permissions.perm_bits": "权限位",
@@ -509,7 +519,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "接收到来自 Wikipedia 的无效响应!",
"hex.builtin.tools.wiki_explain.results": "结果",
"hex.builtin.tools.wiki_explain.search": "搜索",
"hex.builtin.view.bookmarks.address": "0x{0:X} : 0x{1:X} ({2} 字节)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "转到",
"hex.builtin.view.bookmarks.button.remove": "移除",
"hex.builtin.view.bookmarks.default_title": "书签 [0x{0:X} - 0x{1:X}]",
@@ -517,7 +527,7 @@
"hex.builtin.view.bookmarks.header.comment": "注释",
"hex.builtin.view.bookmarks.header.name": "名称",
"hex.builtin.view.bookmarks.name": "书签",
"hex.builtin.view.bookmarks.no_bookmarks": "空空如也--您可以使用 '编辑' 菜单来添加书签。",
"hex.builtin.view.bookmarks.no_bookmarks": "空空如也——您可以使用 '编辑' 菜单来添加书签。",
"hex.builtin.view.bookmarks.title.info": "信息",
"hex.builtin.view.command_palette.name": "命令栏",
"hex.builtin.view.constants.name": "常量",
@@ -592,7 +602,6 @@
"hex.builtin.view.disassembler.ppc.spe": "PowerPC 单核引擎SPE",
"hex.builtin.view.disassembler.region": "代码范围",
"hex.builtin.view.disassembler.riscv.compressed": "压缩的 RISC-V",
"hex.builtin.view.disassembler.settings.header": "设置",
"hex.builtin.view.disassembler.settings.mode": "模式",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "二进制模式",
@@ -653,7 +662,6 @@
"hex.builtin.view.hex_editor.copy.crystal": "Crystal 数组",
"hex.builtin.view.hex_editor.copy.csharp": "C# 数组",
"hex.builtin.view.hex_editor.copy.go": "Go 数组",
"hex.builtin.view.hex_editor.copy.hex": "字符串",
"hex.builtin.view.hex_editor.copy.html": "HTML",
"hex.builtin.view.hex_editor.copy.java": "Java 数组",
"hex.builtin.view.hex_editor.copy.js": "JavaScript 数组",
@@ -696,23 +704,25 @@
"hex.builtin.view.information.analyzing": "分析中...",
"hex.builtin.view.information.block_size": "块大小",
"hex.builtin.view.information.block_size.desc": "{0} 块 × {1} 字节",
"hex.builtin.view.information.byte_types": "",
"hex.builtin.view.information.byte_types": "字节类型",
"hex.builtin.view.information.control": "控制",
"hex.builtin.view.information.description": "描述:",
"hex.builtin.view.information.digram": "",
"hex.builtin.view.information.digram": "",
"hex.builtin.view.information.distribution": "字节分布",
"hex.builtin.view.information.encrypted": "此数据似乎经过了加密或压缩!",
"hex.builtin.view.information.entropy": "熵",
"hex.builtin.view.information.file_entropy": "文件熵",
"hex.builtin.view.information.file_entropy": "",
"hex.builtin.view.information.highest_entropy": "最高熵",
"hex.builtin.view.information.info_analysis": "信息分析",
"hex.builtin.view.information.layered_distribution": "",
"hex.builtin.view.information.layered_distribution": "分层分布",
"hex.builtin.view.information.lowest_entropy": "",
"hex.builtin.view.information.magic": "LibMagic 信息",
"hex.builtin.view.information.magic_db_added": "LibMagic 数据库已添加!",
"hex.builtin.view.information.mime": "MIME 类型:",
"hex.builtin.view.information.name": "数据信息",
"hex.builtin.view.information.plain_text": "",
"hex.builtin.view.information.plain_text_percentage": "",
"hex.builtin.view.information.plain_text": "此数据很可能是纯文本。",
"hex.builtin.view.information.plain_text_percentage": "纯文本百分比",
"hex.builtin.view.information.provider_information": "",
"hex.builtin.view.information.region": "已分析区域",
"hex.builtin.view.patches.name": "补丁",
"hex.builtin.view.patches.offset": "偏移",
@@ -743,7 +753,7 @@
"hex.builtin.view.pattern_editor.section_popup": "段",
"hex.builtin.view.pattern_editor.sections": "段",
"hex.builtin.view.pattern_editor.settings": "设置",
"hex.builtin.view.provider_settings.load_error": "尝试打开此提供器时出现错误",
"hex.builtin.view.provider_settings.load_error": "尝试打开此提供器时出现错误",
"hex.builtin.view.provider_settings.load_popup": "打开提供器",
"hex.builtin.view.provider_settings.name": "提供器设置",
"hex.builtin.view.settings.name": "设置",
@@ -837,6 +847,51 @@
"hex.builtin.welcome.tip_of_the_day": "每日提示",
"hex.builtin.welcome.update.desc": "ImHex {0} 已发布!在这里下载。",
"hex.builtin.welcome.update.link": "https://github.com/WerWolv/ImHex/releases/latest",
"hex.builtin.welcome.update.title": "新的更新可用!"
"hex.builtin.welcome.update.title": "新的更新可用!",
"hex.builtin.common.end": "末尾",
"hex.builtin.menu.file.import.modified_file": "已修改",
"hex.builtin.nodes.arithmetic.ceil.header": "向上取整",
"hex.builtin.nodes.custom": "自定义",
"hex.builtin.nodes.custom.output": "自定义节点输出",
"hex.builtin.nodes.buffer.size": "缓冲区大小",
"hex.builtin.view.theme_manager.name": "主题管理器",
"hex.builtin.view.theme_manager.colors": "颜色",
"hex.builtin.view.theme_manager.export": "导出",
"hex.builtin.view.diff.provider_b": "提供者B",
"hex.builtin.visualizer.binary": "二进制",
"hex.builtin.view.store.tab.nodes": "节点",
"hex.builtin.view.store.tab.themes": "主题",
"hex.builtin.nodes.arithmetic.ceil": "向上取整",
"hex.builtin.common.reset": "重置",
"hex.builtin.nodes.arithmetic.floor.header": "向下取整",
"hex.builtin.nodes.arithmetic.floor": "向下取整",
"hex.builtin.nodes.arithmetic.round": "四舍五入",
"hex.builtin.nodes.arithmetic.round.header": "四舍五入",
"hex.builtin.nodes.bitwise.add": "相加",
"hex.builtin.nodes.bitwise.add.header": "按位相加",
"hex.builtin.nodes.buffer.size.header": "缓冲区大小",
"hex.builtin.nodes.buffer.size.output": "大小",
"hex.builtin.nodes.custom.custom": "新节点",
"hex.builtin.nodes.custom.custom.edit": "编辑",
"hex.builtin.nodes.custom.custom.edit_hint": "按下 SHIFT 以编辑",
"hex.builtin.nodes.custom.custom.header": "自定义节点",
"hex.builtin.nodes.custom.input": "自定义节点输入",
"hex.builtin.nodes.custom.input.header": "节点输入",
"hex.builtin.nodes.custom.output.header": "节点输出",
"hex.builtin.pl_visualizer.3d.rotation": "旋转",
"hex.builtin.pl_visualizer.3d.scale": "缩放",
"hex.builtin.popup.waiting_for_tasks.title": "等待任务进行",
"hex.builtin.popup.waiting_for_tasks.desc": "仍有任务在后台运行。\nImHex 将在完成后关闭。",
"hex.builtin.view.data_processor.menu.save_node": "保存节点",
"hex.builtin.view.diff.added": "添加",
"hex.builtin.view.diff.modified": "修改",
"hex.builtin.view.diff.provider_a": "提供者A",
"hex.builtin.view.diff.removed": "移除",
"hex.builtin.view.hex_editor.copy.custom_encoding": "自定义编码",
"hex.builtin.view.hex_editor.copy.hex_view": "二进制",
"hex.builtin.view.theme_manager.export.name": "主题名称",
"hex.builtin.view.theme_manager.save_theme": "保存主题",
"hex.builtin.view.theme_manager.styles": "样式",
"hex.builtin.common.begin": "起始"
}
}
}

View File

@@ -9,6 +9,7 @@
"hex.builtin.command.web.desc": "網站查詢",
"hex.builtin.command.web.result": "前往 '{0}'",
"hex.builtin.common.address": "位址",
"hex.builtin.common.begin": "",
"hex.builtin.common.big": "大",
"hex.builtin.common.big_endian": "大端序",
"hex.builtin.common.browse": "瀏覽...",
@@ -24,6 +25,7 @@
"hex.builtin.common.encoding.utf16be": "UTF-16BE",
"hex.builtin.common.encoding.utf16le": "UTF-16LE",
"hex.builtin.common.encoding.utf8": "UTF-8",
"hex.builtin.common.end": "",
"hex.builtin.common.endian": "端序",
"hex.builtin.common.error": "錯誤",
"hex.builtin.common.fatal": "嚴重錯誤",
@@ -51,7 +53,9 @@
"hex.builtin.common.range.entire_data": "整筆資料",
"hex.builtin.common.range.selection": "所選",
"hex.builtin.common.region": "區域",
"hex.builtin.common.set": "設置",
"hex.builtin.common.reset": "",
"hex.builtin.common.set": "設定",
"hex.builtin.common.settings": "",
"hex.builtin.common.size": "大小",
"hex.builtin.common.type": "類型",
"hex.builtin.common.type.f32": "float",
@@ -137,6 +141,8 @@
"hex.builtin.menu.file.export": "匯出...",
"hex.builtin.menu.file.export.base64": "",
"hex.builtin.menu.file.export.base64.popup.export_error": "",
"hex.builtin.menu.file.export.bookmark": "",
"hex.builtin.menu.file.export.data_processor": "",
"hex.builtin.menu.file.export.ips": "IPS 修補檔案",
"hex.builtin.menu.file.export.ips.popup.address_out_of_range_error": "",
"hex.builtin.menu.file.export.ips.popup.export_error": "",
@@ -145,22 +151,29 @@
"hex.builtin.menu.file.export.ips.popup.missing_eof_error": "",
"hex.builtin.menu.file.export.ips.popup.patch_too_large_error": "",
"hex.builtin.menu.file.export.ips32": "IPS32 修補檔案",
"hex.builtin.menu.file.export.pattern": "",
"hex.builtin.menu.file.export.popup.create": "無法匯出資料。無法建立檔案!",
"hex.builtin.menu.file.export.title": "匯出檔案",
"hex.builtin.menu.file.import": "匯入...",
"hex.builtin.menu.file.import.base64": "Base64 檔案",
"hex.builtin.menu.file.import.base64.popup.import_error": "檔案並非有效的 Base64 格式!",
"hex.builtin.menu.file.import.base64.popup.open_error": "無法開啟檔案!",
"hex.builtin.menu.file.import.bookmark": "",
"hex.builtin.menu.file.import.custom_encoding": "",
"hex.builtin.menu.file.import.data_processor": "",
"hex.builtin.menu.file.import.ips": "IPS 修補檔案",
"hex.builtin.menu.file.import.ips32": "IPS32 修補檔案",
"hex.builtin.menu.file.import.modified_file": "",
"hex.builtin.menu.file.import.pattern": "",
"hex.builtin.menu.file.open_file": "開啟檔案...",
"hex.builtin.menu.file.open_other": "開啟其他...",
"hex.builtin.menu.file.open_project": "開啟專案...",
"hex.builtin.menu.file.open_recent": "開啟近期",
"hex.builtin.menu.file.project": "",
"hex.builtin.menu.file.project.open": "",
"hex.builtin.menu.file.project.save": "",
"hex.builtin.menu.file.project.save_as": "",
"hex.builtin.menu.file.quit": "退出 ImHex",
"hex.builtin.menu.file.reload_file": "重新載入檔案",
"hex.builtin.menu.file.save_project": "儲存專案",
"hex.builtin.menu.file.save_project_as": "另存專案為...",
"hex.builtin.menu.file.reload_provider": "",
"hex.builtin.menu.help": "幫助",
"hex.builtin.menu.layout": "版面配置",
"hex.builtin.menu.view": "檢視",
@@ -171,17 +184,25 @@
"hex.builtin.nodes.arithmetic.add.header": "加",
"hex.builtin.nodes.arithmetic.average": "平均數",
"hex.builtin.nodes.arithmetic.average.header": "平均數",
"hex.builtin.nodes.arithmetic.ceil": "",
"hex.builtin.nodes.arithmetic.ceil.header": "",
"hex.builtin.nodes.arithmetic.div": "除法",
"hex.builtin.nodes.arithmetic.div.header": "除",
"hex.builtin.nodes.arithmetic.floor": "",
"hex.builtin.nodes.arithmetic.floor.header": "",
"hex.builtin.nodes.arithmetic.median": "中位數",
"hex.builtin.nodes.arithmetic.median.header": "中位數",
"hex.builtin.nodes.arithmetic.mod": "取模",
"hex.builtin.nodes.arithmetic.mod.header": "模",
"hex.builtin.nodes.arithmetic.mul": "乘法",
"hex.builtin.nodes.arithmetic.mul.header": "乘",
"hex.builtin.nodes.arithmetic.round": "",
"hex.builtin.nodes.arithmetic.round.header": "",
"hex.builtin.nodes.arithmetic.sub": "減法",
"hex.builtin.nodes.arithmetic.sub.header": "減",
"hex.builtin.nodes.bitwise": "位元運算",
"hex.builtin.nodes.bitwise.add": "",
"hex.builtin.nodes.bitwise.add.header": "",
"hex.builtin.nodes.bitwise.and": "AND",
"hex.builtin.nodes.bitwise.and.header": "位元 AND",
"hex.builtin.nodes.bitwise.not": "NOT",
@@ -200,6 +221,9 @@
"hex.builtin.nodes.buffer.repeat.header": "重複緩衝",
"hex.builtin.nodes.buffer.repeat.input.buffer": "輸入",
"hex.builtin.nodes.buffer.repeat.input.count": "計數",
"hex.builtin.nodes.buffer.size": "",
"hex.builtin.nodes.buffer.size.header": "",
"hex.builtin.nodes.buffer.size.output": "",
"hex.builtin.nodes.buffer.slice": "分割",
"hex.builtin.nodes.buffer.slice.header": "分割緩衝",
"hex.builtin.nodes.buffer.slice.input.buffer": "輸入",
@@ -266,6 +290,15 @@
"hex.builtin.nodes.crypto.aes.key_length": "金鑰長度",
"hex.builtin.nodes.crypto.aes.mode": "模式",
"hex.builtin.nodes.crypto.aes.nonce": "Nonce",
"hex.builtin.nodes.custom": "",
"hex.builtin.nodes.custom.custom": "",
"hex.builtin.nodes.custom.custom.edit": "",
"hex.builtin.nodes.custom.custom.edit_hint": "",
"hex.builtin.nodes.custom.custom.header": "",
"hex.builtin.nodes.custom.input": "",
"hex.builtin.nodes.custom.input.header": "",
"hex.builtin.nodes.custom.output": "",
"hex.builtin.nodes.custom.output.header": "",
"hex.builtin.nodes.data_access": "資料存取",
"hex.builtin.nodes.data_access.read": "讀取",
"hex.builtin.nodes.data_access.read.address": "位址",
@@ -320,6 +353,8 @@
"hex.builtin.pattern_drawer.var_name": "名稱",
"hex.builtin.pattern_drawer.visualizer.invalid_parameter_count": "",
"hex.builtin.pattern_drawer.visualizer.unknown": "",
"hex.builtin.pl_visualizer.3d.rotation": "",
"hex.builtin.pl_visualizer.3d.scale": "",
"hex.builtin.popup.close_provider.desc": "您對此提供者有未儲存的更動。\n您確定要關閉嗎",
"hex.builtin.popup.close_provider.title": "關閉提供者?",
"hex.builtin.popup.error.create": "無法建立新檔案!",
@@ -332,6 +367,8 @@
"hex.builtin.popup.error.task_exception": "工作 '{}' 擲回了例外狀況:\n\n{}",
"hex.builtin.popup.exit_application.desc": "您的專案有未儲存的更動。\n您確定要離開嗎",
"hex.builtin.popup.exit_application.title": "離開應用程式?",
"hex.builtin.popup.waiting_for_tasks.desc": "",
"hex.builtin.popup.waiting_for_tasks.title": "",
"hex.builtin.provider.disk": "原始磁碟提供者",
"hex.builtin.provider.disk.disk_size": "磁碟大小",
"hex.builtin.provider.disk.reload": "重新載入",
@@ -366,6 +403,7 @@
"hex.builtin.setting.general.auto_load_patterns": "自動載入支援的模式",
"hex.builtin.setting.general.check_for_updates": "Check for updates on startup",
"hex.builtin.setting.general.enable_unicode": "載入所有 unicode 字元",
"hex.builtin.setting.general.save_recent_providers": "",
"hex.builtin.setting.general.show_tips": "啟動時顯示提示",
"hex.builtin.setting.general.sync_pattern_source": "同步提供者之間的模式原始碼",
"hex.builtin.setting.hex_editor": "十六進位編輯器",
@@ -397,8 +435,6 @@
"hex.builtin.setting.interface.scaling.x1_0": "x1.0",
"hex.builtin.setting.interface.scaling.x1_5": "x1.5",
"hex.builtin.setting.interface.scaling.x2_0": "x2.0",
"hex.builtin.setting.interface.scaling.x3_0": "x3.0",
"hex.builtin.setting.interface.scaling.x4_0": "x4.0",
"hex.builtin.setting.interface.wiki_explain_language": "維基百科語言",
"hex.builtin.setting.proxy": "Proxy",
"hex.builtin.setting.proxy.description": "Proxy 將立即在儲存、查詢維基百科,或使用任何外掛程式時生效。",
@@ -412,6 +448,7 @@
"hex.builtin.tools.base_converter.dec": "DEC",
"hex.builtin.tools.base_converter.hex": "HEX",
"hex.builtin.tools.base_converter.oct": "OCT",
"hex.builtin.tools.byte_swapper": "",
"hex.builtin.tools.calc": "計算機",
"hex.builtin.tools.color": "Color picker",
"hex.builtin.tools.demangler": "LLVM Demangler",
@@ -492,6 +529,7 @@
"hex.builtin.tools.invariant_multiplication.description": "",
"hex.builtin.tools.invariant_multiplication.num_bits": "",
"hex.builtin.tools.name": "名稱",
"hex.builtin.tools.output": "",
"hex.builtin.tools.permissions": "UNIX 權限計算機",
"hex.builtin.tools.permissions.absolute": "Absolute Notation",
"hex.builtin.tools.permissions.perm_bits": "權限位元",
@@ -509,7 +547,7 @@
"hex.builtin.tools.wiki_explain.invalid_response": "維基百科回應無效!",
"hex.builtin.tools.wiki_explain.results": "結果",
"hex.builtin.tools.wiki_explain.search": "搜尋",
"hex.builtin.view.bookmarks.address": "0x0:{X} : 0x1:{X} ({2} 位元組)",
"hex.builtin.view.bookmarks.address": "0x{0:02X} - 0x{1:02X}",
"hex.builtin.view.bookmarks.button.jump": "跳至",
"hex.builtin.view.bookmarks.button.remove": "移除",
"hex.builtin.view.bookmarks.default_title": "書籤 [0x0:{X} - 0x1:{X}]",
@@ -536,8 +574,14 @@
"hex.builtin.view.data_processor.menu.remove_link": "移除連結",
"hex.builtin.view.data_processor.menu.remove_node": "移除節點",
"hex.builtin.view.data_processor.menu.remove_selection": "移除所選",
"hex.builtin.view.data_processor.menu.save_node": "",
"hex.builtin.view.data_processor.name": "資料處理器",
"hex.builtin.view.diff.added": "",
"hex.builtin.view.diff.modified": "",
"hex.builtin.view.diff.name": "Diffing",
"hex.builtin.view.diff.provider_a": "",
"hex.builtin.view.diff.provider_b": "",
"hex.builtin.view.diff.removed": "",
"hex.builtin.view.disassembler.16bit": "16 位元",
"hex.builtin.view.disassembler.32bit": "32 位元",
"hex.builtin.view.disassembler.64bit": "64 位元",
@@ -592,7 +636,6 @@
"hex.builtin.view.disassembler.ppc.spe": "訊號處理引擎",
"hex.builtin.view.disassembler.region": "程式碼區域",
"hex.builtin.view.disassembler.riscv.compressed": "Compressed",
"hex.builtin.view.disassembler.settings.header": "設定",
"hex.builtin.view.disassembler.settings.mode": "模式",
"hex.builtin.view.disassembler.sparc.v9": "Sparc V9",
"hex.builtin.view.find.binary_pattern": "Binary Pattern",
@@ -646,12 +689,15 @@
"hex.builtin.view.help.name": "幫助",
"hex.builtin.view.help.pattern_cheat_sheet": "模式語言小抄",
"hex.builtin.view.hex_editor.copy.address": "地址",
"hex.builtin.view.hex_editor.copy.ascii": "",
"hex.builtin.view.hex_editor.copy.base64": "Base64",
"hex.builtin.view.hex_editor.copy.c": "C 陣列",
"hex.builtin.view.hex_editor.copy.cpp": "C++ 陣列",
"hex.builtin.view.hex_editor.copy.crystal": "Crystal 陣列",
"hex.builtin.view.hex_editor.copy.csharp": "C# 陣列",
"hex.builtin.view.hex_editor.copy.custom_encoding": "",
"hex.builtin.view.hex_editor.copy.go": "Go 陣列",
"hex.builtin.view.hex_editor.copy.hex_view": "",
"hex.builtin.view.hex_editor.copy.html": "HTML",
"hex.builtin.view.hex_editor.copy.java": "Java 陣列",
"hex.builtin.view.hex_editor.copy.js": "JavaScript 陣列",
@@ -701,16 +747,18 @@
"hex.builtin.view.information.distribution": "位元組分佈",
"hex.builtin.view.information.encrypted": "此資料很有可能經過加密或壓縮!",
"hex.builtin.view.information.entropy": "熵",
"hex.builtin.view.information.file_entropy": "檔案熵",
"hex.builtin.view.information.highest_entropy": "Highest entropy block",
"hex.builtin.view.information.file_entropy": "",
"hex.builtin.view.information.highest_entropy": "Highest block entropy",
"hex.builtin.view.information.info_analysis": "資訊分析",
"hex.builtin.view.information.layered_distribution": "",
"hex.builtin.view.information.lowest_entropy": "",
"hex.builtin.view.information.magic": "Magic information",
"hex.builtin.view.information.magic_db_added": "Magic database added!",
"hex.builtin.view.information.mime": "MIME 類型:",
"hex.builtin.view.information.name": "資料資訊",
"hex.builtin.view.information.plain_text": "",
"hex.builtin.view.information.plain_text_percentage": "",
"hex.builtin.view.information.provider_information": "",
"hex.builtin.view.information.region": "Analyzed region",
"hex.builtin.view.patches.name": "Patches",
"hex.builtin.view.patches.offset": "位移",
@@ -760,9 +808,17 @@
"hex.builtin.view.store.tab.encodings": "編碼",
"hex.builtin.view.store.tab.libraries": "程式庫",
"hex.builtin.view.store.tab.magics": "Magic Files",
"hex.builtin.view.store.tab.nodes": "",
"hex.builtin.view.store.tab.patterns": "模式",
"hex.builtin.view.store.tab.themes": "",
"hex.builtin.view.store.tab.yara": "Yara 規則",
"hex.builtin.view.store.update": "更新",
"hex.builtin.view.theme_manager.colors": "",
"hex.builtin.view.theme_manager.export": "",
"hex.builtin.view.theme_manager.export.name": "",
"hex.builtin.view.theme_manager.name": "",
"hex.builtin.view.theme_manager.save_theme": "",
"hex.builtin.view.theme_manager.styles": "",
"hex.builtin.view.tools.name": "工具",
"hex.builtin.view.yara.error": "Yara 編譯器錯誤:",
"hex.builtin.view.yara.header.matches": "Matches",
@@ -777,6 +833,7 @@
"hex.builtin.view.yara.reset": "Reset",
"hex.builtin.view.yara.rule_added": " Yara 規則已新增!",
"hex.builtin.view.yara.whole_data": "Whole file matches!",
"hex.builtin.visualizer.binary": "",
"hex.builtin.visualizer.decimal.signed.16bit": "十進位有號數 (16 位元)",
"hex.builtin.visualizer.decimal.signed.32bit": "十進位有號數 (32 位元)",
"hex.builtin.visualizer.decimal.signed.64bit": "十進位有號數 (64 位元)",

View File

@@ -1,6 +1,5 @@
{
"name": "Classic",
"image_postfix": "_dark",
"base": "Classic",
"colors": {
"imgui": {
"border": "#7F7F7F7F",
@@ -59,20 +58,18 @@
"title-background-collapse": "#66668CCC",
"window-background": "#000000D8"
},
"implot": {
"axis-grid": "#E5E5E53F",
"axis-text": "#E5E5E5FF",
"crosshairs": "#7F7F7FBF",
"error-bar": "#E5E5E5FF",
"frame-bg": "#6D6D6D63",
"inlay-text": "#E5E5E5FF",
"legend-bg": "#1C1C23EA",
"legend-border": "#7F7F7F7F",
"legend-text": "#E5E5E5FF",
"plot-bg": "#00000059",
"plot-border": "#7F7F7F7F",
"selection": "#F7F763FF",
"title-text": "#E5E5E5FF"
"imhex": {
"desc-button": "#282850FF",
"desc-button-active": "#505078FF",
"desc-button-hovered": "#3C3C64FF",
"highlight": "#4DC69BFF",
"toolbar-blue": "#06539BFF",
"toolbar-brown": "#DBB377FF",
"toolbar-gray": "#E6E6E6FF",
"toolbar-green": "#388B42FF",
"toolbar-purple": "#672A78FF",
"toolbar-red": "#E74C3CFF",
"toolbar-yellow": "#F1C40FFF"
},
"imnodes": {
"box-selector": "#5252A164",
@@ -105,18 +102,28 @@
"title-bar-hovered": "#5252A1FF",
"title-bar-selected": "#5252A1FF"
},
"imhex": {
"desc-button": "#282850FF",
"desc-button-active": "#505078FF",
"desc-button-hovered": "#3C3C64FF",
"highlight": "#4DC69BFF",
"toolbar-blue": "#06539BFF",
"toolbar-brown": "#DBB377FF",
"toolbar-gray": "#E6E6E6FF",
"toolbar-green": "#388B42FF",
"toolbar-purple": "#672A78FF",
"toolbar-red": "#E74C3CFF",
"toolbar-yellow": "#F1C40FFF"
"implot": {
"axis-bg": "auto",
"axis-bg-active": "auto",
"axis-bg-hovered": "auto",
"axis-grid": "#E5E5E53F",
"axis-text": "#E5E5E5FF",
"axis-tick": "auto",
"crosshairs": "#7F7F7FBF",
"error-bar": "auto",
"fill": "auto",
"frame-bg": "#6D6D6D63",
"inlay-text": "#E5E5E5FF",
"legend-bg": "#1C1C23EA",
"legend-border": "#7F7F7F7F",
"legend-text": "#E5E5E5FF",
"line": "auto",
"marker-fill": "auto",
"marker-outline": "auto",
"plot-bg": "#00000059",
"plot-border": "#7F7F7F7F",
"selection": "#F7F763FF",
"title-text": "#E5E5E5FF"
},
"text-editor": {
"background": "#000080FF",
@@ -141,5 +148,165 @@
"selection": "#00FFFF80",
"string": "#008080FF"
}
},
"image_postfix": "_dark",
"name": "Classic",
"styles": {
"imgui": {
"alpha": 1.0,
"button-text-align": [
0.5,
0.5
],
"cell-padding": [
4.0,
2.0
],
"child-border-size": 1.0,
"child-rounding": 0.0,
"disabled-alpha": 0.6,
"frame-border-size": 0.0,
"frame-padding": [
4.0,
3.0
],
"frame-rounding": 0.0,
"grab-min-size": 12.0,
"grab-rounding": 0.0,
"indent-spacing": 10.0,
"item-inner-spacing": [
4.0,
4.0
],
"item-spacing": [
8.0,
4.0
],
"popup-border-size": 1.0,
"popup-rounding": 0.0,
"scrollbar-rounding": 9.0,
"scrollbar-size": 14.0,
"selectable-text-align": [
0.0,
0.0
],
"tab-rounding": 4.0,
"window-border-size": 1.0,
"window-min-size": [
32.0,
32.0
],
"window-padding": [
8.0,
8.0
],
"window-rounding": 0.0,
"window-title-align": [
0.0,
0.5
]
},
"imnodes": {
"grid-spacing": 24.0,
"link-hover-distance": 10.0,
"link-line-segments-per-length": 0.1,
"link-thickness": 3.0,
"mini-map-offset": [
4.0,
4.0
],
"mini-map-padding": [
8.0,
8.0
],
"node-border-thickness": 1.0,
"node-corner-rounding": 4.0,
"node-padding": [
8.0,
8.0
],
"pin-circle-radius": 4.0,
"pin-hover-radius": 10.0,
"pin-line-thickness": 1.0,
"pin-offset": 0.0,
"pin-quad-side-length": 7.0,
"pin-triangle-side-length": 9.5
},
"implot": {
"annotation-padding": [
2.0,
2.0
],
"digital-bit-gap": 4.0,
"digital-bit-height": 8.0,
"error-bar-size": 5.0,
"error-bar-weight": 1.5,
"fill-alpha": 1.0,
"fit-padding": [
0.0,
0.0
],
"label-padding": [
5.0,
5.0
],
"legend-inner-padding": [
5.0,
5.0
],
"legend-padding": [
10.0,
10.0
],
"legend-spacing": [
5.0,
0.0
],
"line-weight": 1.0,
"major-grid-size": [
1.0,
1.0
],
"major-tick-len": [
10.0,
10.0
],
"major-tick-size": [
1.0,
1.0
],
"marker-size": 4.0,
"marker-weight": 1.0,
"minor-alpha": 0.25,
"minor-grid-size": [
1.0,
1.0
],
"minor-tick-len": [
5.0,
5.0
],
"minor-tick-size": [
1.0,
1.0
],
"mouse-pos-padding": [
10.0,
10.0
],
"plot-border-size": 1.0,
"plot-default-size": [
400.0,
300.0
],
"plot-min-size": [
200.0,
150.0
],
"plot-padding": [
10.0,
10.0
]
}
}
}

View File

@@ -1,6 +1,5 @@
{
"name": "Dark",
"image_postfix": "_dark",
"base": "Dark",
"colors": {
"imgui": {
"border": "#6D6D7F7F",
@@ -59,19 +58,18 @@
"title-background-collapse": "#232323FF",
"window-background": "#0F0F0FEF"
},
"implot": {
"axis-grid": "#FFFFFF3F",
"axis-text": "#FFFFFFFF",
"crosshairs": "#FFFFFF7F",
"frame-bg": "#FFFFFF11",
"inlay-text": "#FFFFFFFF",
"legend-bg": "#141414EF",
"legend-border": "#6D6D7F7F",
"legend-text": "#FFFFFFFF",
"plot-bg": "#0000007F",
"plot-border": "#6D6D7F7F",
"selection": "#FF9900FF",
"title-text": "#FFFFFFFF"
"imhex": {
"desc-button": "#141414FF",
"desc-button-active": "#3C3C3CFF",
"desc-button-hovered": "#282828FF",
"highlight": "#4DC69BFF",
"toolbar-blue": "#06539BFF",
"toolbar-brown": "#DBB377FF",
"toolbar-gray": "#E6E6E6FF",
"toolbar-green": "#388B42FF",
"toolbar-purple": "#672A78FF",
"toolbar-red": "#E74C3CFF",
"toolbar-yellow": "#F1C40FFF"
},
"imnodes": {
"box-selector": "#3D85E01E",
@@ -104,18 +102,28 @@
"title-bar-hovered": "#4296FAFF",
"title-bar-selected": "#4296FAFF"
},
"imhex": {
"desc-button": "#141414FF",
"desc-button-active": "#3C3C3CFF",
"desc-button-hovered": "#282828FF",
"highlight": "#4DC69BFF",
"toolbar-blue": "#06539BFF",
"toolbar-brown": "#DBB377FF",
"toolbar-gray": "#E6E6E6FF",
"toolbar-green": "#388B42FF",
"toolbar-purple": "#672A78FF",
"toolbar-red": "#E74C3CFF",
"toolbar-yellow": "#F1C40FFF"
"implot": {
"axis-bg": "auto",
"axis-bg-active": "auto",
"axis-bg-hovered": "auto",
"axis-grid": "#FFFFFF3F",
"axis-text": "#FFFFFFFF",
"axis-tick": "auto",
"crosshairs": "#FFFFFF7F",
"error-bar": "auto",
"fill": "auto",
"frame-bg": "#FFFFFF11",
"inlay-text": "#FFFFFFFF",
"legend-bg": "#141414EF",
"legend-border": "#6D6D7F7F",
"legend-text": "#FFFFFFFF",
"line": "auto",
"marker-fill": "auto",
"marker-outline": "auto",
"plot-bg": "#0000007F",
"plot-border": "#6D6D7F7F",
"selection": "#FF9900FF",
"title-text": "#FFFFFFFF"
},
"text-editor": {
"background": "#101010FF",
@@ -140,5 +148,165 @@
"selection": "#2060A080",
"string": "#E07070FF"
}
},
"image_postfix": "_dark",
"name": "Dark",
"styles": {
"imgui": {
"alpha": 1.0,
"button-text-align": [
0.5,
0.5
],
"cell-padding": [
4.0,
2.0
],
"child-border-size": 1.0,
"child-rounding": 0.0,
"disabled-alpha": 0.6,
"frame-border-size": 0.0,
"frame-padding": [
4.0,
3.0
],
"frame-rounding": 0.0,
"grab-min-size": 12.0,
"grab-rounding": 0.0,
"indent-spacing": 10.0,
"item-inner-spacing": [
4.0,
4.0
],
"item-spacing": [
8.0,
4.0
],
"popup-border-size": 1.0,
"popup-rounding": 0.0,
"scrollbar-rounding": 9.0,
"scrollbar-size": 14.0,
"selectable-text-align": [
0.0,
0.0
],
"tab-rounding": 4.0,
"window-border-size": 1.0,
"window-min-size": [
32.0,
32.0
],
"window-padding": [
8.0,
8.0
],
"window-rounding": 0.0,
"window-title-align": [
0.0,
0.5
]
},
"imnodes": {
"grid-spacing": 24.0,
"link-hover-distance": 10.0,
"link-line-segments-per-length": 0.1,
"link-thickness": 3.0,
"mini-map-offset": [
4.0,
4.0
],
"mini-map-padding": [
8.0,
8.0
],
"node-border-thickness": 1.0,
"node-corner-rounding": 4.0,
"node-padding": [
8.0,
8.0
],
"pin-circle-radius": 4.0,
"pin-hover-radius": 10.0,
"pin-line-thickness": 1.0,
"pin-offset": 0.0,
"pin-quad-side-length": 7.0,
"pin-triangle-side-length": 9.5
},
"implot": {
"annotation-padding": [
2.0,
2.0
],
"digital-bit-gap": 4.0,
"digital-bit-height": 8.0,
"error-bar-size": 5.0,
"error-bar-weight": 1.5,
"fill-alpha": 1.0,
"fit-padding": [
0.0,
0.0
],
"label-padding": [
5.0,
5.0
],
"legend-inner-padding": [
5.0,
5.0
],
"legend-padding": [
10.0,
10.0
],
"legend-spacing": [
5.0,
0.0
],
"line-weight": 1.0,
"major-grid-size": [
1.0,
1.0
],
"major-tick-len": [
10.0,
10.0
],
"major-tick-size": [
1.0,
1.0
],
"marker-size": 4.0,
"marker-weight": 1.0,
"minor-alpha": 0.25,
"minor-grid-size": [
1.0,
1.0
],
"minor-tick-len": [
5.0,
5.0
],
"minor-tick-size": [
1.0,
1.0
],
"mouse-pos-padding": [
10.0,
10.0
],
"plot-border-size": 1.0,
"plot-default-size": [
400.0,
300.0
],
"plot-min-size": [
200.0,
150.0
],
"plot-padding": [
10.0,
10.0
]
}
}
}

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