diff --git a/Userland/Applications/HexEditor/HexEditor.cpp b/Userland/Applications/HexEditor/HexEditor.cpp index 19dc2e6a86..247b9bb3aa 100644 --- a/Userland/Applications/HexEditor/HexEditor.cpp +++ b/Userland/Applications/HexEditor/HexEditor.cpp @@ -623,3 +623,37 @@ Vector HexEditor::find_all(ByteBuffer& needle, int start) return matches; } + +Vector HexEditor::find_all_strings(size_t min_length) +{ + if (m_buffer.is_empty()) + return {}; + + Vector matches; + + int offset = -1; + StringBuilder builder; + for (size_t i = 0; i < m_buffer.size(); i++) { + char c = m_buffer.bytes().at(i); + if (isprint(c)) { + if (offset == -1) + offset = i; + builder.append(c); + } else { + if (builder.length() >= min_length) { + dbgln("find_all_strings: relative_offset={} string={}", offset, builder.to_string()); + matches.append({ offset, builder.to_string() }); + } + builder.clear(); + offset = -1; + } + } + + if (matches.is_empty()) + return {}; + + auto first_match = matches.at(0); + highlight(first_match.offset, first_match.offset + first_match.value.length()); + + return matches; +} diff --git a/Userland/Applications/HexEditor/HexEditor.h b/Userland/Applications/HexEditor/HexEditor.h index e586d1c25b..eb7764877b 100644 --- a/Userland/Applications/HexEditor/HexEditor.h +++ b/Userland/Applications/HexEditor/HexEditor.h @@ -50,6 +50,7 @@ public: int find(ByteBuffer& needle, int start = 0); int find_and_highlight(ByteBuffer& needle, int start = 0); Vector find_all(ByteBuffer& needle, int start = 0); + Vector find_all_strings(size_t min_length = 4); Function on_status_change; // position, edit mode, selection start, selection end Function on_change; diff --git a/Userland/Applications/HexEditor/HexEditorWidget.cpp b/Userland/Applications/HexEditor/HexEditorWidget.cpp index 144e1e59ee..5d08785881 100644 --- a/Userland/Applications/HexEditor/HexEditorWidget.cpp +++ b/Userland/Applications/HexEditor/HexEditorWidget.cpp @@ -257,6 +257,21 @@ void HexEditorWidget::initialize_menubar(GUI::Menubar& menubar) m_editor->update(); m_last_found_index = result; })); + + edit_menu.add_action(GUI::Action::create("Find All &Strings", { Mod_Ctrl | Mod_Shift, Key_S }, Gfx::Bitmap::load_from_file("/res/icons/16x16/find.png"), [&](const GUI::Action&) { + int min_length = 4; + auto matches = m_editor->find_all_strings(min_length); + m_search_results->set_model(*new SearchResultsModel(move(matches))); + m_search_results->update(); + + if (matches.is_empty()) { + GUI::MessageBox::show(window(), "No strings found in this file", "Not found", GUI::MessageBox::Type::Warning); + return; + } + + set_search_results_visible(true); + m_editor->update(); + })); edit_menu.add_separator(); edit_menu.add_action(*m_goto_offset_action);