Compare commits

...

125 Commits

Author SHA1 Message Date
WerWolv
72ee1d186e build: Bumped version to 1.24.3 2022-10-12 12:48:50 +02:00
WerWolv
ee53eca19f patterns: Updated pattern language 2022-10-12 12:25:22 +02:00
WerWolv
7331b8d5ae node: Limit width of out variable access node 2022-10-12 12:24:54 +02:00
WerWolv
d17911d753 fix: Invalid axis labels in data information view 2022-10-12 12:24:11 +02:00
WerWolv
b41d01f126 lang: Added localization for new nodes 2022-10-12 12:18:27 +02:00
WerWolv
27fc3fd659 nodes: Added out variable access node 2022-10-12 12:18:18 +02:00
WerWolv
cc9dc90655 nodes: Added Float <-> Buffer casting nodes 2022-10-12 12:09:51 +02:00
WerWolv
015266181e fix: Various issue with the hex editor editing mode 2022-10-12 10:56:03 +02:00
WerWolv
299933c4f7 feat: Allow ASCII cells in Hex editor to be edited 2022-10-11 20:18:45 +02:00
WerWolv
5312d6f9fa fix: Data inspector still displaying entries with no selection 2022-10-11 20:18:16 +02:00
WerWolv
16eb7b3dbd ui: Fixed hex editor highlighting sometimes having gaps 2022-10-11 15:06:33 +02:00
WerWolv
cb9458dab4 patterns: Updated pattern language 2022-10-11 14:15:22 +02:00
WerWolv
e32a85a33f patterns: Updated pattern language 2022-10-11 09:00:07 +02:00
WerWolv
e4680fb0a2 fix: 64-Bit hex data visualizer only displaying 32 bit 2022-10-11 09:00:00 +02:00
WerWolv
1c52e0018a fix: Prevent same pl runtime from running simultaneously when loading provider 2022-10-10 23:16:54 +02:00
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
128 changed files with 2766 additions and 1391 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,13 +25,12 @@ jobs:
with: with:
languages: 'cpp' languages: 'cpp'
- name: 📜 Restore ccache - name: 📜 Setup ccache
uses: actions/cache@v3 uses: hendrikmuhs/ccache-action@v1.2
with: with:
path: |
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }} key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache - name: 📜 Restore CMakeCache
uses: actions/cache@v3 uses: actions/cache@v3

View File

@@ -28,21 +28,13 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: 📜 Prepare Cache - name: 📜 Setup ccache
id: prep-ccache uses: hendrikmuhs/ccache-action@v1.2
shell: bash
run: |
mkdir -p "${CCACHE_DIR}"
echo "::set-output name=dir::$CCACHE_DIR"
- name: 📜 Restore ccache
uses: actions/cache@v3
id: cache-ccache id: cache-ccache
with: with:
path: |
${{ steps.prep-ccache.outputs.dir }}
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }} key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache - name: 📜 Restore CMakeCache
uses: actions/cache@v3 uses: actions/cache@v3
@@ -64,43 +56,40 @@ jobs:
glfw:p glfw:p
file:p file:p
mbedtls:p mbedtls:p
python:p
freetype:p freetype:p
dlfcn: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 # Windows cmake build
- name: 🛠️ Build - name: 🛠️ Build
run: | run: |
mkdir -p build mkdir -p build
cd 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" \ cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \ -DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \ -DCREATE_PACKAGE=ON \
-DPython_LIBRARY="$PYTHON_LIB_PATH" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \ -DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \ -DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
.. ..
mingw32-make -j4 install mingw32-make -j4 install
cpack 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 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 - name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
@@ -155,13 +144,12 @@ jobs:
run: | run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
- name: 📜 Restore ccache - name: 📜 Setup ccache
uses: actions/cache@v3 uses: hendrikmuhs/ccache-action@v1.2
with: with:
path: |
~/Library/Caches/ccache
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }} 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 - name: 📜 Restore CMakeCache
@@ -174,6 +162,7 @@ jobs:
- name: ⬇️ Install dependencies - name: ⬇️ Install dependencies
run: | run: |
brew bundle --no-lock --file dist/Brewfile brew bundle --no-lock --file dist/Brewfile
rm -rf /usr/local/Cellar/capstone
- name: ⬇️ Install classic glfw - name: ⬇️ Install classic glfw
if: ${{! matrix.custom_glfw}} if: ${{! matrix.custom_glfw}}
@@ -248,13 +237,12 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: 📜 Restore ccache - name: 📜 Setup ccache
uses: actions/cache@v3 uses: hendrikmuhs/ccache-action@v1.2
with: with:
path: |
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }} key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore other caches - name: 📜 Restore other caches
uses: actions/cache@v3 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 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 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 chmod +x /usr/local/bin/appimagetool
sudo pip3 install appimage-builder==1.0.0 sudo pip3 install appimage-builder
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
# Ubuntu cmake build # Ubuntu cmake build
- name: 🛠️ Build - name: 🛠️ Build
@@ -299,7 +280,6 @@ jobs:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \ -DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \ -DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DRUST_PATH="$HOME/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
.. ..
make -j 4 install DESTDIR=DebDir make -j 4 install DESTDIR=DebDir
@@ -335,7 +315,6 @@ jobs:
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \ -DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \ -DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DRUST_PATH="$HOME/.cargo/bin/" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_PLUGINS_IN_SHARE=ON \ -DIMHEX_PLUGINS_IN_SHARE=ON \
-DIMHEX_USE_BUNDLED_CA=ON \ -DIMHEX_USE_BUNDLED_CA=ON \
@@ -400,13 +379,12 @@ jobs:
run: | run: |
dist/get_deps_archlinux.sh --noconfirm dist/get_deps_archlinux.sh --noconfirm
- name: 📜 Restore ccache - name: 📜 Setup ccache
uses: actions/cache@v3 uses: hendrikmuhs/ccache-action@v1.2
with: with:
path: |
~/.cache/ccache
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }} key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache - name: 📜 Restore CMakeCache
uses: actions/cache@v3 uses: actions/cache@v3
@@ -502,7 +480,6 @@ jobs:
libcurl-devel \ libcurl-devel \
llvm-devel \ llvm-devel \
mbedtls-devel \ mbedtls-devel \
python3-devel \
rpm-build \ rpm-build \
yara-devel yara-devel
@@ -515,13 +492,12 @@ jobs:
run: | run: |
dist/get_deps_fedora.sh dist/get_deps_fedora.sh
- name: 📜 Restore ccache - name: 📜 Setup ccache
uses: actions/cache@v3 uses: hendrikmuhs/ccache-action@v1.2
with: with:
path: |
~/.cache/ccache
key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }} key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build restore-keys: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Set version variable - name: 📜 Set version variable
run: | run: |

View File

@@ -22,13 +22,12 @@ jobs:
with: with:
submodules: recursive submodules: recursive
- name: 📜 Restore ccache - name: 📜 Setup ccache
uses: actions/cache@v3 uses: hendrikmuhs/ccache-action@v1.2
with: with:
path: |
~/.cache/ccache
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }} key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
max-size: 50M
- name: 📜 Restore CMakeCache - 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 # Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}) set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules") set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake") 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 ## 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 ## 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 - **RAM**: 512MB, more may be required for more complicated analysis
- **Storage**: 100MB - **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 ## 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) Information on how to install ImHex can be found in the [Install](/INSTALL.md) guide
### 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)
## Compiling ## 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. 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. 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 ## Credits
### Contributors ### Contributors

View File

@@ -1 +1 @@
1.23.1 1.24.3

View File

@@ -408,7 +408,7 @@ endfunction()
macro(setupCompilerWarnings target) macro(setupCompilerWarnings target)
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Werror") 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_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_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 "libmagic"
brew "pkg-config" brew "pkg-config"
brew "gcc@12" brew "gcc@12"
brew "llvm"

2
dist/Dockerfile vendored
View File

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

View File

@@ -16,7 +16,7 @@ OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \ PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.15" \ MACOSX_DEPLOYMENT_TARGET="10.15" \
cmake \ cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DCMAKE_BUILD_TYPE=Release \
-DCREATE_BUNDLE=ON \ -DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \ -DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \

View File

