diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index b9ca0a149..81aecba73 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -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 diff --git a/plugins/builtin/include/content/differing_byte_searcher.hpp b/plugins/builtin/include/content/differing_byte_searcher.hpp new file mode 100644 index 000000000..5a0dd26a2 --- /dev/null +++ b/plugins/builtin/include/content/differing_byte_searcher.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +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(); +} \ No newline at end of file diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 1f94f6d15..fda92c918 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -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...", diff --git a/plugins/builtin/source/content/differing_byte_searcher.cpp b/plugins/builtin/source/content/differing_byte_searcher.cpp new file mode 100644 index 000000000..1ec978e63 --- /dev/null +++ b/plugins/builtin/source/content/differing_byte_searcher.cpp @@ -0,0 +1,52 @@ +#include +#include + +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; + } +} \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index 3408fcbaa..89d4a748d 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -5,6 +5,8 @@ #include #include +#include + #include #include #include @@ -14,6 +16,7 @@ #include #include +#include #include @@ -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);