Compare commits

..

100 Commits

Author SHA1 Message Date
WerWolv
716d6ae850 build: Bumped version to 1.19.0 2022-07-04 21:53:18 +02:00
iTrooz_
ceb07b7425 build: Added AUR/ArchLinux support (#566)
* store version in file

* use version file in release workflow

* use new version file in build workflow

* ArchLinux build

* setup cache for ArchLinux

* add version check in release CI

* edit step description

* update pkgbuild to install correctly

* AUR deploy

* rename version file to VERSION

* install all default plugins in PKGBUILD

* Added emojis to build workflow

* Added emojis to release workflow

* separate update packages and install dependencies in two steps

* fix Release CI

* add md5Sums to PKGBUILD

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

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

* feat: proxy setting

* refactor: add hex::Net::setProxy

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

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

* change artifacts names

* Release updated

* Set release job name

* set branch to the branch used to release

* Set version for Windows Portable

* git: New cache update (#558)

* add CMakeCache.txt to cache

* added workflow_dispatch to workflows

* remove restore-keys from workflows

* Separated cache

* re-added restore-keys

* put the version file for all OS

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

* update submodules

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

* added workflow_dispatch to workflows

* remove restore-keys from workflows

* Separated cache

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

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

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

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

* updated cache for Ubuntu 22

* using ccache on OBJC and OBJCXX

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

* build: Corrected gcc paths

* build: Enable objective c support on macOS

* build: Enable ObjC and ObjC++ on macOS

* build: Add ObjC and ObjC++ flags

* build: Try compiling objc with clang

* build: Remove invalid flags again

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

* sys: Move macos utils code to its own file

* fix: Missing unistd include on mac

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

* fix: Missing include

* fix: Another missing include

* fix: CFURLCreateWithBytes wants a pointer to mutable data

* fix: Try disabling name mangling of ObjC functions

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

* fix: C Linkage

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

* fix: More missing includes

* fix: Warning error

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

* build: Update libraries

* sys: Fixed build errors

* sys: No const correctness I guess

* sys: Fixed prototypes

* sys: This is C now

* sys: More nullptr -> NULL

* sys: Fix crash on exit

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

* sys: Replaced another hex::is_signed

* build: Upgrade to gcc 12 and MacOS Monterey

* build: Fixed MacOS runner name

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

* build: Still download database resources on other OSes

* build: Try fixing path recursion error

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

* build: Install main executable without installing python stuff

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

* I wanna die

* renamed imhex.app to Imhex.app

* net.WerWolv.ImHex

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

* Ci: removed fetch depth

* Ci: Add information to generated artifacts

* Ci: Updated Linux runner to Ubuntu 22.04

* Packaging: Updated .deb dependencies

* Ci: Removed ELF artifact

* Ci: Upgraded actions versions

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

* Update other icons

* Different gradients

* Reverted macOS icon because of design guidelines

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

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

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

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

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

* Add files via upload

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

View File

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

View File

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

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

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

View File

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

View File

@@ -1,8 +1,9 @@
cmake_minimum_required(VERSION 3.16)
# Updating the version here will update it throughout ImHex as well
set(IMHEX_VERSION "1.18.0")
file(READ "VERSION" IMHEX_VERSION)
project(imhex VERSION ${IMHEX_VERSION})
message("Project version ${IMHEX_VERSION}")
set(CMAKE_CXX_STANDARD 20)
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
@@ -36,6 +37,3 @@ add_subdirectory(tests EXCLUDE_FROM_ALL)
# Configure packaging
createPackage()
# Download and install all current files from the ImHex-Patterns repo
downloadImHexPatternsFiles()

View File

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

1
VERSION Normal file
View File

@@ -0,0 +1 @@
1.19.0

View File

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

View File

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

38
dist/Arch/PKGBUILD vendored Normal file
View File

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

3
dist/Brewfile vendored
View File

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

View File

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

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

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

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

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

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

@@ -0,0 +1,23 @@
### Compiling ImHex on Windows
On Windows, ImHex is built through msys2 / mingw. To install all dependencies, open a mys2 window and run the PKGCONFIG script in the [dist/msys2](dist/msys2) folder.
After all the dependencies are installed, run the following commands to build ImHex:
```sh
mkdir build
cd build
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
..
mingw32-make -j install
```
ImHex will look for any extra resources either in various folders directly next to the executable or in `%localappdata%/imhex`

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env sh
pacman -S --needed \
pacman -S $@ --needed \
cmake \
gcc \
lld \

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -156,7 +156,7 @@ namespace hex {
}
template<hex::derived_from<View> T, typename... Args>
template<std::derived_from<View> T, typename... Args>
void add(Args &&...args) {
return impl::add(new T(std::forward<Args>(args)...));
}
@@ -234,7 +234,7 @@ namespace hex {
}
template<hex::derived_from<dp::Node> T, typename... Args>
template<std::derived_from<dp::Node> T, typename... Args>
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), [=] {
auto node = new T(std::forward<Args>(args)...);
@@ -326,7 +326,7 @@ namespace hex {
}
template<hex::derived_from<hex::prv::Provider> T>
template<std::derived_from<hex::prv::Provider> T>
void add(const std::string &unlocalizedName, bool addToList = true) {
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider) {
if (name != expectedName) return;
@@ -415,12 +415,80 @@ namespace hex {
}
template<hex::derived_from<DataVisualizer> T, typename... Args>
template<std::derived_from<DataVisualizer> T, typename... Args>
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
}
}
namespace Hashes {
class Hash {
public:
Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
class Function {
public:
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
Function(const Hash *type, std::string name, Callback callback)
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {
}
[[nodiscard]] const Hash *getType() const { return this->m_type; }
[[nodiscard]] const std::string &getName() const { return this->m_name; }
const std::vector<u8>& get(const Region& region, prv::Provider *provider) {
if (this->m_cache.empty()) {
this->m_cache = this->m_callback(region, provider);
}
return this->m_cache;
}
void reset() {
this->m_cache.clear();
}
private:
const Hash *m_type;
std::string m_name;
Callback m_callback;
std::vector<u8> m_cache;
};
virtual void draw() { }
[[nodiscard]] virtual Function create(std::string name) = 0;
[[nodiscard]] const std::string &getUnlocalizedName() const {
return this->m_unlocalizedName;
}
protected:
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const {
return { this, name, callback };
}
private:
std::string m_unlocalizedName;
};
namespace impl {
std::vector<Hash*> &getHashes();
void add(Hash* hash);
}
template<typename T, typename ... Args>
void add(Args && ... args) {
impl::add(new T(std::forward<Args>(args)...));
}
}
};
}

View File

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

View File

@@ -12,6 +12,7 @@
#include <hex/helpers/concepts.hpp>
#include <hex/api/task.hpp>
#include <hex/api/keybinding.hpp>
#include <hex/helpers/fs.hpp>
using ImGuiID = unsigned int;
struct ImVec2;
@@ -127,7 +128,7 @@ namespace hex {
void add(prv::Provider *provider);
template<hex::derived_from<prv::Provider> T>
template<std::derived_from<prv::Provider> T>
void add(auto &&...args) {
add(new T(std::forward<decltype(args)>(args)...));
}
@@ -158,6 +159,11 @@ namespace hex {
void setProgramArguments(int argc, char **argv, char **envp);
void setBorderlessWindowMode(bool enabled);
void setCustomFontPath(const std::fs::path &path);
void setFontSize(float size);
void setGPUVendor(const std::string &vendor);
}
struct ProgramArguments {
@@ -166,6 +172,12 @@ namespace hex {
char **envp;
};
enum class Theme {
Dark = 1,
Light = 2,
Classic = 3
};
const ProgramArguments &getProgramArguments();
float getTargetFPS();
@@ -181,6 +193,19 @@ namespace hex {
std::map<std::string, std::string> &getInitArguments();
const std::fs::path &getCustomFontPath();
float getFontSize();
void setTheme(Theme theme);
Theme getTheme();
void enableSystemThemeDetection(bool enabled);
bool usesSystemThemeDetection();
const std::vector<std::fs::path> &getAdditionalFolderPaths();
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths);
const std::string &getGPUVendor();
}
}

View File

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

View File

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

View File

@@ -2,9 +2,19 @@
#include <hex.hpp>
#include <map>
#include <string_view>
#include <vector>
// TODO: Workaround for weird issue picked up by GCC 12.1.0 and later. This seems like a compiler bug mentioned in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98465
#pragma GCC diagnostic push
#if (__GNUC__ >= 12)
#pragma GCC diagnostic ignored "-Wrestrict"
#pragma GCC diagnostic ignored "-Wstringop-overread"
#endif
#include <map>
#include <string_view>
#include <vector>
#pragma GCC diagnostic pop
#include <hex/helpers/fs.hpp>
#include <hex/helpers/file.hpp>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -49,6 +49,8 @@ namespace hex {
void cancel() { this->m_shouldCancel = true; }
static void setProxy(const std::string &url);
private:
void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
std::optional<i32> execute();
@@ -62,6 +64,8 @@ namespace hex {
std::mutex m_transmissionActive;
float m_progress = 0.0F;
bool m_shouldCancel = false;
static std::string s_proxyUrl;
};
}

View File

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

View File

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

View File