@@ -164,7 +164,10 @@ static void ImGui_ImplGlfw_ShutdownPlatformInterface();
// Functions // Functions
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) 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) 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; ImGuiContext& g = *GImGui;
g.ClipboardHandlerData.clear(); g.ClipboardHandlerData.clear();
if (!::OpenClipboard(NULL)) if (!::OpenClipboard(NULL))
return NULL; return "";
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT); HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
if (wbuf_handle == NULL) if (wbuf_handle == NULL)
{ {
::CloseClipboard(); ::CloseClipboard();
return NULL; return "";
} }
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle)) 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); ::GlobalUnlock(wbuf_handle);
::CloseClipboard(); ::CloseClipboard();
return g.ClipboardHandlerData.Data; return g.ClipboardHandlerData.Data == nullptr ? "" : g.ClipboardHandlerData.Data;
} }
static void ImGui_ImplWin_SetClipboardText(void*, const char* text) 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_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(LIBROMFS_RESOURCE_LOCATION ${IMHEX_BASE_FOLDER}/resources/romfs) 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) 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) 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) set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
@@ -136,6 +137,7 @@ set(LIBIMHEX_SOURCES
source/helpers/encoding_file.cpp source/helpers/encoding_file.cpp
source/helpers/logger.cpp source/helpers/logger.cpp
source/helpers/tar.cpp source/helpers/tar.cpp
source/helpers/types.cpp
source/providers/provider.cpp source/providers/provider.cpp
@@ -172,4 +174,5 @@ if (APPLE)
target_link_libraries(libimhex PUBLIC ${FOUNDATION}) target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif () 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 #pragma once
#include <cstdint>
#include <cstddef>
#include <hex/helpers/types.hpp> #include <hex/helpers/types.hpp>
#include <hex/helpers/intrinsics.hpp> #include <hex/helpers/intrinsics.hpp>

View File

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

View File

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

View File

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

View File

@@ -10,6 +10,7 @@
#include <chrono> #include <chrono>
#include <memory> #include <memory>
#include <list> #include <list>
#include <condition_variable>
namespace hex { namespace hex {
@@ -19,7 +20,7 @@ namespace hex {
class Task { class Task {
public: public:
Task() = default; 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(const Task&) = delete;
Task(Task &&other) noexcept; Task(Task &&other) noexcept;
@@ -28,6 +29,7 @@ namespace hex {
void update(u64 value = 0); void update(u64 value = 0);
void setMaxValue(u64 value); void setMaxValue(u64 value);
[[nodiscard]] bool isBackgroundTask() const;
[[nodiscard]] bool isFinished() const; [[nodiscard]] bool isFinished() const;
[[nodiscard]] bool hadException() const; [[nodiscard]] bool hadException() const;
[[nodiscard]] bool wasInterrupted() const; [[nodiscard]] bool wasInterrupted() const;
@@ -51,15 +53,16 @@ namespace hex {
mutable std::mutex m_mutex; mutable std::mutex m_mutex;
std::string m_unlocalizedName; std::string m_unlocalizedName;
u64 m_currValue, m_maxValue; std::atomic<u64> m_currValue = 0, m_maxValue = 0;
std::thread m_thread;
std::function<void()> m_interruptCallback; 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; std::atomic<bool> m_interrupted = false;
bool m_finished = false; std::atomic<bool> m_finished = false;
bool m_hadException = false; std::atomic<bool> m_hadException = false;
std::string m_exceptionMessage; std::string m_exceptionMessage;
struct TaskInterruptor { virtual ~TaskInterruptor() = default; }; struct TaskInterruptor { virtual ~TaskInterruptor() = default; };
@@ -86,9 +89,14 @@ namespace hex {
public: public:
TaskManager() = delete; TaskManager() = delete;
static void init();
static void exit();
constexpr static auto NoProgress = 0; constexpr static auto NoProgress = 0;
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function); 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 void collectGarbage();
static size_t getRunningTaskCount(); static size_t getRunningTaskCount();
@@ -100,7 +108,14 @@ namespace hex {
static std::mutex s_deferredCallsMutex; static std::mutex s_deferredCallsMutex;
static std::list<std::shared_ptr<Task>> s_tasks; 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::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(IOType ioType, Type type, std::string unlocalizedName);
~Attribute(); ~Attribute();
[[nodiscard]] u32 getId() const { return this->m_id; } [[nodiscard]] int getId() const { return this->m_id; }
void setId(u32 id) { this->m_id = id; } void setId(int id) { this->m_id = id; }
[[nodiscard]] IOType getIOType() const { return this->m_ioType; } [[nodiscard]] IOType getIOType() const { return this->m_ioType; }
[[nodiscard]] Type getType() const { return this->m_type; } [[nodiscard]] Type getType() const { return this->m_type; }
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; } [[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
void addConnectedAttribute(u32 linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); } void addConnectedAttribute(int linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
void removeConnectedAttribute(u32 linkId) { this->m_connectedAttributes.erase(linkId); } void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
[[nodiscard]] std::map<u32, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; } [[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
[[nodiscard]] Node *getParentNode() { return this->m_parentNode; } [[nodiscard]] Node *getParentNode() { return this->m_parentNode; }
[[nodiscard]] std::optional<std::vector<u8>> &getOutputData() { return this->m_outputData; } [[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) if (id > Attribute::s_idCounter)
Attribute::s_idCounter = id; Attribute::s_idCounter = id;
} }
private: private:
u32 m_id; int m_id;
IOType m_ioType; IOType m_ioType;
Type m_type; Type m_type;
std::string m_unlocalizedName; std::string m_unlocalizedName;
std::map<u32, Attribute *> m_connectedAttributes; std::map<int, Attribute *> m_connectedAttributes;
Node *m_parentNode = nullptr; Node *m_parentNode = nullptr;
std::optional<std::vector<u8>> m_outputData; std::optional<std::vector<u8>> m_outputData;
@@ -60,7 +60,7 @@ namespace hex::dp {
friend class Node; friend class Node;
void setParentNode(Node *node) { this->m_parentNode = 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 { class Link {
public: public:
Link(u32 from, u32 to); Link(int from, int to);
[[nodiscard]] u32 getId() const { return this->m_id; } [[nodiscard]] int getId() const { return this->m_id; }
void setID(u32 id) { this->m_id = id; } void setID(int id) { this->m_id = id; }
[[nodiscard]] u32 getFromId() const { return this->m_from; } [[nodiscard]] int getFromId() const { return this->m_from; }
[[nodiscard]] u32 getToId() const { return this->m_to; } [[nodiscard]] int getToId() const { return this->m_to; }
static void setIdCounter(u32 id) { static void setIdCounter(int id) {
if (id > Link::s_idCounter) if (id > Link::s_idCounter)
Link::s_idCounter = id; Link::s_idCounter = id;
} }
private: private:
u32 m_id; int m_id;
u32 m_from, m_to; int m_from, m_to;
static u32 s_idCounter; static int s_idCounter;
}; };
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -27,8 +27,8 @@ struct ImVec2;
namespace hex { namespace hex {
long double operator""_scaled(long double value); float operator""_scaled(long double value);
long double operator""_scaled(unsigned long long value); float operator""_scaled(unsigned long long value);
ImVec2 scaled(const ImVec2 &vector); ImVec2 scaled(const ImVec2 &vector);
template<typename T> template<typename T>
@@ -275,6 +275,13 @@ namespace hex {
return iter != a.end(); 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> template<typename T, typename... VariantTypes>
T get_or(const std::variant<VariantTypes...> &variant, T alt) { T get_or(const std::variant<VariantTypes...> &variant, T alt) {
const T *value = std::get_if<T>(&variant); const T *value = std::get_if<T>(&variant);
@@ -297,6 +304,13 @@ namespace hex {
std::optional<std::string> getEnvironmentVariable(const std::string &env); 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 { namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]() #define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
@@ -335,7 +349,7 @@ namespace hex {
namespace first_time_exec { 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> template<class F>
class FirstTimeExecute { class FirstTimeExecute {
@@ -358,7 +372,7 @@ namespace hex {
namespace final_cleanup { 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> template<class F>
class FinalCleanupExecute { class FinalCleanupExecute {

View File

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

View File

@@ -31,27 +31,40 @@ enum ImGuiCustomCol {
namespace ImGui { namespace ImGui {
struct Texture { class Texture {
ImTextureID textureId = nullptr; public:
int width = 0, height = 0; 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 { ~Texture();
return this->textureId != nullptr;
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() { [[nodiscard]] constexpr operator ImTextureID() {
return this->textureId; return this->m_textureId;
} }
[[nodiscard]] auto size() const noexcept { [[nodiscard]] auto getSize() const noexcept {
return ImVec2(this->width, this->height); return ImVec2(this->m_width, this->m_height);
} }
[[nodiscard]] constexpr auto aspectRatio() const noexcept { [[nodiscard]] constexpr auto getAspectRatio() const noexcept {
if (this->height == 0) return 1.0F; 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); 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); 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); void OpenPopupInWindow(const char *window_name, const char *popup_name);
struct ImHexCustomData { struct ImHexCustomData {
@@ -130,6 +139,7 @@ namespace ImGui {
} }
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None); 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 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 InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None); bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);

View File

@@ -586,7 +586,7 @@ namespace hex {
}, &userData); }, &userData);
ImGui::PopID(); ImGui::PopID();
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter); return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
} }
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) { void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {

View File

@@ -11,6 +11,12 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#if defined(OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#endif
namespace hex { namespace hex {
namespace ImHexApi::Common { namespace ImHexApi::Common {
@@ -385,6 +391,13 @@ namespace hex {
s_portableVersion = enabled; 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; 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; static float s_targetFPS = 60.0F;

View File

@@ -1,6 +1,7 @@
#include <hex/api/plugin_manager.hpp> #include <hex/api/plugin_manager.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
#include <filesystem> #include <filesystem>
#include <system_error> #include <system_error>
@@ -16,7 +17,7 @@ namespace hex {
return; return;
} }
#else #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) { if (this->m_handle == nullptr) {
log::error("dlopen failed: {}!", dlerror()); log::error("dlopen failed: {}!", dlerror());
@@ -68,7 +69,7 @@ namespace hex {
bool Plugin::initializePlugin() const { bool Plugin::initializePlugin() const {
const auto requestedVersion = getCompatibleVersion(); const auto requestedVersion = getCompatibleVersion();
if (requestedVersion != IMHEX_VERSION) { 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; return false;
} }

View File

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

View File

@@ -4,59 +4,46 @@
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <algorithm> #include <algorithm>
#include <ranges>
namespace hex { namespace hex {
std::mutex TaskManager::s_deferredCallsMutex; 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; std::list<std::function<void()>> TaskManager::s_deferredCalls;
Task::Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function) std::mutex TaskManager::s_queueMutex;
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue) { std::condition_variable TaskManager::s_jobCondVar;
this->m_thread = std::thread([this, func = std::move(function)] { std::vector<std::jthread> TaskManager::s_workers;
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");
}
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 { 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_function = std::move(other.m_function);
this->m_unlocalizedName = std::move(other.m_unlocalizedName); this->m_unlocalizedName = std::move(other.m_unlocalizedName);
}
this->m_maxValue = other.m_maxValue; this->m_maxValue = u64(other.m_maxValue);
this->m_currValue = other.m_currValue; this->m_currValue = u64(other.m_currValue);
this->m_finished = other.m_finished; this->m_finished = bool(other.m_finished);
this->m_hadException = other.m_hadException; this->m_hadException = bool(other.m_hadException);
this->m_interrupted = other.m_interrupted; this->m_interrupted = bool(other.m_interrupted);
this->m_shouldInterrupt = other.m_shouldInterrupt; this->m_shouldInterrupt = bool(other.m_shouldInterrupt);
} }
Task::~Task() { Task::~Task() {
if (!this->isFinished()) if (!this->isFinished())
this->interrupt(); this->interrupt();
this->m_thread.join();
} }
void Task::update(u64 value) { void Task::update(u64 value) {
std::scoped_lock lock(this->m_mutex);
this->m_currValue = value; this->m_currValue = value;
if (this->m_shouldInterrupt) if (this->m_shouldInterrupt)
@@ -64,15 +51,11 @@ namespace hex {
} }
void Task::setMaxValue(u64 value) { void Task::setMaxValue(u64 value) {
std::scoped_lock lock(this->m_mutex);
this->m_maxValue = value; this->m_maxValue = value;
} }
void Task::interrupt() { void Task::interrupt() {
std::scoped_lock lock(this->m_mutex);
this->m_shouldInterrupt = true; this->m_shouldInterrupt = true;
if (this->m_interruptCallback) if (this->m_interruptCallback)
@@ -83,27 +66,23 @@ namespace hex {
this->m_interruptCallback = std::move(callback); this->m_interruptCallback = std::move(callback);
} }
bool Task::isFinished() const { bool Task::isBackgroundTask() const {
std::scoped_lock lock(this->m_mutex); return this->m_background;
}
bool Task::isFinished() const {
return this->m_finished; return this->m_finished;
} }
bool Task::hadException() const { bool Task::hadException() const {
std::scoped_lock lock(this->m_mutex);
return this->m_hadException; return this->m_hadException;
} }
bool Task::wasInterrupted() const { bool Task::wasInterrupted() const {
std::scoped_lock lock(this->m_mutex);
return this->m_interrupted; return this->m_interrupted;
} }
void Task::clearException() { void Task::clearException() {
std::scoped_lock lock(this->m_mutex);
this->m_hadException = false; this->m_hadException = false;
} }
@@ -126,14 +105,10 @@ namespace hex {
} }
void Task::finish() { void Task::finish() {
std::scoped_lock lock(this->m_mutex);
this->m_finished = true; this->m_finished = true;
} }
void Task::interruption() { void Task::interruption() {
std::scoped_lock lock(this->m_mutex);
this->m_interrupted = true; this->m_interrupted = true;
} }
@@ -146,30 +121,112 @@ namespace hex {
bool TaskHolder::isRunning() const { 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 { 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 { 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() { void TaskHolder::interrupt() {
if (!this->m_task.expired()) if (this->m_task.expired())
this->m_task.lock()->interrupt(); 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) { 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()); return TaskHolder(s_tasks.back());
} }
void TaskManager::collectGarbage() { void TaskManager::collectGarbage() {
std::unique_lock lock(s_queueMutex);
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); }); std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
} }
@@ -178,7 +235,11 @@ namespace hex {
} }
size_t TaskManager::getRunningTaskCount() { 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 { 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)) { 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 { 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 { 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)) { 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) 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"); this->m_file = _wfopen(path.c_str(), L"w+b");
#else #else
if (mode == File::Mode::Read) 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) 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)) 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 #endif
} }
@@ -159,7 +159,7 @@ namespace hex::fs {
bool File::remove() { bool File::remove() {
this->close(); 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() { void File::disableBuffering() {

View File

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

View File

@@ -27,7 +27,7 @@ namespace hex::magic {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
for (const auto &entry : std::fs::directory_iterator(dir, error)) { for (const auto &entry : std::fs::directory_iterator(dir, error)) {
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc"))) { 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 <filesystem>
#include <cstdio> #include <cstdio>
#include <mbedtls/ssl.h>
#include <curl/curl.h> #include <curl/curl.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@@ -52,13 +50,13 @@ namespace hex {
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx); auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
static mbedtls_x509_crt crt; auto crt = static_cast<mbedtls_x509_crt*>(userData);
mbedtls_x509_crt_init(&crt); mbedtls_x509_crt_init(crt);
auto cacert = romfs::get("cacert.pem").string(); 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; 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_CAPATH, nullptr);
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM"); 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_FUNCTION, sslCtxFunction);
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_DATA, &this->m_caCert);
#endif #endif
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str()); 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_mime *mime = curl_mime_init(this->m_ctx);
curl_mimepart *part = curl_mime_addpart(mime); 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(), curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t { [](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto file = static_cast<FILE*>(arg); 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 { namespace hex {
long double operator""_scaled(long double value) { float operator""_scaled(long double value) {
return value * ImHexApi::System::getGlobalScale(); 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(); return value * ImHexApi::System::getGlobalScale();
} }

View File

@@ -113,6 +113,8 @@ namespace hex::prv {
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1); this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
} }
this->markDirty(); this->markDirty();
this->m_patches.emplace_back();
} }
@@ -288,4 +290,15 @@ namespace hex::prv {
return { Region { address, *nextRegionAddress - address }, insideValidRegion }; 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 <hex/ui/imgui_imhex_extensions.h>
#include <imgui.h> #include <imgui.h>
#include <imgui_freetype.h>
#define IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h> #include <imgui_internal.h>
#undef IMGUI_DEFINE_MATH_OPERATORS #undef IMGUI_DEFINE_MATH_OPERATORS
@@ -17,6 +16,76 @@
namespace ImGui { 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) { int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) { if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
auto &string = *static_cast<std::string *>(data->UserData); auto &string = *static_cast<std::string *>(data->UserData);
@@ -35,8 +104,8 @@ namespace ImGui {
ImGuiContext &g = *GImGui; ImGuiContext &g = *GImGui;
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
ImVec2 label_size = CalcTextSize(icon, NULL, false); ImVec2 label_size = CalcTextSize(icon, nullptr, false);
label_size.x += CalcTextSize(" ", NULL, false).x + CalcTextSize(label, NULL, false).x; label_size.x += CalcTextSize(" ", nullptr, false).x + CalcTextSize(label, nullptr, false).x;
ImVec2 pos = window->DC.CursorPos; ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y); ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
@@ -69,7 +138,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui; ImGuiContext &g = *GImGui;
const ImGuiID id = window->GetID(label); 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 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y); ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
@@ -86,7 +155,7 @@ namespace ImGui {
// Render // Render
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive); const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
PushStyleColor(ImGuiCol_Text, ImU32(col)); 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)); GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
PopStyleColor(); PopStyleColor();
@@ -102,7 +171,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui; ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style; const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label); 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 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y) + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f); 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; ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style; const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), NULL, true); const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), nullptr, true);
const ImVec2 label_size = CalcTextSize(label, NULL, true); const ImVec2 label_size = CalcTextSize(label, nullptr, true);
ImVec2 pos = window->DC.CursorPos; 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) 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)); RenderTextWrapped(bb.Min + style.FramePadding * 2, label, nullptr, CalcWrapWidthForPos(window->DC.CursorPos, window->DC.TextWrapPos));
PopStyleColor(); PopStyleColor();
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text)); 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(); PopStyleColor();
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@@ -182,13 +251,13 @@ namespace ImGui {
void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) { void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) {
ImGuiWindow *window = GetCurrentWindow(); 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 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y); ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
PushStyleColor(ImGuiCol_Text, ImU32(color)); 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)); GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(color));
PopStyleColor(); PopStyleColor();
} }
@@ -298,66 +367,6 @@ namespace ImGui {
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155); 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) { void OpenPopupInWindow(const char *window_name, const char *popup_name) {
if (ImGui::Begin(window_name)) { if (ImGui::Begin(window_name)) {
ImGui::OpenPopup(popup_name); ImGui::OpenPopup(popup_name);
@@ -374,7 +383,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui; ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style; const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label); 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 pos = window->DC.CursorPos;
@@ -393,7 +402,7 @@ namespace ImGui {
: ImGuiCol_Button); : ImGuiCol_Button);
RenderNavHighlight(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); 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 // Automatically close popups
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) // if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
@@ -413,7 +422,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui; ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style; const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(symbol); 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; ImVec2 pos = window->DC.CursorPos;
@@ -434,7 +443,7 @@ namespace ImGui {
: ImGuiCol_MenuBarBg); : ImGuiCol_MenuBarBg);
RenderNavHighlight(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding); 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(); PopStyleColor();
@@ -456,7 +465,7 @@ namespace ImGui {
ImGuiContext &g = *GImGui; ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style; const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(symbol); 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; ImVec2 pos = window->DC.CursorPos;
@@ -477,7 +486,7 @@ namespace ImGui {
: ImGuiCol_Button); : ImGuiCol_Button);
RenderNavHighlight(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding); 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(); PopStyleColor();
@@ -555,6 +564,33 @@ namespace ImGui {
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer); 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) { 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); 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; ImGuiContext& g = *GImGui;
if (format == NULL) if (format == nullptr)
format = DataTypeGetInfo(data_type)->PrintFmt; format = DataTypeGetInfo(data_type)->PrintFmt;
char buf[64]; char buf[64];
@@ -613,7 +649,7 @@ namespace ImGui {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style; const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label); 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 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
const ImVec2 pos = window->DC.CursorPos; 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}") add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
if (WIN32) 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 () else ()
target_link_libraries(main PUBLIC libimhex pthread) target_link_libraries(main PRIVATE libimhex libromfs-imhex pthread)
endif () endif ()
if (APPLE) if (APPLE)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,9 +20,8 @@ int main(int argc, char **argv, char **envp) {
bool shouldRestart = false; bool shouldRestart = false;
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
do { do {
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
shouldRestart = false; shouldRestart = false;
// Initialization // Initialization
@@ -33,8 +32,9 @@ int main(int argc, char **argv, char **envp) {
init::WindowSplash splashWindow; init::WindowSplash splashWindow;
for (const auto &[name, task] : init::getInitTasks()) TaskManager::init();
splashWindow.addStartupTask(name, task); for (const auto &[name, task, async] : init::getInitTasks())
splashWindow.addStartupTask(name, task, async);
if (!splashWindow.loop()) if (!splashWindow.loop())
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} }); ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
@@ -42,8 +42,9 @@ int main(int argc, char **argv, char **envp) {
// Clean up // Clean up
ON_SCOPE_EXIT { ON_SCOPE_EXIT {
for (const auto &[name, task] : init::getExitTasks()) for (const auto &[name, task, async] : init::getExitTasks())
task(); task();
TaskManager::exit();
}; };
// Main window // Main window
@@ -53,11 +54,21 @@ int main(int argc, char **argv, char **envp) {
if (argc == 1) if (argc == 1)
; // No arguments provided ; // No arguments provided
else if (argc >= 2) { else if (argc >= 2) {
for (auto i = 1; i < argc; i++) for (auto i = 1; i < argc; i++) {
EventManager::post<RequestOpenFile>(argv[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); } while (shouldRestart);

View File

@@ -43,7 +43,7 @@ namespace hex {
if (data == nullptr) break; if (data == nullptr) break;
std::fs::path path = data; 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); EventManager::post<RequestOpenFile>(path);
break; break;
} }

View File

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

View File

@@ -84,3 +84,9 @@ endif()
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}") add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
setupCompilerWarnings(${PROJECT_NAME}) 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: public:
MathEvaluator() = default; MathEvaluator() = default;
struct Variable {
T value;
bool constant;
};
std::optional<T> evaluate(const std::string &input); std::optional<T> evaluate(const std::string &input);
void registerStandardVariables(); void registerStandardVariables();
void registerStandardFunctions(); 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); 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 { [[nodiscard]] bool hasError() const {
return this->m_lastError.has_value(); return this->m_lastError.has_value();
@@ -106,7 +111,7 @@ namespace hex {
std::optional<std::queue<Token>> toPostfix(std::queue<Token> inputQueue); std::optional<std::queue<Token>> toPostfix(std::queue<Token> inputQueue);
std::optional<T> evaluate(std::queue<Token> postfixTokens); 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::unordered_map<std::string, std::function<std::optional<T>(std::vector<T>)>> m_functions;
std::optional<std::string> m_lastError; std::optional<std::string> m_lastError;

View File

@@ -6,11 +6,6 @@
namespace hex { 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 { class PatternDrawer : public pl::PatternVisitor {
public: public:
PatternDrawer() = default; PatternDrawer() = default;
@@ -36,27 +31,13 @@ namespace hex {
private: private:
void draw(pl::ptrn::Pattern& pattern); void draw(pl::ptrn::Pattern& pattern);
template<ArrayPattern T> constexpr static auto ChunkSize = 512;
void drawArray(T& pattern) { constexpr static auto DisplayEndStep = 64;
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);
void drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::Iteratable &iteratable, bool isInlined);
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern); u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
private: private:
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd; std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
}; };
}; }

View File

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

View File

@@ -7,6 +7,7 @@
#include <vector> #include <vector>
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#endif #endif
@@ -45,7 +46,7 @@ namespace hex::plugin::builtin::prv {
return "hex.builtin.provider.disk"; 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: protected:
void reloadDrives(); void reloadDrives();

View File

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

View File

@@ -49,7 +49,7 @@ namespace hex::plugin::builtin::prv {
return "hex.builtin.provider.gdb"; 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: protected:
hex::Socket m_socket; hex::Socket m_socket;

View File

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

View File

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

View File

@@ -21,6 +21,8 @@ namespace hex::plugin::builtin {
void registerMenuItems(); void registerMenuItems();
private: private:
std::string m_currFilter; 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; u64 m_startAddress = 0;
size_t m_validBytes = 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; std::string m_editingValue;
}; };

View File

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

View File

@@ -24,7 +24,8 @@ namespace hex::plugin::builtin {
struct Occurrence { struct Occurrence {
Region region; 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 { struct BinaryPattern {
@@ -38,7 +39,8 @@ namespace hex::plugin::builtin {
Strings, Strings,
Sequence, Sequence,
Regex, Regex,
BinaryPattern BinaryPattern,
Value
} mode = Mode::Strings; } mode = Mode::Strings;
struct Strings { struct Strings {
@@ -55,7 +57,7 @@ namespace hex::plugin::builtin {
bool m_lineFeeds = false; bool m_lineFeeds = false;
} strings; } strings;
struct Bytes { struct Sequence {
std::string sequence; std::string sequence;
} bytes; } bytes;
@@ -68,6 +70,18 @@ namespace hex::plugin::builtin {
std::string input; std::string input;
std::vector<ViewFind::BinaryPattern> pattern; std::vector<ViewFind::BinaryPattern> pattern;
} binaryPattern; } 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; } m_searchSettings, m_decodeSettings;
using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>; using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>;
@@ -80,12 +94,14 @@ namespace hex::plugin::builtin {
bool m_settingsValid = false; bool m_settingsValid = false;
private: private:
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Strings 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, SearchSettings::Bytes 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, SearchSettings::Regex 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, SearchSettings::BinaryPattern 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::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(); void runSearch();
std::string decodeValue(prv::Provider *provider, Occurrence occurrence) const; std::string decodeValue(prv::Provider *provider, Occurrence occurrence) const;

View File

@@ -6,6 +6,8 @@
#include <hex/helpers/concepts.hpp> #include <hex/helpers/concepts.hpp>
#include <hex/helpers/encoding_file.hpp> #include <hex/helpers/encoding_file.hpp>
#include <content/helpers/provider_extra_data.hpp>
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
@@ -18,57 +20,61 @@ namespace hex::plugin::builtin {
void drawContent() override; void drawContent() override;
private: private:
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
void registerShortcuts(); void registerShortcuts();
void registerEvents(); void registerEvents();
void registerMenuItems(); void registerMenuItems();
void drawCell(u64 address, u8 *data, size_t size, bool hovered); enum class CellType { None, Hex, ASCII };
void drawCell(u64 address, u8 *data, size_t size, bool hovered, CellType cellType);
void drawPopup(); void drawPopup();
void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize); void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize) const;
public: public:
void setSelection(const Region &region) { this->setSelection(region.getStartAddress(), region.getEndAddress()); } void setSelection(const Region &region) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
void setSelection(u128 start, u128 end) { void setSelection(u128 start, u128 end) {
if (!ImHexApi::Provider::isValid()) if (!ImHexApi::Provider::isValid())
return; return;
if (start == InvalidSelection && end == InvalidSelection)
return;
if (start == InvalidSelection)
start = end;
if (end == InvalidSelection)
end = start;
auto provider = ImHexApi::Provider::get(); auto provider = ImHexApi::Provider::get();
auto &data = ProviderExtraData::get(provider).editor;
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1; 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); data.selectionStart = std::clamp<u128>(start, 0, maxAddress);
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress); data.selectionEnd = std::clamp<u128>(end, 0, maxAddress);
if (this->m_selectionChanged) { if (this->m_selectionChanged) {
EventManager::post<EventRegionSelected>(this->getSelection()); EventManager::post<EventRegionSelected>(this->getSelection());
} }
} }
[[nodiscard]] Region getSelection() const { [[nodiscard]] static Region getSelection() {
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd); auto &data = ProviderExtraData::getCurrent().editor;
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
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; const size_t size = end - start + 1;
return { start, size }; return { start, size };
} }
[[nodiscard]] bool isSelectionValid() const { [[nodiscard]] static bool isSelectionValid() {
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; this->m_shouldJumpToSelection = true;
if (center)
this->m_centerOnJump = true;
} }
void scrollToSelection() { void scrollToSelection() {
@@ -110,6 +116,7 @@ namespace hex::plugin::builtin {
void drawFooter(const ImVec2 &size); void drawFooter(const ImVec2 &size);
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered); void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
std::optional<color_t> applySelectionColor(u64 byteAddress, std::optional<color_t> color);
private: private:
u16 m_bytesPerRow = 16; u16 m_bytesPerRow = 16;
@@ -117,15 +124,16 @@ namespace hex::plugin::builtin {
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer; ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
bool m_shouldJumpToSelection = false; bool m_shouldJumpToSelection = false;
bool m_centerOnJump = false;
bool m_shouldScrollToSelection = false; bool m_shouldScrollToSelection = false;
bool m_shouldJumpWhenOffScreen = false; bool m_shouldJumpWhenOffScreen = false;
bool m_shouldUpdateScrollPosition = false;
bool m_selectionChanged = false; bool m_selectionChanged = false;
u64 m_selectionStart = InvalidSelection;
u64 m_selectionEnd = InvalidSelection;
u16 m_visibleRowCount = 0; u16 m_visibleRowCount = 0;
CellType m_editingCellType = CellType::None;
std::optional<u64> m_editingAddress; std::optional<u64> m_editingAddress;
bool m_shouldModifyValue = false; bool m_shouldModifyValue = false;
bool m_enteredEditingMode = false; bool m_enteredEditingMode = false;
@@ -136,6 +144,8 @@ namespace hex::plugin::builtin {
bool m_upperCaseHex = true; bool m_upperCaseHex = true;
bool m_grayOutZero = true; bool m_grayOutZero = true;
bool m_showAscii = true; bool m_showAscii = true;
bool m_syncScrolling = false;
u32 m_byteCellPadding = 0, m_characterCellPadding = 0;
bool m_shouldOpenPopup = false; bool m_shouldOpenPopup = false;
std::unique_ptr<Popup> m_currPopup; std::unique_ptr<Popup> m_currPopup;

View File

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

View File

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

@@ -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) { 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) { ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.js", [](prv::Provider *provider, u64 offset, size_t size) {

View File

@@ -396,13 +396,14 @@ namespace hex::plugin::builtin {
} }
); );
constexpr static auto MaxStringLength = 32;
ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1, ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1,
[](auto buffer, auto endian, auto style) { [](auto buffer, auto endian, auto style) {
hex::unused(buffer, endian, style); hex::unused(buffer, endian, style);
auto currSelection = ImHexApi::HexEditor::getSelection(); auto currSelection = ImHexApi::HexEditor::getSelection();
constexpr static auto MaxStringLength = 32;
std::string value, copyValue; 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) #if defined(OS_WINDOWS) && defined(ARCH_64_BIT)
ContentRegistry::DataInspector::add("hex.builtin.inspector.time32", sizeof(u32), [](auto buffer, auto endian, auto style) { ContentRegistry::DataInspector::add("hex.builtin.inspector.time32", sizeof(u32), [](auto buffer, auto endian, auto style) {

View File

@@ -7,6 +7,8 @@
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/providers/provider.hpp> #include <hex/providers/provider.hpp>
#include <content/helpers/provider_extra_data.hpp>
#include <cctype> #include <cctype>
#include <random> #include <random>
@@ -15,6 +17,7 @@
#include <imgui.h> #include <imgui.h>
#include <implot.h> #include <implot.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <fonts/codicons_font.h>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@@ -66,22 +69,17 @@ namespace hex::plugin::builtin {
class NodeString : public dp::Node { class NodeString : public dp::Node {
public: public:
NodeString() : Node("hex.builtin.nodes.constants.string.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { 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 { void drawNode() override {
ImGui::PushItemWidth(100); 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(); ImGui::PopItemWidth();
} }
void process() override { void process() override {
std::vector<u8> output(std::strlen(this->m_value.c_str()) + 1, 0x00); this->setBufferOnOutput(0, { this->m_value.begin(), this->m_value.end() });
std::strcpy(reinterpret_cast<char *>(output.data()), this->m_value.c_str());
output.pop_back();
this->setBufferOnOutput(0, output);
} }
void store(nlohmann::json &j) override { void store(nlohmann::json &j) override {
@@ -406,8 +404,8 @@ namespace hex::plugin::builtin {
void process() override { void process() override {
auto input = this->getIntegerOnInput(0); auto input = this->getIntegerOnInput(0);
std::vector<u8> output(sizeof(u64), 0x00); std::vector<u8> output(sizeof(input), 0x00);
std::memcpy(output.data(), &input, sizeof(u64)); std::memcpy(output.data(), &input, sizeof(input));
this->setBufferOnOutput(1, output); this->setBufferOnOutput(1, output);
} }
@@ -420,16 +418,47 @@ namespace hex::plugin::builtin {
void process() override { void process() override {
auto input = this->getBufferOnInput(0); auto input = this->getBufferOnInput(0);
if (input.empty() || input.size() > sizeof(u64)) i64 output = 0;
if (input.empty() || input.size() > sizeof(output))
throwNodeError("Buffer is empty or bigger than 64 bits"); throwNodeError("Buffer is empty or bigger than 64 bits");
u64 output = 0;
std::memcpy(&output, input.data(), input.size()); std::memcpy(&output, input.data(), input.size());
this->setIntegerOnOutput(1, output); this->setIntegerOnOutput(1, output);
} }
}; };
class NodeCastFloatToBuffer : public dp::Node {
public:
NodeCastFloatToBuffer() : Node("hex.builtin.nodes.casting.float_to_buffer.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { }
void process() override {
auto input = this->getFloatOnInput(0);
std::vector<u8> output(sizeof(input), 0x00);
std::memcpy(output.data(), &input, sizeof(input));
this->setBufferOnOutput(1, output);
}
};
class NodeCastBufferToFloat : public dp::Node {
public:
NodeCastBufferToFloat() : Node("hex.builtin.nodes.casting.buffer_to_float.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { }
void process() override {
auto input = this->getBufferOnInput(0);
float output = 0;
if (input.empty() || input.size() != sizeof(output))
throwNodeError("Buffer is empty or not the right size to fit a float");
std::memcpy(&output, input.data(), input.size());
this->setFloatOnOutput(1, output);
}
};
class NodeArithmeticAdd : public dp::Node { class NodeArithmeticAdd : public dp::Node {
public: public:
NodeArithmeticAdd() : Node("hex.builtin.nodes.arithmetic.add.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } NodeArithmeticAdd() : Node("hex.builtin.nodes.arithmetic.add.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { }
@@ -960,10 +989,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") }) { } 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 { 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()) { if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); 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(); ImGui::EndTooltip();
} }
} }
@@ -971,10 +1000,7 @@ namespace hex::plugin::builtin {
void process() override { void process() override {
auto rawData = this->getBufferOnInput(0); auto rawData = this->getBufferOnInput(0);
if (this->m_texture.valid()) this->m_texture = ImGui::Texture(rawData.data(), rawData.size());
ImGui::UnloadImage(this->m_texture);
this->m_texture = ImGui::LoadImageFromMemory(rawData.data(), rawData.size());
} }
private: private:
@@ -1026,6 +1052,43 @@ namespace hex::plugin::builtin {
std::array<ImU64, 256> m_counts = { 0 }; std::array<ImU64, 256> m_counts = { 0 };
}; };
class NodePatternLanguageOutVariable : public dp::Node {
public:
NodePatternLanguageOutVariable() : Node("hex.builtin.nodes.pattern_language.out_var.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { }
void drawNode() override {
ImGui::PushItemWidth(100);
ImGui::InputText("##name", this->m_name);
ImGui::PopItemWidth();
}
void process() override {
auto &pl = ProviderExtraData::getCurrent().patternLanguage;
std::scoped_lock lock(pl.runtimeMutex);
const auto &outVars = pl.runtime->getOutVariables();
if (outVars.contains(this->m_name)) {
std::visit(overloaded {
[](const std::string &) {},
[](pl::ptrn::Pattern *) {},
[this](auto &&value) {
std::vector<u8> buffer(std::min<size_t>(sizeof(value), 8));
std::memcpy(buffer.data(), &value, buffer.size());
this->setBufferOnOutput(0, buffer);
}
}, outVars.at(this->m_name));
} else {
throwNodeError(hex::format("Out variable '{}' has not been defined!", this->m_name));
}
}
private:
std::string m_name;
};
void registerDataProcessorNodes() { void registerDataProcessorNodes() {
ContentRegistry::DataProcessorNode::add<NodeInteger>("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.int"); ContentRegistry::DataProcessorNode::add<NodeInteger>("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.int");
ContentRegistry::DataProcessorNode::add<NodeFloat>("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.float"); ContentRegistry::DataProcessorNode::add<NodeFloat>("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.float");
@@ -1045,6 +1108,8 @@ namespace hex::plugin::builtin {
ContentRegistry::DataProcessorNode::add<NodeCastIntegerToBuffer>("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.int_to_buffer"); ContentRegistry::DataProcessorNode::add<NodeCastIntegerToBuffer>("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.int_to_buffer");
ContentRegistry::DataProcessorNode::add<NodeCastBufferToInteger>("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.buffer_to_int"); ContentRegistry::DataProcessorNode::add<NodeCastBufferToInteger>("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.buffer_to_int");
ContentRegistry::DataProcessorNode::add<NodeCastFloatToBuffer>("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.float_to_buffer");
ContentRegistry::DataProcessorNode::add<NodeCastBufferToFloat>("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.buffer_to_float");
ContentRegistry::DataProcessorNode::add<NodeArithmeticAdd>("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.add"); ContentRegistry::DataProcessorNode::add<NodeArithmeticAdd>("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.add");
ContentRegistry::DataProcessorNode::add<NodeArithmeticSubtract>("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.sub"); ContentRegistry::DataProcessorNode::add<NodeArithmeticSubtract>("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.sub");
@@ -1078,6 +1143,8 @@ namespace hex::plugin::builtin {
ContentRegistry::DataProcessorNode::add<NodeVisualizerLayeredDistribution>("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.layered_dist"); ContentRegistry::DataProcessorNode::add<NodeVisualizerLayeredDistribution>("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.layered_dist");
ContentRegistry::DataProcessorNode::add<NodeVisualizerImage>("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.image"); ContentRegistry::DataProcessorNode::add<NodeVisualizerImage>("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.image");
ContentRegistry::DataProcessorNode::add<NodeVisualizerByteDistribution>("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.byte_distribution"); ContentRegistry::DataProcessorNode::add<NodeVisualizerByteDistribution>("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.byte_distribution");
ContentRegistry::DataProcessorNode::add<NodePatternLanguageOutVariable>("hex.builtin.nodes.pattern_language", "hex.builtin.nodes.pattern_language.out_var");
} }
} }

View File

@@ -4,6 +4,7 @@
#include <imgui.h> #include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/utils.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@@ -50,8 +51,8 @@ namespace hex::plugin::builtin {
constexpr static inline auto ByteCount = sizeof(T); constexpr static inline auto ByteCount = sizeof(T);
constexpr static inline auto CharCount = ByteCount * 2; constexpr static inline auto CharCount = ByteCount * 2;
const static inline auto FormattingUpperCase = hex::format("%0{}X", CharCount); const static inline auto FormattingUpperCase = hex::format("%0{}llX", CharCount);
const static inline auto FormattingLowerCase = hex::format("%0{}x", CharCount); const static inline auto FormattingLowerCase = hex::format("%0{}llx", CharCount);
const char *getFormatString(bool upperCase) { const char *getFormatString(bool upperCase) {
if (upperCase) if (upperCase)
@@ -103,10 +104,10 @@ namespace hex::plugin::builtin {
constexpr static inline auto ByteCount = 1; constexpr static inline auto ByteCount = 1;
constexpr static inline auto CharCount = ByteCount * 2; constexpr static inline auto CharCount = ByteCount * 2;
const static inline auto FormattingUpperCase = hex::format("%0{}X", CharCount); const static inline auto FormattingUpperCase = hex::format("%0{}llX", CharCount);
const static inline auto FormattingLowerCase = hex::format("%0{}x", CharCount); const static inline auto FormattingLowerCase = hex::format("%0{}llx", CharCount);
const char *getFormatString(bool upperCase) { static const char *getFormatString(bool upperCase) {
if (upperCase) if (upperCase)
return FormattingUpperCase.c_str(); return FormattingUpperCase.c_str();
else 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 { class DataVisualizerFloatingPoint : public hex::ContentRegistry::HexEditor::DataVisualizer {
public: public:
DataVisualizerFloatingPoint() : DataVisualizer(ByteCount, CharCount) { } 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 { class DataVisualizerRGBA8 : public hex::ContentRegistry::HexEditor::DataVisualizer {
public: public:
DataVisualizerRGBA8() : DataVisualizer(4, 2) { } 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<i32>>("hex.builtin.visualizer.decimal.signed.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i64>>("hex.builtin.visualizer.decimal.signed.64bit"); 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<float>>("hex.builtin.visualizer.floating_point.32bit");
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<double>>("hex.builtin.visualizer.floating_point.64bit"); ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<double>>("hex.builtin.visualizer.floating_point.64bit");

View File

@@ -11,9 +11,9 @@
#include <imgui.h> #include <imgui.h>
#include <nlohmann/json.hpp> #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 { namespace hex::plugin::builtin {
@@ -78,7 +78,9 @@ namespace hex::plugin::builtin {
} else if (name == "Open Project") { } else if (name == "Open Project") {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} }, fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
[](const auto &path) { [](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); 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); evaluationStack.push(result);
} else if (front.type == TokenType::Variable) { } else if (front.type == TokenType::Variable) {
if (this->m_variables.contains(front.name)) 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 { else {
this->setError("Unknown variable!"); this->setError("Unknown variable!");
return std::nullopt; return std::nullopt;
@@ -382,14 +382,14 @@ namespace hex {
template<typename T> template<typename T>
std::optional<T> MathEvaluator<T>::evaluate(const std::string &input) { std::optional<T> MathEvaluator<T>::evaluate(const std::string &input) {
auto inputQueue = parseInput(input); auto inputQueue = parseInput(input);
if (!inputQueue.has_value()) if (!inputQueue.has_value() || inputQueue->empty())
return std::nullopt; return std::nullopt;
std::string resultVariable = "ans"; std::string resultVariable = "ans";
{ {
auto queueCopy = *inputQueue; auto queueCopy = *inputQueue;
if (queueCopy.front().type == TokenType::Variable) { if (queueCopy.front().type == TokenType::Variable && queueCopy.size() > 2) {
resultVariable = queueCopy.front().name; resultVariable = queueCopy.front().name;
queueCopy.pop(); queueCopy.pop();
if (queueCopy.front().type != TokenType::Operator || queueCopy.front().op != Operator::Assign) if (queueCopy.front().type != TokenType::Operator || queueCopy.front().op != Operator::Assign)
@@ -407,16 +407,15 @@ namespace hex {
auto result = evaluate(*postfixTokens); auto result = evaluate(*postfixTokens);
if (result.has_value()) { if (result.has_value() && !this->getVariables()[resultVariable].constant)
this->setVariable(resultVariable, result.value()); this->setVariable(resultVariable, result.value());
}
return result; return result;
} }
template<typename T> template<typename T>
void MathEvaluator<T>::setVariable(const std::string &name, T value) { void MathEvaluator<T>::setVariable(const std::string &name, T value, bool constant) {
this->m_variables[name] = value; this->m_variables[name] = { value, constant };
} }
template<typename T> template<typename T>
@@ -435,6 +434,9 @@ namespace hex {
template<typename T> template<typename T>
void MathEvaluator<T>::registerStandardVariables() { void MathEvaluator<T>::registerStandardVariables() {
this->setVariable("ans", 0); 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> template<typename T>

View File

@@ -34,6 +34,43 @@ namespace hex {
using namespace ::std::literals::string_literals; 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) { void createLeafNode(const pl::ptrn::Pattern& pattern) {
ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf |
ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoTreePushOnOpen |
@@ -44,12 +81,13 @@ namespace hex {
bool createTreeNode(const pl::ptrn::Pattern& pattern) { bool createTreeNode(const pl::ptrn::Pattern& pattern) {
if (pattern.isSealed()) { if (pattern.isSealed()) {
ImGui::Indent(); ImGui::Indent();
ImGui::TextUnformatted(pattern.getDisplayName().c_str()); highlightWhenSelected(pattern, [&]{ ImGui::TextUnformatted(pattern.getDisplayName().c_str()); });
ImGui::Unindent(); ImGui::Unindent();
return false; return false;
} }
else else {
return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); return highlightWhenSelected(pattern, [&]{ return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);});
}
} }
void drawTypenameColumn(const pl::ptrn::Pattern& pattern, const std::string& pattern_name) { 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) { void drawNameColumn(const pl::ptrn::Pattern& pattern) {
ImGui::TextUnformatted(pattern.getDisplayName().c_str()); highlightWhenSelected(pattern, [&]{ ImGui::TextUnformatted(pattern.getDisplayName().c_str()); });
ImGui::TableNextColumn(); ImGui::TableNextColumn();
} }
@@ -119,12 +157,14 @@ namespace hex {
} }
void PatternDrawer::visit(pl::ptrn::PatternArrayDynamic& pattern) { void PatternDrawer::visit(pl::ptrn::PatternArrayDynamic& pattern) {
this->drawArray(pattern); drawArray(pattern, pattern, pattern.isInlined());
} }
void PatternDrawer::visit(pl::ptrn::PatternArrayStatic& pattern) { void PatternDrawer::visit(pl::ptrn::PatternArrayStatic& pattern) {
this->drawArray(pattern); drawArray(pattern, pattern, pattern.isInlined());
} }
void PatternDrawer::visit(pl::ptrn::PatternBitfieldField& pattern) { void PatternDrawer::visit(pl::ptrn::PatternBitfieldField& pattern) {
@@ -272,8 +312,8 @@ namespace hex {
} }
if (open) { if (open) {
pattern.forEachMember([&](auto &member){ pattern.forEachEntry(0, pattern.getMembers().size(), [&](u64, auto *member){
this->draw(member); this->draw(*member);
}); });
if (!pattern.isInlined()) if (!pattern.isInlined())
@@ -302,8 +342,8 @@ namespace hex {
} }
if (open) { if (open) {
pattern.forEachMember([&](auto &member) { pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, auto *member) {
this->draw(member); this->draw(*member);
}); });
if (!pattern.isInlined()) if (!pattern.isInlined())
@@ -331,9 +371,9 @@ namespace hex {
pattern.accept(*this); pattern.accept(*this);
} }
bool PatternDrawer::drawArrayRoot(pl::ptrn::Pattern& pattern, size_t entryCount, bool isInlined) { void PatternDrawer::drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::Iteratable &iteratable, bool isInlined) {
if (entryCount == 0) if (iteratable.getEntryCount() == 0)
return false; return;
bool open = true; bool open = true;
if (!isInlined) { if (!isInlined) {
@@ -354,7 +394,7 @@ namespace hex {
ImGui::TextUnformatted("["); ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0); ImGui::SameLine(0, 0);
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", entryCount); ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", iteratable.getEntryCount());
ImGui::SameLine(0, 0); ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]"); ImGui::TextUnformatted("]");
@@ -362,35 +402,60 @@ namespace hex {
ImGui::TextFormatted("{}", pattern.getFormattedValue()); 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) { chunkCount++;
u64 lastVisible = displayEnd - 1;
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) { auto startOffset = iteratable.getEntry(i)->getOffset();
this->draw(pattern); auto endOffset = iteratable.getEntry(endIndex - 1)->getOffset();
} else if (idx == lastVisible) { auto endSize = iteratable.getEntry(endIndex - 1)->getSize();
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns); size_t chunkSize = (endOffset - startOffset) + endSize;
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
displayEnd += DisplayEndStep;
}
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) { ImGui::TextUnformatted("[");
if (opened) { ImGui::SameLine(0, 0);
if (!inlined) 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(); 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); auto [value, success] = this->m_displayEnd.emplace(&pattern, DisplayEndDefault);
return value->second; return value->second;
} }
}; }

View File

@@ -38,6 +38,14 @@ namespace hex::plugin::builtin {
ImGui::EndMenu(); 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 */ /* File open, quit imhex */
@@ -64,7 +72,9 @@ namespace hex::plugin::builtin {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"}
}, },
[](const auto &path) { [](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"); 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/core/evaluator.hpp>
#include <pl/patterns/pattern.hpp> #include <pl/patterns/pattern.hpp>
#include <llvm/Demangle/Demangle.h>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
void registerPatternLanguageFunctions() { void registerPatternLanguageFunctions() {
@@ -16,7 +17,7 @@ namespace hex::plugin::builtin {
pl::api::Namespace nsHexCore = { "builtin", "hex", "core" }; pl::api::Namespace nsHexCore = { "builtin", "hex", "core" };
{ {
/* get_selection() */ /* 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()) if (!ImHexApi::HexEditor::isSelectionValid())
return std::numeric_limits<u128>::max(); 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" }; pl::api::Namespace nsHexHttp = { "builtin", "hex", "http" };
{ {
/* get(url) */ /* get(url) */

View File

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

View File

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

View File

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

View File

@@ -218,7 +218,7 @@ namespace hex::plugin::builtin::prv {
} }
[[nodiscard]] std::string IntelHexProvider::getName() const { [[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() { bool IntelHexProvider::handleFilePicker() {
@@ -250,11 +250,12 @@ namespace hex::plugin::builtin::prv {
void IntelHexProvider::loadSettings(const nlohmann::json &settings) { void IntelHexProvider::loadSettings(const nlohmann::json &settings) {
Provider::loadSettings(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 { 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); return Provider::storeSettings(settings);
} }

View File

@@ -1,15 +1,11 @@
#include "content/providers/motorola_srec_provider.hpp" #include "content/providers/motorola_srec_provider.hpp"
#include <cstring>
#include <hex/api/imhex_api.hpp>
#include <hex/api/localization.hpp> #include <hex/api/localization.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/file.hpp> #include <hex/helpers/file.hpp>
#include <hex/helpers/fmt.hpp> #include <hex/helpers/fmt.hpp>
#include <nlohmann/json.hpp>
namespace hex::plugin::builtin::prv { namespace hex::plugin::builtin::prv {
namespace motorola_srec { namespace motorola_srec {
@@ -198,7 +194,7 @@ namespace hex::plugin::builtin::prv {
} }
[[nodiscard]] std::string MotorolaSRECProvider::getName() const { [[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() { bool MotorolaSRECProvider::handleFilePicker() {

View File

@@ -14,8 +14,10 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace { 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(); userFolders.clear();
std::vector<std::string> paths = setting; std::vector<std::string> paths = setting;
for (const auto &path : paths) { for (const auto &path : paths) {
@@ -24,7 +26,8 @@ namespace {
userFolders.emplace_back(uString); userFolders.emplace_back(uString);
} }
} }
};
}
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@@ -182,6 +185,17 @@ namespace hex::plugin::builtin {
return false; 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) { 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); static auto color = static_cast<color_t>(setting);
@@ -283,6 +297,39 @@ namespace hex::plugin::builtin {
return result; 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 */ /* Fonts */
@@ -301,7 +348,7 @@ namespace hex::plugin::builtin {
if (ImGui::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { if (ImGui::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
return fs::openFileBrowser(fs::DialogMode::Open, { {"TTF Font", "ttf"} }, return fs::openFileBrowser(fs::DialogMode::Open, { {"TTF Font", "ttf"} },
[&](const std::fs::path &path) { [&](const std::fs::path &path) {
fontPath = path.string(); fontPath = hex::toUTF8String(path);
setting = fontPath; setting = fontPath;
}); });
} }
@@ -360,7 +407,7 @@ namespace hex::plugin::builtin {
} else { } else {
for (size_t n = 0; n < userFolders.size(); n++) { for (size_t n = 0; n < userFolders.size(); n++) {
const bool isSelected = (currentItemIndex == 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(); } if (isSelected) { ImGui::SetItemDefaultFocus(); }
} }
ImGui::EndListBox(); ImGui::EndListBox();
@@ -475,7 +522,7 @@ namespace hex::plugin::builtin {
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) {
auto path = dir / "font.ttf"; auto path = dir / "font.ttf";
if (fs::exists(path)) { if (fs::exists(path)) {
log::info("Loading custom front from {}", path.string()); log::info("Loading custom front from {}", hex::toUTF8String(path));
fontFile = path; fontFile = path;
break; 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 // If a custom font has been loaded now, also load the font size
float fontSize = ImHexApi::System::DefaultFontSize * ImHexApi::System::getGlobalScale(); float fontSize = ImHexApi::System::DefaultFontSize * ImHexApi::System::getGlobalScale();
if (!fontFile.empty()) { 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(); 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/keybinding.hpp>
#include <hex/api/event.hpp> #include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
void registerShortcuts() { void registerShortcuts() {
@@ -16,7 +18,19 @@ namespace hex::plugin::builtin {
// Close file // Close file
ShortcutManager::addGlobalShortcut(CTRL + Keys::W, [] { 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 <chrono>
#include <random> #include <random>
#include <regex> #include <regex>
#include <limits>
#include <llvm/Demangle/Demangle.h> #include <llvm/Demangle/Demangle.h>
#include <content/helpers/math_evaluator.hpp> #include <content/helpers/math_evaluator.hpp>
@@ -75,9 +74,8 @@ namespace hex::plugin::builtin {
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
u32 rowCount = 0;
for (u8 i = 0; i < 0x80 / 4; i++) { for (u8 i = 0; i < 0x80 / 4; i++) {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextFormatted("{0:03d}", i + 32 * tablePart); ImGui::TextFormatted("{0:03d}", i + 32 * tablePart);
@@ -92,10 +90,6 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextFormatted("{0}", hex::makePrintable(i + 32 * tablePart)); ImGui::TextFormatted("{0}", hex::makePrintable(i + 32 * tablePart));
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
rowCount++;
} }
ImGui::EndTable(); ImGui::EndTable();
@@ -113,8 +107,8 @@ namespace hex::plugin::builtin {
static auto replacePattern = [] { std::string s; s.reserve(0xFFF); return s; }(); static auto replacePattern = [] { std::string s; s.reserve(0xFFF); return s; }();
static auto regexOutput = [] { 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 changed1 = ImGui::InputTextIcon("hex.builtin.tools.regex_replacer.pattern"_lang, ICON_VS_REGEX, regexPattern);
bool changed2 = ImGui::InputText("hex.builtin.tools.regex_replacer.replace"_lang, replacePattern); 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)); bool changed3 = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput, ImVec2(0, 0));
if (changed1 || changed2 || changed3) { if (changed1 || changed2 || changed3) {
@@ -391,7 +385,12 @@ namespace hex::plugin::builtin {
ImGui::TableSetupColumn("hex.builtin.tools.value"_lang); ImGui::TableSetupColumn("hex.builtin.tools.value"_lang);
ImGui::TableHeadersRow(); 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::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(name.c_str()); ImGui::TextUnformatted(name.c_str());
@@ -420,7 +419,7 @@ namespace hex::plugin::builtin {
} }
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x); 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(); ImGui::SetKeyboardFocusHere();
evaluate = true; evaluate = true;
} }
@@ -434,10 +433,9 @@ namespace hex::plugin::builtin {
if (evaluate) { if (evaluate) {
try { try {
auto result = mathEvaluator.evaluate(mathInput); auto result = mathEvaluator.evaluate(mathInput);
mathInput.clear();
if (result.has_value()) { if (result.has_value()) {
mathHistory.push_back(result.value()); mathHistory.push_back(result.value());
mathInput.clear();
lastMathError.clear(); lastMathError.clear();
} }
@@ -448,75 +446,45 @@ namespace hex::plugin::builtin {
} }
void drawBaseConverter() { void drawBaseConverter() {
static char buffer[4][0x1000] = { { '0' }, { '0' }, { '0' }, { '0' } }; static std::array<std::string, 4> buffers;
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 auto ConvertBases = [](u8 base) { static auto ConvertBases = [](u8 base) {
u64 number; u64 number;
errno = 0;
switch (base) { switch (base) {
case 16: case 16:
number = std::strtoull(buffer[1], nullptr, base); number = std::strtoull(buffers[1].c_str(), nullptr, base);
break; break;
case 10: case 10:
number = std::strtoull(buffer[0], nullptr, base); number = std::strtoull(buffers[0].c_str(), nullptr, base);
break; break;
case 8: case 8:
number = std::strtoull(buffer[2], nullptr, base); number = std::strtoull(buffers[2].c_str(), nullptr, base);
break; break;
case 2: case 2:
number = std::strtoull(buffer[3], nullptr, base); number = std::strtoull(buffers[3].c_str(), nullptr, base);
break; break;
default: default:
return; return;
} }
auto base10String = std::to_string(number); buffers[0] = std::to_string(number);
auto base16String = hex::format("0x{0:X}", number); buffers[1] = hex::format("0x{0:X}", number);
auto base8String = hex::format("{0:#o}", number); buffers[2] = hex::format("{0:#o}", number);
auto base2String = hex::toBinaryString(number); buffers[3] = 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';
}; };
u8 base = 10; if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.dec"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[0]))
if (ImGui::InputText("hex.builtin.tools.base_converter.dec"_lang, buffer[0], 20 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base)) ConvertBases(10);
ConvertBases(base);
base = 16; if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.hex"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[1]))
if (ImGui::InputText("hex.builtin.tools.base_converter.hex"_lang, buffer[1], 16 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base)) ConvertBases(16);
ConvertBases(base);
base = 8; if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.oct"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[2]))
if (ImGui::InputText("hex.builtin.tools.base_converter.oct"_lang, buffer[2], 22 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base)) ConvertBases(8);
ConvertBases(base);
base = 2; if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.bin"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[3]))
if (ImGui::InputText("hex.builtin.tools.base_converter.bin"_lang, buffer[3], 64 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base)) ConvertBases(2);
ConvertBases(base);
} }
void drawPermissionsCalculator() { void drawPermissionsCalculator() {
@@ -652,9 +620,11 @@ namespace hex::plugin::builtin {
if (response.code == 200) { if (response.code == 200) {
try { try {
auto json = nlohmann::json::parse(response.body); 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"]["url"]["short"],
json["data"]["file"]["metadata"]["size"]["readable"] }); json["data"]["file"]["metadata"]["size"]["readable"]
});
} catch (...) { } catch (...) {
View::showErrorPopup("hex.builtin.tools.file_uploader.invalid_response"_lang); View::showErrorPopup("hex.builtin.tools.file_uploader.invalid_response"_lang);
} }
@@ -691,7 +661,7 @@ namespace hex::plugin::builtin {
bool startSearch; bool startSearch;
startSearch = ImGui::InputText("##search", searchString, ImGuiInputTextFlags_EnterReturnsTrue); startSearch = ImGui::InputTextIcon("##search", ICON_VS_SYMBOL_KEY, searchString, ImGuiInputTextFlags_EnterReturnsTrue);
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginDisabled((searchProcess.valid() && searchProcess.wait_for(0s) != std::future_status::ready) || searchString.empty()); 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; u32 index = 0;
for (auto &file : files) { 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; selectedIndex = index;
index++; index++;
} }
@@ -1099,7 +1069,7 @@ namespace hex::plugin::builtin {
fs::File input(file, fs::File::Mode::Read); fs::File input(file, fs::File::Mode::Read);
if (!input.isValid()) { 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; return;
} }

View File

@@ -127,7 +127,7 @@ namespace hex::plugin::builtin {
u32 index = 0; u32 index = 0;
for (auto &path : s_selectableFiles) { for (auto &path : s_selectableFiles) {
ImGui::PushID(index); ImGui::PushID(index);
if (ImGui::Selectable(path.filename().string().c_str(), index == s_selectableFileIndex)) if (ImGui::Selectable(hex::toUTF8String(path.filename()).c_str(), index == s_selectableFileIndex))
s_selectableFileIndex = index; s_selectableFileIndex = index;
ImGui::PopID(); ImGui::PopID();
@@ -245,6 +245,9 @@ namespace hex::plugin::builtin {
if (ImGui::BeginPopupContextItem("FrontTask", ImGuiPopupFlags_MouseButtonLeft)) { if (ImGui::BeginPopupContextItem("FrontTask", ImGuiPopupFlags_MouseButtonLeft)) {
for (const auto &task : tasks) { for (const auto &task : tasks) {
if (task->isBackgroundTask())
continue;
ImGui::PushID(&task); ImGui::PushID(&task);
ImGui::TextFormatted("{}", LangEntry(task->getUnlocalizedName())); ImGui::TextFormatted("{}", LangEntry(task->getUnlocalizedName()));
ImGui::SameLine(); ImGui::SameLine();

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