2020-01-18 08:38:21 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
2021-09-13 20:48:22 +00:00
|
|
|
* Copyright (c) 2021, Mustafa Quraish <mustafa@serenityos.org>
|
2022-02-10 19:28:48 +00:00
|
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
2022-03-03 14:20:47 +00:00
|
|
|
* Copyright (c) 2022, Timothy Slater <tslater2006@gmail.com>
|
2020-01-18 08:38:21 +00:00
|
|
|
*
|
2021-04-22 08:24:48 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 08:38:21 +00:00
|
|
|
*/
|
|
|
|
|
2019-10-12 23:08:12 +00:00
|
|
|
#pragma once
|
|
|
|
|
2021-11-10 00:37:10 +00:00
|
|
|
#include "HexDocument.h"
|
2021-05-27 15:51:21 +00:00
|
|
|
#include "SearchResultsModel.h"
|
2024-01-09 20:19:45 +00:00
|
|
|
#include "Selection.h"
|
2020-02-14 20:41:10 +00:00
|
|
|
#include <AK/ByteBuffer.h>
|
2019-10-12 23:08:12 +00:00
|
|
|
#include <AK/Function.h>
|
|
|
|
#include <AK/HashMap.h>
|
|
|
|
#include <AK/StdLibExtras.h>
|
2021-09-24 21:30:23 +00:00
|
|
|
#include <LibCore/Timer.h>
|
2021-05-03 18:31:58 +00:00
|
|
|
#include <LibGUI/AbstractScrollableWidget.h>
|
2022-09-07 21:41:37 +00:00
|
|
|
#include <LibGUI/UndoStack.h>
|
2022-04-09 07:28:38 +00:00
|
|
|
#include <LibGfx/Font/Font.h>
|
2020-02-14 20:41:10 +00:00
|
|
|
#include <LibGfx/TextAlignment.h>
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2023-09-28 15:06:49 +00:00
|
|
|
namespace HexEditor {
|
|
|
|
|
2021-05-03 18:31:58 +00:00
|
|
|
class HexEditor : public GUI::AbstractScrollableWidget {
|
2019-10-12 23:08:12 +00:00
|
|
|
C_OBJECT(HexEditor)
|
|
|
|
public:
|
|
|
|
enum EditMode {
|
|
|
|
Hex,
|
|
|
|
Text
|
|
|
|
};
|
|
|
|
|
2024-04-07 11:22:49 +00:00
|
|
|
enum class OffsetFormat {
|
|
|
|
Decimal,
|
|
|
|
Hexadecimal,
|
|
|
|
};
|
|
|
|
static OffsetFormat offset_format_from_string(StringView);
|
|
|
|
|
2022-02-10 19:28:48 +00:00
|
|
|
virtual ~HexEditor() override = default;
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2021-11-10 00:37:10 +00:00
|
|
|
size_t buffer_size() const { return m_document->size(); }
|
2022-07-28 07:34:15 +00:00
|
|
|
ErrorOr<void> open_new_file(size_t size);
|
2023-02-09 02:02:46 +00:00
|
|
|
void open_file(NonnullOwnPtr<Core::File> file);
|
2022-12-07 18:32:07 +00:00
|
|
|
ErrorOr<void> fill_selection(u8 fill_byte);
|
2022-03-03 14:21:10 +00:00
|
|
|
Optional<u8> get_byte(size_t position);
|
2022-04-26 13:14:05 +00:00
|
|
|
ByteBuffer get_selected_bytes();
|
2023-02-09 02:02:46 +00:00
|
|
|
ErrorOr<void> save_as(NonnullOwnPtr<Core::File>);
|
2023-01-15 03:09:43 +00:00
|
|
|
ErrorOr<void> save();
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2022-09-07 21:41:37 +00:00
|
|
|
bool undo();
|
|
|
|
bool redo();
|
|
|
|
GUI::UndoStack& undo_stack();
|
|
|
|
|
2021-05-22 07:44:10 +00:00
|
|
|
void select_all();
|
2024-01-09 20:19:45 +00:00
|
|
|
Selection const& selection() const { return m_selection; }
|
|
|
|
bool has_selection() const { return !m_selection.is_empty() && m_document->size() > 0; }
|
|
|
|
size_t selection_start_offset() const { return m_selection.start; }
|
2019-10-12 23:08:12 +00:00
|
|
|
bool copy_selected_text_to_clipboard();
|
|
|
|
bool copy_selected_hex_to_clipboard();
|
2019-10-23 22:47:42 +00:00
|
|
|
bool copy_selected_hex_to_clipboard_as_c_code();
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2024-04-07 11:01:37 +00:00
|
|
|
void set_show_offsets_column(bool);
|
2024-04-07 11:22:49 +00:00
|
|
|
void set_offset_format(OffsetFormat);
|
2024-04-07 11:01:37 +00:00
|
|
|
|
2024-03-10 18:10:05 +00:00
|
|
|
size_t bytes_per_group() const { return m_bytes_per_group; }
|
|
|
|
void set_bytes_per_group(size_t);
|
|
|
|
size_t groups_per_row() const { return m_groups_per_row; }
|
|
|
|
void set_groups_per_row(size_t);
|
|
|
|
size_t bytes_per_row() const { return m_groups_per_row * m_bytes_per_group; }
|
|
|
|
// FIXME: Deprecated! Set bytes_per_group or groups_per_row instead
|
2021-09-27 11:14:08 +00:00
|
|
|
void set_bytes_per_row(size_t);
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2021-09-27 11:14:08 +00:00
|
|
|
void set_position(size_t position);
|
2022-03-03 14:20:47 +00:00
|
|
|
void set_selection(size_t position, size_t length);
|
2021-09-27 11:14:08 +00:00
|
|
|
void highlight(size_t start, size_t end);
|
|
|
|
Optional<size_t> find(ByteBuffer& needle, size_t start = 0);
|
|
|
|
Optional<size_t> find_and_highlight(ByteBuffer& needle, size_t start = 0);
|
|
|
|
Vector<Match> find_all(ByteBuffer& needle, size_t start = 0);
|
2021-05-29 08:49:35 +00:00
|
|
|
Vector<Match> find_all_strings(size_t min_length = 4);
|
2024-01-09 20:19:45 +00:00
|
|
|
Function<void(size_t position, EditMode, Selection)> on_status_change;
|
2022-09-05 21:49:35 +00:00
|
|
|
Function<void(bool is_document_dirty)> on_change;
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2024-01-10 19:49:40 +00:00
|
|
|
void show_create_annotation_dialog();
|
|
|
|
void show_edit_annotation_dialog(Annotation&);
|
|
|
|
void show_delete_annotation_dialog(Annotation&);
|
|
|
|
|
2024-01-30 11:08:41 +00:00
|
|
|
HexDocument& document() { return *m_document; }
|
|
|
|
|
2019-10-12 23:08:12 +00:00
|
|
|
protected:
|
2020-02-23 11:07:13 +00:00
|
|
|
HexEditor();
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2020-02-02 14:07:41 +00:00
|
|
|
virtual void paint_event(GUI::PaintEvent&) override;
|
|
|
|
virtual void mousedown_event(GUI::MouseEvent&) override;
|
|
|
|
virtual void mouseup_event(GUI::MouseEvent&) override;
|
|
|
|
virtual void mousemove_event(GUI::MouseEvent&) override;
|
|
|
|
virtual void keydown_event(GUI::KeyEvent&) override;
|
2024-01-10 19:49:40 +00:00
|
|
|
virtual void context_menu_event(GUI::ContextMenuEvent&) override;
|
2024-02-05 12:41:00 +00:00
|
|
|
virtual void theme_change_event(GUI::ThemeChangeEvent&) override;
|
2019-10-12 23:08:12 +00:00
|
|
|
|
|
|
|
private:
|
2021-09-27 11:14:08 +00:00
|
|
|
size_t m_line_spacing { 4 };
|
|
|
|
size_t m_content_length { 0 };
|
2024-03-10 18:10:05 +00:00
|
|
|
size_t m_bytes_per_group { 4 };
|
|
|
|
size_t m_groups_per_row { 4 };
|
2024-04-07 11:01:37 +00:00
|
|
|
bool m_show_offsets_column { true };
|
2024-04-07 11:22:49 +00:00
|
|
|
OffsetFormat m_offset_format { OffsetFormat::Hexadecimal };
|
2019-10-12 23:08:12 +00:00
|
|
|
bool m_in_drag_select { false };
|
2024-01-09 20:19:45 +00:00
|
|
|
Selection m_selection;
|
2021-09-27 11:14:08 +00:00
|
|
|
size_t m_position { 0 };
|
|
|
|
bool m_cursor_at_low_nibble { false };
|
2019-10-12 23:08:12 +00:00
|
|
|
EditMode m_edit_mode { Hex };
|
2021-11-10 00:37:10 +00:00
|
|
|
NonnullOwnPtr<HexDocument> m_document;
|
2022-09-07 21:41:37 +00:00
|
|
|
GUI::UndoStack m_undo_stack;
|
2024-01-10 19:49:40 +00:00
|
|
|
Optional<Annotation&> m_hovered_annotation;
|
|
|
|
|
|
|
|
RefPtr<GUI::Menu> m_context_menu;
|
|
|
|
RefPtr<GUI::Action> m_add_annotation_action;
|
|
|
|
RefPtr<GUI::Action> m_edit_annotation_action;
|
|
|
|
RefPtr<GUI::Action> m_delete_annotation_action;
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2021-09-27 11:31:19 +00:00
|
|
|
static constexpr int m_padding = 5;
|
|
|
|
|
2021-09-27 11:14:08 +00:00
|
|
|
void scroll_position_into_view(size_t position);
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2024-04-07 10:51:30 +00:00
|
|
|
size_t total_rows() const;
|
|
|
|
size_t line_height() const;
|
|
|
|
size_t character_width() const;
|
|
|
|
size_t cell_gap() const;
|
|
|
|
size_t cell_width() const;
|
|
|
|
size_t group_gap() const;
|
|
|
|
size_t group_width() const;
|
|
|
|
int offset_area_width() const;
|
|
|
|
int hex_area_width() const;
|
|
|
|
int text_area_width() const;
|
2024-02-05 17:23:13 +00:00
|
|
|
|
2024-01-10 17:13:00 +00:00
|
|
|
struct OffsetData {
|
|
|
|
size_t offset;
|
|
|
|
EditMode panel;
|
|
|
|
};
|
|
|
|
Optional<OffsetData> offset_at(Gfx::IntPoint position) const;
|
|
|
|
|
2022-12-07 18:32:07 +00:00
|
|
|
ErrorOr<void> hex_mode_keydown_event(GUI::KeyEvent&);
|
|
|
|
ErrorOr<void> text_mode_keydown_event(GUI::KeyEvent&);
|
2019-10-12 23:08:12 +00:00
|
|
|
|
2024-02-05 11:57:40 +00:00
|
|
|
void set_content_length(size_t);
|
|
|
|
void update_content_size();
|
2019-10-12 23:08:12 +00:00
|
|
|
void update_status();
|
|
|
|
void did_change();
|
2022-12-07 18:32:07 +00:00
|
|
|
ErrorOr<void> did_complete_action(size_t position, u8 old_value, u8 new_value);
|
|
|
|
ErrorOr<void> did_complete_action(size_t position, ByteBuffer&& old_values, ByteBuffer&& new_values);
|
2020-02-02 14:07:41 +00:00
|
|
|
};
|
2023-09-28 15:06:49 +00:00
|
|
|
|
|
|
|
}
|