@@ -43,7 +43,7 @@ namespace hex {
std::string encodeByteString(const std::vector<u8> &bytes);
std::vector<u8> decodeByteString(const std::string &string);
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
if (from < to) std::swap(from, to);
using ValueType = std::remove_cvref_t<decltype(value)>;
@@ -72,6 +72,18 @@ namespace hex {
return (value ^ mask) - mask;
}
template<std::integral T>
constexpr inline T swapBitOrder(size_t numBits, T value) {
T result = 0x00;
for (size_t bit = 0; bit < numBits; bit++) {
result <<= 1;
result |= (value & (1 << bit)) != 0;
}
return result;
}
template<class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts>
@@ -188,7 +200,7 @@ namespace hex {
return T(1) << bit_width(T(x - 1));
}
template<hex::integral T, hex::integral U>
template<std::integral T, std::integral U>
auto powi(T base, U exp) {
using ResultType = decltype(T{} * U{});
@@ -252,7 +264,7 @@ namespace hex {
return result;
}
inline std::string toBinaryString(hex::unsigned_integral auto number) {
inline std::string toBinaryString(std::unsigned_integral auto number) {
if (number == 0) return "0";
std::string result;
@@ -305,7 +317,7 @@ namespace hex {
return *value;
}
template<hex::integral T>
template<std::integral T>
T alignTo(T value, T alignment) {
T remainder = value % alignment;

View File

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

View File

@@ -35,6 +35,7 @@ namespace hex::prv {
virtual void resize(size_t newSize);
virtual void insert(u64 offset, size_t size);
virtual void remove(u64 offset, size_t size);
virtual void save();
virtual void saveAs(const std::fs::path &path);

View File

@@ -74,7 +74,8 @@ namespace ImGui {
bool ToolBarButton(const char *symbol, ImVec4 color);
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
bool InputIntegerPrefix(const char* label, const char *prefix, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
inline bool HasSecondPassed() {
@@ -134,4 +135,6 @@ namespace ImGui {
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
void HideTooltip();
bool BitCheckbox(const char* label, bool* v);
}

View File

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

View File

@@ -538,7 +538,7 @@ namespace hex {
namespace ContentRegistry::HexEditor {
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_EnterReturnsTrue;
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
struct UserData {
@@ -582,4 +582,18 @@ namespace hex {
}
namespace ContentRegistry::Hashes {
std::vector<Hash *> &impl::getHashes() {
static std::vector<Hash *> hashes;
return hashes;
}
void impl::add(Hash *hash) {
getHashes().push_back(hash);
}
}
}

View File

@@ -1,13 +1,16 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
#include <utility>
#include <utility>
#include <unistd.h>
#include <imgui.h>
#include <nlohmann/json.hpp>
namespace hex {
namespace ImHexApi::Common {
@@ -231,7 +234,7 @@ namespace hex {
}
bool isValid() {
return !s_providers.empty();
return !s_providers.empty() && s_currentProvider < s_providers.size();
}
void add(prv::Provider *provider) {
@@ -246,7 +249,7 @@ namespace hex {
s_providers.erase(it);
if (it - s_providers.begin() == s_currentProvider)
if (it - s_providers.begin() == s_currentProvider && !s_providers.empty())
setCurrentProvider(0);
delete provider;
@@ -315,6 +318,21 @@ namespace hex {
s_borderlessWindowMode = enabled;
}
static std::fs::path s_customFontPath;
void setCustomFontPath(const std::fs::path &path) {
s_customFontPath = path;
}
static float s_fontSize;
void setFontSize(float size) {
s_fontSize = size;
}
static std::string s_gpuVendor;
void setGPUVendor(const std::string &vendor) {
s_gpuVendor = vendor;
}
}
@@ -360,6 +378,54 @@ namespace hex {
return initArgs;
}
const std::fs::path &getCustomFontPath() {
return impl::s_customFontPath;
}
float getFontSize() {
return impl::s_fontSize;
}
static Theme s_theme;
static bool s_systemThemeDetection;
void setTheme(Theme theme) {
s_theme = theme;
EventManager::post<EventSettingsChanged>();
}
Theme getTheme() {
return s_theme;
}
void enableSystemThemeDetection(bool enabled) {
s_systemThemeDetection = enabled;
EventManager::post<EventSettingsChanged>();
}
bool usesSystemThemeDetection() {
return s_systemThemeDetection;
}
static std::vector<std::fs::path> s_additionalFolderPaths;
const std::vector<std::fs::path> &getAdditionalFolderPaths() {
return s_additionalFolderPaths;
}
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths) {
s_additionalFolderPaths = paths;
}
const std::string &getGPUVendor() {
return impl::s_gpuVendor;
}
}
}

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
#include <hex/helpers/fs.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fs_macos.h>
#include <hex/helpers/fs_macos.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/intrinsics.hpp>
@@ -22,8 +22,8 @@ namespace hex::fs {
std::optional<std::fs::path> getExecutablePath() {
#if defined(OS_WINDOWS)
std::string exePath(MAX_PATH, '\0');
if (GetModuleFileName(nullptr, exePath.data(), exePath.length()) == 0)
std::wstring exePath(MAX_PATH, '\0');
if (GetModuleFileNameW(nullptr, exePath.data(), exePath.length()) == 0)
return std::nullopt;
return exePath;
@@ -34,7 +34,15 @@ namespace hex::fs {
return exePath;
#elif defined(OS_MACOS)
return getMacExecutableDirectoryPath();
std::string result;
{
auto string = getMacExecutableDirectoryPath();
result = string;
macFree(string);
}
return result;
#else
return std::nullopt;
#endif
@@ -92,8 +100,7 @@ namespace hex::fs {
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
std::vector<std::fs::path> result;
const auto exePath = getExecutablePath();
const std::string settingName { "hex.builtin.setting.folders" };
auto userDirs = ContentRegistry::Settings::read(settingName, settingName, std::vector<std::string> {});
auto userDirs = ImHexApi::System::getAdditionalFolderPaths();
[[maybe_unused]]
auto addUserDirs = [&userDirs](auto &paths) {
@@ -105,11 +112,11 @@ namespace hex::fs {
#if defined(OS_WINDOWS)
std::fs::path appDataDir;
{
LPWSTR wAppDataPath = nullptr;
PWSTR wAppDataPath = nullptr;
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath)))
throw std::runtime_error("Failed to get APPDATA folder path");
appDataDir = wAppDataPath;
appDataDir = std::wstring(wAppDataPath);
CoTaskMemFree(wAppDataPath);
}
@@ -122,60 +129,60 @@ namespace hex::fs {
case ImHexPath::Patterns:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "patterns").string();
return path / "patterns";
});
break;
case ImHexPath::PatternsInclude:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "includes").string();
return path / "includes";
});
break;
case ImHexPath::Magic:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "magic").string();
return path / "magic";
});
break;
case ImHexPath::Python:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "python").string();
return path / "python";
});
break;
case ImHexPath::Plugins:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "plugins").string();
return path / "plugins";
});
break;
case ImHexPath::Yara:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "yara").string();
return path / "yara";
});
break;
case ImHexPath::Config:
return { (appDataDir / "imhex" / "config").string() };
return { appDataDir / "imhex" / "config" };
case ImHexPath::Resources:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "resources").string();
return path / "resources";
});
break;
case ImHexPath::Constants:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "constants").string();
return path / "constants";
});
break;
case ImHexPath::Encodings:
addUserDirs(paths);
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "encodings").string();
return path / "encodings";
});
break;
case ImHexPath::Logs:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
return (path / "logs").string();
return path / "logs";
});
break;
default:
@@ -183,25 +190,31 @@ namespace hex::fs {
}
#elif defined(OS_MACOS)
// Get path to special directories
const std::fs::path applicationSupportDir(getMacApplicationSupportDirectoryPath());
std::string applicationSupportDir;
{
auto string = getMacApplicationSupportDirectoryPath();
applicationSupportDir = string;
macFree(string);
}
const std::fs::path applicationSupportDirPath(applicationSupportDir);
std::vector<std::fs::path> paths = { applicationSupportDir };
std::vector<std::fs::path> paths = { applicationSupportDirPath };
if (exePath)
paths.push_back(exePath->parent_path());
if (exePath.has_value())
paths.push_back(exePath.value());
switch (path) {
case ImHexPath::Patterns:
result.push_back((applicationSupportDir / "patterns").string());
result.push_back((applicationSupportDirPath / "patterns").string());
break;
case ImHexPath::PatternsInclude:
result.push_back((applicationSupportDir / "includes").string());
result.push_back((applicationSupportDirPath / "includes").string());
break;
case ImHexPath::Magic:
result.push_back((applicationSupportDir / "magic").string());
result.push_back((applicationSupportDirPath / "magic").string());
break;
case ImHexPath::Python:
result.push_back((applicationSupportDir / "python").string());
result.push_back((applicationSupportDirPath / "python").string());
break;
case ImHexPath::Plugins:
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
@@ -209,22 +222,22 @@ namespace hex::fs {
});
break;
case ImHexPath::Yara:
result.push_back((applicationSupportDir / "yara").string());
result.push_back((applicationSupportDirPath / "yara").string());
break;
case ImHexPath::Config:
result.push_back((applicationSupportDir / "config").string());
result.push_back((applicationSupportDirPath / "config").string());
break;
case ImHexPath::Resources:
result.push_back((applicationSupportDir / "resources").string());
result.push_back((applicationSupportDirPath / "resources").string());
break;
case ImHexPath::Constants:
result.push_back((applicationSupportDir / "constants").string());
result.push_back((applicationSupportDirPath / "constants").string());
break;
case ImHexPath::Encodings:
result.push_back((applicationSupportDir / "encodings").string());
result.push_back((applicationSupportDirPath / "encodings").string());
break;
case ImHexPath::Logs:
result.push_back((applicationSupportDir / "logs").string());
result.push_back((applicationSupportDirPath / "logs").string());
break;
default:
hex::unreachable();
@@ -299,4 +312,20 @@ namespace hex::fs {
return result;
}
std::fs::path toShortPath(const std::fs::path &path) {
#if defined(OS_WINDOWS)
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0) * sizeof(TCHAR);
if (size == 0)
return path;
std::wstring newPath(size, 0x00);
GetShortPathNameW(path.c_str(), newPath.data(), newPath.size());
return newPath;
#else
return path;
#endif
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,8 @@
#include <hex/helpers/file.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/api/content_registry.hpp>
#include <filesystem>
#include <cstdio>
@@ -113,6 +115,8 @@ namespace hex {
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
#endif
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
}
std::optional<i32> Net::execute() {
@@ -241,4 +245,10 @@ namespace hex {
return {};
}
std::string Net::s_proxyUrl;
void Net::setProxy(const std::string &url) {
Net::s_proxyUrl = url;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ namespace ImGui {
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
auto &string = *static_cast<std::string *>(data->UserData);
string.resize(data->BufSize);
string.resize(data->BufTextLen);
data->Buf = string.data();
}
@@ -487,7 +487,7 @@ namespace ImGui {
return pressed;
}
bool InputIntegerPrefix(const char *label, const char *prefix, u64 *value, ImGuiInputTextFlags flags) {
bool InputIntegerPrefix(const char *label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags) {
auto window = ImGui::GetCurrentWindow();
const ImGuiID id = window->GetID(label);
const ImGuiStyle &style = GImGui->Style;
@@ -500,7 +500,7 @@ namespace ImGui {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), ImGuiDataType_U64, value, "%llX");
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, "%llX");
bool value_changed = false;
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), flags))
@@ -519,8 +519,12 @@ namespace ImGui {
return value_changed;
}
bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, flags | ImGuiInputTextFlags_CharsHexadecimal);
}
bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, flags | ImGuiInputTextFlags_CharsHexadecimal);
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, flags | ImGuiInputTextFlags_CharsHexadecimal);
}
void SmallProgressBar(float fraction, float yOffset) {
@@ -590,4 +594,47 @@ namespace ImGui {
}
}
bool BitCheckbox(const char* label, bool* v) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
const ImVec2 pos = window->DC.CursorPos;
const ImRect total_bb(pos, pos + size);
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
{
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false;
}
bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
if (pressed)
{
*v = !(*v);
MarkItemEdited(id);
}
const ImRect check_bb(pos, pos + size);
RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
RenderText(check_bb.Min + style.FramePadding, *v ? "1" : "0");
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
if (label_size.x > 0.0f)
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -348,11 +348,12 @@ namespace hex {
ImGui::TableHeadersRow();
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Plugins, true)) {
const auto filePath = path / "builtin.hexplug";
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(path.string().c_str());
ImGui::TextUnformatted(filePath.string().c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(fs::exists(path) ? ICON_VS_CHECK : ICON_VS_CLOSE);
ImGui::TextUnformatted(fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
}
ImGui::EndTable();
}
@@ -420,8 +421,6 @@ namespace hex {
calls.clear();
}
View::drawCommonInterfaces();
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
@@ -653,8 +652,9 @@ namespace hex {
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
{
if (glfwGetPrimaryMonitor() != nullptr) {
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
if (!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland"))
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}

View File

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

View File

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

View File

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

View File

@@ -20,7 +20,6 @@ namespace hex::plugin::builtin {
private:
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
void openFile(const std::fs::path &path);
void registerShortcuts();
void registerEvents();
void registerMenuItems();
@@ -31,15 +30,23 @@ namespace hex::plugin::builtin {
public:
void setSelection(const Region &region) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
void setSelection(i128 start, i128 end) {
if (!ImHexApi::Provider::isValid()) return;
void setSelection(u128 start, u128 end) {
if (!ImHexApi::Provider::isValid())
return;
if (start == InvalidSelection && end == InvalidSelection)
return;
if (start == InvalidSelection)
start = end;
if (end == InvalidSelection)
end = start;
const size_t maxAddress = ImHexApi::Provider::get()->getActualSize() - 1;
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
this->m_selectionStart = std::clamp<decltype(start)>(start, 0, maxAddress);
this->m_selectionEnd = std::clamp<decltype(end)>(end, 0, maxAddress);
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
if (this->m_selectionChanged) {
EventManager::post<EventRegionSelected>(this->getSelection());
@@ -66,6 +73,10 @@ namespace hex::plugin::builtin {
this->m_shouldScrollToSelection = true;
}
void jumpIfOffScreen() {
this->m_shouldJumpWhenOffScreen = true;
}
public:
class Popup {
public:
@@ -105,6 +116,7 @@ namespace hex::plugin::builtin {
bool m_shouldJumpToSelection = false;
bool m_shouldScrollToSelection = false;
bool m_shouldJumpWhenOffScreen = false;
bool m_selectionChanged = false;
u64 m_selectionStart = InvalidSelection;
@@ -115,6 +127,7 @@ namespace hex::plugin::builtin {
std::optional<u64> m_editingAddress;
bool m_shouldModifyValue = false;
bool m_enteredEditingMode = false;
bool m_shouldUpdateEditingValue = false;
std::vector<u8> m_editingBytes;
color_t m_selectionColor = 0x00;

View File

@@ -25,7 +25,7 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
pl::PatternLanguage *m_parserRuntime;
std::unique_ptr<pl::PatternLanguage> m_parserRuntime;
std::vector<std::fs::path> m_possiblePatternFiles;
u32 m_selectedPatternFile = 0;

View File

@@ -26,7 +26,7 @@ namespace hex::plugin::builtin {
u32 tooltipId;
};
std::vector<std::pair<std::string, std::string>> m_rules;
std::vector<std::pair<std::fs::path, std::fs::path>> m_rules;
std::vector<YaraMatch> m_matches;
u32 m_selectedRule = 0;
bool m_matching = false;

View File

@@ -7,8 +7,8 @@
namespace hex {
template<typename T>
concept ArrayPattern = requires(T pattern, std::function<void(int, pl::Pattern&)> fn) {
{ pattern.forEachArrayEntry(fn) } -> std::same_as<void>;
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::Pattern&)> fn) {
{ pattern.forEachArrayEntry(displayEnd, fn) } -> std::same_as<void>;
};
class PatternDrawer : public pl::PatternVisitor {
@@ -48,7 +48,7 @@ namespace hex {
if (opened) {
auto& displayEnd = this->getDisplayEnd(pattern);
pattern.forEachArrayEntry([&] (u64 idx, auto &entry){
pattern.forEachArrayEntry(displayEnd, [&] (u64 idx, auto &entry){
this->drawArrayNode(idx, displayEnd, entry);
});
}
@@ -57,7 +57,7 @@ namespace hex {
}
bool drawArrayRoot(pl::Pattern& pattern, size_t entryCount, bool isInlined);
void drawArrayNode(u64 idx, u64 displayEnd, pl::Pattern& pattern);
void drawArrayNode(u64 idx, u64& displayEnd, pl::Pattern& pattern);
void drawArrayEnd(pl::Pattern& pattern, bool opened);
void drawCommentTooltip(const pl::Pattern &pattern) const;

View File

@@ -84,7 +84,7 @@ namespace hex::plugin::builtin {
[](auto buffer, auto endian, auto style) {
hex::unused(endian, style);
std::string binary = hex::format("0b{:b}", buffer[0]);
std::string binary = hex::format("0b{:08b}", buffer[0]);
return [binary] {
ImGui::TextUnformatted(binary.c_str());
@@ -314,7 +314,7 @@ namespace hex::plugin::builtin {
return [value] { ImGui::TextFormatted("'{0}'", value.c_str()); return value; };
},
[](const std::string &value, std::endian endian) -> std::vector<u8> {
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter("");
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter("Invalid");
std::vector<u8> bytes;
auto wideString = converter.from_bytes(value.c_str());

View File

@@ -777,7 +777,16 @@ namespace hex::plugin::builtin {
NodeVisualizerDigram() : Node("hex.builtin.nodes.visualizer.digram.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { }
void drawNode() override {
const auto viewSize = scaled({ 200, 200 });
drawDigram(scaled({ 200, 200 }));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
drawDigram(scaled({ 600, 600 }));
ImGui::EndTooltip();
}
}
void drawDigram(const ImVec2 &viewSize) {
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImU32(ImColor(0, 0, 0)));
if (ImGui::BeginChild("##visualizer", viewSize, true)) {
auto drawList = ImGui::GetWindowDrawList();
@@ -860,7 +869,15 @@ namespace hex::plugin::builtin {
NodeVisualizerLayeredDistribution() : Node("hex.builtin.nodes.visualizer.layered_dist.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { }
void drawNode() override {
const auto viewSize = scaled({ 200, 200 });
drawLayeredDistribution(scaled({ 200, 200 }));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
drawLayeredDistribution(scaled({ 600, 600 }));
ImGui::EndTooltip();
}
}
void drawLayeredDistribution(const ImVec2 &viewSize) {
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImU32(ImColor(0, 0, 0)));
if (ImGui::BeginChild("##visualizer", viewSize, true)) {
auto drawList = ImGui::GetWindowDrawList();
@@ -944,6 +961,11 @@ namespace hex::plugin::builtin {
void drawNode() override {
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 200, 200)));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 600, 600)));
ImGui::EndTooltip();
}
}
void process() override {
@@ -964,8 +986,18 @@ namespace hex::plugin::builtin {
NodeVisualizerByteDistribution() : Node("hex.builtin.nodes.visualizer.byte_distribution.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { }
void drawNode() override {
drawPlot(scaled({ 400, 300 }));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
drawPlot(scaled({ 700, 550 }));
ImGui::EndTooltip();
}
}
void drawPlot(const ImVec2 &viewSize) {
ImPlot::SetNextPlotLimits(0, 256, 0.5, float(*std::max_element(this->m_counts.begin(), this->m_counts.end())) * 1.1F, ImGuiCond_Always);
if (ImPlot::BeginPlot("##distribution", "Address", "Count", scaled(ImVec2(400, 300)), ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock | ImPlotAxisFlags_LogScale, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels)) {
if (ImPlot::BeginPlot("##distribution", "Address", "Count", viewSize, ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock | ImPlotAxisFlags_LogScale, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels)) {
static auto x = [] {
std::array<ImU64, 256> result { 0 };
std::iota(result.begin(), result.end(), 0);

View File

@@ -22,7 +22,7 @@ namespace hex::plugin::builtin {
else static_assert(hex::always_false<T>::value, "Invalid data type!");
}
template<hex::integral T>
template<std::integral T>
class DataVisualizerHexadecimal : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerHexadecimal() : DataVisualizer(ByteCount, CharCount) { }
@@ -114,7 +114,7 @@ namespace hex::plugin::builtin {
}
};
template<hex::integral T>
template<std::integral T>
class DataVisualizerDecimal : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerDecimal() : DataVisualizer(ByteCount, CharCount) { }
@@ -123,7 +123,7 @@ namespace hex::plugin::builtin {
hex::unused(address, upperCase);
if (size == ByteCount) {
if (hex::is_signed<T>::value)
if (std::is_signed<T>::value)
ImGui::Text(getFormatString(), static_cast<i64>(*reinterpret_cast<const T*>(data)));
else
ImGui::Text(getFormatString(), static_cast<u64>(*reinterpret_cast<const T*>(data)));
@@ -153,14 +153,14 @@ namespace hex::plugin::builtin {
constexpr static inline auto ByteCount = sizeof(T);
constexpr static inline auto CharCount = std::numeric_limits<T>::digits10 + 2;
const static inline auto FormatString = hex::format("%{}{}", CharCount, hex::is_signed<T>::value ? "lld" : "llu");
const static inline auto FormatString = hex::format("%{}{}", CharCount, std::is_signed<T>::value ? "lld" : "llu");
const char *getFormatString() {
return FormatString.c_str();
}
};
template<hex::floating_point T>
template<std::floating_point T>
class DataVisualizerFloatingPoint : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerFloatingPoint() : DataVisualizer(ByteCount, CharCount) { }

View File

@@ -1,9 +1,12 @@
#include <hex/api/event.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/providers/provider.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/project_file_handler.hpp>
#include <hex/api/localization.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/logger.hpp>
#include <imgui.h>
@@ -86,6 +89,11 @@ namespace hex::plugin::builtin {
EventManager::subscribe<EventProviderChanged>([](auto, auto) {
EventManager::post<EventHighlightingChanged>();
});
EventManager::subscribe<EventProviderCreated>([](hex::prv::Provider *provider) {
if (provider->hasLoadInterface())
EventManager::post<RequestOpenPopup>(View::toWindowName("hex.builtin.view.provider_settings.load_popup"));
});
}
}

View File

@@ -0,0 +1,140 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/localization.hpp>
#include <hex/helpers/crypto.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::builtin {
class HashMD5 : public ContentRegistry::Hashes::Hash {
public:
HashMD5() : Hash("hex.builtin.hash.md5") {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::md5(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA1 : public ContentRegistry::Hashes::Hash {
public:
HashSHA1() : Hash("hex.builtin.hash.sha1") {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha1(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA224 : public ContentRegistry::Hashes::Hash {
public:
HashSHA224() : Hash("hex.builtin.hash.sha224") {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha224(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA256 : public ContentRegistry::Hashes::Hash {
public:
HashSHA256() : Hash("hex.builtin.hash.sha256") {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha256(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA384 : public ContentRegistry::Hashes::Hash {
public:
HashSHA384() : Hash("hex.builtin.hash.sha384") {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha384(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA512 : public ContentRegistry::Hashes::Hash {
public:
HashSHA512() : Hash("hex.builtin.hash.sha512") {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha512(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
template<typename T>
class HashCRC : public ContentRegistry::Hashes::Hash {
public:
using CRCFunction = T(*)(prv::Provider*&, u64, size_t, u32, u32, u32, bool, bool);
HashCRC(const std::string &name, const CRCFunction &crcFunction, u32 polynomial, u32 initialValue, u32 xorOut)
: Hash(name), m_crcFunction(crcFunction), m_polynomial(polynomial), m_initialValue(initialValue), m_xorOut(xorOut) {}
void draw() override {
ImGui::InputHexadecimal("hex.builtin.hash.crc.poly"_lang, &this->m_polynomial);
ImGui::InputHexadecimal("hex.builtin.hash.crc.iv"_lang, &this->m_initialValue);
ImGui::InputHexadecimal("hex.builtin.hash.crc.xor_out"_lang, &this->m_xorOut);
ImGui::NewLine();
ImGui::Checkbox("hex.builtin.hash.crc.refl_in"_lang, &this->m_reflectIn);
ImGui::Checkbox("hex.builtin.hash.crc.refl_out"_lang, &this->m_reflectOut);
}
Function create(std::string name) override {
return Hash::create(name, [hash = *this](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto result = hash.m_crcFunction(provider, region.address, region.size, hash.m_polynomial, hash.m_initialValue, hash.m_xorOut, hash.m_reflectIn, hash.m_reflectOut);
std::vector<u8> bytes(sizeof(result), 0x00);
std::memcpy(bytes.data(), &result, bytes.size());
return bytes;
});
}
private:
CRCFunction m_crcFunction;
u32 m_polynomial;
u32 m_initialValue;
u32 m_xorOut;
bool m_reflectIn = false, m_reflectOut = false;
};
void registerHashes() {
ContentRegistry::Hashes::add<HashMD5>();
ContentRegistry::Hashes::add<HashSHA1>();
ContentRegistry::Hashes::add<HashSHA224>();
ContentRegistry::Hashes::add<HashSHA256>();
ContentRegistry::Hashes::add<HashSHA384>();
ContentRegistry::Hashes::add<HashSHA512>();
ContentRegistry::Hashes::add<HashCRC<u16>>("hex.builtin.hash.crc8", crypt::crc8, 0x07, 0x0000, 0x0000);
ContentRegistry::Hashes::add<HashCRC<u16>>("hex.builtin.hash.crc16", crypt::crc16, 0x8005, 0x0000, 0x0000);
ContentRegistry::Hashes::add<HashCRC<u32>>("hex.builtin.hash.crc32", crypt::crc32, 0x04C1'1DB7, 0xFFFF'FFFF, 0xFFFF'FFFF);
}
}

View File

@@ -125,7 +125,7 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
std::thread([path] {
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
auto patchData = fs::File(path, fs::File::Mode::Read).readBytes();
auto patch = hex::loadIPSPatch(patchData);
@@ -149,7 +149,7 @@ namespace hex::plugin::builtin {
if (ImGui::MenuItem("hex.builtin.menu.file.import.ips32"_lang, nullptr, false)) {
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
std::thread([path] {
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
auto patchData = fs::File(path, fs::File::Mode::Read).readBytes();
auto patch = hex::loadIPS32Patch(patchData);
@@ -185,7 +185,7 @@ namespace hex::plugin::builtin {
}
std::thread([patches] {
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
auto data = generateIPSPatch(patches);
@@ -212,7 +212,7 @@ namespace hex::plugin::builtin {
}
std::thread([patches] {
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
auto data = generateIPS32Patch(patches);
@@ -257,7 +257,7 @@ namespace hex::plugin::builtin {
if (ImGui::MenuItem("hex.builtin.menu.edit.bookmark"_lang, nullptr, false, selection.has_value() && providerValid)) {
auto base = provider->getBaseAddress();
ImHexApi::Bookmarks::add(base + selection->getStartAddress(), selection->getEndAddress(), {}, {});
ImHexApi::Bookmarks::add(base + selection->getStartAddress(), selection->size, {}, {});
}
});

View File

@@ -1,248 +1,18 @@
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/net.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/utils.hpp>
#include <pl/token.hpp>
#include <pl/log_console.hpp>
#include <pl/evaluator.hpp>
#include <pl/patterns/pattern.hpp>
#include <vector>
#include <fmt/args.h>
namespace hex::plugin::builtin {
std::string format(const auto &params) {
auto format = pl::Token::literalToString(params[0], true);
std::string message;
fmt::dynamic_format_arg_store<fmt::format_context> formatArgs;
for (u32 i = 1; i < params.size(); i++) {
auto &param = params[i];
std::visit(overloaded {
[&](pl::Pattern *value) {
formatArgs.push_back(value->toString());
},
[&](auto &&value) {
formatArgs.push_back(value);
} },
param);
}
try {
return fmt::vformat(format, formatArgs);
} catch (fmt::format_error &error) {
pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what()));
}
}
void registerPatternLanguageFunctions() {
using namespace pl;
using FunctionParameterCount = pl::api::FunctionParameterCount;
pl::api::Namespace nsStd = { "builtin", "std" };
{
/* print(format, args...) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "print", FunctionParameterCount::moreThan(0), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ctx->getConsole().log(LogConsole::Level::Info, format(params));
return std::nullopt;
});
/* format(format, args...) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "format", FunctionParameterCount::moreThan(0), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return format(params);
});
/* env(name) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "env", FunctionParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto name = Token::literalToString(params[0], false);
auto env = ctx->getEnvVariable(name);
if (env)
return env;
else {
ctx->getConsole().log(LogConsole::Level::Warning, hex::format("environment variable '{}' does not exist", name));
return "";
}
});
/* pack_size(...) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "sizeof_pack", FunctionParameterCount::atLeast(0), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return u128(params.size());
});
/* error(message) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "error", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
LogConsole::abortEvaluation(Token::literalToString(params[0], true));
return std::nullopt;
});
/* warning(message) */
ContentRegistry::PatternLanguage::addFunction(nsStd, "warning", FunctionParameterCount::exactly(1), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ctx->getConsole().log(LogConsole::Level::Warning, Token::literalToString(params[0], true));
return std::nullopt;
});
}
api::Namespace nsStdMem = { "builtin", "std", "mem" };
{
/* base_address() */
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "base_address", FunctionParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
hex::unused(params);
return u128(ctx->getDataBaseAddress());
});
/* size() */
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "size", FunctionParameterCount::none(), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
hex::unused(params);
return u128(ctx->getDataSize());
});
/* find_sequence_in_range(occurrence_index, start_offset, end_offset, bytes...) */
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "find_sequence_in_range", FunctionParameterCount::moreThan(3), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto occurrenceIndex = Token::literalToUnsigned(params[0]);
auto offsetFrom = Token::literalToUnsigned(params[1]);
auto offsetTo = Token::literalToUnsigned(params[2]);
std::vector<u8> sequence;
for (u32 i = 3; i < params.size(); i++) {
auto byte = Token::literalToUnsigned(params[i]);
if (byte > 0xFF)
LogConsole::abortEvaluation(hex::format("byte #{} value out of range: {} > 0xFF", i, u64(byte)));
sequence.push_back(u8(byte & 0xFF));
}
std::vector<u8> bytes(sequence.size(), 0x00);
u32 occurrences = 0;
const u64 bufferSize = ctx->getDataSize();
const u64 endOffset = offsetTo <= offsetFrom ? bufferSize : std::min(bufferSize, u64(offsetTo));
for (u64 offset = offsetFrom; offset < endOffset - sequence.size(); offset++) {
ctx->readData(offset, bytes.data(), bytes.size());
if (bytes == sequence) {
if (occurrences < occurrenceIndex) {
occurrences++;
continue;
}
return u128(offset);
}
}
return i128(-1);
});
/* read_unsigned(address, size) */
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_unsigned", FunctionParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto address = Token::literalToUnsigned(params[0]);
auto size = Token::literalToUnsigned(params[1]);
if (size > 16)
LogConsole::abortEvaluation("read size out of range");
u128 result = 0;
ctx->readData(address, &result, size);
return result;
});
/* read_signed(address, size) */
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_signed", FunctionParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto address = Token::literalToUnsigned(params[0]);
auto size = Token::literalToUnsigned(params[1]);
if (size > 16)
LogConsole::abortEvaluation("read size out of range");
i128 value;
ctx->readData(address, &value, size);
return hex::signExtend(size * 8, value);
});
/* read_string(address, size) */
ContentRegistry::PatternLanguage::addFunction(nsStdMem, "read_string", FunctionParameterCount::exactly(2), [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto address = Token::literalToUnsigned(params[0]);
auto size = Token::literalToUnsigned(params[1]);
std::string result(size, '\x00');
ctx->readData(address, result.data(), size);
return result;
});
}
api::Namespace nsStdString = { "builtin", "std", "string" };
{
/* length(string) */
ContentRegistry::PatternLanguage::addFunction(nsStdString, "length", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
return u128(string.length());
});
/* at(string, index) */
ContentRegistry::PatternLanguage::addFunction(nsStdString, "at", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
auto index = Token::literalToSigned(params[1]);
#if defined(OS_MACOS)
const auto signIndex = index >> (sizeof(index) * 8 - 1);
const auto absIndex = (index ^ signIndex) - signIndex;
#else
const auto absIndex = std::abs(index);
#endif
if (absIndex > string.length())
LogConsole::abortEvaluation("character index out of range");
if (index >= 0)
return char(string[index]);
else
return char(string[string.length() - -index]);
});
/* substr(string, pos, count) */
ContentRegistry::PatternLanguage::addFunction(nsStdString, "substr", FunctionParameterCount::exactly(3), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
auto pos = Token::literalToUnsigned(params[1]);
auto size = Token::literalToUnsigned(params[2]);
if (pos > string.length())
LogConsole::abortEvaluation("character index out of range");
return string.substr(pos, size);
});
/* parse_int(string, base) */
ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_int", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
auto base = Token::literalToUnsigned(params[1]);
return i128(std::strtoll(string.c_str(), nullptr, base));
});
/* parse_float(string) */
ContentRegistry::PatternLanguage::addFunction(nsStdString, "parse_float", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
return double(std::strtod(string.c_str(), nullptr));
});
}
api::Namespace nsStdHttp = { "builtin", "std", "http" };
{
/* get(url) */
@@ -253,267 +23,5 @@ namespace hex::plugin::builtin {
return net.getString(url).get().body;
});
}
api::Namespace nsStdFile = { "builtin", "std", "file" };
{
static u32 fileCounter = 0;
static std::map<u32, fs::File> openFiles;
/* open(path, mode) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "open", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto path = Token::literalToString(params[0], false);
const auto modeEnum = Token::literalToUnsigned(params[1]);
fs::File::Mode mode;
switch (modeEnum) {
case 1:
mode = fs::File::Mode::Read;
break;
case 2:
mode = fs::File::Mode::Write;
break;
case 3:
mode = fs::File::Mode::Create;
break;
default:
LogConsole::abortEvaluation("invalid file open mode");
}
fs::File file(path, mode);
if (!file.isValid())
LogConsole::abortEvaluation(hex::format("failed to open file {}", path));
fileCounter++;
openFiles.emplace(std::pair { fileCounter, std::move(file) });
return u128(fileCounter);
});
/* close(file) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "close", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
openFiles.erase(file);
return std::nullopt;
});
/* read(file, size) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "read", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
const auto size = Token::literalToUnsigned(params[1]);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
return openFiles[file].readString(size);
});
/* write(file, data) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "write", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
const auto data = Token::literalToString(params[1], true);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
openFiles[file].write(data);
return std::nullopt;
});
/* seek(file, offset) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "seek", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
const auto offset = Token::literalToUnsigned(params[1]);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
openFiles[file].seek(offset);
return std::nullopt;
});
/* size(file) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "size", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
return u128(openFiles[file].getSize());
});
/* resize(file, size) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "resize", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
const auto size = Token::literalToUnsigned(params[1]);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
openFiles[file].setSize(size);
return std::nullopt;
});
/* flush(file) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "flush", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
openFiles[file].flush();
return std::nullopt;
});
/* remove(file) */
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdFile, "remove", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto file = Token::literalToUnsigned(params[0]);
if (!openFiles.contains(file))
LogConsole::abortEvaluation("failed to access invalid file");
openFiles[file].remove();
return std::nullopt;
});
}
api::Namespace nsStdMath = { "builtin", "std", "math" };
{
/* floor(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "floor", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::floor(Token::literalToFloatingPoint(params[0]));
});
/* ceil(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ceil", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::ceil(Token::literalToFloatingPoint(params[0]));
});
/* round(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "round", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::round(Token::literalToFloatingPoint(params[0]));
});
/* trunc(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "trunc", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::trunc(Token::literalToFloatingPoint(params[0]));
});
/* log10(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log10", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::log10(Token::literalToFloatingPoint(params[0]));
});
/* log2(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "log2", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::log2(Token::literalToFloatingPoint(params[0]));
});
/* ln(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "ln", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::log(Token::literalToFloatingPoint(params[0]));
});
/* fmod(x, y) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "fmod", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::fmod(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1]));
});
/* pow(base, exp) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "pow", FunctionParameterCount::exactly(2), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::pow(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1]));
});
/* sqrt(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sqrt", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::sqrt(Token::literalToFloatingPoint(params[0]));
});
/* cbrt(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cbrt", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::cbrt(Token::literalToFloatingPoint(params[0]));
});
/* sin(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sin", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::sin(Token::literalToFloatingPoint(params[0]));
});
/* cos(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cos", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::cos(Token::literalToFloatingPoint(params[0]));
});
/* tan(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tan", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::tan(Token::literalToFloatingPoint(params[0]));
});
/* asin(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asin", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::asin(Token::literalToFloatingPoint(params[0]));
});
/* acos(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acos", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::acos(Token::literalToFloatingPoint(params[0]));
});
/* atan(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::atan(Token::literalToFloatingPoint(params[0]));
});
/* atan2(y, x) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atan", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::atan2(Token::literalToFloatingPoint(params[0]), Token::literalToFloatingPoint(params[1]));
});
/* sinh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "sinh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::sinh(Token::literalToFloatingPoint(params[0]));
});
/* cosh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "cosh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::cosh(Token::literalToFloatingPoint(params[0]));
});
/* tanh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "tanh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::tanh(Token::literalToFloatingPoint(params[0]));
});
/* asinh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "asinh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::asinh(Token::literalToFloatingPoint(params[0]));
});
/* acosh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "acosh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::acosh(Token::literalToFloatingPoint(params[0]));
});
/* atanh(value) */
ContentRegistry::PatternLanguage::addFunction(nsStdMath, "atanh", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
return std::atanh(Token::literalToFloatingPoint(params[0]));
});
}
}
}

View File

@@ -123,7 +123,7 @@ namespace hex::plugin::builtin::prv {
auto position = oldSize;
while (position > offset) {
size_t readSize = (position >= (offset + buffer.size())) ? buffer.size() : (position - offset);
const auto readSize = std::min<size_t>(position - offset, buffer.size());
position -= readSize;
@@ -135,6 +135,28 @@ namespace hex::plugin::builtin::prv {
Provider::insert(offset, size);
}
void FileProvider::remove(u64 offset, size_t size) {
auto oldSize = this->getActualSize();
this->resize(oldSize + size);
std::vector<u8> buffer(0x1000);
const auto newSize = oldSize - size;
auto position = offset;
while (position < newSize) {
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
this->readRaw(position + size, buffer.data(), readSize);
this->writeRaw(position, buffer.data(), readSize);
position += readSize;
}
this->resize(newSize);
Provider::insert(offset, size);
}
size_t FileProvider::getRealTimeSize() {
#if defined(OS_LINUX)
if (struct stat newStats; (this->m_fileStatsValid = fstat(this->m_file, &newStats) == 0)) {

View File

@@ -1,12 +1,15 @@
#include <hex/api/imhex_api.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/localization.hpp>
#include <hex/helpers/net.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <fonts/codicons_font.h>
#include <hex/helpers/utils.hpp>
#include <nlohmann/json.hpp>
@@ -52,6 +55,11 @@ namespace hex::plugin::builtin {
if (ImGui::Combo(name.data(), &selection, themes, IM_ARRAYSIZE(themes))) {
setting = selection;
ImHexApi::System::enableSystemThemeDetection(selection == 0);
if (selection != 0)
ImHexApi::System::setTheme(static_cast<ImHexApi::System::Theme>(selection));
return true;
}
@@ -306,17 +314,34 @@ namespace hex::plugin::builtin {
ContentRegistry::Settings::add(dirsSetting, dirsSetting, std::vector<std::string> {}, [](auto name, nlohmann::json &setting) {
hex::unused(name);
static std::vector<std::string> folders = setting;
static size_t currentItemIndex = 0;
static size_t currentItemIndex = 0;
static std::vector<std::fs::path> folders = [&setting]{
std::vector<std::fs::path> result;
std::vector<std::u8string> paths = setting;
for (const auto &path : paths)
result.emplace_back(path);
return result;
}();
bool result = false;
auto writeSetting = [&setting]{
std::vector<std::u8string> folderStrings;
for (const auto &folder : folders)
folderStrings.push_back(folder.u8string());
setting = folderStrings;
ImHexApi::System::setAdditionalFolderPaths(folders);
};
if (!ImGui::BeginListBox("", ImVec2(-38, -FLT_MIN))) {
return false;
} else {
for (size_t n = 0; n < folders.size(); n++) {
const bool isSelected = (currentItemIndex == n);
if (ImGui::Selectable(folders.at(n).c_str(), isSelected)) { currentItemIndex = n; }
if (ImGui::Selectable(folders.at(n).string().c_str(), isSelected)) { currentItemIndex = n; }
if (isSelected) { ImGui::SetItemDefaultFocus(); }
}
ImGui::EndListBox();
@@ -326,11 +351,12 @@ namespace hex::plugin::builtin {
if (ImGui::IconButton(ICON_VS_NEW_FOLDER, ImGui::GetCustomColorVec4(ImGuiCustomCol_DescButton), ImVec2(30, 30))) {
fs::openFileBrowser(fs::DialogMode::Folder, {}, [&](const std::fs::path &path) {
auto pathStr = path.string();
if (std::find(folders.begin(), folders.end(), pathStr) == folders.end()) {
folders.emplace_back(pathStr);
ContentRegistry::Settings::write(dirsSetting, dirsSetting, folders);
if (std::find(folders.begin(), folders.end(), path) == folders.end()) {
folders.emplace_back(path);
writeSetting();
result = true;
}
});
@@ -340,7 +366,9 @@ namespace hex::plugin::builtin {
if (ImGui::IconButton(ICON_VS_REMOVE_CLOSE, ImGui::GetCustomColorVec4(ImGuiCustomCol_DescButton), ImVec2(30, 30))) {
if (!folders.empty()) {
folders.erase(std::next(folders.begin(), currentItemIndex));
ContentRegistry::Settings::write(dirsSetting, dirsSetting, folders);
writeSetting();
result = true;
}
}
@@ -350,6 +378,112 @@ namespace hex::plugin::builtin {
return result;
});
/* Proxy */
static const std::string proxySetting { "hex.builtin.setting.proxy" };
// init hex::Net proxy url
hex::Net::setProxy(ContentRegistry::Settings::read(proxySetting, "hex.builtin.setting.proxy.url", ""));
ContentRegistry::Settings::addCategoryDescription(proxySetting, "hex.builtin.setting.proxy.description");
ContentRegistry::Settings::add(
proxySetting, "hex.builtin.setting.proxy.url", "", [](auto name, nlohmann::json &setting) {
static std::string proxyUrl = static_cast<std::string>(setting);
static bool enableProxy = !proxyUrl.empty();
bool result = false;
if (ImGui::Checkbox("hex.builtin.setting.proxy.enable"_lang, &enableProxy)) {
setting = enableProxy ? proxyUrl : "";
hex::Net::setProxy(enableProxy ? proxyUrl : "");
result = true;
}
ImGui::BeginDisabled(!enableProxy);
if (ImGui::InputText("##proxy_url", proxyUrl)) {
setting = proxyUrl;
hex::Net::setProxy(proxyUrl);
result = true;
}
ImGui::EndDisabled();
ImGui::InfoTooltip("hex.builtin.setting.proxy.url.tooltip"_lang);
ImGui::SameLine();
ImGui::TextFormatted("{}", name);
return result;
},
false);
}
static void loadInterfaceScalingSetting() {
float interfaceScaling = 1.0F;
switch (ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0)) {
default:
case 0:
// Native scaling
break;
case 1:
interfaceScaling = 0.5F;
break;
case 2:
interfaceScaling = 1.0F;
break;
case 3:
interfaceScaling = 1.5F;
break;
case 4:
interfaceScaling = 2.0F;
break;
}
ImHexApi::System::impl::setGlobalScale(interfaceScaling);
}
static void loadFontSettings() {
std::fs::path fontFile = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "");
if (!fs::exists(fontFile))
fontFile.clear();
// If no custom font has been specified, search for a file called "font.ttf" in one of the resource folders
if (fontFile.empty()) {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) {
auto path = dir / "font.ttf";
if (fs::exists(path)) {
log::info("Loading custom front from {}", path.string());
fontFile = path;
break;
}
}
}
// If a custom font has been loaded now, also load the font size
float fontSize = 13.0F * ImHexApi::System::getGlobalScale();
if (!fontFile.empty()) {
ImHexApi::System::impl::setCustomFontPath(fontFile);
fontSize = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13) * ImHexApi::System::getGlobalScale();
}
ImHexApi::System::impl::setFontSize(fontSize);
}
static void loadThemeSettings() {
auto theme = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", static_cast<i64>(ImHexApi::System::Theme::Dark));
ImHexApi::System::enableSystemThemeDetection(theme == 0);
ImHexApi::System::setTheme(static_cast<ImHexApi::System::Theme>(theme));
}
void loadSettings() {
loadInterfaceScalingSetting();
loadFontSettings();
loadThemeSettings();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,25 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/localization.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/api/localization.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/logger.hpp>
#include <codicons_font.h>
#include <imgui.h>
#include <imgui_internal.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <atomic>
namespace hex::plugin::builtin {
static std::string s_popupMessage;
static std::function<void()> s_yesCallback, s_noCallback;
static u32 s_selectableFileIndex;
static std::vector<std::fs::path> s_selectableFiles;
static std::function<void(std::fs::path)> s_selectableFileOpenCallback;
static std::vector<nfdfilteritem_t> s_selectableFilesValidExtensions;
static void drawGlobalPopups() {
// "Are you sure you want to exit?" Popup
@@ -32,10 +36,141 @@ namespace hex::plugin::builtin {
ImGui::EndPopup();
}
auto windowSize = ImHexApi::System::getMainWindowSize();
// Info popup
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.info"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
ImGui::CloseCurrentPopup();
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
// Error popup
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
ImGui::CloseCurrentPopup();
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
// Fatal error popup
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.fatal"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape)) {
ImHexApi::Common::closeImHex();
ImGui::CloseCurrentPopup();
}
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
// Yes/No question popup
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
if (ImGui::BeginPopupModal("hex.builtin.common.question"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
View::confirmButtons(
"hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [] {
s_yesCallback();
ImGui::CloseCurrentPopup(); }, [] {
s_noCallback();
ImGui::CloseCurrentPopup(); });
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
ImGui::EndPopup();
}
// File chooser popup
bool opened = true;
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
if (ImGui::BeginPopupModal("hex.builtin.common.choose_file"_lang, &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
if (ImGui::BeginListBox("##files", ImVec2(300_scaled, 0))) {
u32 index = 0;
for (auto &path : s_selectableFiles) {
if (ImGui::Selectable(path.filename().string().c_str(), index == s_selectableFileIndex))
s_selectableFileIndex = index;
index++;
}
ImGui::EndListBox();
}
if (ImGui::Button("hex.builtin.common.open"_lang)) {
s_selectableFileOpenCallback(s_selectableFiles[s_selectableFileIndex]);
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("hex.builtin.common.browse"_lang)) {
fs::openFileBrowser(fs::DialogMode::Open, s_selectableFilesValidExtensions, [](const auto &path) {
s_selectableFileOpenCallback(path);
ImGui::CloseCurrentPopup();
});
}
ImGui::EndPopup();
}
}
void addGlobalUIItems() {
EventManager::subscribe<EventFrameEnd>(drawGlobalPopups);
EventManager::subscribe<RequestShowInfoPopup>([](const std::string &message) {
s_popupMessage = message;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.info"_lang); });
});
EventManager::subscribe<RequestShowErrorPopup>([](const std::string &message) {
s_popupMessage = message;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.error"_lang); });
});
EventManager::subscribe<RequestShowFatalErrorPopup>([](const std::string &message) {
s_popupMessage = message;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.fatal"_lang); });
});
EventManager::subscribe<RequestShowYesNoQuestionPopup>([](const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback) {
s_popupMessage = message;
s_yesCallback = yesCallback;
s_noCallback = noCallback;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.question"_lang); });
});
EventManager::subscribe<RequestShowFileChooserPopup>([](const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback) {
s_selectableFileIndex = 0;
s_selectableFiles = paths;
s_selectableFilesValidExtensions = validExtensions;
s_selectableFileOpenCallback = callback;
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.choose_file"_lang); });
});
}
void addFooterItems() {
@@ -182,4 +317,17 @@ namespace hex::plugin::builtin {
}
void handleBorderlessWindowMode() {
// Intel's OpenGL driver has weird bugs that cause the drawn window to be offset to the bottom right.
// This can be fixed by either using Mesa3D's OpenGL Software renderer or by simply disabling it.
// If you want to try if it works anyways on your GPU, set the hex.builtin.setting.interface.force_borderless_window_mode setting to 1
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
bool isIntelGPU = hex::containsIgnoreCase(ImHexApi::System::getGPUVendor(), "Intel");
ImHexApi::System::impl::setBorderlessWindowMode(!isIntelGPU);
if (isIntelGPU)
log::warn("Intel GPU detected! Intel's OpenGL driver has bugs that can cause issues when using ImHex. If you experience any rendering bugs, please try the Mesa3D Software Renderer");
}
}
}

View File

@@ -55,7 +55,7 @@ namespace hex::plugin::builtin {
this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(logo.data()), logo.size());
}
ImGui::Image(this->m_logoTexture.textureId, scaled(this->m_logoTexture.size()));
ImGui::Image(this->m_logoTexture.textureId, scaled({ 64, 64 }));
ImGui::TableNextColumn();
ImGui::TextFormatted("ImHex Hex Editor v{} by WerWolv - " ICON_FA_CODE_BRANCH, IMHEX_VERSION);

View File

@@ -61,7 +61,7 @@ namespace hex::plugin::builtin {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
@@ -143,7 +143,7 @@ namespace hex::plugin::builtin {
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, u32(hoverColor));
bool open = true;
if (ImGui::CollapsingHeader(name.c_str(), &open)) {
if (ImGui::CollapsingHeader(hex::format("{}###bookmark", name).c_str(), &open)) {
ImGui::TextUnformatted("hex.builtin.view.bookmarks.title.info"_lang);
ImGui::Separator();
ImGui::TextFormatted("hex.builtin.view.bookmarks.address"_lang, region.address, region.address + region.size - 1, region.size);

View File

@@ -28,15 +28,24 @@ namespace hex::plugin::builtin {
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
ImGui::CloseCurrentPopup();
ImGui::PushItemWidth(-1);
if (ImGui::InputText(
"##command_input", this->m_commandBuffer.data(), this->m_commandBuffer.size(), ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_EnterReturnsTrue, [](ImGuiInputTextCallbackData *callbackData) -> int {
auto _this = static_cast<ViewCommandPalette *>(callbackData->UserData);
_this->m_lastResults = _this->getCommandResults(callbackData->Buf);
if (this->m_focusInputTextBox) {
auto textState = ImGui::GetInputTextState(ImGui::GetID("##command_input"));
if (textState != nullptr) {
textState->Stb.cursor = strlen(this->m_commandBuffer.data());
}
return 0;
},
this)) {
ImGui::SetKeyboardFocusHere(0);
this->m_focusInputTextBox = false;
}
ImGui::PushItemWidth(-1);
if (ImGui::InputText("##command_input", this->m_commandBuffer.data(), this->m_commandBuffer.size(), ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_EnterReturnsTrue,
[](ImGuiInputTextCallbackData *callbackData) -> int {
auto _this = static_cast<ViewCommandPalette *>(callbackData->UserData);
_this->m_lastResults = _this->getCommandResults(callbackData->Buf);
return 0;
}, this)) {
if (!this->m_lastResults.empty()) {
auto &[displayResult, matchedCommand, callback] = this->m_lastResults.front();
callback(matchedCommand);
@@ -52,16 +61,6 @@ namespace hex::plugin::builtin {
this->m_justOpened = false;
}
if (this->m_focusInputTextBox) {
auto textState = ImGui::GetInputTextState(ImGui::GetID("##command_input"));
if (textState != nullptr) {
textState->Stb.cursor = strlen(this->m_commandBuffer.data());
}
ImGui::SetKeyboardFocusHere(0);
this->m_focusInputTextBox = false;
}
ImGui::Separator();
for (const auto &[displayResult, matchedCommand, callback] : this->m_lastResults) {

View File

@@ -1,294 +1,180 @@
#include "content/views/view_hashes.hpp"
#include <hex/providers/provider.hpp>
#include <hex/helpers/crypto.hpp>
#include <vector>
namespace hex::plugin::builtin {
ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") {
EventManager::subscribe<EventDataChanged>(this, [this]() {
this->m_shouldInvalidate = true;
EventManager::subscribe<EventRegionSelected>(this, [this](const Region &) {
for (auto &function : this->m_hashFunctions)
function.reset();
});
EventManager::subscribe<EventRegionSelected>(this, [this](Region region) {
if (this->m_shouldMatchSelection) {
if (region.address == size_t(-1)) {
this->m_hashRegion[0] = this->m_hashRegion[1] = 0;
} else {
this->m_hashRegion[0] = region.address;
this->m_hashRegion[1] = region.size;
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
hex::unused(data);
auto selection = ImHexApi::HexEditor::getSelection();
if (ImGui::GetIO().KeyShift) {
if (!this->m_hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.view.hashes.name"_lang);
ImGui::Separator();
ImGui::Indent();
if (ImGui::BeginTable("##hashes_tooltip", 3, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit)) {
auto provider = ImHexApi::Provider::get();
for (auto &function : this->m_hashFunctions) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextFormatted("{}", function.getName());
ImGui::TableNextColumn();
ImGui::TextFormatted(" ");
ImGui::TableNextColumn();
if (provider != nullptr)
ImGui::TextFormatted("{}", crypt::encode16(function.get(*selection, provider)));
}
ImGui::EndTable();
}
ImGui::Unindent();
ImGui::EndTable();
}
ImGui::EndTooltip();
}
this->m_shouldInvalidate = true;
}
});
}
ViewHashes::~ViewHashes() {
EventManager::unsubscribe<EventDataChanged>(this);
EventManager::unsubscribe<EventRegionSelected>(this);
}
template<size_t Size>
static void formatBigHexInt(std::array<u8, Size> dataArray, char *buffer, size_t bufferSize) {
for (size_t i = 0; i < dataArray.size(); i++)
snprintf(buffer + 2 * i, bufferSize - 2 * i, "%02X", dataArray[i]);
}
void ViewHashes::drawContent() {
const auto &hashes = ContentRegistry::Hashes::impl::getHashes();
if (this->m_selectedHash == nullptr && !hashes.empty()) {
this->m_selectedHash = hashes.front();
}
if (ImGui::Begin(View::toWindowName("hex.builtin.view.hashes.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
if (ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav)) {
if (ImGui::BeginCombo("hex.builtin.view.hashes.function"_lang, this->m_selectedHash != nullptr ? LangEntry(this->m_selectedHash->getUnlocalizedName()) : "")) {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isAvailable()) {
ImGui::TextUnformatted("hex.builtin.common.region"_lang);
ImGui::Separator();
ImGui::InputScalarN("##nolabel", ImGuiDataType_U64, this->m_hashRegion, 2, nullptr, nullptr, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.match_selection"_lang, &this->m_shouldMatchSelection);
if (ImGui::IsItemEdited()) {
// Force execution of Region Selection Event
ImHexApi::HexEditor::setSelection(0, 0);
this->m_shouldInvalidate = true;
}
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.settings"_lang);
ImGui::Separator();
if (ImGui::BeginCombo("hex.builtin.view.hashes.function"_lang, hashFunctionNames[this->m_currHashFunction].second, 0)) {
for (size_t i = 0; i < hashFunctionNames.size(); i++) {
bool is_selected = (static_cast<size_t>(this->m_currHashFunction) == i);
if (ImGui::Selectable(hashFunctionNames[i].second, is_selected))
this->m_currHashFunction = i;
if (is_selected)
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
}
ImGui::EndCombo();
this->m_shouldInvalidate = true;
}
size_t dataSize = provider->getSize();
if (this->m_hashRegion[1] >= provider->getBaseAddress() + dataSize)
this->m_hashRegion[1] = provider->getBaseAddress() + dataSize;
switch (hashFunctionNames[this->m_currHashFunction].first) {
case HashFunctions::Crc8:
{
static int polynomial = 0x07, init = 0x0000, xorout = 0x0000;
static bool reflectIn = false, reflectOut = false;
ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::NewLine();
static u8 result = 0;
if (this->m_shouldInvalidate)
result = crypt::crc8(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut);
char buffer[sizeof(result) * 2 + 1];
snprintf(buffer, sizeof(buffer), "%02X", result);
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Crc16:
{
static int polynomial = 0x8005, init = 0x0000, xorout = 0x0000;
static bool reflectIn = false, reflectOut = false;
ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::NewLine();
static u16 result = 0;
if (this->m_shouldInvalidate)
result = crypt::crc16(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut);
char buffer[sizeof(result) * 2 + 1];
snprintf(buffer, sizeof(buffer), "%04X", result);
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Crc32:
{
static int polynomial = 0x04C11DB7, init = 0xFFFFFFFF, xorout = 0xFFFFFFFF;
static bool reflectIn = true, reflectOut = true;
ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::NewLine();
static u32 result = 0;
if (this->m_shouldInvalidate)
result = crypt::crc32(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut);
char buffer[sizeof(result) * 2 + 1];
snprintf(buffer, sizeof(buffer), "%08X", result);
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Md5:
{
static std::array<u8, 16> result = { 0 };
if (this->m_shouldInvalidate)
result = crypt::md5(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha1:
{
static std::array<u8, 20> result = { 0 };
if (this->m_shouldInvalidate)
result = crypt::sha1(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha224:
{
static std::array<u8, 28> result = { 0 };
if (this->m_shouldInvalidate)
result = crypt::sha224(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha256:
{
static std::array<u8, 32> result;
if (this->m_shouldInvalidate)
result = crypt::sha256(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha384:
{
static std::array<u8, 48> result;
if (this->m_shouldInvalidate)
result = crypt::sha384(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha512:
{
static std::array<u8, 64> result;
if (this->m_shouldInvalidate)
result = crypt::sha512(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
for (const auto hash : hashes) {
if (ImGui::Selectable(LangEntry(hash->getUnlocalizedName()), this->m_selectedHash == hash)) {
this->m_selectedHash = hash;
this->m_newHashName.clear();
}
}
this->m_shouldInvalidate = false;
ImGui::EndCombo();
}
if (this->m_newHashName.empty() && this->m_selectedHash != nullptr)
this->m_newHashName = hex::format("{} {}", LangEntry(this->m_selectedHash->getUnlocalizedName()), static_cast<const char *>("hex.builtin.view.hashes.hash"_lang));
if (ImGui::BeginChild("##settings", ImVec2(ImGui::GetContentRegionAvailWidth(), 200_scaled), true)) {
if (this->m_selectedHash != nullptr) {
auto startPos = ImGui::GetCursorPosY();
this->m_selectedHash->draw();
// Check if no elements have been added
if (startPos == ImGui::GetCursorPosY()) {
ImGui::TextFormattedCentered("hex.builtin.view.hashes.no_settings"_lang);
}
}
}
ImGui::EndChild();
ImGui::NewLine();
ImGui::InputText("##Name", this->m_newHashName);
ImGui::SameLine();
ImGui::BeginDisabled(this->m_newHashName.empty() || this->m_selectedHash == nullptr);
if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
if (this->m_selectedHash != nullptr)
this->m_hashFunctions.push_back(this->m_selectedHash->create(this->m_newHashName));
}
ImGui::EndDisabled();
if (ImGui::BeginTable("##hashes", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders, ImVec2(ImGui::GetContentRegionAvailWidth(), ImGui::GetTextLineHeightWithSpacing() * 10))) {
ImGui::TableSetupColumn("hex.builtin.view.hashes.name"_lang);
ImGui::TableSetupColumn("hex.builtin.view.hashes.type"_lang);
ImGui::TableSetupColumn("hex.builtin.view.hashes.result"_lang, ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow();
auto provider = ImHexApi::Provider::get();
auto selection = ImHexApi::HexEditor::getSelection();
std::optional<u32> indexToRemove;
for (u32 i = 0; i < this->m_hashFunctions.size(); i++) {
auto &function = this->m_hashFunctions[i];
ImGui::PushID(i);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushStyleColor(ImGuiCol_Header, 0x00);
ImGui::PushStyleColor(ImGuiCol_HeaderActive, 0x00);
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, 0x00);
ImGui::Selectable(function.getName().c_str(), false);
ImGui::PopStyleColor(3);
{
const auto ContextMenuId = hex::format("Context Menu {}", i);
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right))
ImGui::OpenPopup(ContextMenuId.c_str());
if (ImGui::BeginPopup(ContextMenuId.c_str())) {
if (ImGui::MenuItem("hex.builtin.view.hashes.remove"_lang))
indexToRemove = i;
ImGui::EndPopup();
}
}
ImGui::TableNextColumn();
ImGui::TextFormatted("{}", LangEntry(function.getType()->getUnlocalizedName()));
ImGui::TableNextColumn();
std::string result;
if (provider != nullptr && selection.has_value())
result = crypt::encode16(function.get(*selection, provider));
else
result = "???";
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
ImGui::InputText("##result", result, ImGuiInputTextFlags_ReadOnly);
ImGui::PopItemWidth();
ImGui::PopID();
}
if (indexToRemove.has_value()) {
this->m_hashFunctions.erase(this->m_hashFunctions.begin() + indexToRemove.value());
}
ImGui::EndTable();
}
ImGui::NewLine();
ImGui::TextWrapped("%s", static_cast<const char *>("hex.builtin.view.hashes.hover_info"_lang));
}
ImGui::End();
}

View File

@@ -199,11 +199,7 @@ namespace hex::plugin::builtin {
reader.seek(this->m_searchPosition.value_or(editor->getSelection().getEndAddress()));
constexpr static auto searchFunction = [](const auto &haystackBegin, const auto &haystackEnd, const auto &needleBegin, const auto &needleEnd) {
#if defined(OS_MACOS)
return std::search(haystackBegin, haystackEnd, needleBegin, needleEnd);
#else
return std::search(haystackBegin, haystackEnd, std::boyer_moore_horspool_searcher(needleBegin, needleEnd));
#endif
return std::search(haystackBegin, haystackEnd, std::boyer_moore_horspool_searcher(needleBegin, needleEnd));
};
if (!backwards) {
@@ -275,9 +271,7 @@ namespace hex::plugin::builtin {
void draw(ViewHexEditor *editor) override {
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.resize"_lang);
if (ImGui::InputHexadecimal("##resize", &this->m_size, ImGuiInputTextFlags_EnterReturnsTrue)) {
resize(static_cast<size_t>(this->m_size));
}
ImGui::InputHexadecimal("##resize", &this->m_size);
View::confirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
[&, this]{
@@ -306,12 +300,8 @@ namespace hex::plugin::builtin {
void draw(ViewHexEditor *editor) override {
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.insert"_lang);
if (ImGui::InputHexadecimal("hex.common.address"_lang, &this->m_address, ImGuiInputTextFlags_EnterReturnsTrue)) {
insert(this->m_address, static_cast<size_t>(this->m_size));
}
if (ImGui::InputHexadecimal("hex.common.size"_lang, &this->m_size, ImGuiInputTextFlags_EnterReturnsTrue)) {
insert(this->m_address, static_cast<size_t>(this->m_size));
}
ImGui::InputHexadecimal("hex.builtin.common.address"_lang, &this->m_address);
ImGui::InputHexadecimal("hex.builtin.common.size"_lang, &this->m_size);
View::confirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
[&, this]{
@@ -334,6 +324,37 @@ namespace hex::plugin::builtin {
u64 m_size;
};
class PopupRemove : public ViewHexEditor::Popup {
public:
PopupRemove(u64 address, size_t size) : m_address(address), m_size(size) {}
void draw(ViewHexEditor *editor) override {
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.remove"_lang);
ImGui::InputHexadecimal("hex.builtin.common.address"_lang, &this->m_address);
ImGui::InputHexadecimal("hex.builtin.common.size"_lang, &this->m_size);
View::confirmButtons("hex.builtin.common.set"_lang, "hex.builtin.common.cancel"_lang,
[&, this]{
remove(this->m_address, static_cast<size_t>(this->m_size));
editor->closePopup();
},
[&]{
editor->closePopup();
});
}
private:
static void remove(u64 address, size_t size) {
if (ImHexApi::Provider::isValid())
ImHexApi::Provider::get()->remove(address, size);
}
private:
u64 m_address;
u64 m_size;
};
ViewHexEditor::ViewHexEditor() : View("hex.builtin.view.hex_editor.name") {
this->m_currDataVisualizer = ContentRegistry::HexEditor::impl::getVisualizers()["hex.builtin.visualizer.hexadecimal.8bit"];
@@ -427,6 +448,10 @@ namespace hex::plugin::builtin {
return { std::string(decoded), advance, color };
}
static auto getCellPosition() {
return ImGui::GetCursorScreenPos() - ImGui::GetStyle().CellPadding;
}
static void drawTooltip(u64 address, const u8 *data, size_t size) {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, scaled(ImVec2(5, 5)));
@@ -439,7 +464,7 @@ namespace hex::plugin::builtin {
ImGui::BeginTooltip();
for (const auto &[id, tooltip] : tooltips) {
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
@@ -465,6 +490,13 @@ namespace hex::plugin::builtin {
void ViewHexEditor::drawCell(u64 address, u8 *data, size_t size, bool hovered) {
auto provider = ImHexApi::Provider::get();
if (this->m_shouldUpdateEditingValue) {
this->m_shouldUpdateEditingValue = false;
this->m_editingBytes.resize(size);
std::memcpy(this->m_editingBytes.data(), data, size);
}
if (this->m_editingAddress != address) {
this->m_currDataVisualizer->draw(address, data, size, this->m_upperCaseHex);
@@ -484,8 +516,9 @@ namespace hex::plugin::builtin {
ImGui::SetKeyboardFocusHere();
ImGui::CaptureKeyboardFromApp(true);
if (this->m_currDataVisualizer->drawEditing(address, this->m_editingBytes.data(), this->m_editingBytes.size(), this->m_upperCaseHex, this->m_enteredEditingMode) || this->m_shouldModifyValue) {
provider->write(address, this->m_editingBytes.data(), this->m_editingBytes.size());
if (this->m_currDataVisualizer->drawEditing(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size(), this->m_upperCaseHex, this->m_enteredEditingMode) || this->m_shouldModifyValue) {
provider->write(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size());
if (!this->m_selectionChanged && !ImGui::IsMouseDown(ImGuiMouseButton_Left) && !ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
auto nextEditingAddress = *this->m_editingAddress + this->m_currDataVisualizer->getBytesPerCell();
@@ -500,6 +533,7 @@ namespace hex::plugin::builtin {
}
this->m_shouldModifyValue = false;
this->m_shouldUpdateEditingValue = true;
}
this->m_enteredEditingMode = false;
@@ -653,24 +687,29 @@ namespace hex::plugin::builtin {
const auto cellBytes = std::min<u64>(validBytes, bytesPerCell);
// Query cell colors
const auto foregroundColor = queryForegroundColor(byteAddress, &bytes[x], cellBytes);
const auto backgroundColor = [&]{
auto color = queryBackgroundColor(byteAddress, &bytes[x], cellBytes);
if (x < validBytes) {
const auto foregroundColor = queryForegroundColor(byteAddress, &bytes[x], cellBytes);
const auto backgroundColor = [&]{
auto color = queryBackgroundColor(byteAddress, &bytes[x], cellBytes);
if ((byteAddress >= selectionMin && byteAddress <= selectionMax)) {
if (color.has_value())
color = (ImAlphaBlendColors(color.value(), this->m_selectionColor)) & 0x00FFFFFF;
else
color = this->m_selectionColor;
}
if ((byteAddress >= selectionMin && byteAddress <= selectionMax)) {
if (color.has_value())
color = ((ImAlphaBlendColors(color.value(), this->m_selectionColor)) & 0x00FFFFFF) | (this->m_selectionColor & 0xFF000000);
else
color = this->m_selectionColor;
}
color = *color | (this->m_selectionColor & 0xFF000000);
return color;
}();
return color;
}();
cellColors.emplace_back(
foregroundColor,
backgroundColor
);
cellColors.emplace_back(
foregroundColor,
backgroundColor
);
}
}
}
@@ -685,7 +724,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
if (x < validBytes) {
auto cellStartPos = (ImGui::GetWindowPos() + ImGui::GetCursorPos()) - ImGui::GetStyle().CellPadding - ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
auto cellStartPos = getCellPosition();
auto cellSize = (CharacterSize * ImVec2(this->m_currDataVisualizer->getMaxCharsPerCell(), 1) + (ImVec2(3, 2) * ImGui::GetStyle().CellPadding) - ImVec2(1, 0) * ImGui::GetStyle().CellPadding) + ImVec2(1, 0);
auto [foregroundColor, backgroundColor] = cellColors[x];
@@ -707,7 +746,7 @@ namespace hex::plugin::builtin {
this->drawSelectionFrame(x, y, byteAddress, bytesPerCell, cellStartPos, cellSize);
}
const bool cellHovered = ImGui::IsMouseHoveringRect(cellStartPos, cellStartPos + cellSize, false);
const bool cellHovered = ImGui::IsMouseHoveringRect(cellStartPos, cellStartPos + cellSize, true);
this->handleSelection(byteAddress, bytesPerCell, &bytes[x], cellHovered);
@@ -742,26 +781,26 @@ namespace hex::plugin::builtin {
const u64 byteAddress = y * this->m_bytesPerRow + x + provider->getBaseAddress() + provider->getCurrentPageAddress();
const auto cellStartPos = (ImGui::GetWindowPos() + ImGui::GetCursorPos()) - ImGui::GetStyle().CellPadding - ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
const auto cellStartPos = getCellPosition();
const auto cellSize = CharacterSize;
const bool cellHovered = ImGui::IsMouseHoveringRect(cellStartPos, cellStartPos + cellSize, false);
this->handleSelection(byteAddress, bytesPerCell, &bytes[x], cellHovered);
auto [foregroundColor, backgroundColor] = cellColors[x / bytesPerCell];
// Draw highlights and selection
if (backgroundColor.has_value()) {
auto drawList = ImGui::GetWindowDrawList();
// Draw background color
drawList->AddRectFilled(cellStartPos, cellStartPos + cellSize, backgroundColor.value());
this->drawSelectionFrame(x, y, byteAddress, 1, cellStartPos, cellSize);
}
const bool cellHovered = ImGui::IsMouseHoveringRect(cellStartPos, cellStartPos + cellSize, true);
if (x < validBytes) {
this->handleSelection(byteAddress, bytesPerCell, &bytes[x], cellHovered);
auto [foregroundColor, backgroundColor] = cellColors[x / bytesPerCell];
// Draw highlights and selection
if (backgroundColor.has_value()) {
auto drawList = ImGui::GetWindowDrawList();
// Draw background color
drawList->AddRectFilled(cellStartPos, cellStartPos + cellSize, backgroundColor.value());
this->drawSelectionFrame(x, y, byteAddress, 1, cellStartPos, cellSize);
}
if (std::isprint(bytes[x]))
ImGui::TextFormatted("{:c}", bytes[x]);
else
@@ -797,25 +836,28 @@ namespace hex::plugin::builtin {
for (const auto &[address, data] : encodingData) {
ImGui::TableNextColumn();
const auto cellStartPos = (ImGui::GetWindowPos() + ImGui::GetCursorPos()) - ImGui::GetStyle().CellPadding - ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
const auto cellStartPos = getCellPosition();
const auto cellSize = CharacterSize * data.advance;
const bool cellHovered = ImGui::IsMouseHoveringRect(cellStartPos, cellStartPos + cellSize, false);
const bool cellHovered = ImGui::IsMouseHoveringRect(cellStartPos, cellStartPos + cellSize, true);
auto [foregroundColor, backgroundColor] = cellColors[address % this->m_bytesPerRow];
const auto x = address % this->m_bytesPerRow;
if (x < validBytes) {
auto [foregroundColor, backgroundColor] = cellColors[x];
// Draw highlights and selection
if (backgroundColor.has_value()) {
auto drawList = ImGui::GetWindowDrawList();
// Draw highlights and selection
if (backgroundColor.has_value()) {
auto drawList = ImGui::GetWindowDrawList();
// Draw background color
drawList->AddRectFilled(cellStartPos, cellStartPos + cellSize, backgroundColor.value());
// Draw background color
drawList->AddRectFilled(cellStartPos, cellStartPos + cellSize, backgroundColor.value());
this->drawSelectionFrame(address % this->m_bytesPerRow, y, address, 1, cellStartPos, cellSize);
this->drawSelectionFrame(x, y, address, 1, cellStartPos, cellSize);
}
ImGui::TextFormattedColored(data.color, "{}", data.displayValue);
this->handleSelection(address, data.advance, &bytes[address % this->m_bytesPerRow], cellHovered);
}
ImGui::TextFormattedColored(data.color, "{}", data.displayValue);
this->handleSelection(address, data.advance, &bytes[address % this->m_bytesPerRow], cellHovered);
}
ImGui::EndTable();
@@ -827,8 +869,8 @@ namespace hex::plugin::builtin {
// Scroll to the cursor if it's either at the top or bottom edge of the screen
if (this->m_shouldScrollToSelection && (this->m_selectionEnd != InvalidSelection) && (this->m_selectionStart != InvalidSelection)) {
// Make sure simply clicking on a byte at the edge of the screen won't cause scrolling
if ((ImGui::IsMouseDown(ImGuiMouseButton_Left) && this->m_selectionStart != this->m_selectionEnd) || (!ImGui::IsMouseDown(ImGuiMouseButton_Left))) {
auto fractionPerLine = 1.0 / this->m_visibleRowCount;
if ((ImGui::IsMouseDown(ImGuiMouseButton_Left) && this->m_selectionStart != this->m_selectionEnd)) {
auto fractionPerLine = 1.0 / (this->m_visibleRowCount + 1);
if (y == clipper.DisplayStart + 2) {
if (i128(this->m_selectionEnd - provider->getBaseAddress() - provider->getCurrentPageAddress()) <= (i64(clipper.DisplayStart + 2) * this->m_bytesPerRow)) {
@@ -845,27 +887,38 @@ namespace hex::plugin::builtin {
}
// If the cursor is off-screen, directly jump to the byte
{
const auto newSelection = this->getSelection();
if (newSelection.getStartAddress() < u64(clipper.DisplayStart * this->m_bytesPerRow))
if (this->m_shouldJumpWhenOffScreen) {
this->m_shouldJumpWhenOffScreen = false;
const auto pageAddress = provider->getCurrentPageAddress() + provider->getBaseAddress();
auto newSelection = this->getSelection();
newSelection.address -= pageAddress;
if ((newSelection.getStartAddress()) < u64(clipper.DisplayStart * this->m_bytesPerRow))
this->jumpToSelection();
if (newSelection.getEndAddress() > u64(clipper.DisplayEnd * this->m_bytesPerRow))
if ((newSelection.getEndAddress()) > u64(clipper.DisplayEnd * this->m_bytesPerRow))
this->jumpToSelection();
}
}
}
}
// Handle jumping to selection
if (this->m_shouldJumpToSelection) {
this->m_shouldJumpToSelection = false;
const auto pageAddress = provider->getCurrentPageAddress() + provider->getBaseAddress();
auto newSelection = this->getSelection();
newSelection.address -= pageAddress;
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (static_cast<long double>(newSelection.getStartAddress()) / this->m_bytesPerRow) * CharacterSize.y, 0.5);
}
} else {
ImGui::TextFormattedCentered("hex.builtin.view.hex_editor.no_bytes"_lang);
}
// Handle jumping to selection
if (this->m_shouldJumpToSelection) {
this->m_shouldJumpToSelection = false;
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (float(this->m_selectionStart) / this->m_bytesPerRow) * CharacterSize.y, 0.5);
}
ImGui::EndTable();
}
ImGui::PopStyleVar();
@@ -914,7 +967,7 @@ namespace hex::plugin::builtin {
auto selection = this->getSelection();
std::string value;
if (this->isSelectionValid())
value = hex::format("0x{0:08X} - 0x{1:08X} ({0} - {1})", selection.getStartAddress(), selection.getEndAddress());
value = hex::format("0x{0:08X} - 0x{1:08X} ({2})", selection.getStartAddress(), selection.getEndAddress(), hex::toByteString(selection.getSize()));
else
value = std::string("hex.builtin.view.hex_editor.selection.none"_lang);
@@ -930,8 +983,8 @@ namespace hex::plugin::builtin {
ImGui::EndTable();
}
ImGui::EndChild();
}
ImGui::EndChild();
}
}
@@ -1014,7 +1067,7 @@ namespace hex::plugin::builtin {
if (clipboard.length() % 2 != 0) return;
// Convert hex string to bytes
std::vector<u8> buffer = hex::decodeByteString(clipboard);
std::vector<u8> buffer = crypt::decode16(clipboard);
// Write bytes
provider->write(selection.getStartAddress() + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), std::min(selection.size, buffer.size()));
@@ -1059,24 +1112,28 @@ namespace hex::plugin::builtin {
auto pos = this->m_selectionEnd - this->m_bytesPerRow;
this->setSelection(pos, pos);
this->scrollToSelection();
this->jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::Down, [this] {
auto pos = this->m_selectionEnd + this->m_bytesPerRow;
this->setSelection(pos, pos);
this->scrollToSelection();
this->jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, Keys::Left, [this] {
if (this->m_selectionEnd > 0) {
auto pos = this->m_selectionEnd - 1;
this->setSelection(pos, pos);
this->scrollToSelection();
this->jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::Right, [this] {
auto pos = this->m_selectionEnd + 1;
this->setSelection(pos, pos);
this->scrollToSelection();
this->jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, Keys::PageUp, [this] {
@@ -1085,32 +1142,56 @@ namespace hex::plugin::builtin {
auto pos = this->m_selectionEnd - visibleByteCount;
this->setSelection(pos, pos);
this->scrollToSelection();
this->jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::PageDown, [this] {
auto pos = this->m_selectionEnd + (this->m_bytesPerRow * this->m_visibleRowCount);
this->setSelection(pos, pos);
this->scrollToSelection();
this->jumpIfOffScreen();
});
// Move selection around
ShortcutManager::addShortcut(this, SHIFT + Keys::Up, [this] {
this->setSelection(this->m_selectionEnd - this->m_bytesPerRow, this->m_selectionEnd);
this->m_selectionStart = std::max<u64>(this->m_selectionStart, this->m_bytesPerRow);
this->setSelection(this->m_selectionStart - this->m_bytesPerRow, this->m_selectionEnd);
this->scrollToSelection();
this->jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, SHIFT + Keys::Down, [this] {
this->setSelection(this->m_selectionEnd + this->m_bytesPerRow, this->m_selectionEnd);
this->setSelection(this->m_selectionStart + this->m_bytesPerRow, this->m_selectionEnd);
this->scrollToSelection();
this->jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, SHIFT + Keys::Left, [this] {
this->setSelection(this->m_selectionEnd - 1, this->m_selectionEnd);
this->scrollToSelection();
this->m_selectionStart = std::max<u64>(this->m_selectionStart, 1);
this->setSelection(this->m_selectionStart - 1, this->m_selectionEnd);
this->scrollToSelection();
this->jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, SHIFT + Keys::Right, [this] {
this->setSelection(this->m_selectionEnd + 1, this->m_selectionEnd);
this->setSelection(this->m_selectionStart + 1, this->m_selectionEnd);
this->scrollToSelection();
this->jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, Keys::PageUp, [this] {
u64 visibleByteCount = this->m_bytesPerRow * this->m_visibleRowCount;
if (this->m_selectionEnd >= visibleByteCount) {
auto pos = this->m_selectionEnd - visibleByteCount;
this->setSelection(pos, this->m_selectionEnd);
this->scrollToSelection();
this->jumpIfOffScreen();
}
});
ShortcutManager::addShortcut(this, Keys::PageDown, [this] {
auto pos = this->m_selectionEnd + (this->m_bytesPerRow * this->m_visibleRowCount);
this->setSelection(pos, this->m_selectionEnd);
this->scrollToSelection();
this->jumpIfOffScreen();
});
ShortcutManager::addShortcut(this, CTRL + Keys::G, [this] {
@@ -1338,6 +1419,10 @@ namespace hex::plugin::builtin {
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.edit.insert"_lang, nullptr, false, providerValid && provider->isResizable())) {
this->openPopup<PopupInsert>(this->getSelection().getStartAddress(), 0x00);
}
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.edit.remove"_lang, nullptr, false, providerValid && provider->isResizable())) {
this->openPopup<PopupRemove>(this->getSelection().getStartAddress(), 0x00);
}
});
}

View File

@@ -49,7 +49,7 @@ namespace hex::plugin::builtin {
ContentRegistry::FileHandler::add({ ".mgc" }, [](const auto &path) {
for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
if (fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) {
View::showMessagePopup("hex.builtin.view.information.magic_db_added"_lang);
View::showInfoPopup("hex.builtin.view.information.magic_db_added"_lang);
return true;
}
}

View File

@@ -21,16 +21,15 @@ namespace hex::plugin::builtin {
static bool initialized = false;
static TextEditor::LanguageDefinition langDef;
if (!initialized) {
static const char *const keywords[] = {
static constexpr std::array keywords = {
"using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "false", "true", "this", "parent", "addressof", "sizeof", "$", "while", "for", "fn", "return", "break", "continue", "namespace", "in", "out"
};
for (auto &k : keywords)
langDef.mKeywords.insert(k);
static const char *const builtInTypes[] = {
static constexpr std::array builtInTypes = {
"u8", "u16", "u32", "u64", "u128", "s8", "s16", "s32", "s64", "s128", "float", "double", "char", "char16", "bool", "padding", "str", "auto"
};
for (const auto name : builtInTypes) {
TextEditor::Identifier id;
id.mDeclaration = "";
@@ -76,7 +75,7 @@ namespace hex::plugin::builtin {
ViewPatternEditor::ViewPatternEditor() : View("hex.builtin.view.pattern_editor.name") {
this->m_parserRuntime = new pl::PatternLanguage();
this->m_parserRuntime = ContentRegistry::PatternLanguage::createDefaultRuntime(nullptr);
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
this->m_textEditor.SetShowWhitespaces(false);
@@ -133,7 +132,7 @@ namespace hex::plugin::builtin {
if (!entry.is_regular_file())
continue;
fs::File file(entry.path().string(), fs::File::Mode::Read);
fs::File file(entry.path(), fs::File::Mode::Read);
if (!file.isValid())
continue;
@@ -231,55 +230,51 @@ namespace hex::plugin::builtin {
});
ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8 *data, size_t size) -> std::optional<color_t> {
ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8 *data, size_t size) -> std::optional<color_t> {
hex::unused(data, size);
const auto &patterns = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns();
for (const auto &pattern : patterns) {
auto child = pattern->getPattern(address);
if (child != nullptr) {
return child->getColor();
}
}
if (this->m_runningEvaluators != 0)
return std::nullopt;
return std::nullopt;
const auto pattern = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPattern(address);
if (pattern != nullptr)
return pattern->getColor();
else
return std::nullopt;
});
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
hex::unused(data, size);
auto &patterns = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns();
for (auto &pattern : patterns) {
auto child = pattern->getPattern(address);
if (child != nullptr) {
ImGui::BeginTooltip();
auto pattern = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPattern(address);
if (pattern != nullptr) {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
this->drawPatternTooltip(child);
this->drawPatternTooltip(pattern);
ImGui::PushStyleColor(ImGuiCol_TableRowBg, pattern->getColor());
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, pattern->getColor());
ImGui::EndTable();
ImGui::PopStyleColor(2);
}
ImGui::EndTooltip();
auto tooltipColor = (pattern->getColor() & 0x00FF'FFFF) | 0x7000'0000;
ImGui::PushStyleColor(ImGuiCol_TableRowBg, tooltipColor);
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, tooltipColor);
ImGui::EndTable();
ImGui::PopStyleColor(2);
}
ImGui::EndTooltip();
}
});
}
ViewPatternEditor::~ViewPatternEditor() {
delete this->m_parserRuntime;
EventManager::unsubscribe<EventProjectFileStore>(this);
EventManager::unsubscribe<EventProjectFileLoad>(this);
EventManager::unsubscribe<RequestSetPatternLanguageCode>(this);
EventManager::unsubscribe<EventFileLoaded>(this);
EventManager::unsubscribe<RequestChangeTheme>(this);
EventManager::unsubscribe<EventFileUnloaded>(this);
EventManager::unsubscribe<RequestChangeTheme>(this);
EventManager::unsubscribe<EventProviderChanged>(this);
}
void ViewPatternEditor::drawContent() {
@@ -704,6 +699,7 @@ namespace hex::plugin::builtin {
this->evaluatePattern(code);
this->m_textEditor.SetText(code);
this->parsePattern(code);
}
}
@@ -711,6 +707,7 @@ namespace hex::plugin::builtin {
if (!ImHexApi::Provider::isValid()) return;
ImHexApi::Provider::get()->getPatternLanguageRuntime().reset();
this->parsePattern("");
}
@@ -788,6 +785,8 @@ namespace hex::plugin::builtin {
this->m_lastEvaluationError = runtime.getError();
}
runtime.flattenPatterns();
this->m_lastEvaluationLog = runtime.getConsoleLog();
this->m_lastEvaluationOutVars = runtime.getOutVariables();
this->m_runningEvaluators--;

View File

@@ -51,7 +51,7 @@ namespace hex::plugin::builtin {
if (ImGui::BeginTabItem(LangEntry(category))) {
const std::string &categoryDesc = descriptions.count(category) ? descriptions.at(category) : category.name;
LangEntry descriptionEntry{categoryDesc};
ImGui::TextUnformatted(descriptionEntry);
ImGui::TextWrapped("%s", static_cast<const char*>(descriptionEntry));
ImGui::InfoTooltip(descriptionEntry);
ImGui::Separator();

View File

@@ -12,12 +12,12 @@
#include <hex/helpers/magic.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/tar.hpp>
#include <fstream>
#include <filesystem>
#include <functional>
#include <nlohmann/json.hpp>
#include <microtar.h>
namespace hex::plugin::builtin {
@@ -76,34 +76,8 @@ namespace hex::plugin::builtin {
entry.hasUpdate = false;
if (entry.isFolder) {
mtar_t ctx;
mtar_open(&ctx, this->m_downloadPath.string().c_str(), "r");
mtar_header_t header;
auto extractBasePath = this->m_downloadPath.parent_path() / this->m_downloadPath.stem();
while (mtar_read_header(&ctx, &header) != MTAR_ENULLRECORD) {
auto filePath = extractBasePath / std::fs::path(header.name);
if (filePath.filename() == "@PaxHeader") {
mtar_next(&ctx);
continue;
}
fs::createDirectories(filePath.parent_path());
fs::File outputFile(filePath.string(), fs::File::Mode::Create);
std::vector<u8> buffer(0x10000);
for (u64 offset = 0; offset < header.size; offset += buffer.size()) {
auto readSize = std::min<u64>(buffer.size(), header.size - offset);
mtar_read_data(&ctx, buffer.data(), readSize);
buffer.resize(readSize);
outputFile.write(buffer);
}
mtar_next(&ctx);
}
mtar_finalize(&ctx);
mtar_close(&ctx);
Tar tar(this->m_downloadPath, Tar::Mode::Read);
tar.extractAll(this->m_downloadPath.parent_path() / this->m_downloadPath.stem());
}
downloadDoneCallback(entry);
@@ -257,12 +231,15 @@ namespace hex::plugin::builtin {
}
bool ViewStore::remove(fs::ImHexPath pathType, const std::string &fileName) {
bool removed = false;
bool removed = true;
for (const auto &path : fs::getDefaultPaths(pathType)) {
bool removedFile = fs::remove(path / std::fs::path(fileName));
bool removedFolder = fs::remove(path / std::fs::path(fileName).stem());
const auto filePath = path / fileName;
const auto folderPath = (path / std::fs::path(fileName).stem());
removed = removed || removedFile || removedFolder;
fs::remove(filePath);
fs::removeAll(folderPath);
removed = removed && !fs::exists(filePath) && !fs::exists(folderPath);
}
return removed;

View File

@@ -113,7 +113,7 @@ namespace hex::plugin::builtin {
if (this->m_minimumLength < 1)
this->m_minimumLength = 1;
ImGui::Checkbox("Regex", &this->m_regex);
ImGui::Checkbox("hex.builtin.view.strings.regex"_lang, &this->m_regex);
bool filterError = this->m_regex && !this->m_pattern_parsed;
if (filterError)

View File

@@ -20,7 +20,7 @@ namespace hex::plugin::builtin {
ContentRegistry::FileHandler::add({ ".yar" }, [](const auto &path) {
for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Yara)) {
if (fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) {
View::showMessagePopup("hex.builtin.view.yara.rule_added"_lang);
View::showInfoPopup("hex.builtin.view.yara.rule_added"_lang);
return true;
}
}
@@ -46,10 +46,10 @@ namespace hex::plugin::builtin {
} else {
ImGui::BeginDisabled(this->m_matching);
{
if (ImGui::BeginCombo("hex.builtin.view.yara.header.rules"_lang, this->m_rules[this->m_selectedRule].first.c_str())) {
if (ImGui::BeginCombo("hex.builtin.view.yara.header.rules"_lang, this->m_rules[this->m_selectedRule].first.string().c_str())) {
for (u32 i = 0; i < this->m_rules.size(); i++) {
const bool selected = (this->m_selectedRule == i);
if (ImGui::Selectable(this->m_rules[i].first.c_str(), selected))
if (ImGui::Selectable(this->m_rules[i].first.string().c_str(), selected))
this->m_selectedRule = i;
if (selected)
@@ -162,7 +162,7 @@ namespace hex::plugin::builtin {
std::error_code error;
for (const auto &entry : std::fs::recursive_directory_iterator(path, error)) {
if (entry.is_regular_file() && entry.path().extension() == ".yar") {
this->m_rules.emplace_back(std::fs::relative(entry.path(), std::fs::path(path)).string(), entry.path().string());
this->m_rules.emplace_back(std::fs::relative(entry.path(), path), entry.path());
}
}
}
@@ -207,7 +207,7 @@ namespace hex::plugin::builtin {
delete[] ptr;
},
this->m_rules[this->m_selectedRule].second.data());
fs::toShortPath(this->m_rules[this->m_selectedRule].second).string().data());
fs::File file(this->m_rules[this->m_selectedRule].second, fs::File::Mode::Read);

View File

@@ -215,11 +215,14 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.disassembler.disassembly.bytes", "Byte" },
{ "hex.builtin.view.hashes.name", "Hashes" },
{ "hex.builtin.view.hashes.settings", "Einstellungen" },
{ "hex.builtin.view.hashes.function", "Hash Funktion" },
{ "hex.builtin.view.hashes.iv", "Startwert" },
{ "hex.builtin.view.hashes.poly", "Polynomial" },
{ "hex.builtin.view.hashes.hash", "Hash" },
{ "hex.builtin.view.hashes.no_settings", "Keine Einstellungen verfügbar" },
{ "hex.builtin.view.hashes.function", "Hashfunktion" },
{ "hex.builtin.view.hashes.name", "Name" },
{ "hex.builtin.view.hashes.type", "Typ" },
{ "hex.builtin.view.hashes.result", "Resultat" },
{ "hex.builtin.view.hashes.remove", "Hash entfernen" },
{ "hex.builtin.view.hashes.hover_info", "Bewege die Maus über die seketierten Bytes im Hex Editor und halte SHIFT gedrückt, um die Hashes dieser Region anzuzeigen." },
{ "hex.builtin.view.help.name", "Hilfe" },
{ "hex.builtin.view.help.about.name", "Über ImHex" },
@@ -331,6 +334,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.strings.copy", "String kopieren" },
{ "hex.builtin.view.strings.demangle", "Demangle" },
{ "hex.builtin.view.strings.min_length", "Minimallänge" },
{ "hex.builtin.view.strings.regex", "Regex" },
{ "hex.builtin.view.strings.filter", "Filter" },
{ "hex.builtin.view.strings.extract", "Extrahieren" },
{ "hex.builtin.view.strings.regex_error", "Ungültiges Regex" },
@@ -641,6 +645,20 @@ namespace hex::plugin::builtin {
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Erstellen der Zieldatei fehlgeschlagen" },
{ "hex.builtin.tools.file_tools.combiner.open_input", "Öffnen der Inputdatei {0} fehlgeschlagen" },
{ "hex.builtin.tools.file_tools.combiner.success", "Dateien erfolgreich kombiniert!" },
{ "hex.builtin.tools.ieee756", "IEEE 756 Fliesskommazahl Tester" },
{ "hex.builtin.tools.ieee756.sign", "Vorzeichen" },
{ "hex.builtin.tools.ieee756.exponent", "Exponent" },
{ "hex.builtin.tools.ieee756.mantissa", "Mantisse" },
{ "hex.builtin.tools.ieee756.exponent_size", "Exponentengrösse" },
{ "hex.builtin.tools.ieee756.mantissa_size", "Mantissengrösse" },
{ "hex.builtin.tools.ieee756.half_precision", "Half Precision" },
{ "hex.builtin.tools.ieee756.singe_precision", "Single Precision" },
{ "hex.builtin.tools.ieee756.double_precision", "Double Precision" },
{ "hex.builtin.tools.ieee756.type", "Typ" },
{ "hex.builtin.tools.ieee756.formula", "Formel" },
{ "hex.builtin.tools.ieee756.result.title", "Resultat" },
{ "hex.builtin.tools.ieee756.result.float", "Fliesskomma Resultat" },
{ "hex.builtin.tools.ieee756.result.hex", "Hexadezimal Resultat" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "Kürzlich geöffnete Dateien" },
@@ -678,6 +696,11 @@ namespace hex::plugin::builtin {
{ "hex.builtin.setting.font", "Schriftart" },
{ "hex.builtin.setting.font.font_path", "Eigene Schriftart" },
{ "hex.builtin.setting.font.font_size", "Schriftgrösse" },
//{ "hex.builtin.setting.proxy", "Proxy" },
//{ "hex.builtin.setting.proxy.description", "Proxy will take effect on store, wikipedia or any other plugin immediately." },
//{ "hex.builtin.setting.proxy.enable", "Enable Proxy" },
//{ "hex.builtin.setting.proxy.url", "Proxy URL" },
//{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" },
{ "hex.builtin.provider.file.path", "Dateipfad" },
{ "hex.builtin.provider.file.size", "Größe" },
@@ -715,6 +738,21 @@ namespace hex::plugin::builtin {
{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
{ "hex.builtin.visualizer.hexii", "HexII" },
{ "hex.builtin.visualizer.rgba8", "RGBA8 Farbe" },
{ "hex.builtin.hash.md5", "MD5" },
{ "hex.builtin.hash.sha1", "SHA1" },
{ "hex.builtin.hash.sha224", "SHA224" },
{ "hex.builtin.hash.sha256", "SHA256" },
{ "hex.builtin.hash.sha384", "SHA384" },
{ "hex.builtin.hash.sha512", "SHA512" },
{ "hex.builtin.hash.crc8", "CRC8" },
{ "hex.builtin.hash.crc16", "CRC16" },
{ "hex.builtin.hash.crc32", "CRC32" },
{ "hex.builtin.hash.crc.poly", "Polynom" },
{ "hex.builtin.hash.crc.iv", "Initialwert" },
{ "hex.builtin.hash.crc.xor_out", "XOR Out" },
{ "hex.builtin.hash.crc.refl_in", "Reflect In" },
{ "hex.builtin.hash.crc.refl_out", "Reflect Out" },
});
}

View File

@@ -81,7 +81,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.common.open", "Open" },
{ "hex.builtin.common.browse", "Browse..." },
{ "hex.builtin.common.choose_file", "Choose file" },
{ "hex.common.processing", "Processing" },
{ "hex.builtin.common.processing", "Processing" },
{ "hex.builtin.popup.exit_application.title", "Exit Application?" },
{ "hex.builtin.popup.exit_application.desc", "You have unsaved changes made to your Project.\nAre you sure you want to exit?" },
@@ -218,14 +218,14 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.disassembler.disassembly.bytes", "Byte" },
{ "hex.builtin.view.hashes.name", "Hashes" },
{ "hex.builtin.view.hashes.settings", "Settings" },
{ "hex.builtin.view.hashes.hash", "Hash" },
{ "hex.builtin.view.hashes.no_settings", "No settings available" },
{ "hex.builtin.view.hashes.function", "Hash function" },
{ "hex.builtin.view.hashes.iv", "Initial value" },
{ "hex.builtin.view.hashes.xorout", "Final XOR value" },
{ "hex.builtin.common.reflectIn", "Reflect input" },
{ "hex.builtin.common.reflectOut", "Reflect output" },
{ "hex.builtin.view.hashes.poly", "Polynomial" },
{ "hex.builtin.view.hashes.name", "Name" },
{ "hex.builtin.view.hashes.type", "Type" },
{ "hex.builtin.view.hashes.result", "Result" },
{ "hex.builtin.view.hashes.remove", "Remove hash" },
{ "hex.builtin.view.hashes.hover_info", "Hover over the Hex Editor selection and hold down SHIFT to view the hashes of that region." },
{ "hex.builtin.view.help.name", "Help" },
{ "hex.builtin.view.help.about.name", "About" },
@@ -278,6 +278,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.hex_editor.menu.edit.set_base", "Set base address" },
{ "hex.builtin.view.hex_editor.menu.edit.resize", "Resize..." },
{ "hex.builtin.view.hex_editor.menu.edit.insert", "Insert..." },
{ "hex.builtin.view.hex_editor.menu.edit.remove", "Remove..." },
{ "hex.builtin.view.information.name", "Data Information" },
{ "hex.builtin.view.information.control", "Control" },
@@ -335,6 +336,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.strings.copy", "Copy string" },
{ "hex.builtin.view.strings.demangle", "Demangle" },
{ "hex.builtin.view.strings.min_length", "Minimum length" },
{ "hex.builtin.view.strings.regex", "Regex" },
{ "hex.builtin.view.strings.filter", "Filter" },
{ "hex.builtin.view.strings.extract", "Extract" },
{ "hex.builtin.view.strings.regex_error", "Invalid regex" },
@@ -645,6 +647,20 @@ namespace hex::plugin::builtin {
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
{ "hex.builtin.tools.ieee756", "IEEE 756 Floating Point Tester" },
{ "hex.builtin.tools.ieee756.sign", "Sign" },
{ "hex.builtin.tools.ieee756.exponent", "Exponent" },
{ "hex.builtin.tools.ieee756.mantissa", "Mantissa" },
{ "hex.builtin.tools.ieee756.exponent_size", "Exponent Size" },
{ "hex.builtin.tools.ieee756.mantissa_size", "Mantissa Size" },
{ "hex.builtin.tools.ieee756.half_precision", "Half Precision" },
{ "hex.builtin.tools.ieee756.singe_precision", "Single Precision" },
{ "hex.builtin.tools.ieee756.double_precision", "Double Precision" },
{ "hex.builtin.tools.ieee756.type", "Type" },
{ "hex.builtin.tools.ieee756.formula", "Formula" },
{ "hex.builtin.tools.ieee756.result.title", "Result" },
{ "hex.builtin.tools.ieee756.result.float", "Floating Point Result" },
{ "hex.builtin.tools.ieee756.result.hex", "Hexadecimal Result" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "Recent Files" },
@@ -682,6 +698,11 @@ namespace hex::plugin::builtin {
{ "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.proxy", "Proxy" },
{ "hex.builtin.setting.proxy.description", "Proxy will take effect on store, wikipedia or any other plugin immediately." },
{ "hex.builtin.setting.proxy.enable", "Enable Proxy" },
{ "hex.builtin.setting.proxy.url", "Proxy URL" },
{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" },
{ "hex.builtin.provider.file.path", "File path" },
{ "hex.builtin.provider.file.size", "Size" },
@@ -719,6 +740,21 @@ namespace hex::plugin::builtin {
{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
{ "hex.builtin.visualizer.hexii", "HexII" },
{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
{ "hex.builtin.hash.md5", "MD5" },
{ "hex.builtin.hash.sha1", "SHA1" },
{ "hex.builtin.hash.sha224", "SHA224" },
{ "hex.builtin.hash.sha256", "SHA256" },
{ "hex.builtin.hash.sha384", "SHA384" },
{ "hex.builtin.hash.sha512", "SHA512" },
{ "hex.builtin.hash.crc8", "CRC8" },
{ "hex.builtin.hash.crc16", "CRC16" },
{ "hex.builtin.hash.crc32", "CRC32" },
{ "hex.builtin.hash.crc.poly", "Polynomial" },
{ "hex.builtin.hash.crc.iv", "Initial Value" },
{ "hex.builtin.hash.crc.xor_out", "XOR Out" },
{ "hex.builtin.hash.crc.refl_in", "Reflect In" },
{ "hex.builtin.hash.crc.refl_out", "Reflect Out" },
});
}

View File

@@ -80,7 +80,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.common.open", "Apri" },
{ "hex.builtin.common.browse", "Esplora..." },
{ "hex.builtin.common.choose_file", "Scegli file" },
//{ "hex.common.processing", "Processing" },
//{ "hex.builtin.common.processing", "Processing" },
{ "hex.builtin.popup.exit_application.title", "Uscire dall'applicazione?" },
{ "hex.builtin.popup.exit_application.desc", "Hai delle modifiche non salvate nel tuo progetto.\nSei sicuro di voler uscire?" },
@@ -216,11 +216,15 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.disassembler.disassembly.bytes", "Byte" },
{ "hex.builtin.view.hashes.name", "Hash" },
{ "hex.builtin.view.hashes.settings", "Impostazioni" },
{ "hex.builtin.view.hashes.hash", "Hash" },
//{ "hex.builtin.view.hashes.no_settings", "No settings available" },
{ "hex.builtin.view.hashes.function", "Funzioni di Hash" },
{ "hex.builtin.view.hashes.iv", "Valore Iniziale" },
{ "hex.builtin.view.hashes.poly", "Polinomio" },
//{ "hex.builtin.view.hashes.name", "Name" },
//{ "hex.builtin.view.hashes.type", "Type" },
{ "hex.builtin.view.hashes.result", "Risultato" },
//{ "hex.builtin.view.hashes.remove", "Remove hash" },
//{ "hex.builtin.view.hashes.hover_info", "Hover over the Hex Editor selection and hold down SHIFT to view the hashes of that region." },
{ "hex.builtin.view.help.name", "Aiuto" },
{ "hex.builtin.view.help.about.name", "Riguardo ImHex" },
@@ -334,6 +338,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.strings.copy", "Copia stringa" },
{ "hex.builtin.view.strings.demangle", "Demangle" },
{ "hex.builtin.view.strings.min_length", "Lunghezza minima" },
//{ "hex.builtin.view.strings.regex", "Regex" },
{ "hex.builtin.view.strings.filter", "Filtro" },
{ "hex.builtin.view.strings.extract", "Estrai" },
{ "hex.builtin.view.strings.searching", "Sto cercando..." },
@@ -646,6 +651,20 @@ namespace hex::plugin::builtin {
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Impossibile creare file di output" },
{ "hex.builtin.tools.file_tools.combiner.open_input", "Impossibile aprire file di input {0}" },
{ "hex.builtin.tools.file_tools.combiner.success", "File combinato con successo!" },
//{ "hex.builtin.tools.ieee756", "IEEE 756 Floating Point Tester" },
//{ "hex.builtin.tools.ieee756.sign", "Sign" },
//{ "hex.builtin.tools.ieee756.exponent", "Exponent" },
//{ "hex.builtin.tools.ieee756.mantissa", "Mantissa" },
//{ "hex.builtin.tools.ieee756.exponent_size", "Exponent Size" },
//{ "hex.builtin.tools.ieee756.mantissa_size", "Mantissa Size" },
//{ "hex.builtin.tools.ieee756.half_precision", "Half Precision" },
//{ "hex.builtin.tools.ieee756.singe_precision", "Single Precision" },
//{ "hex.builtin.tools.ieee756.double_precision", "Double Precision" },
//{ "hex.builtin.tools.ieee756.type", "Type" },
//{ "hex.builtin.tools.ieee756.formula", "Formula" },
//{ "hex.builtin.tools.ieee756.result.title", "Result" },
//{ "hex.builtin.tools.ieee756.result.float", "Floating Point Result" },
//{ "hex.builtin.tools.ieee756.result.hex", "Hexadecimal Result" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "File recenti" },
@@ -683,6 +702,11 @@ namespace hex::plugin::builtin {
//{ "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.proxy", "Proxy" },
//{ "hex.builtin.setting.proxy.description", "Proxy will take effect on store, wikipedia or any other plugin immediately." },
//{ "hex.builtin.setting.proxy.enable", "Enable Proxy" },
//{ "hex.builtin.setting.proxy.url", "Proxy URL" },
//{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" },
{ "hex.builtin.provider.file.path", "Percorso del File" },
{ "hex.builtin.provider.file.size", "Dimensione" },
@@ -720,6 +744,21 @@ namespace hex::plugin::builtin {
//{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
//{ "hex.builtin.visualizer.hexii", "HexII" },
//{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
{ "hex.builtin.hash.md5", "MD5" },
{ "hex.builtin.hash.sha1", "SHA1" },
{ "hex.builtin.hash.sha224", "SHA224" },
{ "hex.builtin.hash.sha256", "SHA256" },
{ "hex.builtin.hash.sha384", "SHA384" },
{ "hex.builtin.hash.sha512", "SHA512" },
{ "hex.builtin.hash.crc8", "CRC8" },
{ "hex.builtin.hash.crc16", "CRC16" },
{ "hex.builtin.hash.crc32", "CRC32" },
{ "hex.builtin.hash.crc.poly", "Polinomio" },
{ "hex.builtin.hash.crc.iv", "Valore Iniziale" },
//{ "hex.builtin.hash.crc.xor_out", "XOR Out" },
//{ "hex.builtin.hash.crc.refl_in", "Reflect In" },
//{ "hex.builtin.hash.crc.refl_out", "Reflect Out" },
});
}

View File

@@ -80,7 +80,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.common.open", "開く" },
{ "hex.builtin.common.browse", "ファイルを参照..." },
{ "hex.builtin.common.choose_file", "ファイルを選択" },
// { "hex.common.processing", "Processing" },
// { "hex.builtin.common.processing", "Processing" },
{ "hex.builtin.popup.exit_application.title", "アプリケーションを終了しますか?" },
{ "hex.builtin.popup.exit_application.desc", "プロジェクトに保存されていない変更があります。\n終了してもよろしいですか?" },
@@ -218,14 +218,14 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.disassembler.disassembly.bytes", "バイト" },
{ "hex.builtin.view.hashes.name", "ハッシュ" },
{ "hex.builtin.view.hashes.settings", "設定" },
//{ "hex.builtin.view.hashes.hash", "Hash" },
//{ "hex.builtin.view.hashes.no_settings", "No settings available" },
{ "hex.builtin.view.hashes.function", "ハッシュ関数" },
{ "hex.builtin.view.hashes.iv", "初期値" },
{ "hex.builtin.view.hashes.xorout", "最終XOR値" },
{ "hex.builtin.common.reflectIn", "入力を反映" },
{ "hex.builtin.common.reflectOut", "出力を反映" },
{ "hex.builtin.view.hashes.poly", "多項式" },
//{ "hex.builtin.view.hashes.name", "Name" },
//{ "hex.builtin.view.hashes.type", "Type" },
{ "hex.builtin.view.hashes.result", "結果" },
//{ "hex.builtin.view.hashes.remove", "Remove hash" },
//{ "hex.builtin.view.hashes.hover_info", "Hover over the Hex Editor selection and hold down SHIFT to view the hashes of that region." },
{ "hex.builtin.view.help.name", "ヘルプ" },
{ "hex.builtin.view.help.about.name", "このソフトについて" },
@@ -337,6 +337,7 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.strings.copy", "文字列をコピー" },
{ "hex.builtin.view.strings.demangle", "デマングル" },
{ "hex.builtin.view.strings.min_length", "最小の長さ" },
//{ "hex.builtin.view.strings.regex", "Regex" },
{ "hex.builtin.view.strings.filter", "フィルタ" },
{ "hex.builtin.view.strings.extract", "抽出" },
{ "hex.builtin.view.strings.regex_error", "無効な正規表現" },
@@ -646,6 +647,20 @@ namespace hex::plugin::builtin {
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "出力ファイルを作成できませんでした" },
{ "hex.builtin.tools.file_tools.combiner.open_input", "入力ファイル {0} を開けませんでした" },
{ "hex.builtin.tools.file_tools.combiner.success", "ファイルの結合に成功しました!" },
//{ "hex.builtin.tools.ieee756", "IEEE 756 Floating Point Tester" },
//{ "hex.builtin.tools.ieee756.sign", "Sign" },
//{ "hex.builtin.tools.ieee756.exponent", "Exponent" },
//{ "hex.builtin.tools.ieee756.mantissa", "Mantissa" },
//{ "hex.builtin.tools.ieee756.exponent_size", "Exponent Size" },
//{ "hex.builtin.tools.ieee756.mantissa_size", "Mantissa Size" },
//{ "hex.builtin.tools.ieee756.half_precision", "Half Precision" },
//{ "hex.builtin.tools.ieee756.singe_precision", "Single Precision" },
//{ "hex.builtin.tools.ieee756.double_precision", "Double Precision" },
//{ "hex.builtin.tools.ieee756.type", "Type" },
//{ "hex.builtin.tools.ieee756.formula", "Formula" },
//{ "hex.builtin.tools.ieee756.result.title", "Result" },
//{ "hex.builtin.tools.ieee756.result.float", "Floating Point Result" },
//{ "hex.builtin.tools.ieee756.result.hex", "Hexadecimal Result" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "最近開いたファイル" },
@@ -684,6 +699,11 @@ namespace hex::plugin::builtin {
//{ "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.proxy", "Proxy" },
//{ "hex.builtin.setting.proxy.description", "Proxy will take effect on store, wikipedia or any other plugin immediately." },
//{ "hex.builtin.setting.proxy.enable", "Enable Proxy" },
//{ "hex.builtin.setting.proxy.url", "Proxy URL" },
//{ "hex.builtin.setting.proxy.url.tooltip", "http(s):// or socks5:// (e.g., http://127.0.0.1:1080)" },
{ "hex.builtin.provider.file.path", "ファイルパス" },
{ "hex.builtin.provider.file.size", "サイズ" },
@@ -721,6 +741,21 @@ namespace hex::plugin::builtin {
//{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
//{ "hex.builtin.visualizer.hexii", "HexII" },
//{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
{ "hex.builtin.hash.md5", "MD5" },
{ "hex.builtin.hash.sha1", "SHA1" },
{ "hex.builtin.hash.sha224", "SHA224" },
{ "hex.builtin.hash.sha256", "SHA256" },
{ "hex.builtin.hash.sha384", "SHA384" },
{ "hex.builtin.hash.sha512", "SHA512" },
{ "hex.builtin.hash.crc8", "CRC8" },
{ "hex.builtin.hash.crc16", "CRC16" },
{ "hex.builtin.hash.crc32", "CRC32" },
{ "hex.builtin.hash.crc.poly", "多項式" },
{ "hex.builtin.hash.crc.iv", "初期値" },
{ "hex.builtin.hash.crc.xor_out", "最終XOR値" },
{ "hex.builtin.hash.crc.refl_in", "入力を反映" },
{ "hex.builtin.hash.crc.refl_out", "出力を反映" },
});
}

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