/* * Copyright (c) 2021, Arne Elster * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include constexpr Time COMMAND_COMMIT_TIME = Time::from_milliseconds(400); class HexDocument : public Weakable { public: enum class Type { Memory, File }; struct Cell { u8 value; bool modified; }; virtual ~HexDocument() = default; virtual Cell get(size_t position) = 0; virtual u8 get_unchanged(size_t position) = 0; virtual void set(size_t position, u8 value); virtual size_t size() const = 0; virtual Type type() const = 0; virtual bool is_dirty() const; virtual void clear_changes() = 0; protected: HashMap m_changes; }; class HexDocumentMemory final : public HexDocument { public: explicit HexDocumentMemory(ByteBuffer&& buffer); virtual ~HexDocumentMemory() = default; Cell get(size_t position) override; u8 get_unchanged(size_t position) override; size_t size() const override; Type type() const override; void clear_changes() override; bool write_to_file(NonnullRefPtr file); private: ByteBuffer m_buffer; }; class HexDocumentFile final : public HexDocument { public: explicit HexDocumentFile(NonnullRefPtr file); virtual ~HexDocumentFile() = default; HexDocumentFile(HexDocumentFile const&) = delete; void set_file(NonnullRefPtr file); NonnullRefPtr file() const; void write_to_file(); bool write_to_file(NonnullRefPtr file); Cell get(size_t position) override; u8 get_unchanged(size_t position) override; size_t size() const override; Type type() const override; void clear_changes() override; private: void ensure_position_in_buffer(size_t position); NonnullRefPtr m_file; size_t m_file_size; Array m_buffer; size_t m_buffer_file_pos; }; class HexDocumentUndoCommand : public GUI::Command { public: HexDocumentUndoCommand(WeakPtr document, size_t position); virtual void undo() override; virtual void redo() override; virtual DeprecatedString action_text() const override { return "Update cell"; } virtual bool merge_with(GUI::Command const& other) override; ErrorOr try_add_changed_byte(u8 old_value, u8 new_value); ErrorOr try_add_changed_bytes(ByteBuffer old_values, ByteBuffer new_values); private: bool commit_time_expired() const { return Time::now_monotonic() - m_timestamp >= COMMAND_COMMIT_TIME; } Time m_timestamp = Time::now_monotonic(); WeakPtr m_document; size_t m_position; ByteBuffer m_old; ByteBuffer m_new; };