Compare commits
244 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86e33a1ee9 | ||
|
|
37850ad85a | ||
|
|
daca49658e | ||
|
|
6975d7e2cd | ||
|
|
5b8bed6083 | ||
|
|
7474aa3e5d | ||
|
|
c6d2d51d4c | ||
|
|
9055105627 | ||
|
|
a44de63e24 | ||
|
|
8fc7931132 | ||
|
|
4070833229 | ||
|
|
3a9c3f939e | ||
|
|
aa42fb5076 | ||
|
|
50158a7977 | ||
|
|
f2ded359d8 | ||
|
|
0e358bbefe | ||
|
|
2cea561468 | ||
|
|
8024b0a186 | ||
|
|
2b135cf7e0 | ||
|
|
ce8c64a679 | ||
|
|
f0da6ec82f | ||
|
|
46e3b9b5d6 | ||
|
|
d5a08ae568 | ||
|
|
11f63f9b02 | ||
|
|
5694eaba8c | ||
|
|
484481f886 | ||
|
|
210106901e | ||
|
|
eb247b8607 | ||
|
|
fb1453d98a | ||
|
|
b734fb5511 | ||
|
|
2cd6cb8814 | ||
|
|
2a93eab14c | ||
|
|
f039ea68d0 | ||
|
|
e0c35e0002 | ||
|
|
5ace199dc4 | ||
|
|
556895744b | ||
|
|
7f2c60b0d7 | ||
|
|
7bb9e7ee82 | ||
|
|
26be4c3ac8 | ||
|
|
b80517ab15 | ||
|
|
b17cd3696c | ||
|
|
accd554600 | ||
|
|
8bf586cfa9 | ||
|
|
ebea409e6a | ||
|
|
6fdba3d555 | ||
|
|
e865883611 | ||
|
|
9c484e7b57 | ||
|
|
b365e16cc9 | ||
|
|
6a07a2f85d | ||
|
|
0fd7461266 | ||
|
|
62eb0ccd1d | ||
|
|
3367237da3 | ||
|
|
3504987ab3 | ||
|
|
554e625bda | ||
|
|
84530e0817 | ||
|
|
663fb88367 | ||
|
|
4d99c4b59d | ||
|
|
12ee235380 | ||
|
|
e30ed35d69 | ||
|
|
e2f8c7d989 | ||
|
|
ca6a8a7a46 | ||
|
|
f52dae4297 | ||
|
|
d643f8f8f7 | ||
|
|
08a12dd2b0 | ||
|
|
b33dd5d4f5 | ||
|
|
e797ac3a57 | ||
|
|
8bd31f6375 | ||
|
|
d3f83e63c9 | ||
|
|
b450f4797e | ||
|
|
0552084673 | ||
|
|
d021e2b362 | ||
|
|
c769e9cc32 | ||
|
|
639390115b | ||
|
|
ceaf80a186 | ||
|
|
86274b8b94 | ||
|
|
669427eb24 | ||
|
|
5ba22e7554 | ||
|
|
65ad88eed9 | ||
|
|
e34703ea5a | ||
|
|
55bd2c6da6 | ||
|
|
96b5221c1d | ||
|
|
3a94be9abb | ||
|
|
9656b40d53 | ||
|
|
7e61b513f3 | ||
|
|
1d4cbbe418 | ||
|
|
e0e2996e25 | ||
|
|
a102f5fcbf | ||
|
|
4e5d56e2c0 | ||
|
|
a55177edfa | ||
|
|
4c01a749de | ||
|
|
7b61268f22 | ||
|
|
b11dbe4fe1 | ||
|
|
6dbff81f95 | ||
|
|
9893e7a965 | ||
|
|
814c595c12 | ||
|
|
f8b4d04713 | ||
|
|
3cdc8c5884 | ||
|
|
5eabc05396 | ||
|
|
b2932773b9 | ||
|
|
59a04e6dbf | ||
|
|
ddf1e8a179 | ||
|
|
17cc87d633 | ||
|
|
fd7beb642f | ||
|
|
b766cf0807 | ||
|
|
6c9469961b | ||
|
|
d8844236d0 | ||
|
|
60eb59c605 | ||
|
|
6a7bbb8752 | ||
|
|
e4431749e1 | ||
|
|
c587b357eb | ||
|
|
7357c26d54 | ||
|
|
73ca45ad3d | ||
|
|
bf00503d1f | ||
|
|
44a90f5c7d | ||
|
|
5c3ee9f499 | ||
|
|
03f357efd1 | ||
|
|
5462575f5c | ||
|
|
120e2bc300 | ||
|
|
c3137df83c | ||
|
|
737155a226 | ||
|
|
66d64cf020 | ||
|
|
42f5c0f484 | ||
|
|
75047e26e2 | ||
|
|
9fa6d82775 | ||
|
|
d1468984e7 | ||
|
|
20a2331504 | ||
|
|
5b00c8ee08 | ||
|
|
bda4aadc54 | ||
|
|
9d7e2eccac | ||
|
|
8c219b981c | ||
|
|
7d87c8bb98 | ||
|
|
13afd96806 | ||
|
|
4fb74a1769 | ||
|
|
aa658b7dbc | ||
|
|
7e3601989a | ||
|
|
3a1c0f8d66 | ||
|
|
91160b4311 | ||
|
|
83f4093796 | ||
|
|
f219395b25 | ||
|
|
ae6a7ad8e5 | ||
|
|
d990ee102a | ||
|
|
cfde9939b4 | ||
|
|
a22725bb67 | ||
|
|
7a4040f6ec | ||
|
|
2fbb351314 | ||
|
|
96e85c0685 | ||
|
|
50577c9ea0 | ||
|
|
073323b517 | ||
|
|
37cc8f3aae | ||
|
|
6367152650 | ||
|
|
ffbaef3872 | ||
|
|
a0b2473bf4 | ||
|
|
95a3104a56 | ||
|
|
2d5f77730b | ||
|
|
033a0dfbb9 | ||
|
|
cb682b6e21 | ||
|
|
7312908d4d | ||
|
|
b44f6035b3 | ||
|
|
b6bc8abf83 | ||
|
|
c60c1154b9 | ||
|
|
219afb6244 | ||
|
|
22b6bdb5cf | ||
|
|
d9a47fe815 | ||
|
|
45e987b413 | ||
|
|
a920696d03 | ||
|
|
f72b153fe0 | ||
|
|
d240b4ed49 | ||
|
|
1a21627cdb | ||
|
|
0a115a3c03 | ||
|
|
7ef11f566b | ||
|
|
7f6aa9f9a6 | ||
|
|
4df1496a0f | ||
|
|
b68eb0bb5e | ||
|
|
7c0fb7c4f2 | ||
|
|
ede8048680 | ||
|
|
b10ba8fea0 | ||
|
|
3eb2cca286 | ||
|
|
721ac837e0 | ||
|
|
f6fef35d3d | ||
|
|
0569770239 | ||
|
|
6689b8ebfa | ||
|
|
3cb6c4f775 | ||
|
|
b687eb88f9 | ||
|
|
33a375910a | ||
|
|
a620400e4e | ||
|
|
cc7dc3597b | ||
|
|
60b5842e94 | ||
|
|
2b9c6ec447 | ||
|
|
742a4e53b5 | ||
|
|
0cd10b6b70 | ||
|
|
aabf718e60 | ||
|
|
03116c4ab8 | ||
|
|
38162c0129 | ||
|
|
f62edea450 | ||
|
|
940f1e30c5 | ||
|
|
af32d68c3f | ||
|
|
eb874ac810 | ||
|
|
a79bf4c3ec | ||
|
|
90adacab9f | ||
|
|
e86ca29b8c | ||
|
|
4f1f9a718c | ||
|
|
cc09014e6e | ||
|
|
de98b40c93 | ||
|
|
a6eaa34f6d | ||
|
|
dacb64ae66 | ||
|
|
c0a5e2012f | ||
|
|
389e53a8a0 | ||
|
|
928fbe235a | ||
|
|
7d85a8b6fc | ||
|
|
d004962e3a | ||
|
|
1462a4689d | ||
|
|
93be4c8ed1 | ||
|
|
536c6df438 | ||
|
|
f8a089a61f | ||
|
|
491ee6aa2f | ||
|
|
6a88c7cbaa | ||
|
|
be82ee15b7 | ||
|
|
1ddd3ea2b9 | ||
|
|
a56a8c1d6c | ||
|
|
9c4e314bb6 | ||
|
|
ea26722a18 | ||
|
|
5aee359700 | ||
|
|
5d11fc960e | ||
|
|
707fec0e2a | ||
|
|
55b877d5e0 | ||
|
|
e779285be4 | ||
|
|
cf6ae52889 | ||
|
|
caad705975 | ||
|
|
0c3fc6f858 | ||
|
|
0529155faa | ||
|
|
aa01d58b33 | ||
|
|
0c0caf6942 | ||
|
|
7e01ff451f | ||
|
|
e0e4b0a5a9 | ||
|
|
0e2c1f1355 | ||
|
|
0ed7341f71 | ||
|
|
29e970fd81 | ||
|
|
43ab72dcb8 | ||
|
|
07dc77f13d | ||
|
|
9b2ee998de | ||
|
|
e1c5cd1e86 | ||
|
|
0d0301f4f6 | ||
|
|
29adeae6a3 | ||
|
|
6b62a1963e |
178
.clang-format
@@ -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
|
||||
...
|
||||
|
||||
150
.github/workflows/build.yml
vendored
@@ -99,14 +99,18 @@ jobs:
|
||||
..
|
||||
mingw32-make -j4 install
|
||||
cpack
|
||||
touch $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: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable
|
||||
path: |
|
||||
build/install/*
|
||||
#- name: 🗝️ Sign Windows Installer
|
||||
# if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
# shell: powershell
|
||||
# env:
|
||||
# WIN_SIGN_CERT: ${{ secrets.WIN_SIGN_CERT }}
|
||||
# WIN_SIGN_PW: ${{ secrets.WIN_SIGN_PW }}
|
||||
# run: |
|
||||
# $buffer = [System.Convert]::FromBase64String($env:WIN_SIGN_CERT)
|
||||
# $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($buffer, $env:WIN_SIGN_PW)
|
||||
# Get-ChildItem -Path ./build -Filter *.msi -Recurse | Set-AuthenticodeSignature -HashAlgorithm SHA256 -Certificate $certificate -TimestampServer http://timestamp.digicert.com
|
||||
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v3
|
||||
@@ -115,23 +119,59 @@ jobs:
|
||||
path: |
|
||||
build/*.msi
|
||||
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
- name: ⬇️ Download Mesa3D for NoGPU version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
|
||||
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
|
||||
7z e mesa.7z
|
||||
mv opengl32.dll build/install
|
||||
|
||||
|
||||
- name: ⬆️ Upload NoGPU Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable NoGPU
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
# MacOS build
|
||||
macos:
|
||||
runs-on: macos-11
|
||||
name: 🍎 macOS 11.0
|
||||
steps:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- suffix: "-NoGPU"
|
||||
custom_glfw: true
|
||||
- suffix: ""
|
||||
custom_glfw: false
|
||||
|
||||
name: 🍎 macOS 11.0${{matrix.suffix}}
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/Library/Caches/ccache
|
||||
key: ${{ runner.os }}-${{ 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
|
||||
|
||||
|
||||
@@ -140,11 +180,43 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
rm -rf /usr/local/Cellar/capstone
|
||||
|
||||
- name: ⬇️ Install classic glfw
|
||||
if: ${{! matrix.custom_glfw}}
|
||||
run: |
|
||||
brew install glfw
|
||||
|
||||
|
||||
- name: 🧰 Checkout glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: glfw/glfw
|
||||
path: glfw
|
||||
|
||||
- name: ⬇️ Patch and install custom glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
run: |
|
||||
cd glfw
|
||||
git apply ../dist/macOS/0001-glfw-SW.patch
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
# MacOS cmake build
|
||||
- name: 🛠️ Build
|
||||
@@ -167,13 +239,14 @@ jobs:
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
|
||||
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}" \
|
||||
..
|
||||
make -j4 package
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS DMG
|
||||
name: macOS DMG${{matrix.suffix}}
|
||||
path: build/*.dmg
|
||||
|
||||
# Ubuntu build
|
||||
@@ -187,7 +260,7 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore cache
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
@@ -200,6 +273,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
build-appimage/CMakeCache.txt
|
||||
.flatpak-builder
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
@@ -225,13 +299,14 @@ jobs:
|
||||
$HOME/.cargo/bin/rustup target add x86_64-unknown-linux-gnu
|
||||
$HOME/.cargo/bin/rustup default nightly
|
||||
|
||||
# Ubuntu cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
@@ -239,7 +314,7 @@ jobs:
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=AppDir
|
||||
make -j 4 install DESTDIR=DebDir
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -256,29 +331,34 @@ jobs:
|
||||
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
cp -r build/DEBIAN build/AppDir
|
||||
dpkg-deb -Zgzip --build build/AppDir
|
||||
mv build/AppDir.deb imhex-${{env.IMHEX_VERSION}}.deb
|
||||
rm -rf build/AppDir/DEBIAN
|
||||
cp -r build/DEBIAN build/DebDir
|
||||
dpkg-deb -Zgzip --build build/DebDir
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04.deb
|
||||
|
||||
# AppImage cmake build
|
||||
- name: 🛠️ Reconfigure build for AppImage
|
||||
run: |
|
||||
# Reconfigure CMake to include a flag needed for AppImage
|
||||
# Other flags are kept from old configuration
|
||||
|
||||
cd build
|
||||
cmake \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
..
|
||||
|
||||
rm -rf AppDir
|
||||
mkdir -p build-appimage
|
||||
cd build-appimage
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
-DIMHEX_USE_BUNDLED_CA=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=AppDir
|
||||
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
cd build
|
||||
cd build-appimage
|
||||
export VERSION=${{env.IMHEX_VERSION}}
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
mv ImHex-AppImage-x86_64.AppImage ../imhex-${{env.IMHEX_VERSION}}.AppImage
|
||||
cd ..
|
||||
|
||||
#- name: ⬆️ Upload Flatpak
|
||||
@@ -291,14 +371,20 @@ jobs:
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux DEB (Ubuntu 22.04)
|
||||
name: Ubuntu 22.04 DEB
|
||||
path: '*.deb'
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage
|
||||
path: '*.AppImage'
|
||||
path: 'build-appimage/*.AppImage'
|
||||
|
||||
- name: ⬆️ Upload AppImage zsync
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage zsync
|
||||
path: 'build-appimage/*.AppImage.zsync'
|
||||
|
||||
# ArchLinux build
|
||||
archlinux-build:
|
||||
|
||||
45
.github/workflows/release.yml
vendored
@@ -6,11 +6,12 @@ name: Release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
release-common:
|
||||
runs-on: ubuntu-latest
|
||||
name: Release
|
||||
name: Release Common
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
@@ -57,8 +58,10 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
- name: 🟩 Rename Windows Portable Zip
|
||||
run: mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
|
||||
- name: 🟩 Rename artifacts when needed
|
||||
run: |
|
||||
mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
|
||||
mv "Windows Portable NoGPU.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-NoGPU.zip
|
||||
|
||||
- name: ⬆️ Upload everything to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
@@ -110,3 +113,37 @@ jobs:
|
||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||
repo: ImHex-Patterns
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: ✉️ Update C++ Plugin Template
|
||||
uses: mvasigh/dispatch-action@main
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repo: ImHex-Cpp-Plugin-Template
|
||||
owner: WerWolv
|
||||
event_type: update_submodule
|
||||
|
||||
release-windows:
|
||||
name: Release Windows
|
||||
needs: release-common
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: ⬇️ Download dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
iwr https://github.com/microsoft/winget-create/releases/download/v1.1.2.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||
- name: ⬆️ Update winget manifest
|
||||
shell: pwsh
|
||||
env:
|
||||
WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.WINGET_GITHUB_TOKEN != '' }}"
|
||||
run: |
|
||||
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
|
||||
$version = $tagname.Replace("v", "")
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-win64.msi"
|
||||
.\wingetcreate.exe update WerWolv.ImHex -u $url --version $version
|
||||
if ($version -notmatch "-") {
|
||||
.\wingetcreate.exe submit .\manifests\w\WerWolv\ImHex\${version}\ --token $env:WINGET_GITHUB_TOKEN
|
||||
}
|
||||
|
||||
18
.github/workflows/tests.yml
vendored
@@ -47,18 +47,18 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
..
|
||||
make -j4 unit_tests install
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest --output-on-failure
|
||||
ctest --output-on-failure
|
||||
|
||||
1
.idea/vcs.xml
generated
@@ -8,6 +8,7 @@
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/cli11" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
# Options
|
||||
option(IMHEX_USE_BUNDLED_CA "Use the CA bundle in romfs instead of the system one" OFF)
|
||||
option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins" OFF)
|
||||
option(IMHEX_STRIP_RELEASE "Strip the release builds" ON)
|
||||
option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
|
||||
option(IMHEX_IGNORE_BAD_CLONE "Disabled the bad clone prevention checks" OFF)
|
||||
option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
|
||||
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
|
||||
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
|
||||
|
||||
# Basic compiler and cmake configurations
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
||||
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||
@@ -46,4 +48,4 @@ enable_testing()
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
|
||||
# Configure packaging
|
||||
createPackage()
|
||||
createPackage()
|
||||
|
||||
52
INSTALL.md
Normal 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.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
48
README.md
@@ -1,4 +1,4 @@
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" >:mag: ImHex</h1></a>
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" ><img height="100px" src="resources/projects/logo_text.svg"></h1></a>
|
||||
|
||||
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
|
||||
|
||||
@@ -104,7 +104,11 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
|
||||
## Pattern Language
|
||||
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
|
||||
The Pattern Language is the completely custom programming language developed for ImHex.
|
||||
It allows you to define structures and data types in a C-like syntax and then use them to parse and highlight a file's content.
|
||||
|
||||
- Source Code: [Link](https://github.com/WerWolv/PatternLanguage/)
|
||||
- Documentation: [Link](https://imhex.werwolv.net/docs/)
|
||||
|
||||
## Database
|
||||
|
||||
@@ -116,40 +120,15 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
|
||||
|
||||
To use ImHex, the following minimal system requirements need to be met:
|
||||
|
||||
- **OS**: Windows 7 or higher, macOS 10.10 (Yosemite) or higher, "Modern" Linux (Ubuntu 22.04+, Fedora Stable/Rawhide and Arch Linux are officially supported)
|
||||
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora Stable/Rawhide, and Arch Linux have official packages, other distributions can use the AppImage)
|
||||
- **CPU**: x86_64 (64 Bit)
|
||||
- **GPU**: OpenGL 3.0 or higher (preferable a dedicated GPU and not Intel HD Graphics)
|
||||
- **RAM**: 512MB, more may be required for more complicated analysis
|
||||
- **Storage**: 100MB
|
||||
|
||||
## Plugin development
|
||||
## Installing
|
||||
|
||||
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)
|
||||
|
||||
|
||||
## 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 DEB](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20DEB%20%28Ubuntu%2022.04%29.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)
|
||||
|
||||
## Third party repositories
|
||||
|
||||
ImHex is available in various third party repositories.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
Information on how to install ImHex can be found in the [Install](/INSTALL.md) guide
|
||||
|
||||
## Compiling
|
||||
|
||||
@@ -160,6 +139,15 @@ All releases are being built using latest available GCC.
|
||||
Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
|
||||
All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
|
||||
|
||||
For more information, check out the [Compiling](/dist/compiling) guide.
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
@@ -84,6 +84,8 @@ macro(detectOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
|
||||
SET(IMHEX_USE_BUNDLED_CA ON)
|
||||
elseif (APPLE)
|
||||
add_compile_definitions(OS_MACOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
@@ -102,10 +104,15 @@ macro(detectOS)
|
||||
# Warning : Do not work with portable versions such as appimage (because the path is hardcoded)
|
||||
add_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex") # "plugins" will be appended from the app
|
||||
endif()
|
||||
|
||||
|
||||
else ()
|
||||
message(FATAL_ERROR "Unknown / unsupported system!")
|
||||
endif()
|
||||
|
||||
if(IMHEX_USE_BUNDLED_CA)
|
||||
add_compile_definitions(IMHEX_USE_BUNDLED_CA)
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
||||
# Detect 32 vs. 64 bit system
|
||||
@@ -133,7 +140,7 @@ macro(configurePackingResources)
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
set(CPACK_PACKAGE_NAME "ImHex")
|
||||
set(CPACK_PACKAGE_NAME "imhex")
|
||||
set(CPACK_PACKAGE_VENDOR "WerWolv")
|
||||
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
|
||||
@@ -258,6 +265,14 @@ macro(createPackage)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
downloadImHexPatternsFiles("./share/imhex")
|
||||
|
||||
# install AppStream file
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/net.werwolv.imhex.metainfo.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
|
||||
|
||||
# install symlink for the old standard name
|
||||
file(CREATE_LINK net.werwolv.imhex.metainfo.xml ${CMAKE_CURRENT_BINARY_DIR}/net.werwolv.imhex.appdata.xml SYMBOLIC)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/net.werwolv.imhex.appdata.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
|
||||
|
||||
endif()
|
||||
|
||||
if (CREATE_BUNDLE)
|
||||
@@ -316,7 +331,9 @@ macro(setDefaultBuiltTypeIfUnset)
|
||||
endmacro()
|
||||
|
||||
function(loadVersion version)
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" read_version)
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||
file(READ "${VERSION_FILE}" read_version)
|
||||
set(${version} ${read_version} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -344,7 +361,7 @@ function(verifyCompiler)
|
||||
message(FATAL_ERROR "ImHex requires GCC 12.0.0 or newer. Please use the latest GCC version.")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14.0.0")
|
||||
message(FATAL_ERROR "ImHex requires Clang 14.0.0 or newer. Please use the latest Clang version.")
|
||||
elseif (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
elseif (NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
|
||||
message(FATAL_ERROR "ImHex can only be compiled with GCC or Clang. ${CMAKE_CXX_COMPILER_ID} is not supported.")
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -375,6 +392,12 @@ function(downloadImHexPatternsFiles dest)
|
||||
|
||||
FetchContent_Populate(imhex_patterns)
|
||||
|
||||
else ()
|
||||
# Maybe patterns are cloned to a subdirectory
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
||||
endif ()
|
||||
|
||||
if (EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest})
|
||||
@@ -385,7 +408,7 @@ endfunction()
|
||||
|
||||
macro(setupCompilerWarnings target)
|
||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Werror")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
|
||||
5
dist/AppImageBuilder.yml
vendored
@@ -6,7 +6,7 @@ AppDir:
|
||||
id: imhex
|
||||
name: ImHex
|
||||
icon: imhex
|
||||
version: AppImage
|
||||
version: "{{VERSION}}"
|
||||
exec: usr/bin/imhex
|
||||
exec_args: $@
|
||||
apt:
|
||||
@@ -136,4 +136,5 @@ AppDir:
|
||||
- usr/share/doc/*/TODO.*
|
||||
AppImage:
|
||||
arch: x86_64
|
||||
update-information: guess
|
||||
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*.AppImage.zsync
|
||||
file_name: imhex-{{VERSION}}.AppImage
|
||||
|
||||
33
dist/Arch/PKGBUILD
vendored
@@ -1,40 +1,29 @@
|
||||
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
|
||||
# Contributor: Morten Linderud <foxboron@archlinux.org>
|
||||
|
||||
pkgname=imhex-bin
|
||||
pkgver=%version%
|
||||
pkgrel=1
|
||||
pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM. "
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
repo=$url
|
||||
license=('GPL 2.0')
|
||||
groups=()
|
||||
license=('GPL2')
|
||||
depends=(glfw mbedtls python freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
|
||||
makedepends=(git)
|
||||
checkdepends=()
|
||||
optdepends=()
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
replaces=()
|
||||
backup=()
|
||||
options=()
|
||||
source=($repo"/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
noextract=()
|
||||
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
md5sums=(SKIP)
|
||||
validpgpkeys=()
|
||||
|
||||
package() {
|
||||
tar -xf imhex-$pkgver-ArchLinux.pkg.tar.zst
|
||||
install -Dm755 "$srcdir/usr/bin/imhex" "$pkgdir/usr/bin/imhex"
|
||||
install -Dm644 "$srcdir/usr/lib/libimhex.so.$pkgver" "$pkgdir/usr/lib/libimhex.so.$pkgver"
|
||||
|
||||
install -DT $srcdir/usr/bin/imhex $pkgdir/usr/bin/imhex
|
||||
install -DT $srcdir/usr/lib/libimhex.so.$pkgver $pkgdir/usr/lib/libimhex.so.$pkgver
|
||||
|
||||
for plugin in $srcdir/usr/lib/imhex/plugins/*.hexplug;
|
||||
do
|
||||
install -DT $plugin $pkgdir/usr/lib/imhex/plugins/`basename $plugin`
|
||||
for plugin in "$srcdir/usr/lib/imhex/plugins/"*.hexplug; do
|
||||
install -Dm644 "$plugin" "$pkgdir/usr/lib/imhex/plugins/${plugin##*/}"
|
||||
done
|
||||
|
||||
mkdir -p $pkgdir/usr/share/imhex
|
||||
cp -r $srcdir/usr/share/imhex/{constants,encodings,includes,magic,patterns} $pkgdir/usr/share/imhex
|
||||
cp -r $srcdir/usr/share/{applications,licenses} $pkgdir/usr/share
|
||||
install -d $pkgdir/usr/share
|
||||
install -d "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/"{applications,licenses} "$pkgdir/usr/share"
|
||||
}
|
||||
|
||||
2
dist/Brewfile
vendored
@@ -1,4 +1,3 @@
|
||||
brew "glfw"
|
||||
brew "mbedtls"
|
||||
brew "nlohmann-json"
|
||||
brew "cmake"
|
||||
@@ -8,3 +7,4 @@ brew "freetype2"
|
||||
brew "libmagic"
|
||||
brew "pkg-config"
|
||||
brew "gcc@12"
|
||||
brew "llvm"
|
||||
|
||||
4
dist/Dockerfile
vendored
@@ -1,6 +1,6 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
MAINTAINER WerWolv "hey@werwolv.net"
|
||||
LABEL maintainer="hey@werwolv.net" = WerWolv
|
||||
|
||||
# Install dependencies
|
||||
RUN pacman -Syy --needed --noconfirm
|
||||
@@ -25,4 +25,4 @@ RUN git clone https://github.com/WerWolv/ImHex --recurse-submodules /root/ImHex
|
||||
RUN mkdir /root/ImHex/build
|
||||
WORKDIR /root/ImHex/build
|
||||
RUN cmake .. && make -j
|
||||
WORKDIR /root/ImHex
|
||||
WORKDIR /root/ImHex
|
||||
|
||||
2
dist/compiling/macOS.md
vendored
@@ -16,7 +16,7 @@ OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
|
||||
25
dist/macOS/0001-glfw-SW.patch
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
From 9c8665af4c2e2ce66555c15c05c72027bfdf0cb6 Mon Sep 17 00:00:00 2001
|
||||
From: iTrooz <itrooz@protonmail.com>
|
||||
Date: Mon, 29 Aug 2022 17:29:38 +0200
|
||||
Subject: [PATCH] Use software rendering on MacOS
|
||||
|
||||
---
|
||||
src/nsgl_context.m | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/nsgl_context.m b/src/nsgl_context.m
|
||||
index fc1f7521..e5906575 100644
|
||||
--- a/src/nsgl_context.m
|
||||
+++ b/src/nsgl_context.m
|
||||
@@ -198,7 +198,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
NSOpenGLPixelFormatAttribute attribs[40];
|
||||
int index = 0;
|
||||
|
||||
- ADD_ATTRIB(NSOpenGLPFAAccelerated);
|
||||
+ ADD_ATTRIB(NSOpenGLPFARendererID);ADD_ATTRIB(kCGLRendererGenericFloatID);
|
||||
ADD_ATTRIB(NSOpenGLPFAClosestPolicy);
|
||||
|
||||
if (ctxconfig->nsgl.offline)
|
||||
--
|
||||
2.37.2
|
||||
|
||||
34
dist/net.werwolv.imhex.metainfo.xml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>imhex</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0</project_license>
|
||||
<name>ImHex</name>
|
||||
<developer_name>WerWolv</developer_name>
|
||||
<update_contact>hey@werwolv.net</update_contact>
|
||||
<summary>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM</summary>
|
||||
<description>
|
||||
<p>ImHex is a feature-rich Hex Editor aimed towards Reverse Engineers working with foreign data formats, malware, executables and raw memory.
|
||||
Besides all the features a common Hex Editor has, ImHex also features a custom scripting language used to declare and dissect data structures, support for running YARA rules, a node-based graphical data pre-processor and support for various data sources such as files, raw disks or GDB Servers.</p>
|
||||
</description>
|
||||
<launchable type="desktop-id">imhex.desktop</launchable>
|
||||
<url type="homepage">https://imhex.werwolv.net</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://user-images.githubusercontent.com/10835354/139717326-8044769d-527b-4d88-8adf-2d4ecafdca1f.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://user-images.githubusercontent.com/10835354/139717323-1f8c9d52-f7eb-4f43-9f11-097ac728ed6c.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
<provides>
|
||||
<id>imhex.desktop</id>
|
||||
</provides>
|
||||
|
||||
<categories>
|
||||
<category>Development</category>
|
||||
</categories>
|
||||
|
||||
|
||||
</component>
|
||||
2
dist/rpm/imhex.spec
vendored
@@ -84,5 +84,7 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/imhex.desktop
|
||||
%{_datadir}/applications/imhex.desktop
|
||||
%{_prefix}/lib64/libimhex.so.%{_version}
|
||||
%{_prefix}/lib64/imhex/plugins/*
|
||||
%{_metainfodir}/net.werwolv.imhex.metainfo.xml
|
||||
%{_metainfodir}/net.werwolv.imhex.appdata.xml
|
||||
|
||||
%changelog
|
||||
|
||||
2
lib/external/curl
vendored
2
lib/external/fmt
vendored
2
lib/external/imgui/include/imconfig.h
vendored
@@ -99,7 +99,7 @@
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
|
||||
11
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
@@ -164,7 +164,10 @@ static void ImGui_ImplGlfw_ShutdownPlatformInterface();
|
||||
// Functions
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
// IMHEX PATCH BEGIN
|
||||
const char *data = glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
return data == nullptr ? "" : data;
|
||||
// IMHEX PATCH END
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
@@ -179,12 +182,12 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.ClipboardHandlerData.clear();
|
||||
if (!::OpenClipboard(NULL))
|
||||
return NULL;
|
||||
return "";
|
||||
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
|
||||
if (wbuf_handle == NULL)
|
||||
{
|
||||
::CloseClipboard();
|
||||
return NULL;
|
||||
return "";
|
||||
}
|
||||
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
|
||||
{
|
||||
@@ -194,7 +197,7 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
}
|
||||
::GlobalUnlock(wbuf_handle);
|
||||
::CloseClipboard();
|
||||
return g.ClipboardHandlerData.Data;
|
||||
return g.ClipboardHandlerData.Data == nullptr ? "" : g.ClipboardHandlerData.Data;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin_SetClipboardText(void*, const char* text)
|
||||
|
||||
2
lib/external/libromfs
vendored
2
lib/external/nativefiledialog
vendored
2
lib/external/pattern_language
vendored
2
lib/external/yara/yara
vendored
@@ -11,8 +11,9 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/microtar ${CMAKE_CURREN
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${IMHEX_BASE_FOLDER}/resources/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME imhex)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/external/libromfs EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libromfs PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/intervaltree ${CMAKE_CURRENT_BINARY_DIR}/external/intervaltree EXCLUDE_FROM_ALL)
|
||||
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
@@ -58,7 +59,7 @@ if(NOT USE_SYSTEM_CURL)
|
||||
set(LIBCURL_LIBRARIES libcurl)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.78.0)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.76.1)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
@@ -136,6 +137,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/encoding_file.cpp
|
||||
source/helpers/logger.cpp
|
||||
source/helpers/tar.cpp
|
||||
source/helpers/types.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
|
||||
@@ -172,4 +174,5 @@ if (APPLE)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl intervaltree)
|
||||
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libpl intervaltree)
|
||||
target_link_libraries(libimhex PRIVATE libromfs-imhex)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include <hex/helpers/types.hpp>
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
using ImGuiDataType = int;
|
||||
using ImGuiInputTextFlags = int;
|
||||
|
||||
namespace pl {
|
||||
class Evaluator;
|
||||
}
|
||||
|
||||
namespace hex {
|
||||
|
||||
class View;
|
||||
@@ -61,7 +57,7 @@ namespace hex {
|
||||
return name < other.name;
|
||||
}
|
||||
|
||||
operator const std::string &() const {
|
||||
explicit operator const std::string &() const {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
@@ -136,7 +132,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider);
|
||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider);
|
||||
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
|
||||
|
||||
@@ -435,7 +431,7 @@ namespace hex {
|
||||
|
||||
class Hash {
|
||||
public:
|
||||
Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
explicit Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
|
||||
class Function {
|
||||
public:
|
||||
@@ -498,6 +494,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ namespace hex {
|
||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestChangeWindowTitle, std::string);
|
||||
EVENT_DEF(RequestCloseImHex, bool);
|
||||
EVENT_DEF(RequestRestartImHex);
|
||||
EVENT_DEF(RequestOpenFile, std::fs::path);
|
||||
EVENT_DEF(RequestChangeTheme, u32);
|
||||
EVENT_DEF(RequestOpenPopup, std::string);
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t)>;
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
|
||||
|
||||
std::map<u32, Highlighting> &getBackgroundHighlights();
|
||||
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions();
|
||||
@@ -150,15 +150,6 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
namespace Tasks {
|
||||
|
||||
Task createTask(const std::string &unlocalizedName, u64 maxValue);
|
||||
|
||||
void doLater(const std::function<void()> &function);
|
||||
std::vector<std::function<void()>> &getDeferredCalls();
|
||||
|
||||
}
|
||||
|
||||
namespace System {
|
||||
|
||||
namespace impl {
|
||||
@@ -180,6 +171,8 @@ namespace hex {
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
|
||||
void setPortableVersion(bool enabled);
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||
}
|
||||
|
||||
struct ProgramArguments {
|
||||
@@ -195,6 +188,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
const ProgramArguments &getProgramArguments();
|
||||
std::optional<std::u8string> getProgramArgument(int index);
|
||||
|
||||
float getTargetFPS();
|
||||
void setTargetFPS(float fps);
|
||||
@@ -210,6 +204,7 @@ namespace hex {
|
||||
|
||||
std::map<std::string, std::string> &getInitArguments();
|
||||
|
||||
constexpr static float DefaultFontSize = 13.0;
|
||||
const std::fs::path &getCustomFontPath();
|
||||
float getFontSize();
|
||||
|
||||
|
||||
@@ -179,10 +179,10 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
static constexpr auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
||||
static constexpr auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
||||
static constexpr auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
||||
static constexpr auto SUPER = Key(static_cast<Keys>(0x8000'0000));
|
||||
constexpr static auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
||||
constexpr static auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
||||
constexpr static auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
||||
constexpr static auto SUPER = Key(static_cast<Keys>(0x8000'0000));
|
||||
|
||||
class ShortcutManager {
|
||||
public:
|
||||
|
||||
@@ -19,12 +19,14 @@ namespace hex {
|
||||
struct Handler {
|
||||
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
bool required;
|
||||
Function load, store;
|
||||
};
|
||||
|
||||
struct ProviderHandler {
|
||||
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
bool required;
|
||||
Function load, store;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,40 +2,120 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class TaskHolder;
|
||||
class TaskManager;
|
||||
|
||||
class Task {
|
||||
public:
|
||||
Task() = default;
|
||||
Task(const std::string &unlocalizedName, u64 maxValue);
|
||||
Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||
|
||||
Task(const Task&) = delete;
|
||||
Task(Task &&other) noexcept;
|
||||
~Task();
|
||||
|
||||
Task(Task &&other) noexcept;
|
||||
void update(u64 value = 0);
|
||||
void setMaxValue(u64 value);
|
||||
|
||||
void setMaxValue(u64 maxValue);
|
||||
void update(u64 currValue);
|
||||
void finish();
|
||||
[[nodiscard]] bool isBackgroundTask() const;
|
||||
[[nodiscard]] bool isFinished() const;
|
||||
[[nodiscard]] bool hadException() const;
|
||||
[[nodiscard]] bool wasInterrupted() const;
|
||||
void clearException();
|
||||
[[nodiscard]] std::string getExceptionMessage() const;
|
||||
|
||||
[[nodiscard]] double getProgress() const;
|
||||
[[nodiscard]] const std::string &getUnlocalizedName();
|
||||
[[nodiscard]] u64 getValue() const;
|
||||
[[nodiscard]] u64 getMaxValue() const;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const;
|
||||
void interrupt();
|
||||
|
||||
[[nodiscard]] bool isPending() const;
|
||||
|
||||
static size_t getRunningTaskCount();
|
||||
static std::list<Task *> &getRunningTasks() { return Task::s_runningTasks; }
|
||||
static std::mutex &getTaskMutex() { return Task::s_taskMutex; }
|
||||
void setInterruptCallback(std::function<void()> callback);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
u64 m_maxValue = 0, m_currValue = 0;
|
||||
void finish();
|
||||
void interruption();
|
||||
void exception(const char *message);
|
||||
|
||||
static std::list<Task *> s_runningTasks;
|
||||
static std::mutex s_taskMutex;
|
||||
private:
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
std::string m_unlocalizedName;
|
||||
std::atomic<u64> m_currValue = 0, m_maxValue = 0;
|
||||
std::function<void()> m_interruptCallback;
|
||||
std::function<void(Task &)> m_function;
|
||||
|
||||
std::atomic<bool> m_shouldInterrupt = false;
|
||||
std::atomic<bool> m_background = true;
|
||||
|
||||
std::atomic<bool> m_interrupted = false;
|
||||
std::atomic<bool> m_finished = false;
|
||||
std::atomic<bool> m_hadException = false;
|
||||
std::string m_exceptionMessage;
|
||||
|
||||
struct TaskInterruptor { virtual ~TaskInterruptor() = default; };
|
||||
|
||||
friend class TaskHolder;
|
||||
friend class TaskManager;
|
||||
};
|
||||
|
||||
class TaskHolder {
|
||||
public:
|
||||
TaskHolder() = default;
|
||||
explicit TaskHolder(std::weak_ptr<Task> task) : m_task(std::move(task)) { }
|
||||
|
||||
[[nodiscard]] bool isRunning() const;
|
||||
[[nodiscard]] bool hadException() const;
|
||||
[[nodiscard]] bool wasInterrupted() const;
|
||||
|
||||
void interrupt();
|
||||
private:
|
||||
std::weak_ptr<Task> m_task;
|
||||
};
|
||||
|
||||
class TaskManager {
|
||||
public:
|
||||
TaskManager() = delete;
|
||||
|
||||
static void init();
|
||||
static void exit();
|
||||
|
||||
constexpr static auto NoProgress = 0;
|
||||
|
||||
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
||||
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
||||
|
||||
static void collectGarbage();
|
||||
|
||||
static size_t getRunningTaskCount();
|
||||
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
||||
|
||||
static void doLater(const std::function<void()> &function);
|
||||
static void runDeferredCalls();
|
||||
private:
|
||||
static std::mutex s_deferredCallsMutex;
|
||||
|
||||
static std::list<std::shared_ptr<Task>> s_tasks;
|
||||
static std::list<std::shared_ptr<Task>> s_taskQueue;
|
||||
static std::list<std::function<void()>> s_deferredCalls;
|
||||
|
||||
static std::mutex s_queueMutex;
|
||||
static std::condition_variable s_jobCondVar;
|
||||
static std::vector<std::jthread> s_workers;
|
||||
|
||||
static void runner(const std::stop_token &stopToken);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -27,32 +27,32 @@ namespace hex::dp {
|
||||
Attribute(IOType ioType, Type type, std::string unlocalizedName);
|
||||
~Attribute();
|
||||
|
||||
[[nodiscard]] u32 getId() const { return this->m_id; }
|
||||
void setId(u32 id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
|
||||
[[nodiscard]] IOType getIOType() const { return this->m_ioType; }
|
||||
[[nodiscard]] Type getType() const { return this->m_type; }
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
|
||||
|
||||
void addConnectedAttribute(u32 linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
|
||||
void removeConnectedAttribute(u32 linkId) { this->m_connectedAttributes.erase(linkId); }
|
||||
[[nodiscard]] std::map<u32, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
|
||||
void addConnectedAttribute(int linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
|
||||
void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
|
||||
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
|
||||
|
||||
[[nodiscard]] Node *getParentNode() { return this->m_parentNode; }
|
||||
|
||||
[[nodiscard]] std::optional<std::vector<u8>> &getOutputData() { return this->m_outputData; }
|
||||
|
||||
static void setIdCounter(u32 id) {
|
||||
static void setIdCounter(int id) {
|
||||
if (id > Attribute::s_idCounter)
|
||||
Attribute::s_idCounter = id;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_id;
|
||||
int m_id;
|
||||
IOType m_ioType;
|
||||
Type m_type;
|
||||
std::string m_unlocalizedName;
|
||||
std::map<u32, Attribute *> m_connectedAttributes;
|
||||
std::map<int, Attribute *> m_connectedAttributes;
|
||||
Node *m_parentNode = nullptr;
|
||||
|
||||
std::optional<std::vector<u8>> m_outputData;
|
||||
@@ -60,7 +60,7 @@ namespace hex::dp {
|
||||
friend class Node;
|
||||
void setParentNode(Node *node) { this->m_parentNode = node; }
|
||||
|
||||
static u32 s_idCounter;
|
||||
static int s_idCounter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,24 +6,24 @@ namespace hex::dp {
|
||||
|
||||
class Link {
|
||||
public:
|
||||
Link(u32 from, u32 to);
|
||||
Link(int from, int to);
|
||||
|
||||
[[nodiscard]] u32 getId() const { return this->m_id; }
|
||||
void setID(u32 id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setID(int id) { this->m_id = id; }
|
||||
|
||||
[[nodiscard]] u32 getFromId() const { return this->m_from; }
|
||||
[[nodiscard]] u32 getToId() const { return this->m_to; }
|
||||
[[nodiscard]] int getFromId() const { return this->m_from; }
|
||||
[[nodiscard]] int getToId() const { return this->m_to; }
|
||||
|
||||
static void setIdCounter(u32 id) {
|
||||
static void setIdCounter(int id) {
|
||||
if (id > Link::s_idCounter)
|
||||
Link::s_idCounter = id;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_id;
|
||||
u32 m_from, m_to;
|
||||
int m_id;
|
||||
int m_from, m_to;
|
||||
|
||||
static u32 s_idCounter;
|
||||
static int s_idCounter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
@@ -23,8 +24,8 @@ namespace hex::dp {
|
||||
|
||||
virtual ~Node() = default;
|
||||
|
||||
[[nodiscard]] u32 getId() const { return this->m_id; }
|
||||
void setId(u32 id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
|
||||
void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
|
||||
@@ -56,19 +57,28 @@ namespace hex::dp {
|
||||
this->m_processedInputs.clear();
|
||||
}
|
||||
|
||||
static void setIdCounter(u32 id) {
|
||||
void setPosition(ImVec2 pos) {
|
||||
this->m_position = pos;
|
||||
}
|
||||
|
||||
[[nodiscard]] ImVec2 getPosition() const {
|
||||
return this->m_position;
|
||||
}
|
||||
|
||||
static void setIdCounter(int id) {
|
||||
if (id > Node::s_idCounter)
|
||||
Node::s_idCounter = id;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_id;
|
||||
int m_id;
|
||||
std::string m_unlocalizedTitle, m_unlocalizedName;
|
||||
std::vector<Attribute> m_attributes;
|
||||
std::set<u32> m_processedInputs;
|
||||
prv::Overlay *m_overlay = nullptr;
|
||||
ImVec2 m_position;
|
||||
|
||||
static u32 s_idCounter;
|
||||
static int s_idCounter;
|
||||
|
||||
Attribute *getConnectedInputAttribute(u32 index) {
|
||||
if (index >= this->getAttributes().size())
|
||||
@@ -90,7 +100,7 @@ namespace hex::dp {
|
||||
|
||||
protected:
|
||||
[[noreturn]] void throwNodeError(const std::string &message) {
|
||||
throw NodeError(this, message);
|
||||
throw NodeError { this, message };
|
||||
}
|
||||
|
||||
std::vector<u8> getBufferOnInput(u32 index);
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace hex {
|
||||
|
||||
class Disassembler {
|
||||
public:
|
||||
static constexpr cs_arch toCapstoneArchitecture(Architecture architecture) {
|
||||
constexpr static cs_arch toCapstoneArchitecture(Architecture architecture) {
|
||||
return static_cast<cs_arch>(architecture);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -66,7 +68,7 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
static inline bool isSubPath(const std::fs::path& base, const std::fs::path& destination) {
|
||||
const auto relative = std::fs::relative(destination, base).string();
|
||||
const auto relative = std::fs::relative(destination, base).u8string();
|
||||
|
||||
return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.');
|
||||
}
|
||||
@@ -75,18 +77,17 @@ namespace hex::fs {
|
||||
|
||||
std::fs::path toShortPath(const std::fs::path &path);
|
||||
|
||||
enum class DialogMode
|
||||
{
|
||||
enum class DialogMode {
|
||||
Open,
|
||||
Save,
|
||||
Folder
|
||||
};
|
||||
|
||||
void setFileBrowserErrorCallback(const std::function<void()> &callback);
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {});
|
||||
|
||||
enum class ImHexPath
|
||||
{
|
||||
Patterns,
|
||||
enum class ImHexPath : u32 {
|
||||
Patterns = 0,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Python,
|
||||
@@ -97,7 +98,11 @@ namespace hex::fs {
|
||||
Constants,
|
||||
Encodings,
|
||||
Logs,
|
||||
Recent
|
||||
Recent,
|
||||
Scripts,
|
||||
Inspectors,
|
||||
|
||||
END
|
||||
};
|
||||
|
||||
std::optional<std::fs::path> getExecutablePath();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/color.h>
|
||||
@@ -30,6 +31,9 @@ namespace hex::log {
|
||||
|
||||
template<typename... T>
|
||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
||||
static std::mutex logMutex;
|
||||
std::scoped_lock lock(logMutex);
|
||||
|
||||
auto dest = getDestination();
|
||||
|
||||
printPrefix(dest, ts, level);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <curl/system.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace hex {
|
||||
Net();
|
||||
~Net();
|
||||
|
||||
static constexpr u32 DefaultTimeout = 2'000;
|
||||
constexpr static u32 DefaultTimeout = 2'000;
|
||||
|
||||
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
@@ -60,6 +61,7 @@ namespace hex {
|
||||
|
||||
private:
|
||||
CURL *m_ctx;
|
||||
mbedtls_x509_crt m_caCert;
|
||||
curl_slist *m_headers = nullptr;
|
||||
|
||||
std::mutex m_transmissionActive;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
@@ -20,29 +23,14 @@ namespace hex {
|
||||
u64 address;
|
||||
size_t size;
|
||||
|
||||
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
|
||||
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress()) && *this != Invalid() && other != Invalid();
|
||||
}
|
||||
[[nodiscard]] bool isWithin(const Region &other) const;
|
||||
[[nodiscard]] bool overlaps(const Region &other) const;
|
||||
|
||||
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
|
||||
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress()) && *this != Invalid() && other != Invalid();
|
||||
}
|
||||
[[nodiscard]] u64 getStartAddress() const;
|
||||
[[nodiscard]] u64 getEndAddress() const;
|
||||
[[nodiscard]] size_t getSize() const;
|
||||
|
||||
[[nodiscard]] constexpr u64 getStartAddress() const {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getEndAddress() const {
|
||||
return this->address + this->size - 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_t getSize() const {
|
||||
return this->size;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const Region &other) const {
|
||||
return this->address == other.address && this->size == other.size;
|
||||
}
|
||||
bool operator==(const Region &other) const;
|
||||
|
||||
constexpr static Region Invalid() {
|
||||
return { 0, 0 };
|
||||
|
||||
@@ -27,10 +27,20 @@ struct ImVec2;
|
||||
|
||||
namespace hex {
|
||||
|
||||
long double operator""_scaled(long double value);
|
||||
long double operator""_scaled(unsigned long long value);
|
||||
float operator""_scaled(long double value);
|
||||
float operator""_scaled(unsigned long long value);
|
||||
ImVec2 scaled(const ImVec2 &vector);
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> operator|(const std::vector<T> &lhs, const std::vector<T> &rhs) {
|
||||
std::vector<T> result;
|
||||
|
||||
std::copy(lhs.begin(), lhs.end(), std::back_inserter(result));
|
||||
std::copy(rhs.begin(), rhs.end(), std::back_inserter(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_string(u128 value);
|
||||
std::string to_string(i128 value);
|
||||
|
||||
@@ -68,7 +78,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
constexpr inline i128 signExtend(size_t numBits, i128 value) {
|
||||
i128 mask = 1U << (numBits - 1);
|
||||
i128 mask = 1ULL << (numBits - 1);
|
||||
return (value ^ mask) - mask;
|
||||
}
|
||||
|
||||
@@ -84,6 +94,13 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr inline size_t strnlen(const char *s, size_t n) {
|
||||
size_t i = 0;
|
||||
while (i < n && s[i] != '\x00') i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template<class... Ts>
|
||||
@@ -258,6 +275,13 @@ namespace hex {
|
||||
return iter != a.end();
|
||||
}
|
||||
|
||||
template<typename T> requires requires(T t) { t.u8string(); }
|
||||
std::string toUTF8String(const T &value) {
|
||||
auto result = value.u8string();
|
||||
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
template<typename T, typename... VariantTypes>
|
||||
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
|
||||
const T *value = std::get_if<T>(&variant);
|
||||
@@ -280,6 +304,13 @@ namespace hex {
|
||||
|
||||
std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||
|
||||
inline std::string limitStringLength(const std::string &string, size_t maxLength) {
|
||||
if (string.length() <= maxLength)
|
||||
return string;
|
||||
|
||||
return string.substr(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
namespace scope_guard {
|
||||
|
||||
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
|
||||
@@ -318,7 +349,7 @@ namespace hex {
|
||||
|
||||
namespace first_time_exec {
|
||||
|
||||
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
|
||||
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
|
||||
|
||||
template<class F>
|
||||
class FirstTimeExecute {
|
||||
@@ -341,7 +372,7 @@ namespace hex {
|
||||
|
||||
namespace final_cleanup {
|
||||
|
||||
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
|
||||
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
|
||||
|
||||
template<class F>
|
||||
class FinalCleanupExecute {
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
#include <vector>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/literals.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
using namespace hex::literals;
|
||||
|
||||
class BufferedReader {
|
||||
public:
|
||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 0xFF'FFFF)
|
||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 16_MiB)
|
||||
: m_provider(provider), m_bufferAddress(provider->getBaseAddress()), m_maxBufferSize(bufferSize),
|
||||
m_startAddress(0x00), m_endAddress(provider->getActualSize()),
|
||||
m_startAddress(0x00), m_endAddress(provider->getActualSize() - 1),
|
||||
m_buffer(bufferSize) {
|
||||
|
||||
}
|
||||
@@ -21,6 +24,9 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
void setEndAddress(u64 address) {
|
||||
if (address >= this->m_provider->getActualSize())
|
||||
address = this->m_provider->getActualSize() - 1;
|
||||
|
||||
this->m_endAddress = address;
|
||||
}
|
||||
|
||||
@@ -215,7 +221,7 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
value_type operator[](i64 offset) const {
|
||||
auto result = this->m_reader->readReverse(this->m_address + offset, 1);
|
||||
auto result = this->m_reader->readReverse(this->m_address - offset, 1);
|
||||
if (result.empty())
|
||||
return 0x00;
|
||||
|
||||
@@ -247,7 +253,7 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
ReverseIterator rend() {
|
||||
return { this, std::numeric_limits<u64>::max() };
|
||||
return { this, 0 };
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -256,6 +262,8 @@ namespace hex::prv {
|
||||
const auto remainingBytes = (this->m_endAddress - address) + 1;
|
||||
if (remainingBytes < this->m_maxBufferSize)
|
||||
this->m_buffer.resize(remainingBytes);
|
||||
else
|
||||
this->m_buffer.resize(this->m_maxBufferSize);
|
||||
|
||||
this->m_provider->read(address, this->m_buffer.data(), this->m_buffer.size());
|
||||
this->m_bufferAddress = address;
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace pl {
|
||||
class PatternLanguage;
|
||||
}
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
class Provider {
|
||||
@@ -70,8 +66,8 @@ namespace hex::prv {
|
||||
[[nodiscard]] virtual std::string getName() const = 0;
|
||||
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool open();
|
||||
virtual void close();
|
||||
[[nodiscard]] virtual bool open() = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false);
|
||||
void createUndoPoint();
|
||||
@@ -90,9 +86,8 @@ namespace hex::prv {
|
||||
virtual void drawLoadInterface();
|
||||
virtual void drawInterface();
|
||||
|
||||
[[nodiscard]] u32 getID() const {
|
||||
return this->m_id;
|
||||
}
|
||||
[[nodiscard]] u32 getID() const;
|
||||
void setID(u32 id);
|
||||
|
||||
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings = { }) const;
|
||||
virtual void loadSettings(const nlohmann::json &settings);
|
||||
@@ -102,7 +97,7 @@ namespace hex::prv {
|
||||
void markDirty(bool dirty = true) { this->m_dirty = dirty; }
|
||||
[[nodiscard]] bool isDirty() const { return this->m_dirty; }
|
||||
|
||||
virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
|
||||
[[nodiscard]] virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
|
||||
|
||||
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
||||
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
|
||||
|
||||
@@ -31,27 +31,40 @@ enum ImGuiCustomCol {
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
struct Texture {
|
||||
ImTextureID textureId = nullptr;
|
||||
int width = 0, height = 0;
|
||||
class Texture {
|
||||
public:
|
||||
Texture() = default;
|
||||
Texture(const ImU8 *buffer, int size);
|
||||
explicit Texture(const char *path);
|
||||
Texture(const Texture&) = delete;
|
||||
Texture(Texture&& other) noexcept;
|
||||
|
||||
[[nodiscard]] constexpr bool valid() const noexcept {
|
||||
return this->textureId != nullptr;
|
||||
~Texture();
|
||||
|
||||
Texture& operator=(const Texture&) = delete;
|
||||
Texture& operator=(Texture&& other) noexcept;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return this->m_textureId != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator ImTextureID() {
|
||||
return this->textureId;
|
||||
return this->m_textureId;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto size() const noexcept {
|
||||
return ImVec2(this->width, this->height);
|
||||
[[nodiscard]] auto getSize() const noexcept {
|
||||
return ImVec2(this->m_width, this->m_height);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto aspectRatio() const noexcept {
|
||||
if (this->height == 0) return 1.0F;
|
||||
[[nodiscard]] constexpr auto getAspectRatio() const noexcept {
|
||||
if (this->m_height == 0) return 1.0F;
|
||||
|
||||
return float(this->width) / float(this->height);
|
||||
return float(this->m_width) / float(this->m_height);
|
||||
}
|
||||
|
||||
private:
|
||||
ImTextureID m_textureId = nullptr;
|
||||
int m_width = 0, m_height = 0;
|
||||
};
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
|
||||
@@ -82,10 +95,6 @@ namespace ImGui {
|
||||
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
|
||||
}
|
||||
|
||||
Texture LoadImageFromPath(const char *path);
|
||||
Texture LoadImageFromMemory(const ImU8 *buffer, int size);
|
||||
void UnloadImage(Texture &texture);
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name);
|
||||
|
||||
struct ImHexCustomData {
|
||||
@@ -130,6 +139,7 @@ namespace ImGui {
|
||||
}
|
||||
|
||||
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
@@ -241,29 +241,30 @@ namespace hex {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider) {
|
||||
auto runtime = std::make_unique<pl::PatternLanguage>();
|
||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
|
||||
runtime.reset();
|
||||
|
||||
if (provider != nullptr) {
|
||||
runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
|
||||
runtime.setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
}, provider->getBaseAddress(), provider->getActualSize());
|
||||
}
|
||||
|
||||
runtime->setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude));
|
||||
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
||||
|
||||
for (const auto &func : getFunctions()) {
|
||||
if (func.dangerous)
|
||||
runtime->addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
else
|
||||
runtime->addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
}
|
||||
|
||||
for (const auto &[name, callback] : getPragmas()) {
|
||||
runtime->addPragma(name, callback);
|
||||
runtime.addPragma(name, callback);
|
||||
}
|
||||
|
||||
return runtime;
|
||||
runtime.addDefine("__IMHEX__");
|
||||
runtime.addDefine("__IMHEX_VERSION__", IMHEX_VERSION);
|
||||
}
|
||||
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace ImHexApi::Common {
|
||||
@@ -20,11 +26,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void restartImHex() {
|
||||
EventManager::post<RequestRestartImHex>();
|
||||
EventManager::post<RequestCloseImHex>(false);
|
||||
std::atexit([] {
|
||||
auto &programArgs = ImHexApi::System::getProgramArguments();
|
||||
execve(programArgs.argv[0], programArgs.argv, programArgs.envp);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -211,7 +214,7 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::Provider {
|
||||
|
||||
static u32 s_currentProvider = std::numeric_limits<u32>::max();
|
||||
static i64 s_currentProvider = -1;
|
||||
static std::vector<prv::Provider *> s_providers;
|
||||
|
||||
namespace impl {
|
||||
@@ -239,7 +242,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setCurrentProvider(u32 index) {
|
||||
if (Task::getRunningTaskCount() > 0)
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (index < s_providers.size() && s_currentProvider != index) {
|
||||
@@ -250,7 +253,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return !s_providers.empty() && s_currentProvider < s_providers.size();
|
||||
return !s_providers.empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers.size());
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
@@ -269,7 +272,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void add(prv::Provider *provider, bool skipLoadInterface) {
|
||||
if (Task::getRunningTaskCount() > 0)
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (skipLoadInterface)
|
||||
@@ -285,7 +288,7 @@ namespace hex {
|
||||
if (provider == nullptr)
|
||||
return;
|
||||
|
||||
if (Task::getRunningTaskCount() > 0)
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (!noQuestions) {
|
||||
@@ -310,6 +313,9 @@ namespace hex {
|
||||
else if (it - s_providers.begin() == s_currentProvider)
|
||||
setCurrentProvider(0);
|
||||
|
||||
provider->close();
|
||||
EventManager::post<EventProviderClosed>(provider);
|
||||
|
||||
delete provider;
|
||||
}
|
||||
|
||||
@@ -322,29 +328,6 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace ImHexApi::Tasks {
|
||||
|
||||
Task createTask(const std::string &unlocalizedName, u64 maxValue) {
|
||||
return { unlocalizedName, maxValue };
|
||||
}
|
||||
|
||||
void doLater(const std::function<void()> &function) {
|
||||
static std::mutex tasksMutex;
|
||||
std::scoped_lock lock(tasksMutex);
|
||||
|
||||
getDeferredCalls().push_back(function);
|
||||
}
|
||||
|
||||
std::vector<std::function<void()>> &getDeferredCalls() {
|
||||
static std::vector<std::function<void()>> deferredCalls;
|
||||
|
||||
return deferredCalls;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace ImHexApi::System {
|
||||
|
||||
namespace impl {
|
||||
@@ -393,7 +376,7 @@ namespace hex {
|
||||
s_customFontPath = path;
|
||||
}
|
||||
|
||||
static float s_fontSize = 13.0;
|
||||
static float s_fontSize = DefaultFontSize;
|
||||
void setFontSize(float size) {
|
||||
s_fontSize = size;
|
||||
}
|
||||
@@ -408,6 +391,13 @@ namespace hex {
|
||||
s_portableVersion = enabled;
|
||||
}
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value) {
|
||||
static std::mutex initArgumentsMutex;
|
||||
std::scoped_lock lock(initArgumentsMutex);
|
||||
|
||||
getInitArguments()[key] = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -415,6 +405,21 @@ namespace hex {
|
||||
return impl::s_programArguments;
|
||||
}
|
||||
|
||||
std::optional<std::u8string> getProgramArgument(int index) {
|
||||
if (index >= impl::s_programArguments.argc) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
std::wstring wideArg = ::CommandLineToArgvW(::GetCommandLineW(), &impl::s_programArguments.argc)[index];
|
||||
std::string byteArg = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(wideArg);
|
||||
|
||||
return std::u8string(byteArg.begin(), byteArg.end());
|
||||
#else
|
||||
return std::u8string(reinterpret_cast<const char8_t *>(impl::s_programArguments.argv[index]));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static float s_targetFPS = 60.0F;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <system_error>
|
||||
@@ -16,7 +17,7 @@ namespace hex {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
|
||||
this->m_handle = dlopen(hex::toUTF8String(path).c_str(), RTLD_LAZY);
|
||||
|
||||
if (this->m_handle == nullptr) {
|
||||
log::error("dlopen failed: {}!", dlerror());
|
||||
@@ -68,7 +69,7 @@ namespace hex {
|
||||
bool Plugin::initializePlugin() const {
|
||||
const auto requestedVersion = getCompatibleVersion();
|
||||
if (requestedVersion != IMHEX_VERSION) {
|
||||
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", this->m_path.filename().string(), requestedVersion);
|
||||
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", hex::toUTF8String(this->m_path.filename()), requestedVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,10 @@ namespace hex {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
ImHexApi::Provider::remove(provider);
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
@@ -45,6 +49,10 @@ namespace hex {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
@@ -57,12 +65,16 @@ namespace hex {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath;
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectFile::store(std::optional<std::fs::path> filePath) {
|
||||
@@ -101,6 +113,8 @@ namespace hex {
|
||||
tar.write(MetadataPath, metadataContent);
|
||||
}
|
||||
|
||||
ImHexApi::Provider::resetDirty();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,71 +1,261 @@
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::list<Task *> Task::s_runningTasks;
|
||||
std::mutex Task::s_taskMutex;
|
||||
std::mutex TaskManager::s_deferredCallsMutex;
|
||||
|
||||
Task::Task(const std::string &unlocalizedName, u64 maxValue) : m_name(LangEntry(unlocalizedName)), m_maxValue(maxValue), m_currValue(0) {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
std::list<std::shared_ptr<Task>> TaskManager::s_tasks, TaskManager::s_taskQueue;
|
||||
std::list<std::function<void()>> TaskManager::s_deferredCalls;
|
||||
|
||||
Task::s_runningTasks.push_back(this);
|
||||
std::mutex TaskManager::s_queueMutex;
|
||||
std::condition_variable TaskManager::s_jobCondVar;
|
||||
std::vector<std::jthread> TaskManager::s_workers;
|
||||
|
||||
Task::Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
|
||||
|
||||
Task::Task(hex::Task &&other) noexcept {
|
||||
{
|
||||
std::scoped_lock thisLock(this->m_mutex);
|
||||
std::scoped_lock otherLock(other.m_mutex);
|
||||
|
||||
this->m_function = std::move(other.m_function);
|
||||
this->m_unlocalizedName = std::move(other.m_unlocalizedName);
|
||||
}
|
||||
|
||||
this->m_maxValue = u64(other.m_maxValue);
|
||||
this->m_currValue = u64(other.m_currValue);
|
||||
|
||||
this->m_finished = bool(other.m_finished);
|
||||
this->m_hadException = bool(other.m_hadException);
|
||||
this->m_interrupted = bool(other.m_interrupted);
|
||||
this->m_shouldInterrupt = bool(other.m_shouldInterrupt);
|
||||
}
|
||||
|
||||
Task::~Task() {
|
||||
this->finish();
|
||||
if (!this->isFinished())
|
||||
this->interrupt();
|
||||
}
|
||||
|
||||
Task::Task(hex::Task &&other) noexcept {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
void Task::update(u64 value) {
|
||||
this->m_currValue = value;
|
||||
|
||||
this->m_name = other.m_name;
|
||||
this->m_maxValue = other.m_maxValue;
|
||||
this->m_currValue = other.m_currValue;
|
||||
if (this->m_shouldInterrupt)
|
||||
throw TaskInterruptor();
|
||||
}
|
||||
|
||||
auto it = std::find(Task::s_runningTasks.begin(), Task::s_runningTasks.end(), &other);
|
||||
if (it != Task::s_runningTasks.end()) {
|
||||
*it = this;
|
||||
}
|
||||
void Task::setMaxValue(u64 value) {
|
||||
this->m_maxValue = value;
|
||||
}
|
||||
|
||||
|
||||
void Task::interrupt() {
|
||||
this->m_shouldInterrupt = true;
|
||||
|
||||
if (this->m_interruptCallback)
|
||||
this->m_interruptCallback();
|
||||
}
|
||||
|
||||
void Task::setInterruptCallback(std::function<void()> callback) {
|
||||
this->m_interruptCallback = std::move(callback);
|
||||
}
|
||||
|
||||
bool Task::isBackgroundTask() const {
|
||||
return this->m_background;
|
||||
}
|
||||
|
||||
bool Task::isFinished() const {
|
||||
return this->m_finished;
|
||||
}
|
||||
|
||||
bool Task::hadException() const {
|
||||
return this->m_hadException;
|
||||
}
|
||||
|
||||
bool Task::wasInterrupted() const {
|
||||
return this->m_interrupted;
|
||||
}
|
||||
|
||||
void Task::clearException() {
|
||||
this->m_hadException = false;
|
||||
}
|
||||
|
||||
std::string Task::getExceptionMessage() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_exceptionMessage;
|
||||
}
|
||||
|
||||
const std::string &Task::getUnlocalizedName() {
|
||||
return this->m_unlocalizedName;
|
||||
}
|
||||
|
||||
u64 Task::getValue() const {
|
||||
return this->m_currValue;
|
||||
}
|
||||
|
||||
u64 Task::getMaxValue() const {
|
||||
return this->m_maxValue;
|
||||
}
|
||||
|
||||
void Task::finish() {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
|
||||
Task::s_runningTasks.remove(this);
|
||||
this->m_finished = true;
|
||||
}
|
||||
|
||||
void Task::setMaxValue(u64 maxValue) {
|
||||
this->m_maxValue = maxValue;
|
||||
void Task::interruption() {
|
||||
this->m_interrupted = true;
|
||||
}
|
||||
|
||||
void Task::update(u64 currValue) {
|
||||
if (this->m_currValue < this->m_maxValue)
|
||||
this->m_currValue = currValue;
|
||||
void Task::exception(const char *message) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_exceptionMessage = message;
|
||||
this->m_hadException = true;
|
||||
}
|
||||
|
||||
double Task::getProgress() const {
|
||||
if (this->m_maxValue == 0)
|
||||
return 100;
|
||||
|
||||
return static_cast<double>(this->m_currValue) / static_cast<double>(this->m_maxValue);
|
||||
bool TaskHolder::isRunning() const {
|
||||
if (this->m_task.expired())
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->isFinished();
|
||||
}
|
||||
|
||||
bool Task::isPending() const {
|
||||
return this->m_maxValue == 0;
|
||||
bool TaskHolder::hadException() const {
|
||||
if (this->m_task.expired())
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->hadException();
|
||||
}
|
||||
|
||||
const std::string &Task::getName() const {
|
||||
return this->m_name;
|
||||
bool TaskHolder::wasInterrupted() const {
|
||||
if (this->m_task.expired())
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->wasInterrupted();
|
||||
}
|
||||
|
||||
size_t Task::getRunningTaskCount() {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
void TaskHolder::interrupt() {
|
||||
if (this->m_task.expired())
|
||||
return;
|
||||
|
||||
return Task::s_runningTasks.size();
|
||||
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) {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
auto task = std::make_shared<Task>(std::move(name), maxValue, false, std::move(function));
|
||||
s_tasks.emplace_back(task);
|
||||
s_taskQueue.emplace_back(task);
|
||||
|
||||
s_jobCondVar.notify_one();
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
|
||||
auto task = std::make_shared<Task>(std::move(name), 0, true, std::move(function));
|
||||
s_tasks.emplace_back(task);
|
||||
s_taskQueue.emplace_back(task);
|
||||
|
||||
s_jobCondVar.notify_one();
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
}
|
||||
|
||||
void TaskManager::collectGarbage() {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<Task>> &TaskManager::getRunningTasks() {
|
||||
return s_tasks;
|
||||
}
|
||||
|
||||
size_t TaskManager::getRunningTaskCount() {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
|
||||
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
|
||||
return !task->isBackgroundTask();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void TaskManager::doLater(const std::function<void()> &function) {
|
||||
std::scoped_lock lock(s_deferredCallsMutex);
|
||||
|
||||
s_deferredCalls.push_back(function);
|
||||
}
|
||||
|
||||
void TaskManager::runDeferredCalls() {
|
||||
std::scoped_lock lock(s_deferredCallsMutex);
|
||||
|
||||
for (const auto &call : s_deferredCalls)
|
||||
call();
|
||||
|
||||
s_deferredCalls.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace hex::dp {
|
||||
|
||||
u32 Attribute::s_idCounter = 1;
|
||||
int Attribute::s_idCounter = 1;
|
||||
|
||||
Attribute::Attribute(IOType ioType, Type type, std::string unlocalizedName) : m_id(Attribute::s_idCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(std::move(unlocalizedName)) {
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
namespace hex::dp {
|
||||
|
||||
u32 Link::s_idCounter = 1;
|
||||
int Link::s_idCounter = 1;
|
||||
|
||||
Link::Link(u32 from, u32 to) : m_id(Link::s_idCounter++), m_from(from), m_to(to) { }
|
||||
Link::Link(int from, int to) : m_id(Link::s_idCounter++), m_from(from), m_to(to) { }
|
||||
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace hex::dp {
|
||||
|
||||
u32 Node::s_idCounter = 1;
|
||||
int Node::s_idCounter = 1;
|
||||
|
||||
Node::Node(std::string unlocalizedTitle, std::vector<Attribute> attributes) : m_id(Node::s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
|
||||
for (auto &attr : this->m_attributes)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
@@ -16,12 +17,12 @@ namespace hex::fs {
|
||||
this->m_file = _wfopen(path.c_str(), L"w+b");
|
||||
#else
|
||||
if (mode == File::Mode::Read)
|
||||
this->m_file = fopen64(path.string().c_str(), "rb");
|
||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "rb");
|
||||
else if (mode == File::Mode::Write)
|
||||
this->m_file = fopen64(path.string().c_str(), "r+b");
|
||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "r+b");
|
||||
|
||||
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
||||
this->m_file = fopen64(path.string().c_str(), "w+b");
|
||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "w+b");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ namespace hex::fs {
|
||||
return "";
|
||||
|
||||
auto cString = reinterpret_cast<const char *>(bytes.data());
|
||||
return { cString, std::min(bytes.size(), std::strlen(cString)) };
|
||||
return { cString, hex::strnlen(cString, bytes.size()) };
|
||||
}
|
||||
|
||||
std::u8string File::readU8String(size_t numBytes) {
|
||||
@@ -104,7 +105,7 @@ namespace hex::fs {
|
||||
return u8"";
|
||||
|
||||
auto cString = reinterpret_cast<const char8_t *>(bytes.data());
|
||||
return { cString, std::min(bytes.size(), std::strlen(reinterpret_cast<const char*>(bytes.data()))) };
|
||||
return { cString, hex::strnlen(reinterpret_cast<const char*>(bytes.data()), bytes.size()) };
|
||||
}
|
||||
|
||||
void File::write(const u8 *buffer, size_t size) {
|
||||
@@ -158,7 +159,7 @@ namespace hex::fs {
|
||||
|
||||
bool File::remove() {
|
||||
this->close();
|
||||
return std::remove(this->m_path.string().c_str()) == 0;
|
||||
return std::remove(hex::toUTF8String(this->m_path).c_str()) == 0;
|
||||
}
|
||||
|
||||
void File::disableBuffering() {
|
||||
|
||||
@@ -75,6 +75,11 @@ namespace hex::fs {
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::function<void()> s_fileBrowserErrorCallback;
|
||||
void setFileBrowserErrorCallback(const std::function<void()> &callback) {
|
||||
s_fileBrowserErrorCallback = callback;
|
||||
}
|
||||
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath) {
|
||||
NFD::Init();
|
||||
|
||||
@@ -94,9 +99,14 @@ namespace hex::fs {
|
||||
hex::unreachable();
|
||||
}
|
||||
|
||||
if (result == NFD_OKAY && outPath != nullptr) {
|
||||
callback(reinterpret_cast<char8_t*>(outPath));
|
||||
NFD::FreePath(outPath);
|
||||
if (result == NFD_OKAY){
|
||||
if(outPath != nullptr) {
|
||||
callback(reinterpret_cast<char8_t*>(outPath));
|
||||
NFD::FreePath(outPath);
|
||||
}
|
||||
} else if (result==NFD_ERROR) {
|
||||
if (s_fileBrowserErrorCallback != nullptr)
|
||||
s_fileBrowserErrorCallback();
|
||||
}
|
||||
|
||||
NFD::Quit();
|
||||
@@ -184,7 +194,7 @@ namespace hex::fs {
|
||||
path = path / folder;
|
||||
|
||||
return paths;
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> getPluginPaths() {
|
||||
std::vector<std::fs::path> paths = getDataPaths();
|
||||
@@ -199,6 +209,8 @@ namespace hex::fs {
|
||||
std::vector<std::fs::path> result;
|
||||
|
||||
switch (path) {
|
||||
case ImHexPath::END:
|
||||
return { };
|
||||
case ImHexPath::Constants:
|
||||
result = appendPath(getDataPaths(), "constants");
|
||||
break;
|
||||
@@ -235,6 +247,12 @@ namespace hex::fs {
|
||||
case ImHexPath::Recent:
|
||||
result = appendPath(getConfigPaths(), "recent");
|
||||
break;
|
||||
case ImHexPath::Scripts:
|
||||
result = appendPath(getDataPaths(), "scripts");
|
||||
break;
|
||||
case ImHexPath::Inspectors:
|
||||
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!listNonExisting) {
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace hex::magic {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
||||
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
||||
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc"))) {
|
||||
magicFiles += fs::toShortPath(entry.path()).string() + MAGIC_PATH_SEPARATOR;
|
||||
magicFiles += hex::toUTF8String(fs::toShortPath(entry.path())) + MAGIC_PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include <filesystem>
|
||||
#include <cstdio>
|
||||
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -52,13 +50,13 @@ namespace hex {
|
||||
|
||||
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
|
||||
|
||||
static mbedtls_x509_crt crt;
|
||||
mbedtls_x509_crt_init(&crt);
|
||||
auto crt = static_cast<mbedtls_x509_crt*>(userData);
|
||||
mbedtls_x509_crt_init(crt);
|
||||
|
||||
auto cacert = romfs::get("cacert.pem").string();
|
||||
mbedtls_x509_crt_parse(&crt, reinterpret_cast<const u8 *>(cacert.data()), cacert.size());
|
||||
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(cacert.data()), cacert.size());
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(cfg, &crt, nullptr);
|
||||
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@@ -109,11 +107,12 @@ namespace hex {
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_NOPROGRESS, 0L);
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(IMHEX_USE_BUNDLED_CA)
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_CAINFO, nullptr);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_DATA, &this->m_caCert);
|
||||
#endif
|
||||
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
|
||||
@@ -124,7 +123,7 @@ namespace hex {
|
||||
if (result != CURLE_OK)
|
||||
log::error("Net request failed with error {0}: '{1}'", u32(result), curl_easy_strerror(result));
|
||||
|
||||
i32 responseCode = 0;
|
||||
long responseCode = 0;
|
||||
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
|
||||
curl_slist_free_all(this->m_headers);
|
||||
@@ -135,7 +134,7 @@ namespace hex {
|
||||
if (result != CURLE_OK)
|
||||
return std::nullopt;
|
||||
else
|
||||
return responseCode;
|
||||
return i32(responseCode);
|
||||
}
|
||||
|
||||
std::future<Response<std::string>> Net::getString(const std::string &url, u32 timeout) {
|
||||
@@ -167,8 +166,10 @@ namespace hex {
|
||||
setCommonSettings(response, url, timeout);
|
||||
|
||||
auto responseCode = execute();
|
||||
|
||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response) };
|
||||
if (!responseCode.has_value())
|
||||
return Response<nlohmann::json> { 0, { } };
|
||||
else
|
||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -187,16 +188,27 @@ namespace hex {
|
||||
curl_mime *mime = curl_mime_init(this->m_ctx);
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
auto fileName = filePath.filename().string();
|
||||
curl_mime_data_cb(
|
||||
part, file.getSize(), [](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
||||
auto fileName = hex::toUTF8String(filePath.filename());
|
||||
curl_mime_data_cb(part, file.getSize(),
|
||||
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
return fread(buffer, size, nitems, file); }, [](void *arg, curl_off_t offset, int origin) -> int {
|
||||
|
||||
return fread(buffer, size, nitems, file);
|
||||
},
|
||||
[](void *arg, curl_off_t offset, int origin) -> int {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
fseek(file, offset, origin);
|
||||
return CURL_SEEKFUNC_OK; }, [](void *arg) {
|
||||
|
||||
if (fseek(file, offset, origin) != 0)
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
else
|
||||
return CURL_SEEKFUNC_OK;
|
||||
},
|
||||
[](void *arg) {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
fclose(file); }, file.getHandle());
|
||||
|
||||
fclose(file);
|
||||
},
|
||||
file.getHandle());
|
||||
curl_mime_filename(part, fileName.c_str());
|
||||
curl_mime_name(part, "file");
|
||||
|
||||
|
||||
41
lib/libimhex/source/helpers/types.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,11 +22,11 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
long double operator""_scaled(long double value) {
|
||||
float operator""_scaled(long double value) {
|
||||
return value * ImHexApi::System::getGlobalScale();
|
||||
}
|
||||
|
||||
long double operator""_scaled(unsigned long long value) {
|
||||
float operator""_scaled(unsigned long long value) {
|
||||
return value * ImHexApi::System::getGlobalScale();
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::string toEngineeringString(double value) {
|
||||
constexpr std::array Suffixes = { "a", "f", "p", "n", "u", "m", "", "k", "M", "G", "T", "P", "E" };
|
||||
constexpr static std::array Suffixes = { "a", "f", "p", "n", "u", "m", "", "k", "M", "G", "T", "P", "E" };
|
||||
|
||||
int8_t suffixIndex = 6;
|
||||
|
||||
@@ -339,7 +339,7 @@ namespace hex {
|
||||
auto c = [&] { return string[offset]; };
|
||||
|
||||
if (c() == '\\') {
|
||||
if ((offset + 2) >= string.length()) return {};
|
||||
if ((offset + 2) > string.length()) return {};
|
||||
|
||||
offset++;
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ namespace hex::prv {
|
||||
Provider::~Provider() {
|
||||
for (auto &overlay : this->m_overlays)
|
||||
this->deleteOverlay(overlay);
|
||||
this->close();
|
||||
}
|
||||
|
||||
void Provider::read(u64 offset, void *buffer, size_t size, bool overlays) {
|
||||
@@ -114,6 +113,8 @@ namespace hex::prv {
|
||||
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
|
||||
}
|
||||
this->markDirty();
|
||||
|
||||
this->m_patches.emplace_back();
|
||||
}
|
||||
|
||||
|
||||
@@ -171,14 +172,6 @@ namespace hex::prv {
|
||||
return page;
|
||||
}
|
||||
|
||||
bool Provider::open() {
|
||||
EventManager::post<EventProviderOpened>(this);
|
||||
return true;
|
||||
}
|
||||
void Provider::close() {
|
||||
EventManager::post<EventProviderClosed>(this);
|
||||
}
|
||||
|
||||
void Provider::addPatch(u64 offset, const void *buffer, size_t size, bool createUndo) {
|
||||
if (this->m_patchTreeOffset > 0) {
|
||||
auto iter = this->m_patches.end();
|
||||
@@ -266,7 +259,7 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
std::pair<Region, bool> Provider::getRegionValidity(u64 address) const {
|
||||
if (address > this->getActualSize())
|
||||
if ((address - this->getBaseAddress()) > this->getActualSize())
|
||||
return { Region::Invalid(), false };
|
||||
|
||||
bool insideValidRegion = false;
|
||||
@@ -297,4 +290,15 @@ namespace hex::prv {
|
||||
return { Region { address, *nextRegionAddress - address }, insideValidRegion };
|
||||
}
|
||||
|
||||
|
||||
u32 Provider::getID() const {
|
||||
return this->m_id;
|
||||
}
|
||||
|
||||
void Provider::setID(u32 id) {
|
||||
this->m_id = id;
|
||||
if (id > s_idCounter)
|
||||
s_idCounter = id + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_freetype.h>
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <imgui_internal.h>
|
||||
#undef IMGUI_DEFINE_MATH_OPERATORS
|
||||
@@ -13,8 +12,80 @@
|
||||
|
||||
#include <imgui_impl_opengl3_loader.h>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
Texture::Texture(const ImU8 *buffer, int size) {
|
||||
unsigned char *imageData = stbi_load_from_memory(buffer, size, &this->m_width, &this->m_height, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return;
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
}
|
||||
|
||||
Texture::Texture(const char *path) {
|
||||
unsigned char *imageData = stbi_load(path, &this->m_width, &this->m_height, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return;
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
}
|
||||
|
||||
Texture::Texture(Texture&& other) noexcept {
|
||||
this->m_textureId = other.m_textureId;
|
||||
this->m_width = other.m_width;
|
||||
this->m_height = other.m_height;
|
||||
|
||||
other.m_textureId = nullptr;
|
||||
}
|
||||
|
||||
Texture& Texture::operator=(Texture&& other) noexcept {
|
||||
this->m_textureId = other.m_textureId;
|
||||
this->m_width = other.m_width;
|
||||
this->m_height = other.m_height;
|
||||
|
||||
other.m_textureId = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
if (this->m_textureId == nullptr)
|
||||
return;
|
||||
|
||||
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(this->m_textureId));
|
||||
glDeleteTextures(1, &glTextureId);
|
||||
}
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
|
||||
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
|
||||
auto &string = *static_cast<std::string *>(data->UserData);
|
||||
@@ -33,8 +104,8 @@ namespace ImGui {
|
||||
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
ImVec2 label_size = CalcTextSize(icon, NULL, false);
|
||||
label_size.x += CalcTextSize(" ", NULL, false).x + CalcTextSize(label, NULL, false).x;
|
||||
ImVec2 label_size = CalcTextSize(icon, nullptr, false);
|
||||
label_size.x += CalcTextSize(" ", nullptr, false).x + CalcTextSize(label, nullptr, false).x;
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
|
||||
@@ -67,7 +138,7 @@ namespace ImGui {
|
||||
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
|
||||
@@ -84,7 +155,7 @@ namespace ImGui {
|
||||
// Render
|
||||
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
|
||||
PushStyleColor(ImGuiCol_Text, ImU32(col));
|
||||
TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
|
||||
PopStyleColor();
|
||||
|
||||
@@ -100,7 +171,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y) + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f);
|
||||
@@ -135,8 +206,8 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), nullptr, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
|
||||
@@ -164,7 +235,7 @@ namespace ImGui {
|
||||
RenderTextWrapped(bb.Min + style.FramePadding * 2, label, nullptr, CalcWrapWidthForPos(window->DC.CursorPos, window->DC.TextWrapPos));
|
||||
PopStyleColor();
|
||||
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text));
|
||||
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, NULL, &text_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, nullptr, &text_size, style.ButtonTextAlign, &bb);
|
||||
PopStyleColor();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
@@ -180,13 +251,13 @@ namespace ImGui {
|
||||
void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) {
|
||||
ImGuiWindow *window = GetCurrentWindow();
|
||||
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
|
||||
|
||||
PushStyleColor(ImGuiCol_Text, ImU32(color));
|
||||
TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(color));
|
||||
PopStyleColor();
|
||||
}
|
||||
@@ -296,66 +367,6 @@ namespace ImGui {
|
||||
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
|
||||
}
|
||||
|
||||
Texture LoadImageFromPath(const char *path) {
|
||||
int imageWidth = 0;
|
||||
int imageHeight = 0;
|
||||
|
||||
unsigned char *imageData = stbi_load(path, &imageWidth, &imageHeight, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return { nullptr, -1, -1 };
|
||||
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
|
||||
}
|
||||
|
||||
Texture LoadImageFromMemory(const ImU8 *buffer, int size) {
|
||||
int imageWidth = 0;
|
||||
int imageHeight = 0;
|
||||
|
||||
|
||||
unsigned char *imageData = stbi_load_from_memory(buffer, size, &imageWidth, &imageHeight, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return { nullptr, -1, -1 };
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
|
||||
}
|
||||
|
||||
void UnloadImage(Texture &texture) {
|
||||
if (texture.textureId == nullptr)
|
||||
return;
|
||||
|
||||
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(texture.textureId));
|
||||
glDeleteTextures(1, &glTextureId);
|
||||
|
||||
texture = { nullptr, 0, 0 };
|
||||
}
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
|
||||
if (ImGui::Begin(window_name)) {
|
||||
ImGui::OpenPopup(popup_name);
|
||||
@@ -372,7 +383,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -391,7 +402,7 @@ namespace ImGui {
|
||||
: ImGuiCol_Button);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
// Automatically close popups
|
||||
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
|
||||
@@ -411,7 +422,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(symbol);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -432,7 +443,7 @@ namespace ImGui {
|
||||
: ImGuiCol_MenuBarBg);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
@@ -454,7 +465,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(symbol);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -475,7 +486,7 @@ namespace ImGui {
|
||||
: ImGuiCol_Button);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
@@ -536,7 +547,7 @@ namespace ImGui {
|
||||
const ImGuiStyle &style = g.Style;
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos + ImVec2(0, yOffset);
|
||||
ImVec2 size = CalcItemSize(ImVec2(100, 5), 100, g.FontSize + style.FramePadding.y * 2.0f);
|
||||
ImVec2 size = CalcItemSize(ImVec2(100, 5) * hex::ImHexApi::System::getGlobalScale(), 100, g.FontSize + style.FramePadding.y * 2.0f);
|
||||
ImRect bb(pos, pos + size);
|
||||
ItemSize(size, 0);
|
||||
if (!ItemAdd(bb, 0))
|
||||
@@ -553,6 +564,33 @@ namespace ImGui {
|
||||
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||
}
|
||||
|
||||
bool InputTextIcon(const char *label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags) {
|
||||
auto window = ImGui::GetCurrentWindow();
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImGuiStyle &style = GImGui->Style;
|
||||
|
||||
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
const ImVec2 icon_frame_size = CalcTextSize(icon) + style.FramePadding * 2.0f;
|
||||
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), icon_frame_size.x, label_size.y + style.FramePadding.y * 2.0f);
|
||||
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
|
||||
|
||||
bool value_changed = ImGui::InputTextEx(label, nullptr, buffer.data(), buffer.size() + 1, ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||
|
||||
if (value_changed)
|
||||
MarkItemEdited(GImGui->LastItemData.ID);
|
||||
|
||||
RenderNavHighlight(frame_bb, id);
|
||||
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
|
||||
RenderFrame(frame_bb.Min, frame_bb.Min + icon_frame_size, GetColorU32(ImGuiCol_TableBorderStrong), true, style.FrameRounding);
|
||||
RenderText(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y * 2), icon);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags) {
|
||||
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||
}
|
||||
@@ -572,7 +610,7 @@ namespace ImGui {
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
if (format == NULL)
|
||||
if (format == nullptr)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
|
||||
char buf[64];
|
||||
@@ -611,7 +649,7 @@ namespace ImGui {
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
const ImVec2 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
|
||||
const ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
ImVec2 View::getMinSize() const {
|
||||
return scaled(ImVec2(480, 720));
|
||||
return scaled(ImVec2(10, 10));
|
||||
}
|
||||
|
||||
ImVec2 View::getMaxSize() const {
|
||||
|
||||
@@ -26,9 +26,9 @@ set_target_properties(main PROPERTIES
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(main PUBLIC usp10 libimhex wsock32 ws2_32 Dwmapi.lib)
|
||||
target_link_libraries(main PRIVATE usp10 libimhex libromfs-imhex wsock32 ws2_32 Dwmapi.lib)
|
||||
else ()
|
||||
target_link_libraries(main PUBLIC libimhex pthread)
|
||||
target_link_libraries(main PRIVATE libimhex libromfs-imhex pthread)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -19,14 +19,14 @@ namespace hex::init {
|
||||
|
||||
bool loop();
|
||||
|
||||
void addStartupTask(const std::string &taskName, const TaskFunction &task) {
|
||||
this->m_tasks.emplace_back(taskName, task);
|
||||
void addStartupTask(const std::string &taskName, const TaskFunction &task, bool async) {
|
||||
this->m_tasks.emplace_back(taskName, task, async);
|
||||
}
|
||||
|
||||
private:
|
||||
GLFWwindow *m_window;
|
||||
std::mutex m_progressMutex;
|
||||
float m_progress = 0;
|
||||
std::atomic<float> m_progress = 0;
|
||||
std::string m_currTaskName;
|
||||
|
||||
void initGLFW();
|
||||
@@ -37,7 +37,7 @@ namespace hex::init {
|
||||
|
||||
std::future<bool> processTasksAsync();
|
||||
|
||||
std::vector<std::pair<std::string, TaskFunction>> m_tasks;
|
||||
std::vector<std::tuple<std::string, TaskFunction, bool>> m_tasks;
|
||||
|
||||
std::string m_gpuVendor;
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace hex::init {
|
||||
struct Task {
|
||||
std::string name;
|
||||
std::function<bool()> function;
|
||||
bool async;
|
||||
};
|
||||
|
||||
std::vector<Task> getInitTasks();
|
||||
|
||||
@@ -50,8 +50,9 @@ namespace hex {
|
||||
|
||||
double m_lastFrameTime = 0;
|
||||
|
||||
ImGui::Texture m_logoTexture = { nullptr };
|
||||
ImGui::Texture m_logoTexture;
|
||||
|
||||
std::mutex m_popupMutex;
|
||||
std::list<std::string> m_popupsToOpen;
|
||||
std::vector<int> m_pressedKeys;
|
||||
|
||||
|
||||
@@ -43,28 +43,41 @@ namespace hex::init {
|
||||
return std::async(std::launch::async, [this] {
|
||||
bool status = true;
|
||||
|
||||
for (const auto &[name, task] : this->m_tasks) {
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_currTaskName = name;
|
||||
}
|
||||
std::atomic<u32> tasksCompleted = 0;
|
||||
for (const auto &[name, task, async] : this->m_tasks) {
|
||||
auto runTask = [&, task = task, name = name] {
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_currTaskName = name;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!task())
|
||||
status = false;
|
||||
|
||||
tasksCompleted++;
|
||||
|
||||
this->m_progress = float(tasksCompleted) / this->m_tasks.size();
|
||||
};
|
||||
|
||||
try {
|
||||
if (async) {
|
||||
TaskManager::createBackgroundTask(name, [runTask](auto&){ runTask(); });
|
||||
} else {
|
||||
runTask();
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
log::error("Init task '{}' threw an exception: {}", name, e.what());
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_progress += 1.0F / this->m_tasks.size();
|
||||
}
|
||||
while (tasksCompleted < this->m_tasks.size()) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
|
||||
// Small extra delay so the last progress step is visible
|
||||
std::this_thread::sleep_for(200ms);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
|
||||
return status;
|
||||
});
|
||||
@@ -72,15 +85,13 @@ namespace hex::init {
|
||||
|
||||
bool WindowSplash::loop() {
|
||||
auto splash = romfs::get("splash.png");
|
||||
ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
|
||||
ImGui::Texture splashTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
|
||||
|
||||
if (splashTexture == nullptr) {
|
||||
if (!splashTexture.isValid()) {
|
||||
log::fatal("Could not load splash screen image!");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT { ImGui::UnloadImage(splashTexture); };
|
||||
|
||||
auto tasksSucceeded = processTasksAsync();
|
||||
|
||||
auto scale = ImHexApi::System::getGlobalScale();
|
||||
@@ -97,7 +108,7 @@ namespace hex::init {
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.size() * scale);
|
||||
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.getSize() * scale);
|
||||
|
||||
drawList->AddText(ImVec2(15, 120) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str());
|
||||
|
||||
@@ -107,15 +118,15 @@ namespace hex::init {
|
||||
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
|
||||
#endif
|
||||
|
||||
drawList->AddRectFilled(ImVec2(0, splashTexture.size().y - 5) * scale, ImVec2(splashTexture.size().x * this->m_progress, splashTexture.size().y) * scale, 0xFFFFFFFF);
|
||||
drawList->AddText(ImVec2(15, splashTexture.size().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
|
||||
drawList->AddRectFilled(ImVec2(0, splashTexture.getSize().y - 5) * scale, ImVec2(splashTexture.getSize().x * this->m_progress, splashTexture.getSize().y) * scale, 0xFFFFFFFF);
|
||||
drawList->AddText(ImVec2(15, splashTexture.getSize().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(this->m_window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearColor(0.00F, 0.00F, 0.00F, 0.00F);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <imgui_freetype.h>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/net.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
@@ -39,7 +40,7 @@ namespace hex::init {
|
||||
auto latestVersion = releases.body["tag_name"].get<std::string_view>();
|
||||
|
||||
if (latestVersion != currVersion)
|
||||
ImHexApi::System::getInitArguments().insert({ "update-available", latestVersion.data() });
|
||||
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -51,7 +52,7 @@ namespace hex::init {
|
||||
if (tip.code != 200)
|
||||
return false;
|
||||
|
||||
ImHexApi::System::getInitArguments().insert({ "tip-of-the-day", tip.body });
|
||||
ImHexApi::System::impl::addInitArgument("tip-of-the-day", tip.body);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -60,20 +61,6 @@ namespace hex::init {
|
||||
bool result = true;
|
||||
|
||||
using enum fs::ImHexPath;
|
||||
constexpr std::array paths = {
|
||||
Patterns,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Plugins,
|
||||
Resources,
|
||||
Config,
|
||||
Constants,
|
||||
Yara,
|
||||
Encodings,
|
||||
Python,
|
||||
Logs,
|
||||
Recent
|
||||
};
|
||||
|
||||
// Check if ImHex is installed in portable mode
|
||||
{
|
||||
@@ -86,19 +73,19 @@ namespace hex::init {
|
||||
}
|
||||
|
||||
// Create all folders
|
||||
for (auto path : paths) {
|
||||
for (auto &folder : fs::getDefaultPaths(path, true)) {
|
||||
for (u32 path = 0; path < u32(fs::ImHexPath::END); path++) {
|
||||
for (auto &folder : fs::getDefaultPaths(static_cast<fs::ImHexPath>(path), true)) {
|
||||
try {
|
||||
fs::createDirectories(folder);
|
||||
} catch (...) {
|
||||
log::error("Failed to create folder {}!", folder.string());
|
||||
log::error("Failed to create folder {}!", hex::toUTF8String(folder));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
ImHexApi::System::getInitArguments().insert({ "folder-creation-error", {} });
|
||||
ImHexApi::System::impl::addInitArgument("folder-creation-error");
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -132,7 +119,7 @@ namespace hex::init {
|
||||
0x0100, 0xFFF0, 0
|
||||
};
|
||||
|
||||
auto fontFile = ImHexApi::System::getCustomFontPath();
|
||||
const auto &fontFile = ImHexApi::System::getCustomFontPath();
|
||||
float fontSize = ImHexApi::System::getFontSize();
|
||||
if (fontFile.empty()) {
|
||||
// Load default font if no custom one has been specified
|
||||
@@ -148,7 +135,7 @@ namespace hex::init {
|
||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
||||
cfg.SizePixels = fontSize;
|
||||
|
||||
fonts->AddFontFromFileTTF(fontFile.string().c_str(), std::floor(fontSize), &cfg, ranges.Data); // Needs conversion to char for Windows
|
||||
fonts->AddFontFromFileTTF(hex::toUTF8String(fontFile).c_str(), std::floor(fontSize), &cfg, ranges.Data); // Needs conversion to char for Windows
|
||||
}
|
||||
|
||||
cfg.MergeMode = true;
|
||||
@@ -173,7 +160,6 @@ namespace hex::init {
|
||||
ContentRegistry::Provider::getEntries().clear();
|
||||
|
||||
ImHexApi::System::getInitArguments().clear();
|
||||
ImHexApi::Tasks::getDeferredCalls().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getForegroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear();
|
||||
@@ -215,12 +201,13 @@ namespace hex::init {
|
||||
|
||||
ShortcutManager::clearShortcuts();
|
||||
|
||||
hex::Task::getRunningTasks().clear();
|
||||
TaskManager::getRunningTasks().clear();
|
||||
|
||||
ContentRegistry::DataProcessorNode::getEntries().clear();
|
||||
|
||||
ContentRegistry::DataFormatter::getEntries().clear();
|
||||
ContentRegistry::FileHandler::getEntries().clear();
|
||||
ContentRegistry::Hashes::impl::getHashes().clear();
|
||||
|
||||
{
|
||||
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
|
||||
@@ -229,6 +216,11 @@ namespace hex::init {
|
||||
visualizers.clear();
|
||||
}
|
||||
|
||||
ProjectFile::getHandlers().clear();
|
||||
ProjectFile::getProviderHandlers().clear();
|
||||
|
||||
fs::setFileBrowserErrorCallback(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -242,7 +234,7 @@ namespace hex::init {
|
||||
if (plugins.empty()) {
|
||||
log::error("No plugins found!");
|
||||
|
||||
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} });
|
||||
ImHexApi::System::impl::addInitArgument("no-plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -254,7 +246,7 @@ namespace hex::init {
|
||||
if (builtinPlugins > 1) continue;
|
||||
|
||||
if (!plugin.initializePlugin()) {
|
||||
log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
|
||||
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
|
||||
loadErrors++;
|
||||
}
|
||||
}
|
||||
@@ -263,24 +255,24 @@ namespace hex::init {
|
||||
if (plugin.isBuiltinPlugin()) continue;
|
||||
|
||||
if (!plugin.initializePlugin()) {
|
||||
log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
|
||||
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
|
||||
loadErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (loadErrors == plugins.size()) {
|
||||
log::error("No plugins loaded successfully!");
|
||||
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} });
|
||||
ImHexApi::System::impl::addInitArgument("no-plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (builtinPlugins == 0) {
|
||||
log::error("Built-in plugin not found!");
|
||||
ImHexApi::System::getInitArguments().insert({ "no-builtin-plugin", {} });
|
||||
ImHexApi::System::impl::addInitArgument("no-builtin-plugin");
|
||||
return false;
|
||||
} else if (builtinPlugins > 1) {
|
||||
log::error("Found more than one built-in plugin!");
|
||||
ImHexApi::System::getInitArguments().insert({ "multiple-builtin-plugins", {} });
|
||||
ImHexApi::System::impl::addInitArgument("multiple-builtin-plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -320,20 +312,20 @@ namespace hex::init {
|
||||
|
||||
std::vector<Task> getInitTasks() {
|
||||
return {
|
||||
{"Checking for updates...", checkForUpdates },
|
||||
{ "Downloading information...", downloadInformation},
|
||||
{ "Creating directories...", createDirectories },
|
||||
{ "Loading settings...", loadSettings },
|
||||
{ "Loading plugins...", loadPlugins },
|
||||
{ "Loading fonts...", loadFonts },
|
||||
{ "Creating directories...", createDirectories, false },
|
||||
{ "Loading settings...", loadSettings, false },
|
||||
{ "Loading plugins...", loadPlugins, false },
|
||||
{ "Checking for updates...", checkForUpdates, true },
|
||||
{ "Downloading information...", downloadInformation, true },
|
||||
{ "Loading fonts...", loadFonts, true },
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<Task> getExitTasks() {
|
||||
return {
|
||||
{"Saving settings...", storeSettings },
|
||||
{ "Cleaning up shared data...", deleteSharedData},
|
||||
{ "Unloading plugins...", unloadPlugins },
|
||||
{ "Saving settings...", storeSettings, false },
|
||||
{ "Cleaning up shared data...", deleteSharedData, false },
|
||||
{ "Unloading plugins...", unloadPlugins, false },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,42 +18,60 @@ int main(int argc, char **argv, char **envp) {
|
||||
ImHexApi::System::impl::setBorderlessWindowMode(true);
|
||||
#endif
|
||||
|
||||
// Initialization
|
||||
{
|
||||
Window::initNative();
|
||||
bool shouldRestart = false;
|
||||
|
||||
hex::log::info("Welcome to ImHex!");
|
||||
do {
|
||||
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
|
||||
shouldRestart = false;
|
||||
|
||||
init::WindowSplash splashWindow;
|
||||
// Initialization
|
||||
{
|
||||
Window::initNative();
|
||||
|
||||
for (const auto &[name, task] : init::getInitTasks())
|
||||
splashWindow.addStartupTask(name, task);
|
||||
hex::log::info("Welcome to ImHex!");
|
||||
|
||||
if (!splashWindow.loop())
|
||||
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
|
||||
}
|
||||
init::WindowSplash splashWindow;
|
||||
|
||||
// Clean up
|
||||
ON_SCOPE_EXIT {
|
||||
for (const auto &[name, task] : init::getExitTasks())
|
||||
task();
|
||||
};
|
||||
TaskManager::init();
|
||||
for (const auto &[name, task, async] : init::getInitTasks())
|
||||
splashWindow.addStartupTask(name, task, async);
|
||||
|
||||
// Main window
|
||||
{
|
||||
Window window;
|
||||
|
||||
if (argc == 1)
|
||||
; // No arguments provided
|
||||
else if (argc == 2)
|
||||
EventManager::post<RequestOpenFile>(argv[1]);
|
||||
else {
|
||||
hex::log::fatal("Usage: {} [<file_name>]", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
if (!splashWindow.loop())
|
||||
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
|
||||
}
|
||||
|
||||
window.loop();
|
||||
}
|
||||
// Clean up
|
||||
ON_SCOPE_EXIT {
|
||||
for (const auto &[name, task, async] : init::getExitTasks())
|
||||
task();
|
||||
TaskManager::exit();
|
||||
};
|
||||
|
||||
// Main window
|
||||
{
|
||||
Window window;
|
||||
|
||||
if (argc == 1)
|
||||
; // No arguments provided
|
||||
else if (argc >= 2) {
|
||||
for (auto i = 1; i < argc; i++) {
|
||||
if (auto argument = ImHexApi::System::getProgramArgument(i); argument.has_value())
|
||||
EventManager::post<RequestOpenFile>(argument.value());
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,39 @@ namespace hex {
|
||||
static float g_titleBarHeight;
|
||||
static ImGuiMouseCursor g_mouseCursorIcon;
|
||||
|
||||
static LRESULT windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
static LRESULT commonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_COPYDATA:
|
||||
{
|
||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (message == nullptr) break;
|
||||
|
||||
auto data = reinterpret_cast<const char8_t *>(message->lpData);
|
||||
if (data == nullptr) break;
|
||||
|
||||
std::fs::path path = data;
|
||||
log::info("Opening file in existing instance: {}", hex::toUTF8String(path));
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (lParam == 0) break;
|
||||
|
||||
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT borderlessWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_NCACTIVATE:
|
||||
case WM_NCPAINT:
|
||||
@@ -106,11 +138,11 @@ namespace hex {
|
||||
return HTNOWHERE;
|
||||
}
|
||||
|
||||
constexpr auto RegionClient = 0b0000;
|
||||
constexpr auto RegionLeft = 0b0001;
|
||||
constexpr auto RegionRight = 0b0010;
|
||||
constexpr auto RegionTop = 0b0100;
|
||||
constexpr auto RegionBottom = 0b1000;
|
||||
constexpr static auto RegionClient = 0b0000;
|
||||
constexpr static auto RegionLeft = 0b0001;
|
||||
constexpr static auto RegionRight = 0b0010;
|
||||
constexpr static auto RegionTop = 0b0100;
|
||||
constexpr static auto RegionBottom = 0b1000;
|
||||
|
||||
const auto result =
|
||||
RegionLeft * (cursor.x < (window.left + border.x)) |
|
||||
@@ -146,35 +178,11 @@ namespace hex {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (lParam == 0) break;
|
||||
|
||||
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_COPYDATA:
|
||||
{
|
||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (message == nullptr) break;
|
||||
|
||||
auto data = reinterpret_cast<const char8_t *>(message->lpData);
|
||||
if (data == nullptr) break;
|
||||
|
||||
std::fs::path path = data;
|
||||
log::info("Opening file in existing instance: {}", path.string());
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
return commonWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +263,7 @@ namespace hex {
|
||||
|
||||
|
||||
if (borderlessWindowMode) {
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)windowProc);
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)borderlessWindowProc);
|
||||
|
||||
MARGINS borderless = { 1, 1, 1, 1 };
|
||||
::DwmExtendFrameIntoClientArea(hwnd, &borderless);
|
||||
@@ -265,6 +273,8 @@ namespace hex {
|
||||
|
||||
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
|
||||
::SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW);
|
||||
} else {
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)commonWindowProc);
|
||||
}
|
||||
|
||||
// Catch heap corruption
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <fmt/printf.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
@@ -80,17 +81,17 @@ namespace hex {
|
||||
#else
|
||||
std::raise(signalNumber);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
{
|
||||
for (const auto &[argument, value] : ImHexApi::System::getInitArguments()) {
|
||||
if (argument == "no-plugins") {
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("No Plugins"); });
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("No Plugins"); });
|
||||
} else if (argument == "no-builtin-plugin") {
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("No Builtin Plugin"); });
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("No Builtin Plugin"); });
|
||||
} else if (argument == "multiple-builtin-plugins") {
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("Multiple Builtin Plugins"); });
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("Multiple Builtin Plugins"); });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,35 +115,38 @@ namespace hex {
|
||||
|
||||
if (ImHexApi::Provider::isValid()) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (!windowTitle.empty())
|
||||
if (!windowTitle.empty() && provider != nullptr) {
|
||||
title += " - " + windowTitle;
|
||||
|
||||
if (provider->isDirty())
|
||||
title += " (*)";
|
||||
if (provider->isDirty())
|
||||
title += " (*)";
|
||||
|
||||
if (!provider->isWritable())
|
||||
title += " (Read Only)";
|
||||
if (!provider->isWritable())
|
||||
title += " (Read Only)";
|
||||
}
|
||||
}
|
||||
|
||||
this->m_windowTitle = title;
|
||||
glfwSetWindowTitle(this->m_window, title.c_str());
|
||||
});
|
||||
|
||||
constexpr auto CrashBackupFileName = "crash_backup.hexproj";
|
||||
constexpr static auto CrashBackupFileName = "crash_backup.hexproj";
|
||||
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this, CrashBackupFileName](int) {
|
||||
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this](int) {
|
||||
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
|
||||
|
||||
if (!ImHexApi::Provider::isDirty())
|
||||
return;
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
if (ProjectFile::store((std::fs::path(path) / CrashBackupFileName).string()))
|
||||
if (ProjectFile::store(path / CrashBackupFileName))
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestOpenPopup>(this, [this](auto name) {
|
||||
std::scoped_lock lock(this->m_popupMutex);
|
||||
|
||||
this->m_popupsToOpen.push_back(name);
|
||||
});
|
||||
|
||||
@@ -152,8 +156,8 @@ namespace hex {
|
||||
std::signal(SIGFPE, signalHandler);
|
||||
std::set_terminate([]{ signalHandler(SIGABRT); });
|
||||
|
||||
auto imhexLogo = romfs::get("logo.png");
|
||||
this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(imhexLogo.data()), imhexLogo.size());
|
||||
auto logoData = romfs::get("logo.png");
|
||||
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logoData.data()), logoData.size());
|
||||
|
||||
ContentRegistry::Settings::store();
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
@@ -179,7 +183,7 @@ namespace hex {
|
||||
} else {
|
||||
glfwPollEvents();
|
||||
|
||||
bool frameRateUnlocked = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 || this->m_mouseButtonDown || this->m_hadEvent || !this->m_pressedKeys.empty();
|
||||
bool frameRateUnlocked = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || TaskManager::getRunningTaskCount() > 0 || this->m_mouseButtonDown || this->m_hadEvent || !this->m_pressedKeys.empty();
|
||||
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime));
|
||||
|
||||
if ((this->m_lastFrameTime - this->m_frameRateUnlockTime) > 5 && this->m_frameRateTemporarilyUnlocked && !frameRateUnlocked) {
|
||||
@@ -196,14 +200,16 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this->frameBegin();
|
||||
this->frame();
|
||||
this->frameEnd();
|
||||
|
||||
const auto targetFps = ImHexApi::System::getTargetFPS();
|
||||
if (targetFps <= 200)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(u64((this->m_lastFrameTime + 1 / targetFps - glfwGetTime()) * 1000)));
|
||||
if (targetFps <= 200) {
|
||||
auto leftoverFrameTime = i64((this->m_lastFrameTime + 1 / targetFps - glfwGetTime()) * 1000);
|
||||
if (leftoverFrameTime > 0)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(leftoverFrameTime));
|
||||
}
|
||||
|
||||
this->m_lastFrameTime = glfwGetTime();
|
||||
|
||||
@@ -372,7 +378,7 @@ namespace hex {
|
||||
const auto filePath = path / "builtin.hexplug";
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(filePath.string().c_str());
|
||||
ImGui::TextUnformatted(hex::toUTF8String(filePath).c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
|
||||
}
|
||||
@@ -420,28 +426,24 @@ namespace hex {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock(this->m_popupMutex);
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
else
|
||||
ImGui::OpenPopup(name.c_str());
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
else
|
||||
ImGui::OpenPopup(name.c_str());
|
||||
|
||||
return false;
|
||||
});
|
||||
TaskManager::runDeferredCalls();
|
||||
|
||||
EventManager::post<EventFrameBegin>();
|
||||
}
|
||||
|
||||
void Window::frame() {
|
||||
{
|
||||
auto &calls = ImHexApi::Tasks::getDeferredCalls();
|
||||
for (const auto &callback : calls)
|
||||
callback();
|
||||
calls.clear();
|
||||
}
|
||||
|
||||
auto &io = ImGui::GetIO();
|
||||
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
|
||||
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
|
||||
@@ -452,7 +454,8 @@ namespace hex {
|
||||
continue;
|
||||
|
||||
if (view->isAvailable()) {
|
||||
ImGui::SetNextWindowSizeConstraints(scaled(view->getMinSize()), scaled(view->getMaxSize()));
|
||||
float fontScaling = std::max(1.0F, ImHexApi::System::getFontSize() / ImHexApi::System::DefaultFontSize);
|
||||
ImGui::SetNextWindowSizeConstraints(view->getMinSize() * fontScaling, view->getMaxSize() * fontScaling);
|
||||
view->drawContent();
|
||||
}
|
||||
|
||||
@@ -485,13 +488,15 @@ namespace hex {
|
||||
void Window::frameEnd() {
|
||||
EventManager::post<EventFrameEnd>();
|
||||
|
||||
TaskManager::collectGarbage();
|
||||
|
||||
this->endNativeWindowFrame();
|
||||
ImGui::Render();
|
||||
|
||||
int displayWidth, displayHeight;
|
||||
glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight);
|
||||
glViewport(0, 0, displayWidth, displayHeight);
|
||||
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
|
||||
glClearColor(0.00F, 0.00F, 0.00F, 1.00f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
@@ -679,8 +684,9 @@ namespace hex {
|
||||
|
||||
if (glfwGetPrimaryMonitor() != nullptr) {
|
||||
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
|
||||
bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", 1) != 0;
|
||||
|
||||
if (!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland"))
|
||||
if ((!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland")) && multiWindowEnabled)
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
}
|
||||
|
||||
@@ -741,7 +747,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
if (!this->m_imguiSettingsPath.empty() && fs::exists(this->m_imguiSettingsPath))
|
||||
ImGui::LoadIniSettingsFromDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
ImGui::LoadIniSettingsFromDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(this->m_window, true);
|
||||
|
||||
@@ -766,7 +772,7 @@ namespace hex {
|
||||
ImNodes::PopAttributeFlag();
|
||||
ImNodes::PopAttributeFlag();
|
||||
|
||||
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
|
||||
@@ -52,16 +52,16 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/views/view_provider_settings.cpp
|
||||
source/content/views/view_find.cpp
|
||||
|
||||
source/content/helpers/math_evaluator.cpp
|
||||
source/content/helpers/pattern_drawer.cpp
|
||||
|
||||
source/math_evaluator.cpp
|
||||
source/pattern_drawer.cpp
|
||||
|
||||
source/lang/en_US.cpp
|
||||
source/lang/de_DE.cpp
|
||||
source/lang/en_US.cpp
|
||||
source/lang/it_IT.cpp
|
||||
source/lang/zh_CN.cpp
|
||||
source/lang/ja_JP.cpp
|
||||
source/lang/ko_KR.cpp
|
||||
source/lang/pt_BR.cpp
|
||||
source/lang/zh_CN.cpp
|
||||
source/lang/zh_TW.cpp
|
||||
)
|
||||
|
||||
@@ -69,7 +69,7 @@ add_library(${PROJECT_NAME} SHARED
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE include)
|
||||
|
||||
# Add additional libraries here #
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE libimhex LLVMDemangle)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE libimhex)
|
||||
|
||||
# ---- No need to change anything from here downwards unless you know what you're doing ---- #
|
||||
|
||||
@@ -84,3 +84,9 @@ endif()
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
setupCompilerWarnings(${PROJECT_NAME})
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME ${PROJECT_NAME})
|
||||
add_subdirectory(../../lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBROMFS_LIBRARY})
|
||||
|
||||
@@ -16,15 +16,20 @@ namespace hex {
|
||||
public:
|
||||
MathEvaluator() = default;
|
||||
|
||||
struct Variable {
|
||||
T value;
|
||||
bool constant;
|
||||
};
|
||||
|
||||
std::optional<T> evaluate(const std::string &input);
|
||||
|
||||
void registerStandardVariables();
|
||||
void registerStandardFunctions();
|
||||
|
||||
void setVariable(const std::string &name, T value);
|
||||
void setVariable(const std::string &name, T value, bool constant = false);
|
||||
void setFunction(const std::string &name, const std::function<std::optional<T>(std::vector<T>)> &function, size_t minNumArgs, size_t maxNumArgs);
|
||||
|
||||
std::unordered_map<std::string, T> &getVariables() { return this->m_variables; }
|
||||
std::unordered_map<std::string, Variable> &getVariables() { return this->m_variables; }
|
||||
|
||||
[[nodiscard]] bool hasError() const {
|
||||
return this->m_lastError.has_value();
|
||||
@@ -98,7 +103,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
static i16 comparePrecedence(const Operator &a, const Operator &b);
|
||||
static bool isLeftAssociative(const Operator op);
|
||||
static bool isLeftAssociative(const Operator &op);
|
||||
static std::pair<Operator, size_t> toOperator(const std::string &input);
|
||||
|
||||
private:
|
||||
@@ -106,7 +111,7 @@ namespace hex {
|
||||
std::optional<std::queue<Token>> toPostfix(std::queue<Token> inputQueue);
|
||||
std::optional<T> evaluate(std::queue<Token> postfixTokens);
|
||||
|
||||
std::unordered_map<std::string, T> m_variables;
|
||||
std::unordered_map<std::string, Variable> m_variables;
|
||||
std::unordered_map<std::string, std::function<std::optional<T>(std::vector<T>)>> m_functions;
|
||||
|
||||
std::optional<std::string> m_lastError;
|
||||
43
plugins/builtin/include/content/helpers/pattern_drawer.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/pattern_visitor.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class PatternDrawer : public pl::PatternVisitor {
|
||||
public:
|
||||
PatternDrawer() = default;
|
||||
|
||||
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
|
||||
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfield& pattern) override;
|
||||
void visit(pl::ptrn::PatternBoolean& pattern) override;
|
||||
void visit(pl::ptrn::PatternCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternEnum& pattern) override;
|
||||
void visit(pl::ptrn::PatternFloat& pattern) override;
|
||||
void visit(pl::ptrn::PatternPadding& pattern) override;
|
||||
void visit(pl::ptrn::PatternPointer& pattern) override;
|
||||
void visit(pl::ptrn::PatternSigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternString& pattern) override;
|
||||
void visit(pl::ptrn::PatternStruct& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnion& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnsigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideString& pattern) override;
|
||||
|
||||
private:
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
constexpr static auto ChunkSize = 512;
|
||||
constexpr static auto DisplayEndStep = 64;
|
||||
|
||||
void drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::Iteratable &iteratable, bool isInlined);
|
||||
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
|
||||
|
||||
private:
|
||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||
};
|
||||
}
|
||||
@@ -18,6 +18,7 @@ namespace hex::plugin::builtin {
|
||||
struct {
|
||||
std::string sourceCode;
|
||||
std::unique_ptr<pl::PatternLanguage> runtime;
|
||||
bool executionDone = true;
|
||||
} patternLanguage;
|
||||
|
||||
std::list<ImHexApi::Bookmarks::Entry> bookmarks;
|
||||
@@ -30,6 +31,11 @@ namespace hex::plugin::builtin {
|
||||
std::vector<hex::prv::Overlay *> dataOverlays;
|
||||
std::optional<dp::Node::NodeError> currNodeError;
|
||||
} dataProcessor;
|
||||
|
||||
struct {
|
||||
std::optional<u64> selectionStart, selectionEnd;
|
||||
float scrollPosition = 0.0F;
|
||||
} editor;
|
||||
};
|
||||
|
||||
static Data& getCurrent() {
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
@@ -45,7 +46,7 @@ namespace hex::plugin::builtin::prv {
|
||||
return "hex.builtin.provider.disk";
|
||||
}
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
void reloadDrives();
|
||||
|
||||
@@ -7,15 +7,12 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
@@ -41,7 +38,6 @@ namespace hex::plugin::builtin::prv {
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||
[[nodiscard]] size_t getActualSize() const override;
|
||||
[[nodiscard]] size_t getRealTimeSize();
|
||||
|
||||
void save() override;
|
||||
void saveAs(const std::fs::path &path) override;
|
||||
@@ -49,8 +45,8 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override;
|
||||
|
||||
bool hasFilePicker() const override { return true; }
|
||||
bool handleFilePicker() override;
|
||||
[[nodiscard]] bool hasFilePicker() const override { return true; }
|
||||
[[nodiscard]] bool handleFilePicker() override;
|
||||
|
||||
void setPath(const std::fs::path &path);
|
||||
|
||||
@@ -67,17 +63,6 @@ namespace hex::plugin::builtin::prv {
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
HANDLE m_file = INVALID_HANDLE_VALUE;
|
||||
HANDLE m_mapping = INVALID_HANDLE_VALUE;
|
||||
|
||||
#else
|
||||
|
||||
int m_file = -1;
|
||||
|
||||
#endif
|
||||
|
||||
std::fs::path m_path;
|
||||
void *m_mappedFile = nullptr;
|
||||
size_t m_fileSize = 0;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace hex::plugin::builtin::prv {
|
||||
return "hex.builtin.provider.gdb";
|
||||
}
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
hex::Socket m_socket;
|
||||
|
||||
@@ -17,6 +17,8 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] bool isResizable() const override { return false; }
|
||||
[[nodiscard]] bool isSavable() const override { return false; }
|
||||
|
||||
void setBaseAddress(u64 address) override;
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||
[[nodiscard]] size_t getActualSize() const override;
|
||||
@@ -34,8 +36,8 @@ namespace hex::plugin::builtin::prv {
|
||||
return "hex.builtin.provider.intel_hex";
|
||||
}
|
||||
|
||||
bool hasFilePicker() const override { return true; }
|
||||
bool handleFilePicker() override;
|
||||
[[nodiscard]] bool hasFilePicker() const override { return true; }
|
||||
[[nodiscard]] bool handleFilePicker() override;
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] bool isResizable() const override { return false; }
|
||||
[[nodiscard]] bool isSavable() const override { return false; }
|
||||
|
||||
[[nodiscard]] bool open() override { return true; }
|
||||
void close() override { }
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override { hex::unused(offset, buffer, size); }
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override { hex::unused(offset, buffer, size); }
|
||||
[[nodiscard]] size_t getActualSize() const override { return 0x00; }
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace hex::plugin::builtin {
|
||||
class ViewAbout : public View {
|
||||
public:
|
||||
ViewAbout();
|
||||
~ViewAbout() override;
|
||||
|
||||
void drawContent() override;
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace hex::plugin::builtin {
|
||||
void registerMenuItems();
|
||||
private:
|
||||
std::string m_currFilter;
|
||||
|
||||
std::list<ImHexApi::Bookmarks::Entry>::iterator m_dragStartIterator;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -33,7 +33,9 @@ namespace hex::plugin::builtin {
|
||||
|
||||
u64 m_startAddress = 0;
|
||||
size_t m_validBytes = 0;
|
||||
std::vector<InspectorCacheEntry> m_cachedData;
|
||||
std::atomic<bool> m_dataValid = false;
|
||||
std::vector<InspectorCacheEntry> m_cachedData, m_workData;
|
||||
TaskHolder m_updateTask;
|
||||
|
||||
std::string m_editingValue;
|
||||
};
|
||||
|
||||
@@ -20,12 +20,13 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
bool m_justSwitchedProvider = false;
|
||||
int m_rightClickedId = -1;
|
||||
ImVec2 m_rightClickedCoords;
|
||||
|
||||
bool m_continuousEvaluation = false;
|
||||
|
||||
void eraseLink(u32 id);
|
||||
void eraseLink(int id);
|
||||
void eraseNodes(const std::vector<int> &ids);
|
||||
void processNodes();
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
bool m_disassembling = false;
|
||||
TaskHolder m_disassemblerTask;
|
||||
|
||||
u64 m_baseAddress = 0;
|
||||
ui::SelectedRegion m_range = ui::SelectedRegion::EntireData;
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
struct Occurrence {
|
||||
Region region;
|
||||
enum class DecodeType { ASCII, Binary, UTF16LE, UTF16BE } decodeType;
|
||||
enum class DecodeType { ASCII, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
|
||||
std::endian endian = std::endian::native;
|
||||
};
|
||||
|
||||
struct BinaryPattern {
|
||||
@@ -38,7 +39,8 @@ namespace hex::plugin::builtin {
|
||||
Strings,
|
||||
Sequence,
|
||||
Regex,
|
||||
BinaryPattern
|
||||
BinaryPattern,
|
||||
Value
|
||||
} mode = Mode::Strings;
|
||||
|
||||
struct Strings {
|
||||
@@ -55,36 +57,51 @@ namespace hex::plugin::builtin {
|
||||
bool m_lineFeeds = false;
|
||||
} strings;
|
||||
|
||||
struct Bytes {
|
||||
struct Sequence {
|
||||
std::string sequence;
|
||||
} bytes;
|
||||
|
||||
struct Regex {
|
||||
std::string pattern;
|
||||
bool fullMatch = true;
|
||||
} regex;
|
||||
|
||||
struct BinaryPattern {
|
||||
std::string input;
|
||||
std::vector<ViewFind::BinaryPattern> pattern;
|
||||
} binaryPattern;
|
||||
|
||||
struct Value {
|
||||
std::string inputMin, inputMax;
|
||||
std::endian endian = std::endian::native;
|
||||
|
||||
enum class Type {
|
||||
U8 = 0, U16 = 1, U32 = 2, U64 = 3,
|
||||
I8 = 4, I16 = 5, I32 = 6, I64 = 7,
|
||||
F32 = 8, F64 = 9
|
||||
} type = Type::U8;
|
||||
} value;
|
||||
|
||||
} m_searchSettings, m_decodeSettings;
|
||||
|
||||
using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>;
|
||||
|
||||
std::map<prv::Provider*, std::vector<Occurrence>> m_foundOccurrences, m_sortedOccurrences;
|
||||
std::map<prv::Provider*, OccurrenceTree> m_occurrenceTree;
|
||||
std::map<prv::Provider*, std::string> m_currFilter;
|
||||
|
||||
std::atomic<bool> m_searchRunning;
|
||||
TaskHolder m_searchTask;
|
||||
bool m_settingsValid = false;
|
||||
|
||||
std::string m_currFilter;
|
||||
private:
|
||||
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Strings settings);
|
||||
static std::vector<Occurrence> searchSequence(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Bytes settings);
|
||||
static std::vector<Occurrence> searchRegex(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Regex settings);
|
||||
static std::vector<Occurrence> searchBinaryPattern(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::BinaryPattern settings);
|
||||
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Strings &settings);
|
||||
static std::vector<Occurrence> searchSequence(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Sequence &settings);
|
||||
static std::vector<Occurrence> searchRegex(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Regex &settings);
|
||||
static std::vector<Occurrence> searchBinaryPattern(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::BinaryPattern &settings);
|
||||
static std::vector<Occurrence> searchValue(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Value &settings);
|
||||
|
||||
static std::vector<BinaryPattern> parseBinaryPatternString(std::string string);
|
||||
static std::tuple<bool, std::variant<u64, i64, float, double>, size_t> parseNumericValueInput(const std::string &input, SearchSettings::Value::Type type);
|
||||
|
||||
void runSearch();
|
||||
std::string decodeValue(prv::Provider *provider, Occurrence occurrence) const;
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/encoding_file.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
@@ -18,8 +20,6 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
|
||||
|
||||
void registerShortcuts();
|
||||
void registerEvents();
|
||||
void registerMenuItems();
|
||||
@@ -33,22 +33,16 @@ namespace hex::plugin::builtin {
|
||||
void setSelection(u128 start, u128 end) {
|
||||
if (!ImHexApi::Provider::isValid())
|
||||
return;
|
||||
if (start == InvalidSelection && end == InvalidSelection)
|
||||
return;
|
||||
|
||||
if (start == InvalidSelection)
|
||||
start = end;
|
||||
if (end == InvalidSelection)
|
||||
end = start;
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto &data = ProviderExtraData::get(provider).editor;
|
||||
|
||||
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
|
||||
|
||||
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
|
||||
this->m_selectionChanged = data.selectionStart != start || data.selectionEnd != end;
|
||||
|
||||
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
|
||||
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
|
||||
data.selectionStart = std::clamp<u128>(start, 0, maxAddress);
|
||||
data.selectionEnd = std::clamp<u128>(end, 0, maxAddress);
|
||||
|
||||
if (this->m_selectionChanged) {
|
||||
EventManager::post<EventRegionSelected>(this->getSelection());
|
||||
@@ -56,19 +50,29 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
[[nodiscard]] Region getSelection() const {
|
||||
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd);
|
||||
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
|
||||
auto &data = ProviderExtraData::getCurrent().editor;
|
||||
|
||||
if (!isSelectionValid())
|
||||
return Region::Invalid();
|
||||
|
||||
const auto start = std::min(*data.selectionStart, *data.selectionEnd);
|
||||
const auto end = std::max(*data.selectionStart, *data.selectionEnd);
|
||||
const size_t size = end - start + 1;
|
||||
|
||||
return { start, size };
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isSelectionValid() const {
|
||||
return this->m_selectionStart != InvalidSelection && this->m_selectionEnd != InvalidSelection;
|
||||
auto &data = ProviderExtraData::getCurrent().editor;
|
||||
|
||||
return data.selectionStart.has_value() && data.selectionEnd.has_value();
|
||||
}
|
||||
|
||||
void jumpToSelection() {
|
||||
void jumpToSelection(bool center = true) {
|
||||
this->m_shouldJumpToSelection = true;
|
||||
|
||||
if (center)
|
||||
this->m_centerOnJump = true;
|
||||
}
|
||||
|
||||
void scrollToSelection() {
|
||||
@@ -110,6 +114,7 @@ namespace hex::plugin::builtin {
|
||||
void drawFooter(const ImVec2 &size);
|
||||
|
||||
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
|
||||
std::optional<color_t> applySelectionColor(u64 byteAddress, std::optional<color_t> color);
|
||||
|
||||
private:
|
||||
u16 m_bytesPerRow = 16;
|
||||
@@ -117,12 +122,12 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
|
||||
|
||||
bool m_shouldJumpToSelection = false;
|
||||
bool m_centerOnJump = false;
|
||||
bool m_shouldScrollToSelection = false;
|
||||
bool m_shouldJumpWhenOffScreen = false;
|
||||
bool m_shouldUpdateScrollPosition = false;
|
||||
|
||||
bool m_selectionChanged = false;
|
||||
u64 m_selectionStart = InvalidSelection;
|
||||
u64 m_selectionEnd = InvalidSelection;
|
||||
|
||||
u16 m_visibleRowCount = 0;
|
||||
|
||||
@@ -136,6 +141,8 @@ namespace hex::plugin::builtin {
|
||||
bool m_upperCaseHex = true;
|
||||
bool m_grayOutZero = true;
|
||||
bool m_showAscii = true;
|
||||
bool m_syncScrolling = false;
|
||||
u32 m_byteCellPadding = 0, m_characterCellPadding = 0;
|
||||
|
||||
bool m_shouldOpenPopup = false;
|
||||
std::unique_ptr<Popup> m_currPopup;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
@@ -27,7 +28,7 @@ namespace hex::plugin::builtin {
|
||||
double m_entropyHandlePosition;
|
||||
|
||||
std::array<ImU64, 256> m_valueCounts = { 0 };
|
||||
bool m_analyzing = false;
|
||||
TaskHolder m_analyzerTask;
|
||||
|
||||
Region m_analyzedRegion = { 0, 0 };
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace hex::plugin::builtin {
|
||||
class ViewPatches : public View {
|
||||
public:
|
||||
explicit ViewPatches();
|
||||
~ViewPatches() override;
|
||||
~ViewPatches() override = default;
|
||||
|
||||
void drawContent() override;
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "pattern_drawer.hpp"
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <content/helpers/pattern_drawer.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <cstdio>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace hex::plugin::builtin {
|
||||
[[nodiscard]] bool isAvailable() const override { return true; }
|
||||
[[nodiscard]] bool hasViewMenuItemEntry() const override { return false; }
|
||||
|
||||
[[nodiscard]] ImVec2 getMinSize() const override { return { 500, 300 }; }
|
||||
[[nodiscard]] ImVec2 getMaxSize() const override { return { 500, 300 }; }
|
||||
[[nodiscard]] ImVec2 getMinSize() const override { return { 700, 400 }; }
|
||||
[[nodiscard]] ImVec2 getMaxSize() const override { return { 700, 400 }; }
|
||||
|
||||
private:
|
||||
bool m_restartRequested = false;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
class ViewYara : public View {
|
||||
@@ -29,7 +31,7 @@ namespace hex::plugin::builtin {
|
||||
std::vector<std::pair<std::fs::path, std::fs::path>> m_rules;
|
||||
std::vector<YaraMatch> m_matches;
|
||||
u32 m_selectedRule = 0;
|
||||
bool m_matching = false;
|
||||
TaskHolder m_matcherTask;
|
||||
|
||||
std::vector<std::string> m_consoleMessages;
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/pattern_visitor.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::ptrn::Pattern&)> fn) {
|
||||
{ pattern.forEachArrayEntry(displayEnd, fn) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
class PatternDrawer : public pl::PatternVisitor {
|
||||
public:
|
||||
PatternDrawer() = default;
|
||||
|
||||
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
|
||||
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfield& pattern) override;
|
||||
void visit(pl::ptrn::PatternBoolean& pattern) override;
|
||||
void visit(pl::ptrn::PatternCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternEnum& pattern) override;
|
||||
void visit(pl::ptrn::PatternFloat& pattern) override;
|
||||
void visit(pl::ptrn::PatternPadding& pattern) override;
|
||||
void visit(pl::ptrn::PatternPointer& pattern) override;
|
||||
void visit(pl::ptrn::PatternSigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternString& pattern) override;
|
||||
void visit(pl::ptrn::PatternStruct& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnion& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnsigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideString& pattern) override;
|
||||
|
||||
private:
|
||||
void createDefaultEntry(const pl::ptrn::Pattern &pattern, const std::string &value, pl::core::Token::Literal &&literal) const;
|
||||
void createLeafNode(const pl::ptrn::Pattern& pattern) const;
|
||||
bool createTreeNode(const pl::ptrn::Pattern& pattern) const;
|
||||
|
||||
void makeSelectable(const pl::ptrn::Pattern &pattern) const;
|
||||
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
template<ArrayPattern T>
|
||||
void drawArray(T& pattern) {
|
||||
bool opened = this->drawArrayRoot(pattern, pattern.getEntryCount(), pattern.isInlined());
|
||||
|
||||
if (opened) {
|
||||
auto& displayEnd = this->getDisplayEnd(pattern);
|
||||
pattern.forEachArrayEntry(displayEnd, [&] (u64 idx, auto &entry){
|
||||
this->drawArrayNode(idx, displayEnd, entry);
|
||||
});
|
||||
}
|
||||
|
||||
this->drawArrayEnd(pattern, opened);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
void drawCommentTooltip(const pl::ptrn::Pattern &pattern) const;
|
||||
void drawTypenameColumn(const pl::ptrn::Pattern& pattern, const std::string& pattern_name) const;
|
||||
void drawNameColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
void drawColorColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
void drawOffsetColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
void drawSizeColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
|
||||
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
|
||||
|
||||
private:
|
||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||
};
|
||||
};
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
plugins/builtin/romfs/logo.png
Normal file
|
After Width: | Height: | Size: 157 KiB |