mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-29 00:10:02 -05:00
feat: Added skipping sequences of repeating bytes (#2228)
This PR implements a neat little feature I missed - the ability to jump to the next/previous differing byte, skipping the chunk of repeating bytes. Very useful when you analyze a raw flash dump and want to skip the large sections of `0x00`s/`0xFF`s. Some implementation details worth validating: - I wasn't sure what is the correct place to put the new menu entries into. The possible candidates were `File -> Go to address...` and `Edit -> Follow selection`. I chose the former, although the latter may be a better fit since it already states that the action is related to the selection. Overall, it may be a good moment to refine these menu entries in general. - I didn't add any tests since I'm not sure what is the project's policy for those. Please let me know if I need to add some! - I added the machine-generated translations for the new menu entries which may be considered a questionable thing. Please let me know if you're unhappy with those, I'll drop the commit. Also, thanks for such a nice tool, I use it a lot and was glad to build a new feature for it!
This commit is contained in:
@@ -19,6 +19,7 @@ add_imhex_plugin(
|
||||
source/content/command_line_interface.cpp
|
||||
source/content/communication_interface.cpp
|
||||
source/content/data_inspector.cpp
|
||||
source/content/differing_byte_searcher.cpp
|
||||
source/content/pl_builtin_functions.cpp
|
||||
source/content/pl_builtin_types.cpp
|
||||
source/content/pl_pragmas.cpp
|
||||
|
||||
19
plugins/builtin/include/content/differing_byte_searcher.hpp
Normal file
19
plugins/builtin/include/content/differing_byte_searcher.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <wolv/types.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void findNextDifferingByte(
|
||||
const std::function< u64(prv::Provider*) >& lastValidAddressProvider,
|
||||
const std::function< bool(u64, u64) >& addressComparator,
|
||||
const std::function< void(u64*) >& addressStepper,
|
||||
bool *didFindNextValue,
|
||||
bool *didReachEndAddress,
|
||||
u64* foundAddress
|
||||
);
|
||||
|
||||
bool canSearchForDifferingByte();
|
||||
}
|
||||
@@ -862,6 +862,11 @@
|
||||
"hex.builtin.view.hex_editor.menu.edit.set_base": "Set Base Address...",
|
||||
"hex.builtin.view.hex_editor.menu.edit.set_page_size": "Set Page Size...",
|
||||
"hex.builtin.view.hex_editor.menu.file.goto": "Go to address...",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until": "Skip Until",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until.previous_differing_byte": "Previous Differing Byte",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until.next_differing_byte": "Next Differing Byte",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until.beginning_reached": "No more differing bytes till the beginning of the file",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until.end_reached": "No more differing bytes till the end of the file",
|
||||
"hex.builtin.view.hex_editor.menu.file.load_encoding_file": "Load custom encoding...",
|
||||
"hex.builtin.view.hex_editor.menu.file.save": "Save",
|
||||
"hex.builtin.view.hex_editor.menu.file.save_as": "Save As...",
|
||||
|
||||
52
plugins/builtin/source/content/differing_byte_searcher.cpp
Normal file
52
plugins/builtin/source/content/differing_byte_searcher.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <content/differing_byte_searcher.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void findNextDifferingByte(
|
||||
const std::function< u64(prv::Provider*) >& lastValidAddressProvider,
|
||||
const std::function< bool(u64, u64) >& addressComparator,
|
||||
const std::function< void(u64*) >& addressStepper,
|
||||
bool *didFindNextValue,
|
||||
bool *didReachEndAddress,
|
||||
u64* foundAddress
|
||||
) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (provider == nullptr)
|
||||
return;
|
||||
const auto selection = ImHexApi::HexEditor::getSelection();
|
||||
if (!selection.has_value())
|
||||
return;
|
||||
if (selection->getSize() != 1)
|
||||
return;
|
||||
|
||||
auto currentAddress = selection->getStartAddress();
|
||||
|
||||
u8 givenValue = 0;
|
||||
provider->read(currentAddress, &givenValue, 1);
|
||||
|
||||
u8 currentValue = 0;
|
||||
|
||||
*didFindNextValue = false;
|
||||
*didReachEndAddress = false;
|
||||
|
||||
auto endAddress = lastValidAddressProvider(provider);
|
||||
|
||||
while (addressComparator(currentAddress, endAddress)) {
|
||||
addressStepper(¤tAddress);
|
||||
if (currentAddress == endAddress) {
|
||||
*didReachEndAddress = true;
|
||||
}
|
||||
provider->read(currentAddress, ¤tValue, 1);
|
||||
if (currentValue != givenValue) {
|
||||
*didFindNextValue = true;
|
||||
*foundAddress = currentAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool canSearchForDifferingByte() {
|
||||
return ImHexApi::Provider::isValid() && ImHexApi::HexEditor::isSelectionValid() && ImHexApi::HexEditor::getSelection()->getSize() == 1;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/api/achievement_manager.hpp>
|
||||
|
||||
#include <content/differing_byte_searcher.hpp>
|
||||
|
||||
#include <hex/api/events/events_provider.hpp>
|
||||
#include <hex/api/events/requests_interaction.hpp>
|
||||
#include <hex/api/events/requests_gui.hpp>
|
||||
@@ -14,6 +16,7 @@
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <hex/providers/buffered_reader.hpp>
|
||||
#include <toasts/toast_notification.hpp>
|
||||
|
||||
#include <wolv/math_eval/math_evaluator.hpp>
|
||||
|
||||
@@ -1260,6 +1263,88 @@ namespace hex::plugin::builtin {
|
||||
ImHexApi::Provider::isValid,
|
||||
this);
|
||||
|
||||
/* Skip until */
|
||||
ContentRegistry::Interface::addMenuItemSubMenu({ "hex.builtin.menu.file", "hex.builtin.view.hex_editor.menu.file.skip_until" }, ICON_VS_DEBUG_STEP_OVER, 1610,
|
||||
[]{},
|
||||
canSearchForDifferingByte);
|
||||
|
||||
/* Skip until previous differing byte */
|
||||
ContentRegistry::Interface::addMenuItem({
|
||||
"hex.builtin.menu.file",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until.previous_differing_byte"
|
||||
},
|
||||
ICON_VS_DEBUG_STEP_BACK,
|
||||
1620,
|
||||
CTRLCMD + Keys::LeftBracket,
|
||||
[this] {
|
||||
bool didFindNextValue = false;
|
||||
bool didReachBeginning = false;
|
||||
u64 foundAddress;
|
||||
|
||||
findNextDifferingByte(
|
||||
[] (prv::Provider* provider) -> u64 {
|
||||
return provider->getBaseAddress();
|
||||
},
|
||||
[] (u64 currentAddress, u64 endAddress) -> bool {
|
||||
return currentAddress > endAddress;
|
||||
},
|
||||
[] (u64* currentAddress) {
|
||||
(*currentAddress)--;
|
||||
},
|
||||
&didFindNextValue,
|
||||
&didReachBeginning,
|
||||
&foundAddress
|
||||
);
|
||||
|
||||
if (didFindNextValue) {
|
||||
ImHexApi::HexEditor::setSelection(foundAddress, 1);
|
||||
}
|
||||
|
||||
if (!didFindNextValue && didReachBeginning) {
|
||||
ui::ToastInfo::open("hex.builtin.view.hex_editor.menu.file.skip_until.beginning_reached"_lang);
|
||||
}
|
||||
},
|
||||
canSearchForDifferingByte);
|
||||
|
||||
/* Skip until next differing byte */
|
||||
ContentRegistry::Interface::addMenuItem({
|
||||
"hex.builtin.menu.file",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until.next_differing_byte"
|
||||
},
|
||||
ICON_VS_DEBUG_STEP_OVER,
|
||||
1630,
|
||||
CTRLCMD + Keys::RightBracket,
|
||||
[this] {
|
||||
bool didFindNextValue = false;
|
||||
bool didReachEnd = false;
|
||||
u64 foundAddress;
|
||||
|
||||
findNextDifferingByte(
|
||||
[] (prv::Provider* provider) -> u64 {
|
||||
return provider->getBaseAddress() + provider->getActualSize() - 1;
|
||||
},
|
||||
[] (u64 currentAddress, u64 endAddress) -> bool {
|
||||
return currentAddress < endAddress;
|
||||
},
|
||||
[] (u64* currentAddress) {
|
||||
(*currentAddress)++;
|
||||
},
|
||||
&didFindNextValue,
|
||||
&didReachEnd,
|
||||
&foundAddress
|
||||
);
|
||||
|
||||
if (didFindNextValue) {
|
||||
ImHexApi::HexEditor::setSelection(foundAddress, 1);
|
||||
}
|
||||
|
||||
if (!didFindNextValue && didReachEnd) {
|
||||
ui::ToastInfo::open("hex.builtin.view.hex_editor.menu.file.skip_until.end_reached"_lang);
|
||||
}
|
||||
},
|
||||
canSearchForDifferingByte);
|
||||
|
||||
|
||||
ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.edit" }, 1100, this);
|
||||
|
||||
Reference in New Issue
Block a user