Compare commits

...

117 Commits

Author SHA1 Message Date
WerWolv
ee2838bada build: Bumped version to 1.24.2 2022-10-10 20:52:48 +02:00
iTrooz_
4d17265e90 git: Use action to manage ccache + minor fixes (#775)
* use action for ccache + limit cache size

* remove 'prepare cache' step for Windows

* remove libpython from CI

* fix the restore key for MacOS

* remove Rust from CI

* do not pin appimage-builder version since issue with it has been resolved

* use ccache action for CodeQL

* Rebased onto latest master

Co-authored-by: WerWolv <werwolv98@gmail.com>
2022-10-10 20:37:00 +02:00
WerWolv
6a6b860622 patterns: Updated pattern language 2022-10-10 20:33:43 +02:00
WerWolv
e78c452daf fix: Hex editor selection not showing rendering properly 2022-10-10 20:33:34 +02:00
WerWolv
86e33a1ee9 build: Bumped version to 1.24.1 2022-10-10 19:11:30 +02:00
WerWolv
37850ad85a patterns: Updated pattern language 2022-10-10 18:15:11 +02:00
WerWolv
daca49658e ui: Fix highlighting of separator column in hex editor
Fixes #776
2022-10-10 17:26:05 +02:00
WerWolv
6975d7e2cd patterns: Updated pattern language 2022-10-10 16:09:50 +02:00
WerWolv
5b8bed6083 patterns: Updated pattern language 2022-10-10 14:42:13 +02:00
WerWolv
7474aa3e5d fix: New lines in wide string messing up data inspector drawing 2022-10-10 14:41:24 +02:00
WerWolv
c6d2d51d4c ui: Make sure sealed patterns get highlighted properly when selected 2022-10-10 14:40:49 +02:00
WerWolv
9055105627 fix: Evaluator not exiting evaluating state correctly on error 2022-10-09 17:31:06 +02:00
WerWolv
a44de63e24 fix: Build failing on Linux 2022-10-09 16:34:53 +02:00
WerWolv
8fc7931132 patterns: Updated pattern language 2022-10-09 15:56:41 +02:00
WerWolv
4070833229 ui: Highlight selected patterns in pattern data view 2022-10-09 15:56:26 +02:00
WerWolv
3a9c3f939e sys: Properly center hex view around selection when jumping 2022-10-09 14:47:38 +02:00
WerWolv
aa42fb5076 patterns: Updated pattern language 2022-10-08 16:28:49 +02:00
WerWolv
50158a7977 sys: Fixed hex editor scrolling issues 2022-10-08 16:23:15 +02:00
WerWolv
f2ded359d8 build: Bumped version to 1.24.0 2022-10-08 10:03:47 +02:00
WerWolv
0e358bbefe patterns: Updated pattern language 2022-10-08 10:00:57 +02:00
WerWolv
2cea561468 ui: Make sure modified bytes are correctly highlighted 2022-10-08 10:00:37 +02:00
WerWolv
8024b0a186 sys: Improve drag scrolling behaviour in hex editor view 2022-10-07 22:13:25 +02:00
WerWolv
2b135cf7e0 ui: Limit maximum length of data displayed in pattern tooltip 2022-10-07 16:27:29 +02:00
WerWolv
ce8c64a679 ui: Make sure ASCII cell content in hex editor is always centered 2022-10-07 16:18:09 +02:00
WerWolv
f0da6ec82f fix: Crash on exit when ImHex is launched through the terminal 2022-10-07 15:35:26 +02:00
WerWolv
46e3b9b5d6 build: Fixed macOS build instructions 2022-10-07 13:20:29 +02:00
WerWolv
d5a08ae568 patterns: Updated pattern language 2022-10-07 13:17:47 +02:00
WerWolv
11f63f9b02 ui: Added optional byte cell and char cell padding
Closes #771
2022-10-07 11:28:44 +02:00
WerWolv
5694eaba8c feat: Added palette to bookmark color picker
#771
2022-10-07 10:53:08 +02:00
WerWolv
484481f886 fix: Opening files with unicode names through the command line 2022-10-07 10:14:24 +02:00
WerWolv
210106901e sys: Added setting to disable multi-window support 2022-10-06 21:26:24 +02:00
WerWolv
eb247b8607 patterns: Updated pattern language 2022-10-06 21:09:58 +02:00
WerWolv
fb1453d98a lang: Fixed some language strings 2022-10-06 16:55:42 +02:00
WerWolv
b734fb5511 build: Delete system capstone in macOS CI 2022-10-06 15:22:38 +02:00
WerWolv
2cd6cb8814 patterns: Updated pattern language 2022-10-06 14:11:03 +02:00
WerWolv
2a93eab14c ui: Make sure pattern data view doesn't flicker when executing pattern 2022-10-06 13:24:22 +02:00
WerWolv
f039ea68d0 fix: Potential crashes when pasting with no clipboard content 2022-10-06 09:35:18 +02:00
WerWolv
e0c35e0002 fix: Data processor nodes not remembering their positions correctly 2022-10-06 09:14:46 +02:00
WerWolv
5ace199dc4 fix: Foreground tasks not being cancellable 2022-10-05 21:25:52 +02:00
WerWolv
556895744b build: Disable more bogus stringop warnings 2022-10-05 15:09:41 +02:00
WerWolv
7f2c60b0d7 fix: Race condition with data inspector 2022-10-05 12:02:40 +02:00
WerWolv
7bb9e7ee82 sys: Replaced awful task system with a much more efficient thread pool 2022-10-04 23:37:48 +02:00
WerWolv
26be4c3ac8 patterns: Updated pattern language 2022-10-04 23:37:25 +02:00
WerWolv
b80517ab15 sys: Improved UTF-8 path handling in various places
Fixes #768
2022-10-04 09:10:58 +02:00
WerWolv
b17cd3696c fix: Handling of exceptions that are not being caught 2022-10-03 10:36:19 +02:00
WerWolv
accd554600 sys: Reduce compile time on Windows a bit 2022-10-02 20:35:38 +02:00
WerWolv
8bf586cfa9 patterns: Fixed bitfield order not resetting correctly
Fixes #756
2022-10-02 19:20:35 +02:00
VocalFan
ebea409e6a build: Fix deprecated MAINTAINER flag in DockerFile (#767) 2022-10-02 17:53:37 +02:00
Nik
6fdba3d555 build: Remove terrible clang-format files (#766) 2022-10-02 17:35:02 +02:00
Nik
e865883611 git: Remove msi signing again since Microsoft doesn't care at all (#765) 2022-10-02 17:31:40 +02:00
Nik
9c484e7b57 fix: Various clang / clang-tidy warnings (#764) 2022-10-02 17:30:26 +02:00
WerWolv
b365e16cc9 fix: Multiple issues with the calculator 2022-10-02 14:18:56 +02:00
WerWolv
6a07a2f85d feat: Look for custom inspector entries in imhex/scripts/inspectors 2022-10-02 14:18:40 +02:00
xtexChooser
0fd7461266 lang: Updated Chinese(Simplified) translations (#762) 2022-10-02 11:32:06 +02:00
Marcelo Conceição
62eb0ccd1d fix: Bad optional access when inspectors.hexpat is missing (#761) 2022-10-02 10:28:37 +02:00
WerWolv
3367237da3 feat: Added very primitive support for adding custom data inspector entries 2022-10-01 23:16:55 +02:00
WerWolv
3504987ab3 sys: Fix OpenGL clear color 2022-10-01 21:14:49 +02:00
Aniruddha Deb
554e625bda build: Make local includes take priority over system includes (#759) 2022-10-01 11:02:59 +02:00
WerWolv
84530e0817 patterns: Added demangle function 2022-09-30 12:49:49 +02:00
WerWolv
663fb88367 sys: Various cleanup 2022-09-30 12:49:28 +02:00
WerWolv
4d99c4b59d patterns: Updated pattern language 2022-09-30 12:45:43 +02:00
WerWolv
12ee235380 fix: Hardcoded colors used in ASCII table
Fixes #757
2022-09-29 20:46:50 +02:00
WerWolv
e30ed35d69 build: Make sure windows plugin romfs folder sticks around 2022-09-29 10:57:02 +02:00
WerWolv
e2f8c7d989 build: Enable PIC for romfs libraries 2022-09-29 10:47:34 +02:00
WerWolv
ca6a8a7a46 sys: Move resources into their relevant subprojects 2022-09-29 10:33:39 +02:00
WerWolv
f52dae4297 feat: Added Edit -> Jump to option to jump to selected address 2022-09-28 22:36:43 +02:00
WerWolv
d643f8f8f7 feat: Allow bookmarks to be reordered
Closes #750
2022-09-28 21:40:31 +02:00
WerWolv
08a12dd2b0 fix: Crash when dragging the mouse onto the hex view 2022-09-28 21:39:46 +02:00
WerWolv
b33dd5d4f5 lang: Added localization for float 16 visualizer 2022-09-28 18:33:11 +02:00
WerWolv
e797ac3a57 feat: Added Float16 data visualizer
Closes #749
2022-09-28 18:30:41 +02:00
WerWolv
8bd31f6375 fix: Crash when hex editor visualizer size is not divisible by row count 2022-09-28 18:29:56 +02:00
WerWolv
d3f83e63c9 build: Properly install llvm dependency on macOS 2022-09-28 16:21:17 +02:00
WerWolv
b450f4797e feat: Added wide string to data inspector 2022-09-28 16:10:40 +02:00
WerWolv
0552084673 patterns: Updated pattern language 2022-09-28 15:41:57 +02:00
WerWolv
d021e2b362 fix: Make sure correct close function gets called 2022-09-28 15:02:55 +02:00
WerWolv
c769e9cc32 ui: Highlight modified bytes in red 2022-09-28 15:01:43 +02:00
WerWolv
639390115b sys: Allow file inspector to read bytes over the page boundary
Fixes #751
2022-09-26 11:53:29 +02:00
WerWolv
ceaf80a186 sys: Don't keep files open in File Provider
Closes #752
2022-09-26 11:49:35 +02:00
WerWolv
86274b8b94 patterns: Updated pattern language 2022-09-23 21:33:55 +02:00
WerWolv
669427eb24 patterns: Updated pattern language 2022-09-23 21:20:52 +02:00
WerWolv
5ba22e7554 patterns: Updated pattern language 2022-09-23 20:50:55 +02:00
WerWolv
65ad88eed9 patterns: Updated pattern language 2022-09-22 09:05:32 +02:00
WerWolv
e34703ea5a fix: Saving and loading projects not working correctly 2022-09-22 09:05:09 +02:00
WerWolv
55bd2c6da6 git: Add code signing for Windows installer 2022-09-21 21:24:47 +02:00
WerWolv
96b5221c1d patterns: Updated pattern language 2022-09-21 11:55:47 +02:00
iTrooz_
3a94be9abb ux: Display an error message if file picker can't be opened (#748)
* add error message for the file picker

* set a different message for Windows/MacOS

* fix typos

* Moved file dialog error handling to a callback function

Co-authored-by: Nik <werwolv98@gmail.com>
2022-09-20 15:47:59 +02:00
WerWolv
9656b40d53 fix: Clearing custom font path not updating setting correctly 2022-09-20 15:47:28 +02:00
WerWolv
7e61b513f3 patterns: Fixed highlighting of arrays of arrays 2022-09-20 15:42:07 +02:00
WerWolv
1d4cbbe418 ux: Handle project loading errors better 2022-09-20 15:33:36 +02:00
WerWolv
e0e2996e25 fix: Custom fonts not being loaded 2022-09-20 14:09:41 +02:00
WerWolv
a102f5fcbf sys: Updated a bunch of dependencies 2022-09-19 23:21:59 +02:00
WerWolv
4e5d56e2c0 fix: Files opened by the file provider appearing locked for other applications 2022-09-19 23:07:44 +02:00
WerWolv
a55177edfa fix: Curl SSL context not being thread safe in the slightest 2022-09-19 21:56:43 +02:00
WerWolv
4c01a749de sys: Improved startup time by running startup tasks in parallel 2022-09-19 16:54:19 +02:00
WerWolv
7b61268f22 ux: Reduce file loading time to basically zero 2022-09-19 16:09:22 +02:00
WerWolv
b11dbe4fe1 fix: Build failing on macOS 2022-09-19 15:26:25 +02:00
WerWolv
6dbff81f95 ui: Added chunk type information to pattern data view 2022-09-19 14:21:36 +02:00
WerWolv
9893e7a965 ui: Display array patterns in pattern data view in chunks of 512 entries 2022-09-19 14:16:23 +02:00
WerWolv
814c595c12 ui: Added functionality icons to most text input fields 2022-09-19 11:29:51 +02:00
WerWolv
f8b4d04713 feat: Added numeric value search to find view 2022-09-19 10:34:57 +02:00
WerWolv
3cdc8c5884 fix: OpenGL textures not being cleaned up correctly 2022-09-18 20:38:45 +02:00
suetake
5eabc05396 git: Fix broken link in install guide (#744) 2022-09-18 16:26:44 +02:00
WerWolv
b2932773b9 feat: Added unique selection and scrolling position to each provider 2022-09-18 16:22:08 +02:00
WerWolv
59a04e6dbf fix: Copy-As python array having a semicolon at the end 2022-09-18 15:05:56 +02:00
Nik
ddf1e8a179 git: Embed font into banner logo 2022-09-17 17:23:49 +02:00
WerWolv
17cc87d633 git: Make sure readme logo has the same font everywhere 2022-09-17 16:43:06 +02:00
WerWolv
fd7beb642f build: Bumped version to 1.23.2 2022-09-17 15:49:19 +02:00
WerWolv
b766cf0807 patterns: Updated pattern language 2022-09-17 15:48:12 +02:00
Nik
6c9469961b git: Added flatpak link to install guide 2022-09-17 13:35:54 +02:00
WerWolv
d8844236d0 git: Added install guide file, cleaned up readme 2022-09-17 10:38:02 +02:00
WerWolv
60eb59c605 build: Bumped version to 1.23.1 2022-09-17 09:00:39 +02:00
WerWolv
6a7bbb8752 fix: Crash on some Linux systems when opening files 2022-09-17 08:55:18 +02:00
WerWolv
e4431749e1 patterns: Updated pattern language 2022-09-16 15:12:12 +02:00
WerWolv
c587b357eb patterns: Updated pattern language 2022-09-16 10:52:49 +02:00
WerWolv
7357c26d54 ux: Pre-fill remove popup size value with current selection size 2022-09-16 08:33:18 +02:00
WerWolv
73ca45ad3d git: Updated winget-create to the latest release 2022-09-16 08:30:42 +02:00
WerWolv
bf00503d1f fix: BufferedReader messing up the second to last byte 2022-09-16 08:30:28 +02:00
129 changed files with 2484 additions and 1338 deletions

View File

@@ -1,178 +0,0 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: false
AlignArrayOfStructures: Left
AlignConsecutiveMacros: Consecutive
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: AcrossEmptyLinesAndComments
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: false
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: AfterComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 0
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: true
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: true
IndentGotoLabels: true
IndentPPDirectives: BeforeHash
IndentExternBlock: Indent
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Right
PPIndentWidth: 4
ReferenceAlignment: Pointer
ReflowComments: true
ShortNamespaceLines: 5
SortIncludes: Never
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 4
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

View File

@@ -25,14 +25,13 @@ jobs:
with:
languages: 'cpp'
- name: 📜 Restore ccache
uses: actions/cache@v3
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
path: |
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:

View File

@@ -28,21 +28,13 @@ jobs:
with:
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
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
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
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
@@ -64,43 +56,40 @@ jobs:
glfw:p
file:p
mbedtls:p
python:p
freetype:p
dlfcn:p
- name: ⬇️ Install dependencies
run: |
curl --proto '=https' --tlsv1.2 -sSf https://win.rustup.rs > rustup-init.exe
./rustup-init.exe -y --default-host=x86_64-pc-windows-gnu --default-toolchain=none
rm rustup-init.exe
$USERPROFILE/.cargo/bin/rustup.exe target add x86_64-pc-windows-gnu
$USERPROFILE/.cargo/bin/rustup.exe default nightly
# Windows cmake build
- name: 🛠️ Build
run: |
mkdir -p build
cd build
# Get path to mingw python library
PYTHON_LIB_NAME=$(pkg-config --libs-only-l python3 | sed 's/^-l//' | sed 's/ //')
PYTHON_LIB_PATH=$(cygpath -m $(which lib${PYTHON_LIB_NAME}.dll))
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \
-DPython_LIBRARY="$PYTHON_LIB_PATH" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
..
mingw32-make -j4 install
cpack
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
#- name: 🗝️ Sign Windows Installer
# if: github.event_name == 'push' && github.ref == 'refs/heads/master'
# shell: powershell
# env:
# WIN_SIGN_CERT: ${{ secrets.WIN_SIGN_CERT }}
# WIN_SIGN_PW: ${{ secrets.WIN_SIGN_PW }}
# run: |
# $buffer = [System.Convert]::FromBase64String($env:WIN_SIGN_CERT)
# $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($buffer, $env:WIN_SIGN_PW)
# Get-ChildItem -Path ./build -Filter *.msi -Recurse | Set-AuthenticodeSignature -HashAlgorithm SHA256 -Certificate $certificate -TimestampServer http://timestamp.digicert.com
- name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v3
with:
@@ -155,13 +144,12 @@ jobs:
run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
- name: 📜 Restore ccache
uses: actions/cache@v3
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
path: |
~/Library/Caches/ccache
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
restore-keys: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
@@ -174,6 +162,7 @@ jobs:
- name: ⬇️ Install dependencies
run: |
brew bundle --no-lock --file dist/Brewfile
rm -rf /usr/local/Cellar/capstone
- name: ⬇️ Install classic glfw
if: ${{! matrix.custom_glfw}}
@@ -248,13 +237,12 @@ jobs:
with:
submodules: recursive
- name: 📜 Restore ccache
uses: actions/cache@v3
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
path: |
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore other caches
uses: actions/cache@v3
@@ -278,14 +266,7 @@ jobs:
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
sudo chmod +x /usr/local/bin/appimagetool
sudo pip3 install appimage-builder==1.0.0
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
sh rustup-init.sh -y --default-toolchain none
rm rustup-init.sh
$HOME/.cargo/bin/rustup install nightly
$HOME/.cargo/bin/rustup target add x86_64-unknown-linux-gnu
$HOME/.cargo/bin/rustup default nightly
sudo pip3 install appimage-builder
# Ubuntu cmake build
- name: 🛠️ Build
@@ -299,7 +280,6 @@ jobs:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DRUST_PATH="$HOME/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
..
make -j 4 install DESTDIR=DebDir
@@ -335,7 +315,6 @@ jobs:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DRUST_PATH="$HOME/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_PLUGINS_IN_SHARE=ON \
-DIMHEX_USE_BUNDLED_CA=ON \
@@ -400,13 +379,12 @@ jobs:
run: |
dist/get_deps_archlinux.sh --noconfirm
- name: 📜 Restore ccache
uses: actions/cache@v3
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
path: |
~/.cache/ccache
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
@@ -502,7 +480,6 @@ jobs:
libcurl-devel \
llvm-devel \
mbedtls-devel \
python3-devel \
rpm-build \
yara-devel
@@ -515,13 +492,12 @@ jobs:
run: |
dist/get_deps_fedora.sh
- name: 📜 Restore ccache
uses: actions/cache@v3
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
path: |
~/.cache/ccache
key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Set version variable
run: |

View File

@@ -133,7 +133,7 @@ jobs:
- name: ⬇️ Download dependencies
shell: pwsh
run: |
iwr https://github.com/microsoft/winget-create/releases/download/v1.0.4.0/wingetcreate.exe -OutFile wingetcreate.exe
iwr https://github.com/microsoft/winget-create/releases/download/v1.1.2.0/wingetcreate.exe -OutFile wingetcreate.exe
- name: ⬆️ Update winget manifest
shell: pwsh
env:

View File

@@ -22,13 +22,12 @@ jobs:
with:
submodules: recursive
- name: 📜 Restore ccache
uses: actions/cache@v3
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
path: |
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache

View File

@@ -11,6 +11,7 @@ option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler"
# Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")

52
INSTALL.md Normal file
View File

@@ -0,0 +1,52 @@
# Installing ImHex
## Official Releases
The easiest way to install ImHex is to download the latest release from the [GitHub releases page](github.com/WerWolv/ImHex/releases/latest).
There's also a NoGPU version available for users who don't have a GPU or want to run ImHex in a VM without GPU passthrough.
## Nighly Builds
The GitHub Actions CI builds a new release package on every commit made to repository. These builds are available on the [GitHub Actions page](https://github.com/WerWolv/ImHex/actions?query=workflow%3A%22Build%22).
These builds are not guaranteed to be stable and may contain bugs, however they also contain new features that are not yet available in the official releases.
## Building from source
Build instructions for Windows, Linux and macOS can be found under `/dist/compiling`:
- Windows: [Link](dist/compiling/windows.md)
- macOS: [Link](dist/compiling/macOS.md)
- Linux: [Link](dist/compiling/linux.md)
## Package managers
ImHex is also available on various package managers. The officially supported ones are listed here:
### Windows
- **Cocolatey**
- [imhex](https://community.chocolatey.org/packages/imhex) (Thanks to @Jarcho)
- `choco install imhex`
- **winget**
- [WerWolv.ImHex](https://github.com/microsoft/winget-pkgs/tree/master/manifests/w/WerWolv/ImHex)
- `winget install WerWolv.ImHex`
### Linux
- **Arch Linux AUR**
- [imhex-bin](https://aur.archlinux.org/packages/imhex-bin/) (Thanks to @iTrooz)
- `yay -S imhex-bin`
- [imhex](https://aur.archlinux.org/packages/imhex/) (Thanks to @KokaKiwi)
- `yay -S imhex`
- **Fedora**
- [imhex](https://src.fedoraproject.org/rpms/imhex/) (Thanks to @jonathanspw)
- `dnf install imhex`
- **Flatpak**
- [net.werwolv.Imhex](https://flathub.org/apps/details/net.werwolv.ImHex) (Thanks to @Mailaender)
- `flatpak install flathub net.werwolv.ImHex`
### Available on other package managers
Packages that aren't explicitly mentioned above are not officially supported but they will most likely still work.
Contact the maintainer of the package if you have any issues.
[![Packaging status](https://repology.org/badge/vertical-allrepos/imhex.svg)](https://repology.org/project/imhex/versions)

View File

@@ -104,7 +104,11 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
## Pattern Language
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
The Pattern Language is the completely custom programming language developed for ImHex.
It allows you to define structures and data types in a C-like syntax and then use them to parse and highlight a file's content.
- Source Code: [Link](https://github.com/WerWolv/PatternLanguage/)
- Documentation: [Link](https://imhex.werwolv.net/docs/)
## Database
@@ -122,47 +126,9 @@ To use ImHex, the following minimal system requirements need to be met:
- **RAM**: 512MB, more may be required for more complicated analysis
- **Storage**: 100MB
## Plugin development
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
## Installing
The following OSs have packages available in their repositories making it easy to install ImHex.
### Fedora (36+)
```
dnf install imhex
```
### RHEL 9 / AlmaLinux 9 (coming soon)
### Arch Linux (AUR)
```
yay -S imhex-bin
```
## Third Party Repositories
ImHex is available in various thid party repositores.
[![Packaging status](https://repology.org/badge/vertical-allrepos/imhex.svg)](https://repology.org/project/imhex/versions)
## Nightly builds
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
- Windows • __x86_64__
- [Installer](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
- [Portable](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable.zip)
- MacOS • __x86_64__
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
- Linux • __x86_64__
- [Ubuntu 22.04 DEB](https://nightly.link/WerWolv/ImHex/workflows/build/master/Ubuntu%2022.04%20DEB.zip)
- [AppImage](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20AppImage.zip)
- [Arch Package](https://nightly.link/WerWolv/ImHex/workflows/build/master/ArchLinux%20.pkg.tar.zst.zip)
- [Fedora Rawhide RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Rawhide%20RPM.zip)
- [Fedora Stable RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Latest%20RPM.zip)
Information on how to install ImHex can be found in the [Install](/INSTALL.md) guide
## Compiling
@@ -173,6 +139,15 @@ All releases are being built using latest available GCC.
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 more information, check out the [Compiling](/dist/compiling) guide.
## Plugin development
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
## Credits
### Contributors

View File

@@ -1 +1 @@
1.23.0
1.24.2

View File

@@ -408,7 +408,7 @@ endfunction()
macro(setupCompilerWarnings target)
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Werror")
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread")
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")

1
dist/Brewfile vendored
View File

@@ -7,3 +7,4 @@ brew "freetype2"
brew "libmagic"
brew "pkg-config"
brew "gcc@12"
brew "llvm"

4
dist/Dockerfile vendored
View File

@@ -1,6 +1,6 @@
FROM archlinux:latest
MAINTAINER WerWolv "hey@werwolv.net"
LABEL maintainer="hey@werwolv.net" = WerWolv
# Install dependencies
RUN pacman -Syy --needed --noconfirm
@@ -25,4 +25,4 @@ RUN git clone https://github.com/WerWolv/ImHex --recurse-submodules /root/ImHex
RUN mkdir /root/ImHex/build
WORKDIR /root/ImHex/build
RUN cmake .. && make -j
WORKDIR /root/ImHex
WORKDIR /root/ImHex

View File

@@ -16,7 +16,7 @@ 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 \
-DCMAKE_BUILD_TYPE=Release \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \

View File

@@ -164,7 +164,10 @@ static void ImGui_ImplGlfw_ShutdownPlatformInterface();
// Functions
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
{
return glfwGetClipboardString((GLFWwindow*)user_data);
// IMHEX PATCH BEGIN
const char *data = glfwGetClipboardString((GLFWwindow*)user_data);
return data == nullptr ? "" : data;
// IMHEX PATCH END
}
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
@@ -179,12 +182,12 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
ImGuiContext& g = *GImGui;
g.ClipboardHandlerData.clear();
if (!::OpenClipboard(NULL))
return NULL;
return "";
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
if (wbuf_handle == NULL)
{
::CloseClipboard();
return NULL;
return "";
}
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
{
@@ -194,7 +197,7 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
}
::GlobalUnlock(wbuf_handle);
::CloseClipboard();
return g.ClipboardHandlerData.Data;
return g.ClipboardHandlerData.Data == nullptr ? "" : g.ClipboardHandlerData.Data;
}
static void ImGui_ImplWin_SetClipboardText(void*, const char* text)

View File

@@ -11,8 +11,9 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/microtar ${CMAKE_CURREN
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(LIBROMFS_RESOURCE_LOCATION ${IMHEX_BASE_FOLDER}/resources/romfs)
set(LIBROMFS_PROJECT_NAME imhex)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/external/libromfs EXCLUDE_FROM_ALL)
set_target_properties(libromfs PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/intervaltree ${CMAKE_CURRENT_BINARY_DIR}/external/intervaltree EXCLUDE_FROM_ALL)
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
@@ -136,6 +137,7 @@ set(LIBIMHEX_SOURCES
source/helpers/encoding_file.cpp
source/helpers/logger.cpp
source/helpers/tar.cpp
source/helpers/types.cpp
source/providers/provider.cpp
@@ -172,4 +174,5 @@ if (APPLE)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl intervaltree)
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libpl intervaltree)
target_link_libraries(libimhex PRIVATE libromfs-imhex)

View File

@@ -1,8 +1,5 @@
#pragma once
#include <cstdint>
#include <cstddef>
#include <hex/helpers/types.hpp>
#include <hex/helpers/intrinsics.hpp>

View File

@@ -20,10 +20,6 @@
using ImGuiDataType = int;
using ImGuiInputTextFlags = int;
namespace pl {
class Evaluator;
}
namespace hex {
class View;
@@ -61,7 +57,7 @@ namespace hex {
return name < other.name;
}
operator const std::string &() const {
explicit operator const std::string &() const {
return name;
}
};
@@ -435,7 +431,7 @@ namespace hex {
class Hash {
public:
Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
explicit Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
class Function {
public:
@@ -498,6 +494,6 @@ namespace hex {
}
}
};
}
}

View File

@@ -66,7 +66,7 @@ namespace hex {
namespace impl {
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t)>;
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
std::map<u32, Highlighting> &getBackgroundHighlights();
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions();
@@ -171,6 +171,8 @@ namespace hex {
void setGPUVendor(const std::string &vendor);
void setPortableVersion(bool enabled);
void addInitArgument(const std::string &key, const std::string &value = { });
}
struct ProgramArguments {
@@ -186,6 +188,7 @@ namespace hex {
};
const ProgramArguments &getProgramArguments();
std::optional<std::u8string> getProgramArgument(int index);
float getTargetFPS();
void setTargetFPS(float fps);

View File

@@ -19,12 +19,14 @@ namespace hex {
struct Handler {
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
std::fs::path basePath;
bool required;
Function load, store;
};
struct ProviderHandler {
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
std::fs::path basePath;
bool required;
Function load, store;
};

View File

@@ -10,6 +10,7 @@
#include <chrono>
#include <memory>
#include <list>
#include <condition_variable>
namespace hex {
@@ -19,7 +20,7 @@ namespace hex {
class Task {
public:
Task() = default;
Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function);
Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
Task(const Task&) = delete;
Task(Task &&other) noexcept;
@@ -28,6 +29,7 @@ namespace hex {
void update(u64 value = 0);
void setMaxValue(u64 value);
[[nodiscard]] bool isBackgroundTask() const;
[[nodiscard]] bool isFinished() const;
[[nodiscard]] bool hadException() const;
[[nodiscard]] bool wasInterrupted() const;
@@ -51,15 +53,16 @@ namespace hex {
mutable std::mutex m_mutex;
std::string m_unlocalizedName;
u64 m_currValue, m_maxValue;
std::thread m_thread;
std::atomic<u64> m_currValue = 0, m_maxValue = 0;
std::function<void()> m_interruptCallback;
std::function<void(Task &)> m_function;
bool m_shouldInterrupt = false;
std::atomic<bool> m_shouldInterrupt = false;
std::atomic<bool> m_background = true;
bool m_interrupted = false;
bool m_finished = false;
bool m_hadException = false;
std::atomic<bool> m_interrupted = false;
std::atomic<bool> m_finished = false;
std::atomic<bool> m_hadException = false;
std::string m_exceptionMessage;
struct TaskInterruptor { virtual ~TaskInterruptor() = default; };
@@ -86,9 +89,14 @@ namespace hex {
public:
TaskManager() = delete;
static void init();
static void exit();
constexpr static auto NoProgress = 0;
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
static void collectGarbage();
static size_t getRunningTaskCount();
@@ -100,7 +108,14 @@ namespace hex {
static std::mutex s_deferredCallsMutex;
static std::list<std::shared_ptr<Task>> s_tasks;
static std::list<std::shared_ptr<Task>> s_taskQueue;
static std::list<std::function<void()>> s_deferredCalls;
static std::mutex s_queueMutex;
static std::condition_variable s_jobCondVar;
static std::vector<std::jthread> s_workers;
static void runner(const std::stop_token &stopToken);
};
}

View File

@@ -27,32 +27,32 @@ namespace hex::dp {
Attribute(IOType ioType, Type type, std::string unlocalizedName);
~Attribute();
[[nodiscard]] u32 getId() const { return this->m_id; }
void setId(u32 id) { this->m_id = id; }
[[nodiscard]] int getId() const { return this->m_id; }
void setId(int id) { this->m_id = id; }
[[nodiscard]] IOType getIOType() const { return this->m_ioType; }
[[nodiscard]] Type getType() const { return this->m_type; }
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
void addConnectedAttribute(u32 linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
void removeConnectedAttribute(u32 linkId) { this->m_connectedAttributes.erase(linkId); }
[[nodiscard]] std::map<u32, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
void addConnectedAttribute(int linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
[[nodiscard]] Node *getParentNode() { return this->m_parentNode; }
[[nodiscard]] std::optional<std::vector<u8>> &getOutputData() { return this->m_outputData; }
static void setIdCounter(u32 id) {
static void setIdCounter(int id) {
if (id > Attribute::s_idCounter)
Attribute::s_idCounter = id;
}
private:
u32 m_id;
int m_id;
IOType m_ioType;
Type m_type;
std::string m_unlocalizedName;
std::map<u32, Attribute *> m_connectedAttributes;
std::map<int, Attribute *> m_connectedAttributes;
Node *m_parentNode = nullptr;
std::optional<std::vector<u8>> m_outputData;
@@ -60,7 +60,7 @@ namespace hex::dp {
friend class Node;
void setParentNode(Node *node) { this->m_parentNode = node; }
static u32 s_idCounter;
static int s_idCounter;
};
}

View File

@@ -6,24 +6,24 @@ namespace hex::dp {
class Link {
public:
Link(u32 from, u32 to);
Link(int from, int to);
[[nodiscard]] u32 getId() const { return this->m_id; }
void setID(u32 id) { this->m_id = id; }
[[nodiscard]] int getId() const { return this->m_id; }
void setID(int id) { this->m_id = id; }
[[nodiscard]] u32 getFromId() const { return this->m_from; }
[[nodiscard]] u32 getToId() const { return this->m_to; }
[[nodiscard]] int getFromId() const { return this->m_from; }
[[nodiscard]] int getToId() const { return this->m_to; }
static void setIdCounter(u32 id) {
static void setIdCounter(int id) {
if (id > Link::s_idCounter)
Link::s_idCounter = id;
}
private:
u32 m_id;
u32 m_from, m_to;
int m_id;
int m_from, m_to;
static u32 s_idCounter;
static int s_idCounter;
};
}

View File

@@ -9,6 +9,7 @@
#include <vector>
#include <nlohmann/json_fwd.hpp>
#include <imgui.h>
namespace hex::prv {
class Provider;
@@ -23,8 +24,8 @@ namespace hex::dp {
virtual ~Node() = default;
[[nodiscard]] u32 getId() const { return this->m_id; }
void setId(u32 id) { this->m_id = id; }
[[nodiscard]] int getId() const { return this->m_id; }
void setId(int id) { this->m_id = id; }
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
@@ -56,19 +57,28 @@ namespace hex::dp {
this->m_processedInputs.clear();
}
static void setIdCounter(u32 id) {
void setPosition(ImVec2 pos) {
this->m_position = pos;
}
[[nodiscard]] ImVec2 getPosition() const {
return this->m_position;
}
static void setIdCounter(int id) {
if (id > Node::s_idCounter)
Node::s_idCounter = id;
}
private:
u32 m_id;
int m_id;
std::string m_unlocalizedTitle, m_unlocalizedName;
std::vector<Attribute> m_attributes;
std::set<u32> m_processedInputs;
prv::Overlay *m_overlay = nullptr;
ImVec2 m_position;
static u32 s_idCounter;
static int s_idCounter;
Attribute *getConnectedInputAttribute(u32 index) {
if (index >= this->getAttributes().size())

View File

@@ -1,5 +1,7 @@
#pragma once
#include <hex.hpp>
#include <optional>
#include <string>
#include <vector>
@@ -66,7 +68,7 @@ namespace hex::fs {
}
static inline bool isSubPath(const std::fs::path& base, const std::fs::path& destination) {
const auto relative = std::fs::relative(destination, base).string();
const auto relative = std::fs::relative(destination, base).u8string();
return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.');
}
@@ -75,18 +77,17 @@ namespace hex::fs {
std::fs::path toShortPath(const std::fs::path &path);
enum class DialogMode
{
enum class DialogMode {
Open,
Save,
Folder
};
void setFileBrowserErrorCallback(const std::function<void()> &callback);
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {});
enum class ImHexPath
{
Patterns,
enum class ImHexPath : u32 {
Patterns = 0,
PatternsInclude,
Magic,
Python,
@@ -97,7 +98,11 @@ namespace hex::fs {
Constants,
Encodings,
Logs,
Recent
Recent,
Scripts,
Inspectors,
END
};
std::optional<std::fs::path> getExecutablePath();

View File

@@ -3,6 +3,7 @@
#include <hex.hpp>
#include <chrono>
#include <mutex>
#include <fmt/core.h>
#include <fmt/color.h>
@@ -30,6 +31,9 @@ namespace hex::log {
template<typename... T>
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
static std::mutex logMutex;
std::scoped_lock lock(logMutex);
auto dest = getDestination();
printPrefix(dest, ts, level);

View File

@@ -11,6 +11,7 @@
#include <nlohmann/json_fwd.hpp>
#include <curl/system.h>
#include <mbedtls/ssl.h>
#include <hex/helpers/fs.hpp>
@@ -60,6 +61,7 @@ namespace hex {
private:
CURL *m_ctx;
mbedtls_x509_crt m_caCert;
curl_slist *m_headers = nullptr;
std::mutex m_transmissionActive;

View File

@@ -1,5 +1,8 @@
#pragma once
#include <cstddef>
#include <cstdint>
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
@@ -20,29 +23,14 @@ namespace hex {
u64 address;
size_t size;
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress()) && *this != Invalid() && other != Invalid();
}
[[nodiscard]] bool isWithin(const Region &other) const;
[[nodiscard]] bool overlaps(const Region &other) const;
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress()) && *this != Invalid() && other != Invalid();
}
[[nodiscard]] u64 getStartAddress() const;
[[nodiscard]] u64 getEndAddress() const;
[[nodiscard]] size_t getSize() const;
[[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;
}
constexpr bool operator==(const Region &other) const {
return this->address == other.address && this->size == other.size;
}
bool operator==(const Region &other) const;
constexpr static Region Invalid() {
return { 0, 0 };

View File

@@ -27,8 +27,8 @@ struct ImVec2;
namespace hex {
long double operator""_scaled(long double value);
long double operator""_scaled(unsigned long long value);
float operator""_scaled(long double value);
float operator""_scaled(unsigned long long value);
ImVec2 scaled(const ImVec2 &vector);
template<typename T>
@@ -275,6 +275,13 @@ namespace hex {
return iter != a.end();
}
template<typename T> requires requires(T t) { t.u8string(); }
std::string toUTF8String(const T &value) {
auto result = value.u8string();
return { result.begin(), result.end() };
}
template<typename T, typename... VariantTypes>
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
const T *value = std::get_if<T>(&variant);
@@ -297,6 +304,13 @@ namespace hex {
std::optional<std::string> getEnvironmentVariable(const std::string &env);
inline std::string limitStringLength(const std::string &string, size_t maxLength) {
if (string.length() <= maxLength)
return string;
return string.substr(0, maxLength - 3) + "...";
}
namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
@@ -335,7 +349,7 @@ namespace hex {
namespace first_time_exec {
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
template<class F>
class FirstTimeExecute {
@@ -358,7 +372,7 @@ namespace hex {
namespace final_cleanup {
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
template<class F>
class FinalCleanupExecute {

View File

@@ -24,6 +24,9 @@ namespace hex::prv {
}
void setEndAddress(u64 address) {
if (address >= this->m_provider->getActualSize())
address = this->m_provider->getActualSize() - 1;
this->m_endAddress = address;
}
@@ -256,7 +259,7 @@ namespace hex::prv {
private:
void updateBuffer(u64 address, size_t size) {
if (!this->m_bufferValid || address < this->m_bufferAddress || address + size > (this->m_bufferAddress + this->m_buffer.size())) {
const auto remainingBytes = (this->m_endAddress - address) - 1;
const auto remainingBytes = (this->m_endAddress - address) + 1;
if (remainingBytes < this->m_maxBufferSize)
this->m_buffer.resize(remainingBytes);
else

View File

@@ -86,9 +86,8 @@ namespace hex::prv {
virtual void drawLoadInterface();
virtual void drawInterface();
[[nodiscard]] u32 getID() const {
return this->m_id;
}
[[nodiscard]] u32 getID() const;
void setID(u32 id);
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings = { }) const;
virtual void loadSettings(const nlohmann::json &settings);
@@ -98,7 +97,7 @@ namespace hex::prv {
void markDirty(bool dirty = true) { this->m_dirty = dirty; }
[[nodiscard]] bool isDirty() const { return this->m_dirty; }
virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
[[nodiscard]] virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
void skipLoadInterface() { this->m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }

View File

@@ -31,27 +31,40 @@ enum ImGuiCustomCol {
namespace ImGui {
struct Texture {
ImTextureID textureId = nullptr;
int width = 0, height = 0;
class Texture {
public:
Texture() = default;
Texture(const ImU8 *buffer, int size);
explicit Texture(const char *path);
Texture(const Texture&) = delete;
Texture(Texture&& other) noexcept;
[[nodiscard]] constexpr bool valid() const noexcept {
return this->textureId != nullptr;
~Texture();
Texture& operator=(const Texture&) = delete;
Texture& operator=(Texture&& other) noexcept;
[[nodiscard]] constexpr bool isValid() const noexcept {
return this->m_textureId != nullptr;
}
[[nodiscard]] constexpr operator ImTextureID() {
return this->textureId;
return this->m_textureId;
}
[[nodiscard]] auto size() const noexcept {
return ImVec2(this->width, this->height);
[[nodiscard]] auto getSize() const noexcept {
return ImVec2(this->m_width, this->m_height);
}
[[nodiscard]] constexpr auto aspectRatio() const noexcept {
if (this->height == 0) return 1.0F;
[[nodiscard]] constexpr auto getAspectRatio() const noexcept {
if (this->m_height == 0) return 1.0F;
return float(this->width) / float(this->height);
return float(this->m_width) / float(this->m_height);
}
private:
ImTextureID m_textureId = nullptr;
int m_width = 0, m_height = 0;
};
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
@@ -82,10 +95,6 @@ namespace ImGui {
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
}
Texture LoadImageFromPath(const char *path);
Texture LoadImageFromMemory(const ImU8 *buffer, int size);
void UnloadImage(Texture &texture);
void OpenPopupInWindow(const char *window_name, const char *popup_name);
struct ImHexCustomData {
@@ -130,6 +139,7 @@ namespace ImGui {
}
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);

View File

@@ -11,6 +11,12 @@
#include <nlohmann/json.hpp>
#if defined(OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#endif
namespace hex {
namespace ImHexApi::Common {
@@ -247,7 +253,7 @@ namespace hex {
}
bool isValid() {
return !s_providers.empty() && s_currentProvider < i64(s_providers.size());
return !s_providers.empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers.size());
}
void markDirty() {
@@ -385,6 +391,13 @@ namespace hex {
s_portableVersion = enabled;
}
void addInitArgument(const std::string &key, const std::string &value) {
static std::mutex initArgumentsMutex;
std::scoped_lock lock(initArgumentsMutex);
getInitArguments()[key] = value;
}
}
@@ -392,6 +405,21 @@ namespace hex {
return impl::s_programArguments;
}
std::optional<std::u8string> getProgramArgument(int index) {
if (index >= impl::s_programArguments.argc) {
return std::nullopt;
}
#if defined(OS_WINDOWS)
std::wstring wideArg = ::CommandLineToArgvW(::GetCommandLineW(), &impl::s_programArguments.argc)[index];
std::string byteArg = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(wideArg);
return std::u8string(byteArg.begin(), byteArg.end());
#else
return std::u8string(reinterpret_cast<const char8_t *>(impl::s_programArguments.argv[index]));
#endif
}
static float s_targetFPS = 60.0F;

View File

@@ -1,6 +1,7 @@
#include <hex/api/plugin_manager.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
#include <filesystem>
#include <system_error>
@@ -16,7 +17,7 @@ namespace hex {
return;
}
#else
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
this->m_handle = dlopen(hex::toUTF8String(path).c_str(), RTLD_LAZY);
if (this->m_handle == nullptr) {
log::error("dlopen failed: {}!", dlerror());
@@ -68,7 +69,7 @@ namespace hex {
bool Plugin::initializePlugin() const {
const auto requestedVersion = getCompatibleVersion();
if (requestedVersion != IMHEX_VERSION) {
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", this->m_path.filename().string(), requestedVersion);
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", hex::toUTF8String(this->m_path.filename()), requestedVersion);
return false;
}

View File

@@ -36,6 +36,10 @@ namespace hex {
return false;
}
for (const auto &provider : ImHexApi::Provider::getProviders()) {
ImHexApi::Provider::remove(provider);
}
bool result = true;
for (const auto &handler : ProjectFile::getHandlers()) {
try {
@@ -45,6 +49,10 @@ namespace hex {
log::info("{}", e.what());
result = false;
}
if (!result && handler.required) {
return false;
}
}
for (const auto &provider : ImHexApi::Provider::getProviders()) {
@@ -57,12 +65,16 @@ namespace hex {
log::info("{}", e.what());
result = false;
}
if (!result && handler.required) {
return false;
}
}
}
ProjectFile::s_currProjectPath = filePath;
return result;
return true;
}
bool ProjectFile::store(std::optional<std::fs::path> filePath) {

View File

@@ -4,59 +4,46 @@
#include <hex/helpers/logger.hpp>
#include <algorithm>
#include <ranges>
namespace hex {
std::mutex TaskManager::s_deferredCallsMutex;
std::list<std::shared_ptr<Task>> TaskManager::s_tasks;
std::list<std::shared_ptr<Task>> TaskManager::s_tasks, TaskManager::s_taskQueue;
std::list<std::function<void()>> TaskManager::s_deferredCalls;
Task::Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function)
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue) {
this->m_thread = std::thread([this, func = std::move(function)] {
try {
func(*this);
} catch (const TaskInterruptor &) {
this->interruption();
} catch (const std::exception &e) {
log::error("Exception in task {}: {}", this->m_unlocalizedName, e.what());
this->exception(e.what());
} catch (...) {
log::error("Exception in task {}", this->m_unlocalizedName);
this->exception("Unknown Exception");
}
std::mutex TaskManager::s_queueMutex;
std::condition_variable TaskManager::s_jobCondVar;
std::vector<std::jthread> TaskManager::s_workers;
this->finish();
});
}
Task::Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
Task::Task(hex::Task &&other) noexcept {
std::scoped_lock thisLock(this->m_mutex);
std::scoped_lock otherLock(other.m_mutex);
{
std::scoped_lock thisLock(this->m_mutex);
std::scoped_lock otherLock(other.m_mutex);
this->m_thread = std::move(other.m_thread);
this->m_unlocalizedName = std::move(other.m_unlocalizedName);
this->m_function = std::move(other.m_function);
this->m_unlocalizedName = std::move(other.m_unlocalizedName);
}
this->m_maxValue = other.m_maxValue;
this->m_currValue = other.m_currValue;
this->m_maxValue = u64(other.m_maxValue);
this->m_currValue = u64(other.m_currValue);
this->m_finished = other.m_finished;
this->m_hadException = other.m_hadException;
this->m_interrupted = other.m_interrupted;
this->m_shouldInterrupt = other.m_shouldInterrupt;
this->m_finished = bool(other.m_finished);
this->m_hadException = bool(other.m_hadException);
this->m_interrupted = bool(other.m_interrupted);
this->m_shouldInterrupt = bool(other.m_shouldInterrupt);
}
Task::~Task() {
if (!this->isFinished())
this->interrupt();
this->m_thread.join();
}
void Task::update(u64 value) {
std::scoped_lock lock(this->m_mutex);
this->m_currValue = value;
if (this->m_shouldInterrupt)
@@ -64,15 +51,11 @@ namespace hex {
}
void Task::setMaxValue(u64 value) {
std::scoped_lock lock(this->m_mutex);
this->m_maxValue = value;
}
void Task::interrupt() {
std::scoped_lock lock(this->m_mutex);
this->m_shouldInterrupt = true;
if (this->m_interruptCallback)
@@ -83,27 +66,23 @@ namespace hex {
this->m_interruptCallback = std::move(callback);
}
bool Task::isFinished() const {
std::scoped_lock lock(this->m_mutex);
bool Task::isBackgroundTask() const {
return this->m_background;
}
bool Task::isFinished() const {
return this->m_finished;
}
bool Task::hadException() const {
std::scoped_lock lock(this->m_mutex);
return this->m_hadException;
}
bool Task::wasInterrupted() const {
std::scoped_lock lock(this->m_mutex);
return this->m_interrupted;
}
void Task::clearException() {
std::scoped_lock lock(this->m_mutex);
this->m_hadException = false;
}
@@ -126,14 +105,10 @@ namespace hex {
}
void Task::finish() {
std::scoped_lock lock(this->m_mutex);
this->m_finished = true;
}
void Task::interruption() {
std::scoped_lock lock(this->m_mutex);
this->m_interrupted = true;
}
@@ -146,30 +121,112 @@ namespace hex {
bool TaskHolder::isRunning() const {
return !m_task.expired() && !m_task.lock()->isFinished();
if (this->m_task.expired())
return false;
auto task = this->m_task.lock();
return !task->isFinished();
}
bool TaskHolder::hadException() const {
return m_task.expired() || m_task.lock()->hadException();
if (this->m_task.expired())
return false;
auto task = this->m_task.lock();
return !task->hadException();
}
bool TaskHolder::wasInterrupted() const {
return m_task.expired() || m_task.lock()->wasInterrupted();
if (this->m_task.expired())
return false;
auto task = this->m_task.lock();
return !task->wasInterrupted();
}
void TaskHolder::interrupt() {
if (!this->m_task.expired())
this->m_task.lock()->interrupt();
if (this->m_task.expired())
return;
auto task = this->m_task.lock();
task->interrupt();
}
void TaskManager::init() {
for (u32 i = 0; i < std::thread::hardware_concurrency(); i++)
TaskManager::s_workers.emplace_back(TaskManager::runner);
}
void TaskManager::exit() {
for (auto &task : TaskManager::s_tasks)
task->interrupt();
for (auto &thread : TaskManager::s_workers)
thread.request_stop();
s_jobCondVar.notify_all();
TaskManager::s_workers.clear();
}
void TaskManager::runner(const std::stop_token &stopToken) {
std::mutex mutex;
while (true) {
std::shared_ptr<Task> task;
{
std::unique_lock lock(s_queueMutex);
s_jobCondVar.wait(lock, [&] {
return !s_taskQueue.empty() || stopToken.stop_requested();
});
if (stopToken.stop_requested())
break;
task = std::move(s_taskQueue.front());
s_taskQueue.pop_front();
}
try {
task->m_function(*task);
} catch (const Task::TaskInterruptor &) {
task->interruption();
} catch (const std::exception &e) {
log::error("Exception in task {}: {}", task->m_unlocalizedName, e.what());
task->exception(e.what());
} catch (...) {
log::error("Exception in task {}", task->m_unlocalizedName);
task->exception("Unknown Exception");
}
task->finish();
}
}
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
s_tasks.emplace_back(std::make_shared<Task>(std::move(name), maxValue, std::move(function)));
std::unique_lock lock(s_queueMutex);
auto task = std::make_shared<Task>(std::move(name), maxValue, false, std::move(function));
s_tasks.emplace_back(task);
s_taskQueue.emplace_back(task);
s_jobCondVar.notify_one();
return TaskHolder(s_tasks.back());
}
TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
std::unique_lock lock(s_queueMutex);
auto task = std::make_shared<Task>(std::move(name), 0, true, std::move(function));
s_tasks.emplace_back(task);
s_taskQueue.emplace_back(task);
s_jobCondVar.notify_one();
return TaskHolder(s_tasks.back());
}
void TaskManager::collectGarbage() {
std::unique_lock lock(s_queueMutex);
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
}
@@ -178,7 +235,11 @@ namespace hex {
}
size_t TaskManager::getRunningTaskCount() {
return s_tasks.size();
std::unique_lock lock(s_queueMutex);
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
return !task->isBackgroundTask();
});
}

View File

@@ -3,7 +3,7 @@
namespace hex::dp {
u32 Attribute::s_idCounter = 1;
int Attribute::s_idCounter = 1;
Attribute::Attribute(IOType ioType, Type type, std::string unlocalizedName) : m_id(Attribute::s_idCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(std::move(unlocalizedName)) {
}

View File

@@ -3,9 +3,9 @@
namespace hex::dp {
u32 Link::s_idCounter = 1;
int Link::s_idCounter = 1;
Link::Link(u32 from, u32 to) : m_id(Link::s_idCounter++), m_from(from), m_to(to) { }
Link::Link(int from, int to) : m_id(Link::s_idCounter++), m_from(from), m_to(to) { }
}

View File

@@ -7,7 +7,7 @@
namespace hex::dp {
u32 Node::s_idCounter = 1;
int Node::s_idCounter = 1;
Node::Node(std::string unlocalizedTitle, std::vector<Attribute> attributes) : m_id(Node::s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
for (auto &attr : this->m_attributes)

View File

@@ -17,12 +17,12 @@ namespace hex::fs {
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");
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "rb");
else if (mode == File::Mode::Write)
this->m_file = fopen64(path.string().c_str(), "r+b");
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "r+b");
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
this->m_file = fopen64(path.string().c_str(), "w+b");
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "w+b");
#endif
}
@@ -159,7 +159,7 @@ namespace hex::fs {
bool File::remove() {
this->close();
return std::remove(this->m_path.string().c_str()) == 0;
return std::remove(hex::toUTF8String(this->m_path).c_str()) == 0;
}
void File::disableBuffering() {

View File

@@ -75,6 +75,11 @@ namespace hex::fs {
return result;
}
static std::function<void()> s_fileBrowserErrorCallback;
void setFileBrowserErrorCallback(const std::function<void()> &callback) {
s_fileBrowserErrorCallback = callback;
}
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath) {
NFD::Init();
@@ -94,9 +99,14 @@ namespace hex::fs {
hex::unreachable();
}
if (result == NFD_OKAY && outPath != nullptr) {
callback(reinterpret_cast<char8_t*>(outPath));
NFD::FreePath(outPath);
if (result == NFD_OKAY){
if(outPath != nullptr) {
callback(reinterpret_cast<char8_t*>(outPath));
NFD::FreePath(outPath);
}
} else if (result==NFD_ERROR) {
if (s_fileBrowserErrorCallback != nullptr)
s_fileBrowserErrorCallback();
}
NFD::Quit();
@@ -184,7 +194,7 @@ namespace hex::fs {
path = path / folder;
return paths;
};
}
std::vector<std::fs::path> getPluginPaths() {
std::vector<std::fs::path> paths = getDataPaths();
@@ -199,6 +209,8 @@ namespace hex::fs {
std::vector<std::fs::path> result;
switch (path) {
case ImHexPath::END:
return { };
case ImHexPath::Constants:
result = appendPath(getDataPaths(), "constants");
break;
@@ -235,6 +247,12 @@ namespace hex::fs {
case ImHexPath::Recent:
result = appendPath(getConfigPaths(), "recent");
break;
case ImHexPath::Scripts:
result = appendPath(getDataPaths(), "scripts");
break;
case ImHexPath::Inspectors:
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
break;
}
if (!listNonExisting) {

View File

@@ -27,7 +27,7 @@ namespace hex::magic {
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 += fs::toShortPath(entry.path()).string() + MAGIC_PATH_SEPARATOR;
magicFiles += hex::toUTF8String(fs::toShortPath(entry.path())) + MAGIC_PATH_SEPARATOR;
}
}
}

View File

@@ -9,8 +9,6 @@
#include <filesystem>
#include <cstdio>
#include <mbedtls/ssl.h>
#include <curl/curl.h>
#include <nlohmann/json.hpp>
@@ -52,13 +50,13 @@ namespace hex {
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
static mbedtls_x509_crt crt;
mbedtls_x509_crt_init(&crt);
auto crt = static_cast<mbedtls_x509_crt*>(userData);
mbedtls_x509_crt_init(crt);
auto cacert = romfs::get("cacert.pem").string();
mbedtls_x509_crt_parse(&crt, reinterpret_cast<const u8 *>(cacert.data()), cacert.size());
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(cacert.data()), cacert.size());
mbedtls_ssl_conf_ca_chain(cfg, &crt, nullptr);
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
return CURLE_OK;
}
@@ -114,6 +112,7 @@ namespace hex {
curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr);
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_DATA, &this->m_caCert);
#endif
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
@@ -189,7 +188,7 @@ namespace hex {
curl_mime *mime = curl_mime_init(this->m_ctx);
curl_mimepart *part = curl_mime_addpart(mime);
auto fileName = filePath.filename().string();
auto fileName = hex::toUTF8String(filePath.filename());
curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto file = static_cast<FILE*>(arg);

View File

@@ -0,0 +1,41 @@
#include <hex/helpers/types.hpp>
namespace hex {
[[nodiscard]] bool Region::isWithin(const Region &other) const {
if (*this == Invalid() || other == Invalid())
return false;
if (this->getStartAddress() >= other.getStartAddress() && this->getEndAddress() <= other.getEndAddress())
return true;
return false;
}
[[nodiscard]] bool Region::overlaps(const Region &other) const {
if (*this == Invalid() || other == Invalid())
return false;
if (this->getEndAddress() >= other.getStartAddress() && this->getStartAddress() <= other.getEndAddress())
return true;
return false;
}
[[nodiscard]] u64 Region::getStartAddress() const {
return this->address;
}
[[nodiscard]] u64 Region::getEndAddress() const {
return this->address + this->size - 1;
}
[[nodiscard]] size_t Region::getSize() const {
return this->size;
}
bool Region::operator==(const Region &other) const {
return this->address == other.address && this->size == other.size;
}
}

View File

@@ -22,11 +22,11 @@
namespace hex {
long double operator""_scaled(long double value) {
float operator""_scaled(long double value) {
return value * ImHexApi::System::getGlobalScale();
}
long double operator""_scaled(unsigned long long value) {
float operator""_scaled(unsigned long long value) {
return value * ImHexApi::System::getGlobalScale();
}

View File

@@ -113,6 +113,8 @@ namespace hex::prv {
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
}
this->markDirty();
this->m_patches.emplace_back();
}
@@ -288,4 +290,15 @@ namespace hex::prv {
return { Region { address, *nextRegionAddress - address }, insideValidRegion };
}
u32 Provider::getID() const {
return this->m_id;
}
void Provider::setID(u32 id) {
this->m_id = id;
if (id > s_idCounter)
s_idCounter = id + 1;
}
}

View File

@@ -1,7 +1,6 @@
#include <hex/ui/imgui_imhex_extensions.h>
#include <imgui.h>
#include <imgui_freetype.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#undef IMGUI_DEFINE_MATH_OPERATORS
@@ -17,6 +16,76 @@
namespace ImGui {
Texture::Texture(const ImU8 *buffer, int size) {
unsigned char *imageData = stbi_load_from_memory(buffer, size, &this->m_width, &this->m_height, nullptr, 4);
if (imageData == nullptr)
return;
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
}
Texture::Texture(const char *path) {
unsigned char *imageData = stbi_load(path, &this->m_width, &this->m_height, nullptr, 4);
if (imageData == nullptr)
return;
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
}
Texture::Texture(Texture&& other) noexcept {
this->m_textureId = other.m_textureId;
this->m_width = other.m_width;
this->m_height = other.m_height;
other.m_textureId = nullptr;
}
Texture& Texture::operator=(Texture&& other) noexcept {
this->m_textureId = other.m_textureId;
this->m_width = other.m_width;
this->m_height = other.m_height;
other.m_textureId = nullptr;
return *this;
}
Texture::~Texture() {
if (this->m_textureId == nullptr)
return;
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(this->m_textureId));
glDeleteTextures(1, &glTextureId);
}
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
auto &string = *static_cast<std::string *>(data->UserData);
@@ -35,8 +104,8 @@ namespace ImGui {
ImGuiContext &g = *GImGui;
const ImGuiID id = window->GetID(label);
ImVec2 label_size = CalcTextSize(icon, NULL, false);
label_size.x += CalcTextSize(" ", NULL, false).x + CalcTextSize(label, NULL, false).x;
ImVec2 label_size = CalcTextSize(icon, nullptr, false);
label_size.x += CalcTextSize(" ", nullptr, false).x + CalcTextSize(label, nullptr, false).x;
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
@@ -69,7 +138,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
@@ -86,7 +155,7 @@ namespace ImGui {
// Render
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
PushStyleColor(ImGuiCol_Text, ImU32(col));
TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
PopStyleColor();
@@ -102,7 +171,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y) + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f);
@@ -137,8 +206,8 @@ namespace ImGui {
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), NULL, true);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), nullptr, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
@@ -166,7 +235,7 @@ namespace ImGui {
RenderTextWrapped(bb.Min + style.FramePadding * 2, label, nullptr, CalcWrapWidthForPos(window->DC.CursorPos, window->DC.TextWrapPos));
PopStyleColor();
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text));
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, NULL, &text_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, nullptr, &text_size, style.ButtonTextAlign, &bb);
PopStyleColor();
ImGui::PopStyleVar();
@@ -182,13 +251,13 @@ namespace ImGui {
void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) {
ImGuiWindow *window = GetCurrentWindow();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
PushStyleColor(ImGuiCol_Text, ImU32(color));
TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(color));
PopStyleColor();
}
@@ -298,66 +367,6 @@ namespace ImGui {
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
}
Texture LoadImageFromPath(const char *path) {
int imageWidth = 0;
int imageHeight = 0;
unsigned char *imageData = stbi_load(path, &imageWidth, &imageHeight, nullptr, 4);
if (imageData == nullptr)
return { nullptr, -1, -1 };
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
}
Texture LoadImageFromMemory(const ImU8 *buffer, int size) {
int imageWidth = 0;
int imageHeight = 0;
unsigned char *imageData = stbi_load_from_memory(buffer, size, &imageWidth, &imageHeight, nullptr, 4);
if (imageData == nullptr)
return { nullptr, -1, -1 };
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
}
void UnloadImage(Texture &texture) {
if (texture.textureId == nullptr)
return;
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(texture.textureId));
glDeleteTextures(1, &glTextureId);
texture = { nullptr, 0, 0 };
}
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
if (ImGui::Begin(window_name)) {
ImGui::OpenPopup(popup_name);
@@ -374,7 +383,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
@@ -393,7 +402,7 @@ namespace ImGui {
: ImGuiCol_Button);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb);
// Automatically close popups
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
@@ -413,7 +422,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(symbol);
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
@@ -434,7 +443,7 @@ namespace ImGui {
: ImGuiCol_MenuBarBg);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
PopStyleColor();
@@ -456,7 +465,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(symbol);
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
@@ -477,7 +486,7 @@ namespace ImGui {
: ImGuiCol_Button);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
PopStyleColor();
@@ -555,6 +564,33 @@ namespace ImGui {
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
}
bool InputTextIcon(const char *label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags) {
auto window = ImGui::GetCurrentWindow();
const ImGuiID id = window->GetID(label);
const ImGuiStyle &style = GImGui->Style;
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
const ImVec2 icon_frame_size = CalcTextSize(icon) + style.FramePadding * 2.0f;
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), icon_frame_size.x, label_size.y + style.FramePadding.y * 2.0f);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
bool value_changed = ImGui::InputTextEx(label, nullptr, buffer.data(), buffer.size() + 1, ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
if (value_changed)
MarkItemEdited(GImGui->LastItemData.ID);
RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
RenderFrame(frame_bb.Min, frame_bb.Min + icon_frame_size, GetColorU32(ImGuiCol_TableBorderStrong), true, style.FrameRounding);
RenderText(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y * 2), icon);
return value_changed;
}
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags) {
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
}
@@ -574,7 +610,7 @@ namespace ImGui {
ImGuiContext& g = *GImGui;
if (format == NULL)
if (format == nullptr)
format = DataTypeGetInfo(data_type)->PrintFmt;
char buf[64];
@@ -613,7 +649,7 @@ namespace ImGui {
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
const ImVec2 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
const ImVec2 pos = window->DC.CursorPos;

View File

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

View File

@@ -19,14 +19,14 @@ namespace hex::init {
bool loop();
void addStartupTask(const std::string &taskName, const TaskFunction &task) {
this->m_tasks.emplace_back(taskName, task);
void addStartupTask(const std::string &taskName, const TaskFunction &task, bool async) {
this->m_tasks.emplace_back(taskName, task, async);
}
private:
GLFWwindow *m_window;
std::mutex m_progressMutex;
float m_progress = 0;
std::atomic<float> m_progress = 0;
std::string m_currTaskName;
void initGLFW();
@@ -37,7 +37,7 @@ namespace hex::init {
std::future<bool> processTasksAsync();
std::vector<std::pair<std::string, TaskFunction>> m_tasks;
std::vector<std::tuple<std::string, TaskFunction, bool>> m_tasks;
std::string m_gpuVendor;
};

View File

@@ -9,6 +9,7 @@ namespace hex::init {
struct Task {
std::string name;
std::function<bool()> function;
bool async;
};
std::vector<Task> getInitTasks();

View File

@@ -50,8 +50,9 @@ namespace hex {
double m_lastFrameTime = 0;
ImGui::Texture m_logoTexture = { nullptr };
ImGui::Texture m_logoTexture;
std::mutex m_popupMutex;
std::list<std::string> m_popupsToOpen;
std::vector<int> m_pressedKeys;

View File

@@ -43,28 +43,41 @@ namespace hex::init {
return std::async(std::launch::async, [this] {
bool status = true;
for (const auto &[name, task] : this->m_tasks) {
{
std::lock_guard guard(this->m_progressMutex);
this->m_currTaskName = name;
}
std::atomic<u32> tasksCompleted = 0;
for (const auto &[name, task, async] : this->m_tasks) {
auto runTask = [&, task = task, name = name] {
{
std::lock_guard guard(this->m_progressMutex);
this->m_currTaskName = name;
}
try {
if (!task())
status = false;
tasksCompleted++;
this->m_progress = float(tasksCompleted) / this->m_tasks.size();
};
try {
if (async) {
TaskManager::createBackgroundTask(name, [runTask](auto&){ runTask(); });
} else {
runTask();
}
} catch (std::exception &e) {
log::error("Init task '{}' threw an exception: {}", name, e.what());
status = false;
}
}
{
std::lock_guard guard(this->m_progressMutex);
this->m_progress += 1.0F / this->m_tasks.size();
}
while (tasksCompleted < this->m_tasks.size()) {
std::this_thread::sleep_for(100ms);
}
// Small extra delay so the last progress step is visible
std::this_thread::sleep_for(200ms);
std::this_thread::sleep_for(100ms);
return status;
});
@@ -72,15 +85,13 @@ namespace hex::init {
bool WindowSplash::loop() {
auto splash = romfs::get("splash.png");
ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
ImGui::Texture splashTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
if (splashTexture == nullptr) {
if (!splashTexture.isValid()) {
log::fatal("Could not load splash screen image!");
exit(EXIT_FAILURE);
}
ON_SCOPE_EXIT { ImGui::UnloadImage(splashTexture); };
auto tasksSucceeded = processTasksAsync();
auto scale = ImHexApi::System::getGlobalScale();
@@ -97,7 +108,7 @@ namespace hex::init {
auto drawList = ImGui::GetForegroundDrawList();
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.size() * scale);
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.getSize() * scale);
drawList->AddText(ImVec2(15, 120) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str());
@@ -107,15 +118,15 @@ namespace hex::init {
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
#endif
drawList->AddRectFilled(ImVec2(0, splashTexture.size().y - 5) * scale, ImVec2(splashTexture.size().x * this->m_progress, splashTexture.size().y) * scale, 0xFFFFFFFF);
drawList->AddText(ImVec2(15, splashTexture.size().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
drawList->AddRectFilled(ImVec2(0, splashTexture.getSize().y - 5) * scale, ImVec2(splashTexture.getSize().x * this->m_progress, splashTexture.getSize().y) * scale, 0xFFFFFFFF);
drawList->AddText(ImVec2(15, splashTexture.getSize().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
}
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(this->m_window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(0, 0, 0, 0);
glClearColor(0.00F, 0.00F, 0.00F, 0.00F);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

View File

@@ -40,7 +40,7 @@ namespace hex::init {
auto latestVersion = releases.body["tag_name"].get<std::string_view>();
if (latestVersion != currVersion)
ImHexApi::System::getInitArguments().insert({ "update-available", latestVersion.data() });
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
return true;
}
@@ -52,7 +52,7 @@ namespace hex::init {
if (tip.code != 200)
return false;
ImHexApi::System::getInitArguments().insert({ "tip-of-the-day", tip.body });
ImHexApi::System::impl::addInitArgument("tip-of-the-day", tip.body);
return true;
}
@@ -61,20 +61,6 @@ namespace hex::init {
bool result = true;
using enum fs::ImHexPath;
constexpr std::array paths = {
Patterns,
PatternsInclude,
Magic,
Plugins,
Resources,
Config,
Constants,
Yara,
Encodings,
Python,
Logs,
Recent
};
// Check if ImHex is installed in portable mode
{
@@ -87,19 +73,19 @@ namespace hex::init {
}
// Create all folders
for (auto path : paths) {
for (auto &folder : fs::getDefaultPaths(path, true)) {
for (u32 path = 0; path < u32(fs::ImHexPath::END); path++) {
for (auto &folder : fs::getDefaultPaths(static_cast<fs::ImHexPath>(path), true)) {
try {
fs::createDirectories(folder);
} catch (...) {
log::error("Failed to create folder {}!", folder.string());
log::error("Failed to create folder {}!", hex::toUTF8String(folder));
result = false;
}
}
}
if (!result)
ImHexApi::System::getInitArguments().insert({ "folder-creation-error", {} });
ImHexApi::System::impl::addInitArgument("folder-creation-error");
return result;
}
@@ -133,7 +119,7 @@ namespace hex::init {
0x0100, 0xFFF0, 0
};
auto fontFile = ImHexApi::System::getCustomFontPath();
const auto &fontFile = ImHexApi::System::getCustomFontPath();
float fontSize = ImHexApi::System::getFontSize();
if (fontFile.empty()) {
// Load default font if no custom one has been specified
@@ -149,7 +135,7 @@ namespace hex::init {
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
cfg.SizePixels = fontSize;
fonts->AddFontFromFileTTF(fontFile.string().c_str(), std::floor(fontSize), &cfg, ranges.Data); // Needs conversion to char for Windows
fonts->AddFontFromFileTTF(hex::toUTF8String(fontFile).c_str(), std::floor(fontSize), &cfg, ranges.Data); // Needs conversion to char for Windows
}
cfg.MergeMode = true;
@@ -233,6 +219,8 @@ namespace hex::init {
ProjectFile::getHandlers().clear();
ProjectFile::getProviderHandlers().clear();
fs::setFileBrowserErrorCallback(nullptr);
return true;
}
@@ -246,7 +234,7 @@ namespace hex::init {
if (plugins.empty()) {
log::error("No plugins found!");
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} });
ImHexApi::System::impl::addInitArgument("no-plugins");
return false;
}
@@ -258,7 +246,7 @@ namespace hex::init {
if (builtinPlugins > 1) continue;
if (!plugin.initializePlugin()) {
log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
loadErrors++;
}
}
@@ -267,24 +255,24 @@ namespace hex::init {
if (plugin.isBuiltinPlugin()) continue;
if (!plugin.initializePlugin()) {
log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
loadErrors++;
}
}
if (loadErrors == plugins.size()) {
log::error("No plugins loaded successfully!");
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} });
ImHexApi::System::impl::addInitArgument("no-plugins");
return false;
}
if (builtinPlugins == 0) {
log::error("Built-in plugin not found!");
ImHexApi::System::getInitArguments().insert({ "no-builtin-plugin", {} });
ImHexApi::System::impl::addInitArgument("no-builtin-plugin");
return false;
} else if (builtinPlugins > 1) {
log::error("Found more than one built-in plugin!");
ImHexApi::System::getInitArguments().insert({ "multiple-builtin-plugins", {} });
ImHexApi::System::impl::addInitArgument("multiple-builtin-plugins");
return false;
}
@@ -324,20 +312,20 @@ namespace hex::init {
std::vector<Task> getInitTasks() {
return {
{"Checking for updates...", checkForUpdates },
{ "Downloading information...", downloadInformation},
{ "Creating directories...", createDirectories },
{ "Loading settings...", loadSettings },
{ "Loading plugins...", loadPlugins },
{ "Loading fonts...", loadFonts },
{ "Creating directories...", createDirectories, false },
{ "Loading settings...", loadSettings, false },
{ "Loading plugins...", loadPlugins, false },
{ "Checking for updates...", checkForUpdates, true },
{ "Downloading information...", downloadInformation, true },
{ "Loading fonts...", loadFonts, true },
};
}
std::vector<Task> getExitTasks() {
return {
{"Saving settings...", storeSettings },
{ "Cleaning up shared data...", deleteSharedData},
{ "Unloading plugins...", unloadPlugins },
{ "Saving settings...", storeSettings, false },
{ "Cleaning up shared data...", deleteSharedData, false },
{ "Unloading plugins...", unloadPlugins, false },
};
}

View File

@@ -20,9 +20,8 @@ int main(int argc, char **argv, char **envp) {
bool shouldRestart = false;
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
do {
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
shouldRestart = false;
// Initialization
@@ -33,8 +32,9 @@ int main(int argc, char **argv, char **envp) {
init::WindowSplash splashWindow;
for (const auto &[name, task] : init::getInitTasks())
splashWindow.addStartupTask(name, task);
TaskManager::init();
for (const auto &[name, task, async] : init::getInitTasks())
splashWindow.addStartupTask(name, task, async);
if (!splashWindow.loop())
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
@@ -42,8 +42,9 @@ int main(int argc, char **argv, char **envp) {
// Clean up
ON_SCOPE_EXIT {
for (const auto &[name, task] : init::getExitTasks())
for (const auto &[name, task, async] : init::getExitTasks())
task();
TaskManager::exit();
};
// Main window
@@ -53,11 +54,21 @@ int main(int argc, char **argv, char **envp) {
if (argc == 1)
; // No arguments provided
else if (argc >= 2) {
for (auto i = 1; i < argc; i++)
EventManager::post<RequestOpenFile>(argv[i]);
for (auto i = 1; i < argc; i++) {
if (auto argument = ImHexApi::System::getProgramArgument(i); argument.has_value())
EventManager::post<RequestOpenFile>(argument.value());
}
}
window.loop();
try {
window.loop();
} catch (const std::exception &e) {
log::fatal("Exception thrown in main loop: {}", e.what());
throw;
} catch (...) {
log::fatal("Unknown exception thrown in main loop!");
throw;
}
}
} while (shouldRestart);

View File

@@ -43,7 +43,7 @@ namespace hex {
if (data == nullptr) break;
std::fs::path path = data;
log::info("Opening file in existing instance: {}", path.string());
log::info("Opening file in existing instance: {}", hex::toUTF8String(path));
EventManager::post<RequestOpenFile>(path);
break;
}

View File

@@ -9,6 +9,7 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <fmt/printf.h>
#include <chrono>
#include <csignal>
@@ -80,7 +81,7 @@ namespace hex {
#else
std::raise(signalNumber);
#endif
};
}
Window::Window() {
{
@@ -132,18 +133,20 @@ namespace hex {
constexpr static auto CrashBackupFileName = "crash_backup.hexproj";
EventManager::subscribe<EventAbnormalTermination>(this, [this](int) {
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
if (!ImHexApi::Provider::isDirty())
return;
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) {
if (ProjectFile::store((std::fs::path(path) / CrashBackupFileName).string()))
if (ProjectFile::store(path / CrashBackupFileName))
break;
}
});
EventManager::subscribe<RequestOpenPopup>(this, [this](auto name) {
std::scoped_lock lock(this->m_popupMutex);
this->m_popupsToOpen.push_back(name);
});
@@ -153,8 +156,8 @@ namespace hex {
std::signal(SIGFPE, signalHandler);
std::set_terminate([]{ signalHandler(SIGABRT); });
auto imhexLogo = romfs::get("logo.png");
this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(imhexLogo.data()), imhexLogo.size());
auto logoData = romfs::get("logo.png");
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logoData.data()), logoData.size());
ContentRegistry::Settings::store();
EventManager::post<EventSettingsChanged>();
@@ -197,7 +200,6 @@ namespace hex {
}
}
this->frameBegin();
this->frame();
this->frameEnd();
@@ -376,7 +378,7 @@ namespace hex {
const auto filePath = path / "builtin.hexplug";
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(filePath.string().c_str());
ImGui::TextUnformatted(hex::toUTF8String(filePath).c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
}
@@ -424,15 +426,17 @@ namespace hex {
ImGui::EndPopup();
}
}
{
std::scoped_lock lock(this->m_popupMutex);
this->m_popupsToOpen.remove_if([](const auto &name) {
if (ImGui::IsPopupOpen(name.c_str()))
return true;
else
ImGui::OpenPopup(name.c_str());
this->m_popupsToOpen.remove_if([](const auto &name) {
if (ImGui::IsPopupOpen(name.c_str()))
return true;
else
ImGui::OpenPopup(name.c_str());
return false;
});
return false;
});
}
TaskManager::runDeferredCalls();
@@ -492,7 +496,7 @@ namespace hex {
int displayWidth, displayHeight;
glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight);
glViewport(0, 0, displayWidth, displayHeight);
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
glClearColor(0.00F, 0.00F, 0.00F, 1.00f);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
@@ -680,8 +684,9 @@ namespace hex {
if (glfwGetPrimaryMonitor() != nullptr) {
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", 1) != 0;
if (!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland"))
if ((!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland")) && multiWindowEnabled)
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
}
@@ -742,7 +747,7 @@ namespace hex {
}
if (!this->m_imguiSettingsPath.empty() && fs::exists(this->m_imguiSettingsPath))
ImGui::LoadIniSettingsFromDisk(this->m_imguiSettingsPath.string().c_str());
ImGui::LoadIniSettingsFromDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
ImGui_ImplGlfw_InitForOpenGL(this->m_window, true);
@@ -767,7 +772,7 @@ namespace hex {
ImNodes::PopAttributeFlag();
ImNodes::PopAttributeFlag();
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();

View File

@@ -84,3 +84,9 @@ endif()
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
setupCompilerWarnings(${PROJECT_NAME})
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
set(LIBROMFS_PROJECT_NAME ${PROJECT_NAME})
add_subdirectory(../../lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBROMFS_LIBRARY})

View File

@@ -16,15 +16,20 @@ namespace hex {
public:
MathEvaluator() = default;
struct Variable {
T value;
bool constant;
};
std::optional<T> evaluate(const std::string &input);
void registerStandardVariables();
void registerStandardFunctions();
void setVariable(const std::string &name, T value);
void setVariable(const std::string &name, T value, bool constant = false);
void setFunction(const std::string &name, const std::function<std::optional<T>(std::vector<T>)> &function, size_t minNumArgs, size_t maxNumArgs);
std::unordered_map<std::string, T> &getVariables() { return this->m_variables; }
std::unordered_map<std::string, Variable> &getVariables() { return this->m_variables; }
[[nodiscard]] bool hasError() const {
return this->m_lastError.has_value();
@@ -106,7 +111,7 @@ namespace hex {
std::optional<std::queue<Token>> toPostfix(std::queue<Token> inputQueue);
std::optional<T> evaluate(std::queue<Token> postfixTokens);
std::unordered_map<std::string, T> m_variables;
std::unordered_map<std::string, Variable> m_variables;
std::unordered_map<std::string, std::function<std::optional<T>(std::vector<T>)>> m_functions;
std::optional<std::string> m_lastError;

View File

@@ -6,11 +6,6 @@
namespace hex {
template<typename T>
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::ptrn::Pattern&)> fn) {
{ pattern.forEachArrayEntry(displayEnd, fn) } -> std::same_as<void>;
};
class PatternDrawer : public pl::PatternVisitor {
public:
PatternDrawer() = default;
@@ -36,27 +31,13 @@ namespace hex {
private:
void draw(pl::ptrn::Pattern& pattern);
template<ArrayPattern T>
void drawArray(T& pattern) {
bool opened = this->drawArrayRoot(pattern, pattern.getEntryCount(), pattern.isInlined());
if (opened) {
auto& displayEnd = this->getDisplayEnd(pattern);
pattern.forEachArrayEntry(displayEnd, [&] (u64 idx, auto &entry){
this->drawArrayNode(idx, displayEnd, entry);
});
}
this->drawArrayEnd(pattern, opened, pattern.isInlined());
}
bool drawArrayRoot(pl::ptrn::Pattern& pattern, size_t entryCount, bool isInlined);
void drawArrayNode(u64 idx, u64& displayEnd, pl::ptrn::Pattern& pattern);
void drawArrayEnd(pl::ptrn::Pattern& pattern, bool opened, bool inlined);
constexpr static auto ChunkSize = 512;
constexpr static auto DisplayEndStep = 64;
void drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::Iteratable &iteratable, bool isInlined);
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
private:
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
};
};
}

View File

@@ -18,6 +18,7 @@ namespace hex::plugin::builtin {
struct {
std::string sourceCode;
std::unique_ptr<pl::PatternLanguage> runtime;
bool executionDone = true;
} patternLanguage;
std::list<ImHexApi::Bookmarks::Entry> bookmarks;
@@ -30,6 +31,11 @@ namespace hex::plugin::builtin {
std::vector<hex::prv::Overlay *> dataOverlays;
std::optional<dp::Node::NodeError> currNodeError;
} dataProcessor;
struct {
std::optional<u64> selectionStart, selectionEnd;
float scrollPosition = 0.0F;
} editor;
};
static Data& getCurrent() {

View File

@@ -7,6 +7,7 @@
#include <vector>
#if defined(OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
@@ -45,7 +46,7 @@ namespace hex::plugin::builtin::prv {
return "hex.builtin.provider.disk";
}
std::pair<Region, bool> getRegionValidity(u64 address) const override;
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
protected:
void reloadDrives();

View File

@@ -7,15 +7,12 @@
#include <sys/stat.h>
#if defined(OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#include <sys/fcntl.h>
#endif
namespace hex::plugin::builtin::prv {
@@ -41,7 +38,6 @@ namespace hex::plugin::builtin::prv {
void readRaw(u64 offset, void *buffer, size_t size) override;
void writeRaw(u64 offset, const void *buffer, size_t size) override;
[[nodiscard]] size_t getActualSize() const override;
[[nodiscard]] size_t getRealTimeSize();
void save() override;
void saveAs(const std::fs::path &path) override;
@@ -49,8 +45,8 @@ namespace hex::plugin::builtin::prv {
[[nodiscard]] std::string getName() const override;
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override;
bool hasFilePicker() const override { return true; }
bool handleFilePicker() override;
[[nodiscard]] bool hasFilePicker() const override { return true; }
[[nodiscard]] bool handleFilePicker() override;
void setPath(const std::fs::path &path);
@@ -67,17 +63,6 @@ namespace hex::plugin::builtin::prv {
std::pair<Region, bool> getRegionValidity(u64 address) const override;
protected:
#if defined(OS_WINDOWS)
HANDLE m_file = INVALID_HANDLE_VALUE;
HANDLE m_mapping = INVALID_HANDLE_VALUE;
#else
int m_file = -1;
#endif
std::fs::path m_path;
void *m_mappedFile = nullptr;
size_t m_fileSize = 0;

View File

@@ -49,7 +49,7 @@ namespace hex::plugin::builtin::prv {
return "hex.builtin.provider.gdb";
}
std::pair<Region, bool> getRegionValidity(u64 address) const override;
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
protected:
hex::Socket m_socket;

View File

@@ -36,8 +36,8 @@ namespace hex::plugin::builtin::prv {
return "hex.builtin.provider.intel_hex";
}
bool hasFilePicker() const override { return true; }
bool handleFilePicker() override;
[[nodiscard]] bool hasFilePicker() const override { return true; }
[[nodiscard]] bool handleFilePicker() override;
std::pair<Region, bool> getRegionValidity(u64 address) const override;

View File

@@ -14,7 +14,6 @@ namespace hex::plugin::builtin {
class ViewAbout : public View {
public:
ViewAbout();
~ViewAbout() override;
void drawContent() override;

View File

@@ -21,6 +21,8 @@ namespace hex::plugin::builtin {
void registerMenuItems();
private:
std::string m_currFilter;
std::list<ImHexApi::Bookmarks::Entry>::iterator m_dragStartIterator;
};
}

View File

@@ -33,7 +33,9 @@ namespace hex::plugin::builtin {
u64 m_startAddress = 0;
size_t m_validBytes = 0;
std::vector<InspectorCacheEntry> m_cachedData;
std::atomic<bool> m_dataValid = false;
std::vector<InspectorCacheEntry> m_cachedData, m_workData;
TaskHolder m_updateTask;
std::string m_editingValue;
};

View File

@@ -20,12 +20,13 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
bool m_justSwitchedProvider = false;
int m_rightClickedId = -1;
ImVec2 m_rightClickedCoords;
bool m_continuousEvaluation = false;
void eraseLink(u32 id);
void eraseLink(int id);
void eraseNodes(const std::vector<int> &ids);
void processNodes();

View File

@@ -24,7 +24,8 @@ namespace hex::plugin::builtin {
struct Occurrence {
Region region;
enum class DecodeType { ASCII, Binary, UTF16LE, UTF16BE } decodeType;
enum class DecodeType { ASCII, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
std::endian endian = std::endian::native;
};
struct BinaryPattern {
@@ -38,7 +39,8 @@ namespace hex::plugin::builtin {
Strings,
Sequence,
Regex,
BinaryPattern
BinaryPattern,
Value
} mode = Mode::Strings;
struct Strings {
@@ -55,7 +57,7 @@ namespace hex::plugin::builtin {
bool m_lineFeeds = false;
} strings;
struct Bytes {
struct Sequence {
std::string sequence;
} bytes;
@@ -68,6 +70,18 @@ namespace hex::plugin::builtin {
std::string input;
std::vector<ViewFind::BinaryPattern> pattern;
} binaryPattern;
struct Value {
std::string inputMin, inputMax;
std::endian endian = std::endian::native;
enum class Type {
U8 = 0, U16 = 1, U32 = 2, U64 = 3,
I8 = 4, I16 = 5, I32 = 6, I64 = 7,
F32 = 8, F64 = 9
} type = Type::U8;
} value;
} m_searchSettings, m_decodeSettings;
using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>;
@@ -80,12 +94,14 @@ namespace hex::plugin::builtin {
bool m_settingsValid = false;
private:
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Strings settings);
static std::vector<Occurrence> searchSequence(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Bytes settings);
static std::vector<Occurrence> searchRegex(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Regex settings);
static std::vector<Occurrence> searchBinaryPattern(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::BinaryPattern settings);
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Strings &settings);
static std::vector<Occurrence> searchSequence(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Sequence &settings);
static std::vector<Occurrence> searchRegex(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Regex &settings);
static std::vector<Occurrence> searchBinaryPattern(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::BinaryPattern &settings);
static std::vector<Occurrence> searchValue(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Value &settings);
static std::vector<BinaryPattern> parseBinaryPatternString(std::string string);
static std::tuple<bool, std::variant<u64, i64, float, double>, size_t> parseNumericValueInput(const std::string &input, SearchSettings::Value::Type type);
void runSearch();
std::string decodeValue(prv::Provider *provider, Occurrence occurrence) const;

View File

@@ -6,6 +6,8 @@
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/encoding_file.hpp>
#include <content/helpers/provider_extra_data.hpp>
#include <algorithm>
#include <limits>
@@ -18,8 +20,6 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
void registerShortcuts();
void registerEvents();
void registerMenuItems();
@@ -33,22 +33,16 @@ namespace hex::plugin::builtin {
void setSelection(u128 start, u128 end) {
if (!ImHexApi::Provider::isValid())
return;
if (start == InvalidSelection && end == InvalidSelection)
return;
if (start == InvalidSelection)
start = end;
if (end == InvalidSelection)
end = start;
auto provider = ImHexApi::Provider::get();
auto &data = ProviderExtraData::get(provider).editor;
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
this->m_selectionChanged = data.selectionStart != start || data.selectionEnd != end;
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
data.selectionStart = std::clamp<u128>(start, 0, maxAddress);
data.selectionEnd = std::clamp<u128>(end, 0, maxAddress);
if (this->m_selectionChanged) {
EventManager::post<EventRegionSelected>(this->getSelection());
@@ -56,19 +50,29 @@ namespace hex::plugin::builtin {
}
[[nodiscard]] Region getSelection() const {
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd);
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
auto &data = ProviderExtraData::getCurrent().editor;
if (!isSelectionValid())
return Region::Invalid();
const auto start = std::min(*data.selectionStart, *data.selectionEnd);
const auto end = std::max(*data.selectionStart, *data.selectionEnd);
const size_t size = end - start + 1;
return { start, size };
}
[[nodiscard]] bool isSelectionValid() const {
return this->m_selectionStart != InvalidSelection && this->m_selectionEnd != InvalidSelection;
auto &data = ProviderExtraData::getCurrent().editor;
return data.selectionStart.has_value() && data.selectionEnd.has_value();
}
void jumpToSelection() {
void jumpToSelection(bool center = true) {
this->m_shouldJumpToSelection = true;
if (center)
this->m_centerOnJump = true;
}
void scrollToSelection() {
@@ -110,6 +114,7 @@ namespace hex::plugin::builtin {
void drawFooter(const ImVec2 &size);
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
std::optional<color_t> applySelectionColor(u64 byteAddress, std::optional<color_t> color);
private:
u16 m_bytesPerRow = 16;
@@ -117,12 +122,12 @@ namespace hex::plugin::builtin {
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
bool m_shouldJumpToSelection = false;
bool m_centerOnJump = false;
bool m_shouldScrollToSelection = false;
bool m_shouldJumpWhenOffScreen = false;
bool m_shouldUpdateScrollPosition = false;
bool m_selectionChanged = false;
u64 m_selectionStart = InvalidSelection;
u64 m_selectionEnd = InvalidSelection;
u16 m_visibleRowCount = 0;
@@ -136,6 +141,8 @@ namespace hex::plugin::builtin {
bool m_upperCaseHex = true;
bool m_grayOutZero = true;
bool m_showAscii = true;
bool m_syncScrolling = false;
u32 m_byteCellPadding = 0, m_characterCellPadding = 0;
bool m_shouldOpenPopup = false;
std::unique_ptr<Popup> m_currPopup;

View File

@@ -12,7 +12,7 @@ namespace hex::plugin::builtin {
class ViewPatches : public View {
public:
explicit ViewPatches();
~ViewPatches() override;
~ViewPatches() override = default;
void drawContent() override;

View File

@@ -17,8 +17,8 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool isAvailable() const override { return true; }
[[nodiscard]] bool hasViewMenuItemEntry() const override { return false; }
[[nodiscard]] ImVec2 getMinSize() const override { return { 500, 300 }; }
[[nodiscard]] ImVec2 getMaxSize() const override { return { 500, 300 }; }
[[nodiscard]] ImVec2 getMinSize() const override { return { 700, 400 }; }
[[nodiscard]] ImVec2 getMaxSize() const override { return { 700, 400 }; }
private:
bool m_restartRequested = false;

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

View File

@@ -18,7 +18,7 @@ namespace hex::plugin::builtin {
auto reader = prv::BufferedReader(provider);
reader.seek(offset);
reader.setEndAddress(offset + size);
reader.setEndAddress(offset + size - 1);
u64 index = 0x00;
for (u8 byte : reader) {
@@ -64,7 +64,7 @@ namespace hex::plugin::builtin {
});
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.python", [](prv::Provider *provider, u64 offset, size_t size) {
return formatLanguageArray(provider, offset, size, "data = bytes([", "0x{0:02X}, ", "]);");
return formatLanguageArray(provider, offset, size, "data = bytes([", "0x{0:02X}, ", "])");
});
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.js", [](prv::Provider *provider, u64 offset, size_t size) {
@@ -160,7 +160,7 @@ namespace hex::plugin::builtin {
auto reader = prv::BufferedReader(provider);
reader.seek(offset);
reader.setEndAddress(offset + size);
reader.setEndAddress((offset + size) - 1);
u64 address = offset & ~u64(0x0F);
std::string asciiRow;

View File

@@ -396,13 +396,14 @@ namespace hex::plugin::builtin {
}
);
constexpr static auto MaxStringLength = 32;
ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1,
[](auto buffer, auto endian, auto style) {
hex::unused(buffer, endian, style);
auto currSelection = ImHexApi::HexEditor::getSelection();
constexpr static auto MaxStringLength = 32;
std::string value, copyValue;
@@ -430,6 +431,46 @@ namespace hex::plugin::builtin {
}
);
ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", 2,
[](auto buffer, auto endian, auto style) {
hex::unused(buffer, endian, style);
auto currSelection = ImHexApi::HexEditor::getSelection();
std::string value, copyValue;
if (currSelection.has_value()) {
std::u16string stringBuffer(std::min<size_t>(currSelection->size, 0x1000), 0x00);
ImHexApi::Provider::get()->read(currSelection->address, stringBuffer.data(), stringBuffer.size());
for (auto &c : stringBuffer)
c = hex::changeEndianess(c, endian);
auto it = std::remove_if(buffer.begin(), buffer.end(),
[](auto c) { return c == 0x00; });
buffer.erase(it, buffer.end());
auto string = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>("Invalid").to_bytes(stringBuffer.data());
value = copyValue = hex::encodeByteString({ string.begin(), string.end() });
if (value.size() > MaxStringLength) {
value.resize(MaxStringLength);
value += "...";
}
} else {
value = "";
copyValue = "";
}
return [value, copyValue] { ImGui::TextFormatted("L\"{0}\"", value.c_str()); return copyValue; };
},
[](const std::string &value, std::endian endian) -> std::vector<u8> {
hex::unused(endian);
return hex::decodeByteString(value);
}
);
#if defined(OS_WINDOWS) && defined(ARCH_64_BIT)
ContentRegistry::DataInspector::add("hex.builtin.inspector.time32", sizeof(u32), [](auto buffer, auto endian, auto style) {

View File

@@ -15,6 +15,7 @@
#include <imgui.h>
#include <implot.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <fonts/codicons_font.h>
namespace hex::plugin::builtin {
@@ -66,22 +67,17 @@ namespace hex::plugin::builtin {
class NodeString : public dp::Node {
public:
NodeString() : Node("hex.builtin.nodes.constants.string.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) {
this->m_value.resize(0xFFF, 0x00);
}
void drawNode() override {
ImGui::PushItemWidth(100);
ImGui::InputText("##string", reinterpret_cast<char *>(this->m_value.data()), this->m_value.size() - 1);
ImGui::InputTextIcon("##string", ICON_VS_SYMBOL_KEY, this->m_value);
ImGui::PopItemWidth();
}
void process() override {
std::vector<u8> output(std::strlen(this->m_value.c_str()) + 1, 0x00);
std::strcpy(reinterpret_cast<char *>(output.data()), this->m_value.c_str());
output.pop_back();
this->setBufferOnOutput(0, output);
this->setBufferOnOutput(0, { this->m_value.begin(), this->m_value.end() });
}
void store(nlohmann::json &j) override {
@@ -960,10 +956,10 @@ namespace hex::plugin::builtin {
NodeVisualizerImage() : Node("hex.builtin.nodes.visualizer.image.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { }
void drawNode() override {
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 200, 200)));
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 200, 200)));
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 600, 600)));
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 600, 600)));
ImGui::EndTooltip();
}
}
@@ -971,10 +967,7 @@ namespace hex::plugin::builtin {
void process() override {
auto rawData = this->getBufferOnInput(0);
if (this->m_texture.valid())
ImGui::UnloadImage(this->m_texture);
this->m_texture = ImGui::LoadImageFromMemory(rawData.data(), rawData.size());
this->m_texture = ImGui::Texture(rawData.data(), rawData.size());
}
private:

View File

@@ -4,6 +4,7 @@
#include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
namespace hex::plugin::builtin {
@@ -106,7 +107,7 @@ namespace hex::plugin::builtin {
const static inline auto FormattingUpperCase = hex::format("%0{}X", CharCount);
const static inline auto FormattingLowerCase = hex::format("%0{}x", CharCount);
const char *getFormatString(bool upperCase) {
static const char *getFormatString(bool upperCase) {
if (upperCase)
return FormattingUpperCase.c_str();
else
@@ -160,7 +161,9 @@ namespace hex::plugin::builtin {
}
};
template<std::floating_point T>
enum class Float16 : u16 {};
template<typename T>
class DataVisualizerFloatingPoint : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerFloatingPoint() : DataVisualizer(ByteCount, CharCount) { }
@@ -206,6 +209,42 @@ namespace hex::plugin::builtin {
}
};
template<>
class DataVisualizerFloatingPoint<Float16> : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerFloatingPoint() : DataVisualizer(ByteCount, CharCount) { }
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
hex::unused(address);
if (size == ByteCount)
ImGui::Text(getFormatString(upperCase), hex::float16ToFloat32(*reinterpret_cast<const u16*>(data)));
else
ImGui::TextFormatted("{: {}s}", CharCount);
}
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
hex::unused(startedEditing);
this->draw(address, data, size, upperCase);
return false;
}
private:
constexpr static inline auto ByteCount = sizeof(Float16);
constexpr static inline auto CharCount = 14;
const static inline auto FormatStringUpperCase = hex::format("%{}G", CharCount);
const static inline auto FormatStringLowerCase = hex::format("%{}g", CharCount);
static const char *getFormatString(bool upperCase) {
if (upperCase)
return FormatStringUpperCase.c_str();
else
return FormatStringLowerCase.c_str();
}
};
class DataVisualizerRGBA8 : public hex::ContentRegistry::HexEditor::DataVisualizer {
public:
DataVisualizerRGBA8() : DataVisualizer(4, 2) { }
@@ -262,6 +301,7 @@ namespace hex::plugin::builtin {
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i32>>("hex.builtin.visualizer.decimal.signed.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i64>>("hex.builtin.visualizer.decimal.signed.64bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<Float16>>("hex.builtin.visualizer.floating_point.16bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<float>>("hex.builtin.visualizer.floating_point.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<double>>("hex.builtin.visualizer.floating_point.64bit");

View File

@@ -11,9 +11,9 @@
#include <imgui.h>
#include <nlohmann/json.hpp>
#include "provider_extra_data.hpp"
#include <content/helpers/provider_extra_data.hpp>
#include "content/providers/file_provider.hpp"
#include <content/providers/file_provider.hpp>
namespace hex::plugin::builtin {
@@ -78,7 +78,9 @@ namespace hex::plugin::builtin {
} else if (name == "Open Project") {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
[](const auto &path) {
ProjectFile::load(path);
if (!ProjectFile::load(path)) {
View::showErrorPopup("hex.builtin.popup.error.project.load"_lang);
}
});
}
});
@@ -121,6 +123,14 @@ namespace hex::plugin::builtin {
ProviderExtraData::erase(provider);
});
fs::setFileBrowserErrorCallback([]{
#if defined(NFD_PORTAL)
View::showErrorPopup("hex.builtin.popup.error.file_dialog.portal"_lang);
#else
View::showErrorPopup("hex.builtin.popup.error.file_dialog.common"_lang);
#endif
});
}
}

View File

@@ -345,7 +345,7 @@ namespace hex {
evaluationStack.push(result);
} else if (front.type == TokenType::Variable) {
if (this->m_variables.contains(front.name))
evaluationStack.push(this->m_variables.at(front.name));
evaluationStack.push(this->m_variables.at(front.name).value);
else {
this->setError("Unknown variable!");
return std::nullopt;
@@ -382,14 +382,14 @@ namespace hex {
template<typename T>
std::optional<T> MathEvaluator<T>::evaluate(const std::string &input) {
auto inputQueue = parseInput(input);
if (!inputQueue.has_value())
if (!inputQueue.has_value() || inputQueue->empty())
return std::nullopt;
std::string resultVariable = "ans";
{
auto queueCopy = *inputQueue;
if (queueCopy.front().type == TokenType::Variable) {
if (queueCopy.front().type == TokenType::Variable && queueCopy.size() > 2) {
resultVariable = queueCopy.front().name;
queueCopy.pop();
if (queueCopy.front().type != TokenType::Operator || queueCopy.front().op != Operator::Assign)
@@ -407,16 +407,15 @@ namespace hex {
auto result = evaluate(*postfixTokens);
if (result.has_value()) {
if (result.has_value() && !this->getVariables()[resultVariable].constant)
this->setVariable(resultVariable, result.value());
}
return result;
}
template<typename T>
void MathEvaluator<T>::setVariable(const std::string &name, T value) {
this->m_variables[name] = value;
void MathEvaluator<T>::setVariable(const std::string &name, T value, bool constant) {
this->m_variables[name] = { value, constant };
}
template<typename T>
@@ -435,6 +434,9 @@ namespace hex {
template<typename T>
void MathEvaluator<T>::registerStandardVariables() {
this->setVariable("ans", 0);
this->setVariable("pi", std::numbers::pi, true);
this->setVariable("e", std::numbers::e, true);
this->setVariable("phi", std::numbers::phi, true);
}
template<typename T>

View File

@@ -34,6 +34,43 @@ namespace hex {
using namespace ::std::literals::string_literals;
bool isPatternSelected(u64 address, u64 size) {
auto currSelection = ImHexApi::HexEditor::getSelection();
if (!currSelection.has_value())
return false;
return Region{ address, size }.overlaps(*currSelection);
}
template<typename T>
auto highlightWhenSelected(u64 address, u64 size, const T &callback) {
constexpr bool HasReturn = !requires(T t) { { t() } -> std::same_as<void>; };
auto selected = isPatternSelected(address, size);
if (selected)
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_HeaderActive));
if constexpr (HasReturn) {
auto result = callback();
if (selected)
ImGui::PopStyleColor();
return result;
} else {
callback();
if (selected)
ImGui::PopStyleColor();
}
}
template<typename T>
auto highlightWhenSelected(const pl::ptrn::Pattern& pattern, const T &callback) {
return highlightWhenSelected(pattern.getOffset(), pattern.getSize(), callback);
}
void createLeafNode(const pl::ptrn::Pattern& pattern) {
ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf |
ImGuiTreeNodeFlags_NoTreePushOnOpen |
@@ -44,12 +81,13 @@ namespace hex {
bool createTreeNode(const pl::ptrn::Pattern& pattern) {
if (pattern.isSealed()) {
ImGui::Indent();
ImGui::TextUnformatted(pattern.getDisplayName().c_str());
highlightWhenSelected(pattern, [&]{ ImGui::TextUnformatted(pattern.getDisplayName().c_str()); });
ImGui::Unindent();
return false;
}
else
return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
else {
return highlightWhenSelected(pattern, [&]{ return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);});
}
}
void drawTypenameColumn(const pl::ptrn::Pattern& pattern, const std::string& pattern_name) {
@@ -60,7 +98,7 @@ namespace hex {
}
void drawNameColumn(const pl::ptrn::Pattern& pattern) {
ImGui::TextUnformatted(pattern.getDisplayName().c_str());
highlightWhenSelected(pattern, [&]{ ImGui::TextUnformatted(pattern.getDisplayName().c_str()); });
ImGui::TableNextColumn();
}
@@ -119,12 +157,14 @@ namespace hex {
}
void PatternDrawer::visit(pl::ptrn::PatternArrayDynamic& pattern) {
this->drawArray(pattern);
drawArray(pattern, pattern, pattern.isInlined());
}
void PatternDrawer::visit(pl::ptrn::PatternArrayStatic& pattern) {
this->drawArray(pattern);
drawArray(pattern, pattern, pattern.isInlined());
}
void PatternDrawer::visit(pl::ptrn::PatternBitfieldField& pattern) {
@@ -272,8 +312,8 @@ namespace hex {
}
if (open) {
pattern.forEachMember([&](auto &member){
this->draw(member);
pattern.forEachEntry(0, pattern.getMembers().size(), [&](u64, auto *member){
this->draw(*member);
});
if (!pattern.isInlined())
@@ -302,8 +342,8 @@ namespace hex {
}
if (open) {
pattern.forEachMember([&](auto &member) {
this->draw(member);
pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, auto *member) {
this->draw(*member);
});
if (!pattern.isInlined())
@@ -331,9 +371,9 @@ namespace hex {
pattern.accept(*this);
}
bool PatternDrawer::drawArrayRoot(pl::ptrn::Pattern& pattern, size_t entryCount, bool isInlined) {
if (entryCount == 0)
return false;
void PatternDrawer::drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::Iteratable &iteratable, bool isInlined) {
if (iteratable.getEntryCount() == 0)
return;
bool open = true;
if (!isInlined) {
@@ -354,7 +394,7 @@ namespace hex {
ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0);
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", entryCount);
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", iteratable.getEntryCount());
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]");
@@ -362,35 +402,60 @@ namespace hex {
ImGui::TextFormatted("{}", pattern.getFormattedValue());
}
return open;
}
if (open) {
u64 chunkCount = 0;
for (u64 i = 0; i < iteratable.getEntryCount(); i += ChunkSize) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
void PatternDrawer::drawArrayNode(u64 idx, u64& displayEnd, pl::ptrn::Pattern& pattern) {
u64 lastVisible = displayEnd - 1;
chunkCount++;
ImGui::PushID(reinterpret_cast<void*>(pattern.getOffset()));
auto &displayEnd = this->getDisplayEnd(pattern);
if (chunkCount > displayEnd) {
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
displayEnd += DisplayEndStep;
break;
} else {
auto endIndex = std::min<u64>(iteratable.getEntryCount(), i + ChunkSize);
if (idx < lastVisible) {
this->draw(pattern);
} else if (idx == lastVisible) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
auto startOffset = iteratable.getEntry(i)->getOffset();
auto endOffset = iteratable.getEntry(endIndex - 1)->getOffset();
auto endSize = iteratable.getEntry(endIndex - 1)->getSize();
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
displayEnd += DisplayEndStep;
}
size_t chunkSize = (endOffset - startOffset) + endSize;
ImGui::PopID();
}
auto chunkOpen = highlightWhenSelected(startOffset, ((endOffset + endSize) - startOffset) - 1, [&]{ return ImGui::TreeNodeEx(hex::format("[{} ... {}]", i, endIndex - 1).c_str(), ImGuiTreeNodeFlags_SpanFullWidth); });
ImGui::TableNextColumn();
drawColorColumn(pattern);
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", startOffset, startOffset + chunkSize - (pattern.getSize() == 0 ? 0 : 1));
ImGui::TableNextColumn();
ImGui::TextFormatted("0x{0:04X}", chunkSize);
ImGui::TableNextColumn();
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", pattern.getTypeName());
ImGui::SameLine(0, 0);
void PatternDrawer::drawArrayEnd(pl::ptrn::Pattern& pattern, bool opened, bool inlined) {
if (opened) {
if (!inlined)
ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0);
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", endIndex - i);
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]");
ImGui::TableNextColumn();
ImGui::TextFormatted("[ ... ]");
if (chunkOpen) {
iteratable.forEachEntry(i, endIndex, [&](u64, auto *entry){
this->draw(*entry);
});
ImGui::TreePop();
}
}
}
if (!isInlined)
ImGui::TreePop();
} else {
auto& displayEnd = this->getDisplayEnd(pattern);
displayEnd = DisplayEndDefault;
}
}
@@ -403,4 +468,4 @@ namespace hex {
auto [value, success] = this->m_displayEnd.emplace(&pattern, DisplayEndDefault);
return value->second;
}
};
}

View File

@@ -38,6 +38,14 @@ namespace hex::plugin::builtin {
ImGui::EndMenu();
}
if (ImGui::MenuItem("hex.builtin.menu.file.reload_file"_lang, "CTRL + R", false, !taskRunning && ImHexApi::Provider::isValid())) {
auto provider = ImHexApi::Provider::get();
provider->close();
if (!provider->open())
ImHexApi::Provider::remove(provider, true);
}
});
/* File open, quit imhex */
@@ -64,7 +72,9 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"}
},
[](const auto &path) {
ProjectFile::load(path);
if (!ProjectFile::load(path)) {
View::showErrorPopup("hex.builtin.popup.error.project.load"_lang);
}
});
}
@@ -75,7 +85,9 @@ namespace hex::plugin::builtin {
path.replace_extension(".hexproj");
}
ProjectFile::store(path);
if (!ProjectFile::store(path)) {
View::showErrorPopup("hex.builtin.popup.error.project.save"_lang);
}
});
}
});

View File

@@ -7,6 +7,7 @@
#include <pl/core/evaluator.hpp>
#include <pl/patterns/pattern.hpp>
#include <llvm/Demangle/Demangle.h>
namespace hex::plugin::builtin {
void registerPatternLanguageFunctions() {
@@ -16,7 +17,7 @@ namespace hex::plugin::builtin {
pl::api::Namespace nsHexCore = { "builtin", "hex", "core" };
{
/* get_selection() */
ContentRegistry::PatternLanguage::addDangerousFunction(nsHexCore, "get_selection", FunctionParameterCount::none(), [](Evaluator *, auto) -> std::optional<Token::Literal> {
ContentRegistry::PatternLanguage::addFunction(nsHexCore, "get_selection", FunctionParameterCount::none(), [](Evaluator *, auto) -> std::optional<Token::Literal> {
if (!ImHexApi::HexEditor::isSelectionValid())
return std::numeric_limits<u128>::max();
@@ -26,6 +27,16 @@ namespace hex::plugin::builtin {
});
}
pl::api::Namespace nsHexDec = { "builtin", "hex", "dec" };
{
/* demangle(mangled_string) */
ContentRegistry::PatternLanguage::addFunction(nsHexDec, "demangle", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
const auto mangledString = Token::literalToString(params[0], false);
return llvm::demangle(mangledString);
});
}
pl::api::Namespace nsHexHttp = { "builtin", "hex", "http" };
{
/* get(url) */

View File

@@ -24,6 +24,7 @@ namespace hex::plugin::builtin {
ProjectFile::registerHandler({
.basePath = "providers",
.required = true,
.load = [](const std::fs::path &basePath, Tar &tar) {
auto json = nlohmann::json::parse(tar.readString(basePath / "providers.json"));
auto providerIds = json["providers"].get<std::vector<int>>();
@@ -33,13 +34,15 @@ namespace hex::plugin::builtin {
auto providerSettings = nlohmann::json::parse(tar.readString(basePath / hex::format("{}.json", id)));
auto provider = ImHexApi::Provider::createProvider(providerSettings["type"].get<std::string>(), true);
ON_SCOPE_EXIT { if (!success) ImHexApi::Provider::remove(provider, true); };
if (provider == nullptr) {
success = false;
continue;
}
provider->setID(id);
provider->loadSettings(providerSettings["settings"]);
if (!provider->open())
if (!provider->open() || !provider->isAvailable() || !provider->isReadable())
success = false;
else
EventManager::post<EventProviderOpened>(provider);

View File

@@ -11,22 +11,17 @@
#include <imgui.h>
#if defined(OS_WINDOWS)
#include <winioctl.h>
#elif defined(OS_LINUX) || defined(OS_MACOS)
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
#if defined(OS_LINUX)
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define lseek lseek64
#elif defined(OS_MACOS)
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
namespace hex::plugin::builtin::prv {
@@ -264,14 +259,14 @@ namespace hex::plugin::builtin::prv {
}
std::string DiskProvider::getName() const {
return this->m_path.string();
return hex::toUTF8String(this->m_path);
}
std::vector<std::pair<std::string, std::string>> DiskProvider::getDataInformation() const {
return {
{"hex.builtin.provider.disk.selected_disk"_lang, this->m_path.string() },
{ "hex.builtin.provider.disk.disk_size"_lang, hex::toByteString(this->m_diskSize) },
{ "hex.builtin.provider.disk.sector_size"_lang, hex::toByteString(this->m_sectorSize)}
{ "hex.builtin.provider.disk.selected_disk"_lang, hex::toUTF8String(this->m_path) },
{ "hex.builtin.provider.disk.disk_size"_lang, hex::toByteString(this->m_diskSize) },
{ "hex.builtin.provider.disk.sector_size"_lang, hex::toByteString(this->m_sectorSize) }
};
}
@@ -346,7 +341,7 @@ namespace hex::plugin::builtin::prv {
}
nlohmann::json DiskProvider::storeSettings(nlohmann::json settings) const {
settings["path"] = this->m_path.string();
settings["path"] = hex::toUTF8String(this->m_path);
return Provider::storeSettings(settings);
}
@@ -354,7 +349,8 @@ namespace hex::plugin::builtin::prv {
void DiskProvider::loadSettings(const nlohmann::json &settings) {
Provider::loadSettings(settings);
this->setPath(settings["path"].get<std::string>());
auto path = settings["path"].get<std::string>();
this->setPath(std::u8string(path.begin(), path.end()));
this->reloadDrives();
}

View File

@@ -13,11 +13,7 @@
namespace hex::plugin::builtin::prv {
bool FileProvider::isAvailable() const {
#if defined(OS_WINDOWS)
return this->m_file != INVALID_HANDLE_VALUE && this->m_mapping != INVALID_HANDLE_VALUE && this->m_mappedFile != nullptr;
#else
return this->m_file != -1 && this->m_mappedFile != nullptr;
#endif
return this->m_mappedFile != nullptr;
}
bool FileProvider::isReadable() const {
@@ -59,7 +55,7 @@ namespace hex::plugin::builtin::prv {
}
void FileProvider::readRaw(u64 offset, void *buffer, size_t size) {
if ((offset + size) > this->getRealTimeSize() || buffer == nullptr || size == 0)
if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0)
return;
std::memcpy(buffer, reinterpret_cast<u8 *>(this->m_mappedFile) + offset, size);
@@ -151,32 +147,18 @@ namespace hex::plugin::builtin::prv {
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)) {
if (static_cast<off_t>(this->m_fileSize) != newStats.st_size ||
std::memcmp(&newStats.st_mtim, &this->m_fileStats.st_mtim, sizeof(newStats.st_mtim))) {
this->m_fileStats = newStats;
this->m_fileSize = this->m_fileStats.st_size;
msync(this->m_mappedFile, this->m_fileStats.st_size, MS_INVALIDATE);
}
}
#endif
return getActualSize();
}
size_t FileProvider::getActualSize() const {
return this->m_fileSize;
}
std::string FileProvider::getName() const {
return std::fs::path(this->m_path).filename().string();
return hex::toUTF8String(this->m_path.filename());
}
std::vector<std::pair<std::string, std::string>> FileProvider::getDataInformation() const {
std::vector<std::pair<std::string, std::string>> result;
result.emplace_back("hex.builtin.provider.file.path"_lang, this->m_path.string());
result.emplace_back("hex.builtin.provider.file.path"_lang, hex::toUTF8String(this->m_path));
result.emplace_back("hex.builtin.provider.file.size"_lang, hex::toByteString(this->getActualSize()));
if (this->m_fileStatsValid) {
@@ -208,67 +190,51 @@ namespace hex::plugin::builtin::prv {
this->m_fileStatsValid = wstat(path.c_str(), &this->m_fileStats) == 0;
LARGE_INTEGER fileSize = {};
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
auto file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
GetFileSizeEx(this->m_file, &fileSize);
GetFileSizeEx(file, &fileSize);
this->m_fileSize = fileSize.QuadPart;
CloseHandle(this->m_file);
CloseHandle(file);
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
if (file == nullptr || file == INVALID_HANDLE_VALUE) {
file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
this->m_writable = false;
}
auto fileCleanup = SCOPE_GUARD {
CloseHandle(this->m_file);
this->m_readable = false;
this->m_file = nullptr;
};
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
if (file == nullptr || file == INVALID_HANDLE_VALUE) {
return false;
}
ON_SCOPE_EXIT { CloseHandle(file); };
if (this->m_fileSize > 0) {
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, 0, 0, nullptr);
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) {
HANDLE mapping = CreateFileMapping(file, nullptr, PAGE_READWRITE, 0, 0, nullptr);
ON_SCOPE_EXIT { CloseHandle(mapping); };
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (mapping == nullptr || mapping == INVALID_HANDLE_VALUE) {
mapping = CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE)
if (mapping == nullptr || mapping == INVALID_HANDLE_VALUE)
return false;
}
auto mappingCleanup = SCOPE_GUARD {
CloseHandle(this->m_mapping);
this->m_mapping = nullptr;
this->m_readable = false;
};
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
this->m_mappedFile = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
if (this->m_mappedFile == nullptr) {
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_READ, 0, 0, this->m_fileSize);
this->m_mappedFile = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, this->m_fileSize);
if (this->m_mappedFile == nullptr) {
this->m_readable = false;
return false;
}
}
mappingCleanup.release();
} else if (!this->m_emptyFile) {
this->m_emptyFile = true;
this->resize(1);
} else {
return false;
}
fileCleanup.release();
#else
const auto &path = this->m_path.native();
@@ -276,27 +242,25 @@ namespace hex::plugin::builtin::prv {
int mmapprot = PROT_READ | PROT_WRITE;
this->m_file = ::open(path.c_str(), O_RDWR);
if (this->m_file == -1) {
this->m_file = ::open(path.c_str(), O_RDONLY);
auto file = ::open(path.c_str(), O_RDWR);
if (file == -1) {
file = ::open(path.c_str(), O_RDONLY);
this->m_writable = false;
mmapprot &= ~(PROT_WRITE);
}
if (this->m_file == -1) {
if (file == -1) {
this->m_readable = false;
return false;
}
ON_SCOPE_EXIT { ::close(file); };
this->m_fileSize = this->m_fileStats.st_size;
this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, this->m_file, 0);
if (this->m_mappedFile == MAP_FAILED) {
::close(this->m_file);
this->m_file = -1;
this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, file, 0);
if (this->m_mappedFile == MAP_FAILED)
return false;
}
#endif
@@ -308,15 +272,11 @@ namespace hex::plugin::builtin::prv {
if (this->m_mappedFile != nullptr)
::UnmapViewOfFile(this->m_mappedFile);
if (this->m_mapping != nullptr)
::CloseHandle(this->m_mapping);
if (this->m_file != nullptr)
::CloseHandle(this->m_file);
#else
::munmap(this->m_mappedFile, this->m_fileSize);
::close(this->m_file);
if (this->m_mappedFile != nullptr)
::munmap(this->m_mappedFile, this->m_fileSize);
#endif
}
@@ -324,11 +284,12 @@ namespace hex::plugin::builtin::prv {
void FileProvider::loadSettings(const nlohmann::json &settings) {
Provider::loadSettings(settings);
this->setPath(settings["path"].get<std::string>());
auto path = settings["path"].get<std::string>();
this->setPath(std::u8string(path.begin(), path.end()));
}
nlohmann::json FileProvider::storeSettings(nlohmann::json settings) const {
settings["path"] = this->m_path.string();
settings["path"] = hex::toUTF8String(this->m_path);
return Provider::storeSettings(settings);
}

View File

@@ -218,7 +218,7 @@ namespace hex::plugin::builtin::prv {
}
[[nodiscard]] std::string IntelHexProvider::getName() const {
return hex::format("hex.builtin.provider.intel_hex.name"_lang, this->m_sourceFilePath.filename().string());
return hex::format("hex.builtin.provider.intel_hex.name"_lang, hex::toUTF8String(this->m_sourceFilePath.filename()));
}
bool IntelHexProvider::handleFilePicker() {
@@ -250,11 +250,12 @@ namespace hex::plugin::builtin::prv {
void IntelHexProvider::loadSettings(const nlohmann::json &settings) {
Provider::loadSettings(settings);
this->m_sourceFilePath = settings["path"].get<std::string>();
auto path = settings["path"].get<std::string>();
this->m_sourceFilePath = std::u8string(path.begin(), path.end());
}
nlohmann::json IntelHexProvider::storeSettings(nlohmann::json settings) const {
settings["path"] = this->m_sourceFilePath.string();
settings["path"] = hex::toUTF8String(this->m_sourceFilePath);
return Provider::storeSettings(settings);
}

View File

@@ -1,15 +1,11 @@
#include "content/providers/motorola_srec_provider.hpp"
#include <cstring>
#include <hex/api/imhex_api.hpp>
#include <hex/api/localization.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/fmt.hpp>
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin::prv {
namespace motorola_srec {
@@ -198,7 +194,7 @@ namespace hex::plugin::builtin::prv {
}
[[nodiscard]] std::string MotorolaSRECProvider::getName() const {
return hex::format("hex.builtin.provider.motorola_srec.name"_lang, this->m_sourceFilePath.filename().string());
return hex::format("hex.builtin.provider.motorola_srec.name"_lang, hex::toUTF8String(this->m_sourceFilePath.filename()));
}
bool MotorolaSRECProvider::handleFilePicker() {

View File

@@ -14,8 +14,10 @@
#include <nlohmann/json.hpp>
namespace {
static std::vector<std::fs::path> userFolders;
static void loadUserFoldersFromSetting(nlohmann::json &setting) {
std::vector<std::fs::path> userFolders;
void loadUserFoldersFromSetting(nlohmann::json &setting) {
userFolders.clear();
std::vector<std::string> paths = setting;
for (const auto &path : paths) {
@@ -24,7 +26,8 @@ namespace {
userFolders.emplace_back(uString);
}
}
};
}
namespace hex::plugin::builtin {
@@ -182,6 +185,17 @@ namespace hex::plugin::builtin {
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", 1, [](auto name, nlohmann::json &setting) {
static bool enabled = static_cast<int>(setting);
if (ImGui::Checkbox(name.data(), &enabled)) {
setting = static_cast<int>(enabled);
return true;
}
return false;
}, true);
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.highlight_color", 0x60C08080, [](auto name, nlohmann::json &setting) {
static auto color = static_cast<color_t>(setting);
@@ -283,6 +297,39 @@ namespace hex::plugin::builtin {
return result;
});
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", 0, [](auto name, nlohmann::json &setting) {
static bool syncScrolling = static_cast<int>(setting);
if (ImGui::Checkbox(name.data(), &syncScrolling)) {
setting = static_cast<int>(syncScrolling);
return true;
}
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", 0, [](auto name, nlohmann::json &setting) {
static int padding = static_cast<int>(setting);
if (ImGui::SliderInt(name.data(), &padding, 0, 50)) {
setting = padding;
return true;
}
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", 0, [](auto name, nlohmann::json &setting) {
static int padding = static_cast<int>(setting);
if (ImGui::SliderInt(name.data(), &padding, 0, 50)) {
setting = padding;
return true;
}
return false;
});
/* Fonts */
@@ -301,7 +348,7 @@ namespace hex::plugin::builtin {
if (ImGui::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
return fs::openFileBrowser(fs::DialogMode::Open, { {"TTF Font", "ttf"} },
[&](const std::fs::path &path) {
fontPath = path.string();
fontPath = hex::toUTF8String(path);
setting = fontPath;
});
}
@@ -360,7 +407,7 @@ namespace hex::plugin::builtin {
} else {
for (size_t n = 0; n < userFolders.size(); n++) {
const bool isSelected = (currentItemIndex == n);
if (ImGui::Selectable(userFolders.at(n).string().c_str(), isSelected)) { currentItemIndex = n; }
if (ImGui::Selectable(hex::toUTF8String(userFolders.at(n)).c_str(), isSelected)) { currentItemIndex = n; }
if (isSelected) { ImGui::SetItemDefaultFocus(); }
}
ImGui::EndListBox();
@@ -475,7 +522,7 @@ namespace hex::plugin::builtin {
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());
log::info("Loading custom front from {}", hex::toUTF8String(path));
fontFile = path;
break;
@@ -483,11 +530,11 @@ namespace hex::plugin::builtin {
}
}
ImHexApi::System::impl::setCustomFontPath(fontFile);
// If a custom font has been loaded now, also load the font size
float fontSize = ImHexApi::System::DefaultFontSize * 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();
}

View File

@@ -1,6 +1,8 @@
#include <hex/api/keybinding.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
namespace hex::plugin::builtin {
void registerShortcuts() {
@@ -16,7 +18,19 @@ namespace hex::plugin::builtin {
// Close file
ShortcutManager::addGlobalShortcut(CTRL + Keys::W, [] {
ImHexApi::Provider::remove(ImHexApi::Provider::get());
if (ImHexApi::Provider::isValid())
ImHexApi::Provider::remove(ImHexApi::Provider::get());
});
// Reload file
ShortcutManager::addGlobalShortcut(CTRL + Keys::R, [] {
if (ImHexApi::Provider::isValid()) {
auto provider = ImHexApi::Provider::get();
provider->close();
if (!provider->open())
ImHexApi::Provider::remove(provider, true);
}
});
}

View File

@@ -16,7 +16,6 @@
#include <chrono>
#include <random>
#include <regex>
#include <limits>
#include <llvm/Demangle/Demangle.h>
#include <content/helpers/math_evaluator.hpp>
@@ -75,9 +74,8 @@ namespace hex::plugin::builtin {
ImGui::TableHeadersRow();
u32 rowCount = 0;
for (u8 i = 0; i < 0x80 / 4; i++) {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextFormatted("{0:03d}", i + 32 * tablePart);
@@ -92,10 +90,6 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
ImGui::TextFormatted("{0}", hex::makePrintable(i + 32 * tablePart));
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
rowCount++;
}
ImGui::EndTable();
@@ -113,8 +107,8 @@ namespace hex::plugin::builtin {
static auto replacePattern = [] { std::string s; s.reserve(0xFFF); return s; }();
static auto regexOutput = [] { std::string s; s.reserve(0xFFF); return s; }();
bool changed1 = ImGui::InputText("hex.builtin.tools.regex_replacer.pattern"_lang, regexPattern);
bool changed2 = ImGui::InputText("hex.builtin.tools.regex_replacer.replace"_lang, replacePattern);
bool changed1 = ImGui::InputTextIcon("hex.builtin.tools.regex_replacer.pattern"_lang, ICON_VS_REGEX, regexPattern);
bool changed2 = ImGui::InputTextIcon("hex.builtin.tools.regex_replacer.replace"_lang, ICON_VS_REGEX, replacePattern);
bool changed3 = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput, ImVec2(0, 0));
if (changed1 || changed2 || changed3) {
@@ -391,7 +385,12 @@ namespace hex::plugin::builtin {
ImGui::TableSetupColumn("hex.builtin.tools.value"_lang);
ImGui::TableHeadersRow();
for (const auto &[name, value] : mathEvaluator.getVariables()) {
for (const auto &[name, variable] : mathEvaluator.getVariables()) {
const auto &[value, constant] = variable;
if (constant)
continue;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(name.c_str());
@@ -420,7 +419,7 @@ namespace hex::plugin::builtin {
}
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputText("##input", mathInput, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
if (ImGui::InputTextIcon("##input", ICON_VS_SYMBOL_OPERATOR, mathInput, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
ImGui::SetKeyboardFocusHere();
evaluate = true;
}
@@ -434,10 +433,9 @@ namespace hex::plugin::builtin {
if (evaluate) {
try {
auto result = mathEvaluator.evaluate(mathInput);
mathInput.clear();
if (result.has_value()) {
mathHistory.push_back(result.value());
mathInput.clear();
lastMathError.clear();
}
@@ -448,75 +446,45 @@ namespace hex::plugin::builtin {
}
void drawBaseConverter() {
static char buffer[4][0x1000] = { { '0' }, { '0' }, { '0' }, { '0' } };
static auto CharFilter = [](ImGuiInputTextCallbackData *data) -> int {
switch (*static_cast<u32 *>(data->UserData)) {
case 16:
return std::isxdigit(data->EventChar);
case 10:
return std::isdigit(data->EventChar);
case 8:
return std::isdigit(data->EventChar) && data->EventChar < '8';
case 2:
return data->EventChar == '0' || data->EventChar == '1';
default:
return false;
}
};
static std::array<std::string, 4> buffers;
static auto ConvertBases = [](u8 base) {
u64 number;
errno = 0;
switch (base) {
case 16:
number = std::strtoull(buffer[1], nullptr, base);
number = std::strtoull(buffers[1].c_str(), nullptr, base);
break;
case 10:
number = std::strtoull(buffer[0], nullptr, base);
number = std::strtoull(buffers[0].c_str(), nullptr, base);
break;
case 8:
number = std::strtoull(buffer[2], nullptr, base);
number = std::strtoull(buffers[2].c_str(), nullptr, base);
break;
case 2:
number = std::strtoull(buffer[3], nullptr, base);
number = std::strtoull(buffers[3].c_str(), nullptr, base);
break;
default:
return;
}
auto base10String = std::to_string(number);
auto base16String = hex::format("0x{0:X}", number);
auto base8String = hex::format("{0:#o}", number);
auto base2String = hex::toBinaryString(number);
std::strncpy(buffer[0], base10String.c_str(), sizeof(buffer[0]) - 1);
std::strncpy(buffer[1], base16String.c_str(), sizeof(buffer[1]) - 1);
std::strncpy(buffer[2], base8String.c_str(), sizeof(buffer[2]) - 1);
std::strncpy(buffer[3], base2String.c_str(), sizeof(buffer[3]) - 1);
buffer[0][0xFFF] = '\x00';
buffer[1][0xFFF] = '\x00';
buffer[2][0xFFF] = '\x00';
buffer[3][0xFFF] = '\x00';
buffers[0] = std::to_string(number);
buffers[1] = hex::format("0x{0:X}", number);
buffers[2] = hex::format("{0:#o}", number);
buffers[3] = hex::toBinaryString(number);
};
u8 base = 10;
if (ImGui::InputText("hex.builtin.tools.base_converter.dec"_lang, buffer[0], 20 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
ConvertBases(base);
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.dec"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[0]))
ConvertBases(10);
base = 16;
if (ImGui::InputText("hex.builtin.tools.base_converter.hex"_lang, buffer[1], 16 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
ConvertBases(base);
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.hex"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[1]))
ConvertBases(16);
base = 8;
if (ImGui::InputText("hex.builtin.tools.base_converter.oct"_lang, buffer[2], 22 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
ConvertBases(base);
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.oct"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[2]))
ConvertBases(8);
base = 2;
if (ImGui::InputText("hex.builtin.tools.base_converter.bin"_lang, buffer[3], 64 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
ConvertBases(base);
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.bin"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[3]))
ConvertBases(2);
}
void drawPermissionsCalculator() {
@@ -652,9 +620,11 @@ namespace hex::plugin::builtin {
if (response.code == 200) {
try {
auto json = nlohmann::json::parse(response.body);
links.push_back({ currFile.filename().string(),
links.push_back({
hex::toUTF8String(currFile.filename()),
json["data"]["file"]["url"]["short"],
json["data"]["file"]["metadata"]["size"]["readable"] });
json["data"]["file"]["metadata"]["size"]["readable"]
});
} catch (...) {
View::showErrorPopup("hex.builtin.tools.file_uploader.invalid_response"_lang);
}
@@ -691,7 +661,7 @@ namespace hex::plugin::builtin {
bool startSearch;
startSearch = ImGui::InputText("##search", searchString, ImGuiInputTextFlags_EnterReturnsTrue);
startSearch = ImGui::InputTextIcon("##search", ICON_VS_SYMBOL_KEY, searchString, ImGuiInputTextFlags_EnterReturnsTrue);
ImGui::SameLine();
ImGui::BeginDisabled((searchProcess.valid() && searchProcess.wait_for(0s) != std::future_status::ready) || searchString.empty());
@@ -1007,7 +977,7 @@ namespace hex::plugin::builtin {
u32 index = 0;
for (auto &file : files) {
if (ImGui::Selectable(std::fs::path(file).filename().string().c_str(), index == selectedIndex))
if (ImGui::Selectable(hex::toUTF8String(file).c_str(), index == selectedIndex))
selectedIndex = index;
index++;
}
@@ -1099,7 +1069,7 @@ namespace hex::plugin::builtin {
fs::File input(file, fs::File::Mode::Read);
if (!input.isValid()) {
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, std::fs::path(file).filename().string()));
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, hex::toUTF8String(file)));
return;
}

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