diff --git a/UEFIExtract/CMakeLists.txt b/UEFIExtract/CMakeLists.txt index 850a74d..933300e 100644 --- a/UEFIExtract/CMakeLists.txt +++ b/UEFIExtract/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR) +CMAKE_MINIMUM_REQUIRED(VERSION 3.22) PROJECT(UEFIExtract) diff --git a/UEFIFind/CMakeLists.txt b/UEFIFind/CMakeLists.txt index 5fb986c..4ba4a19 100644 --- a/UEFIFind/CMakeLists.txt +++ b/UEFIFind/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR) +CMAKE_MINIMUM_REQUIRED(VERSION 3.22) PROJECT(UEFIFind) diff --git a/UEFITool/CMakeLists.txt b/UEFITool/CMakeLists.txt index aef60d0..a09438e 100644 --- a/UEFITool/CMakeLists.txt +++ b/UEFITool/CMakeLists.txt @@ -23,7 +23,6 @@ SET(PROJECT_HEADERS hexviewdialog.h gotobasedialog.h gotoaddressdialog.h - qhexview5/qhexview.h ) SET(PROJECT_SOURCES @@ -36,19 +35,6 @@ SET(PROJECT_SOURCES hexlineedit.cpp ffsfinder.cpp hexspinbox.cpp - qhexview5/model/buffer/qhexbuffer.cpp - qhexview5/model/buffer/qdevicebuffer.cpp - qhexview5/model/buffer/qmemorybuffer.cpp - qhexview5/model/commands/hexcommand.cpp - qhexview5/model/commands/insertcommand.cpp - qhexview5/model/commands/removecommand.cpp - qhexview5/model/commands/replacecommand.cpp - qhexview5/model/qhexcursor.cpp - qhexview5/model/qhexdelegate.cpp - qhexview5/model/qhexdocument.cpp - qhexview5/model/qhexmetadata.cpp - qhexview5/model/qhexutils.cpp - qhexview5/qhexview.cpp ../common/fitparser.cpp ../common/guiddatabase.cpp ../common/nvram.cpp @@ -124,6 +110,9 @@ TARGET_INCLUDE_DIRECTORIES(UEFITool PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") TARGET_LINK_LIBRARIES(UEFITool PRIVATE Qt6::Widgets) +ADD_SUBDIRECTORY(QHexView) +TARGET_LINK_LIBRARIES(UEFITool PRIVATE QHexView) + SET_TARGET_PROPERTIES(UEFITool PROPERTIES WIN32_EXECUTABLE ON MACOSX_BUNDLE ON diff --git a/UEFITool/QHexView/CMakeLists.txt b/UEFITool/QHexView/CMakeLists.txt new file mode 100644 index 0000000..8fbb2a8 --- /dev/null +++ b/UEFITool/QHexView/CMakeLists.txt @@ -0,0 +1,91 @@ +cmake_minimum_required(VERSION 3.13) + +project(QHexView) + +option(QHEXVIEW_BUILD_EXAMPLE "Build Example Application" OFF) +option(QHEXVIEW_USE_QT5 "Enable Qt5 build" OFF) +option(QHEXVIEW_ENABLE_DIALOGS "BuiltIn dialogs" OFF) + +if(QHEXVIEW_USE_QT5) + find_package(Qt5 REQUIRED COMPONENTS Widgets) +else() + find_package(Qt6 COMPONENTS Widgets) + + if(NOT Qt6_FOUND) + find_package(Qt5 REQUIRED COMPONENTS Widgets) + endif() +endif() + +add_library(${PROJECT_NAME} STATIC) + +set_target_properties(${PROJECT_NAME} + PROPERTIES + CXX_STANDARD_REQUIRED YES + CXX_STANDARD 11 + AUTOMOC ON +) + +target_link_libraries(${PROJECT_NAME} + PUBLIC + Qt::Widgets +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + "${PROJECT_SOURCE_DIR}/include" +) + +target_sources(${PROJECT_NAME} + PRIVATE + include/QHexView/model/buffer/qdevicebuffer.h + include/QHexView/model/buffer/qhexbuffer.h + include/QHexView/model/buffer/qmappedfilebuffer.h + include/QHexView/model/buffer/qmemorybuffer.h + include/QHexView/model/buffer/qmemoryrefbuffer.h + include/QHexView/model/commands/hexcommand.h + include/QHexView/model/commands/insertcommand.h + include/QHexView/model/commands/removecommand.h + include/QHexView/model/commands/replacecommand.h + include/QHexView/model/commands/replacecommand.h + include/QHexView/model/qhexcursor.h + include/QHexView/model/qhexdelegate.h + include/QHexView/model/qhexdocument.h + include/QHexView/model/qhexmetadata.h + include/QHexView/model/qhexoptions.h + include/QHexView/model/qhexutils.h + include/QHexView/qhexview.h + + PRIVATE + src/model/commands/hexcommand.cpp + src/model/commands/insertcommand.cpp + src/model/commands/removecommand.cpp + src/model/commands/replacecommand.cpp + src/model/buffer/qdevicebuffer.cpp + src/model/buffer/qhexbuffer.cpp + src/model/buffer/qmemorybuffer.cpp + src/model/buffer/qmemoryrefbuffer.cpp + src/model/buffer/qmappedfilebuffer.cpp + src/model/qhexdelegate.cpp + src/model/qhexutils.cpp + src/model/qhexcursor.cpp + src/model/qhexmetadata.cpp + src/model/qhexdocument.cpp + src/qhexview.cpp +) + +if(QHEXVIEW_ENABLE_DIALOGS) + target_sources(${PROJECT_NAME} + PRIVATE + include/QHexView/dialogs/hexfinddialog.h + src/dialogs/hexfinddialog.cpp + ) + + target_compile_definitions(${PROJECT_NAME} + PUBLIC + QHEXVIEW_ENABLE_DIALOGS + ) +endif() + +if(QHEXVIEW_BUILD_EXAMPLE) + add_subdirectory(example) +endif() diff --git a/UEFITool/qhexview5/LICENSE b/UEFITool/QHexView/LICENSE similarity index 100% rename from UEFITool/qhexview5/LICENSE rename to UEFITool/QHexView/LICENSE diff --git a/UEFITool/QHexView/include/QHexView/dialogs/hexfinddialog.h b/UEFITool/QHexView/include/QHexView/dialogs/hexfinddialog.h new file mode 100644 index 0000000..d041db9 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/dialogs/hexfinddialog.h @@ -0,0 +1,56 @@ +#pragma once + +#include <QDialog> +#include <QHexView/model/qhexutils.h> + +class QRegularExpressionValidator; +class QDoubleValidator; +class QIntValidator; +class QHexView; + +class HexFindDialog: public QDialog { + Q_OBJECT + +public: + enum class Type { Find, Replace }; + +public: + explicit HexFindDialog(HexFindDialog::Type type = Type::Find, + QHexView* parent = nullptr); + QHexView* hexView() const; + +private Q_SLOTS: + void updateFindOptions(int); + void validateActions(); + void replace(); + void find(); + +private: + bool prepareOptions(QString& q, QHexFindMode& mode, QHexFindDirection& fd); + bool validateIntRange(uint v) const; + void checkResult(const QString& q, qint64 offset, QHexFindDirection fd); + void prepareTextMode(QLayout* l); + void prepareHexMode(QLayout* l); + void prepareIntMode(QLayout* l); + void prepareFloatMode(QLayout* l); + +private: + QRegularExpressionValidator *m_hexvalidator, *m_hexpvalidator; + QDoubleValidator* m_dblvalidator; + QIntValidator* m_intvalidator; + int m_oldidxbits{-1}, m_oldidxendian{-1}; + unsigned int m_findoptions{0}; + qint64 m_startoffset{-1}; + Type m_type; + +private: + static const QString BUTTONBOX; + static const QString CBFINDMODE; + static const QString LEFIND; + static const QString LEREPLACE; + static const QString HLAYOUT; + static const QString GBOPTIONS; + static const QString RBALL; + static const QString RBFORWARD; + static const QString RBBACKWARD; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/buffer/qdevicebuffer.h b/UEFITool/QHexView/include/QHexView/model/buffer/qdevicebuffer.h new file mode 100644 index 0000000..39fccef --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/buffer/qdevicebuffer.h @@ -0,0 +1,24 @@ +#pragma once + +#include <QHexView/model/buffer/qhexbuffer.h> + +class QDeviceBuffer: public QHexBuffer { + Q_OBJECT + +public: + explicit QDeviceBuffer(QObject* parent = nullptr); + virtual ~QDeviceBuffer(); + uchar at(qint64 idx) override; + qint64 length() const override; + void insert(qint64 offset, const QByteArray& data) override; + void replace(qint64 offset, const QByteArray& data) override; + void remove(qint64 offset, int length) override; + QByteArray read(qint64 offset, int length) override; + bool read(QIODevice* device) override; + void write(QIODevice* device) override; + qint64 indexOf(const QByteArray& ba, qint64 from) override; + qint64 lastIndexOf(const QByteArray& ba, qint64 from) override; + +protected: + QIODevice* m_device{nullptr}; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/buffer/qhexbuffer.h b/UEFITool/QHexView/include/QHexView/model/buffer/qhexbuffer.h new file mode 100644 index 0000000..0c6424f --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/buffer/qhexbuffer.h @@ -0,0 +1,29 @@ +#pragma once + +#include <QIODevice> +#include <QObject> + +class QHexBuffer: public QObject { + Q_OBJECT + +public: + explicit QHexBuffer(QObject* parent = nullptr); + bool isEmpty() const; + +public: + virtual uchar at(qint64 idx); + virtual bool accept(qint64 idx) const; + virtual void replace(qint64 offset, const QByteArray& data); + virtual void read(char* data, int size); + virtual void read(const QByteArray& ba); + +public: + virtual qint64 length() const = 0; + virtual void insert(qint64 offset, const QByteArray& data) = 0; + virtual void remove(qint64 offset, int length) = 0; + virtual QByteArray read(qint64 offset, int length) = 0; + virtual bool read(QIODevice* iodevice) = 0; + virtual void write(QIODevice* iodevice) = 0; + virtual qint64 indexOf(const QByteArray& ba, qint64 from) = 0; + virtual qint64 lastIndexOf(const QByteArray& ba, qint64 from) = 0; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/buffer/qmappedfilebuffer.h b/UEFITool/QHexView/include/QHexView/model/buffer/qmappedfilebuffer.h new file mode 100644 index 0000000..f4f9239 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/buffer/qmappedfilebuffer.h @@ -0,0 +1,20 @@ +#pragma once + +#include <QHexView/model/buffer/qdevicebuffer.h> + +class QMappedFileBuffer: public QDeviceBuffer { +public: + explicit QMappedFileBuffer(QObject* parent = nullptr); + virtual ~QMappedFileBuffer(); + +public: + QByteArray read(qint64 offset, int length) override; + bool read(QIODevice* iodevice) override; + void write(QIODevice* iodevice) override; + +private: + void remap(); + +private: + uchar* m_mappeddata{nullptr}; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/buffer/qmemorybuffer.h b/UEFITool/QHexView/include/QHexView/model/buffer/qmemorybuffer.h new file mode 100644 index 0000000..b8f4c5b --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/buffer/qmemorybuffer.h @@ -0,0 +1,22 @@ +#pragma once + +#include <QHexView/model/buffer/qhexbuffer.h> + +class QMemoryBuffer: public QHexBuffer { + Q_OBJECT + +public: + explicit QMemoryBuffer(QObject* parent = nullptr); + uchar at(qint64 idx) override; + qint64 length() const override; + void insert(qint64 offset, const QByteArray& data) override; + void remove(qint64 offset, int length) override; + QByteArray read(qint64 offset, int length) override; + bool read(QIODevice* device) override; + void write(QIODevice* device) override; + qint64 indexOf(const QByteArray& ba, qint64 from) override; + qint64 lastIndexOf(const QByteArray& ba, qint64 from) override; + +private: + QByteArray m_buffer; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/buffer/qmemoryrefbuffer.h b/UEFITool/QHexView/include/QHexView/model/buffer/qmemoryrefbuffer.h new file mode 100644 index 0000000..d1f29b5 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/buffer/qmemoryrefbuffer.h @@ -0,0 +1,12 @@ +#pragma once + +#include <QHexView/model/buffer/qdevicebuffer.h> + +class QMemoryRefBuffer: public QDeviceBuffer { + Q_OBJECT + +public: + explicit QMemoryRefBuffer(QObject* parent = nullptr); + bool read(QIODevice* device) override; + void write(QIODevice* device) override; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/commands/hexcommand.h b/UEFITool/QHexView/include/QHexView/model/commands/hexcommand.h new file mode 100644 index 0000000..16637f4 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/commands/hexcommand.h @@ -0,0 +1,19 @@ +#pragma once + +#include <QHexView/model/buffer/qhexbuffer.h> +#include <QUndoCommand> + +class QHexDocument; + +class HexCommand: public QUndoCommand { +public: + HexCommand(QHexBuffer* buffer, QHexDocument* document, + QUndoCommand* parent = nullptr); + +protected: + QHexDocument* m_hexdocument; + QHexBuffer* m_buffer; + qint64 m_offset; + int m_length; + QByteArray m_data; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/commands/insertcommand.h b/UEFITool/QHexView/include/QHexView/model/commands/insertcommand.h new file mode 100644 index 0000000..971a4d9 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/commands/insertcommand.h @@ -0,0 +1,11 @@ +#pragma once + +#include <QHexView/model/commands/hexcommand.h> + +class InsertCommand: public HexCommand { +public: + InsertCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, + const QByteArray& data, QUndoCommand* parent = nullptr); + void undo() override; + void redo() override; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/commands/removecommand.h b/UEFITool/QHexView/include/QHexView/model/commands/removecommand.h new file mode 100644 index 0000000..a1bf13b --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/commands/removecommand.h @@ -0,0 +1,11 @@ +#pragma once + +#include <QHexView/model/commands/hexcommand.h> + +class RemoveCommand: public HexCommand { +public: + RemoveCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, + int length, QUndoCommand* parent = nullptr); + void undo() override; + void redo() override; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/commands/replacecommand.h b/UEFITool/QHexView/include/QHexView/model/commands/replacecommand.h new file mode 100644 index 0000000..13912d7 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/commands/replacecommand.h @@ -0,0 +1,14 @@ +#pragma once + +#include <QHexView/model/commands/hexcommand.h> + +class ReplaceCommand: public HexCommand { +public: + ReplaceCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, + const QByteArray& data, QUndoCommand* parent = nullptr); + void undo() override; + void redo() override; + +private: + QByteArray m_olddata; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/qhexcursor.h b/UEFITool/QHexView/include/QHexView/model/qhexcursor.h new file mode 100644 index 0000000..3651398 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/qhexcursor.h @@ -0,0 +1,73 @@ +#pragma once + +#include <QHexView/model/qhexoptions.h> +#include <QHexView/model/qhexutils.h> +#include <QObject> + +class QHexView; + +class QHexCursor: public QObject { + Q_OBJECT + +public: + enum class Mode { Overwrite, Insert }; + +private: + explicit QHexCursor(const QHexOptions* options, QHexView* parent = nullptr); + +public: + QHexView* hexView() const; + Mode mode() const; + qint64 line() const; + qint64 column() const; + qint64 offset() const; + qint64 address() const; + quint64 lineAddress() const; + qint64 selectionStartOffset() const; + qint64 selectionEndOffset() const; + qint64 selectionLength() const; + QHexPosition position() const; + QHexPosition selectionStart() const; + QHexPosition selectionEnd() const; + QByteArray selectedBytes() const; + bool hasSelection() const; + bool isSelected(qint64 line, qint64 column) const; + void setMode(Mode m); + void move(qint64 offset); + void move(qint64 line, qint64 column); + void move(QHexPosition pos); + void select(qint64 offset); + void select(qint64 line, qint64 column); + void select(QHexPosition pos); + void selectSize(qint64 length); + qint64 replace(const QVariant& oldvalue, const QVariant& newvalue, + qint64 offset, QHexFindMode mode = QHexFindMode::Text, + unsigned int options = QHexFindOptions::None, + QHexFindDirection fd = QHexFindDirection::Forward) const; + qint64 find(const QVariant& value, qint64 offset, + QHexFindMode mode = QHexFindMode::Text, + unsigned int options = QHexFindOptions::None, + QHexFindDirection fd = QHexFindDirection::Forward) const; + qint64 positionToOffset(QHexPosition pos) const; + QHexPosition offsetToPosition(qint64 offset) const; + +public Q_SLOTS: + void cut(bool hex = false); + void copy(bool hex = false) const; + void paste(bool hex = false); + void selectAll(); + void removeSelection(); + void clearSelection(); + void switchMode(); + +Q_SIGNALS: + void positionChanged(); + void modeChanged(); + +private: + const QHexOptions* m_options; + Mode m_mode{Mode::Overwrite}; + QHexPosition m_position{}, m_selection{}; + + friend class QHexView; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/qhexdelegate.h b/UEFITool/QHexView/include/QHexView/model/qhexdelegate.h new file mode 100644 index 0000000..c698589 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/qhexdelegate.h @@ -0,0 +1,30 @@ +#pragma once + +#include <QHexView/model/qhexutils.h> +#include <QObject> +#include <QTextCharFormat> + +class QHexView; + +class QHexDelegate: public QObject { + Q_OBJECT + +public: + explicit QHexDelegate(QObject* parent = nullptr); + virtual ~QHexDelegate() = default; + virtual QString addressHeader(const QHexView* hexview) const; + virtual QString hexHeader(const QHexView* hexview) const; + virtual QString asciiHeader(const QHexView* hexview) const; + virtual void renderAddress(quint64 address, QTextCharFormat& cf, + const QHexView* hexview) const; + virtual void renderHeader(QTextBlockFormat& bf, + const QHexView* hexview) const; + virtual void renderHeaderPart(const QString& s, QHexArea area, + QTextCharFormat& cf, + const QHexView* hexview) const; + virtual bool render(quint64 offset, quint8 b, QTextCharFormat& outcf, + const QHexView* hexview) const; + virtual bool paintSeparator(QPainter* painter, QLineF line, + const QHexView* hexview) const; + virtual void paint(QPainter* painter, const QHexView* hexview) const; +}; diff --git a/UEFITool/QHexView/include/QHexView/model/qhexdocument.h b/UEFITool/QHexView/include/QHexView/model/qhexdocument.h new file mode 100644 index 0000000..30f9d99 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/qhexdocument.h @@ -0,0 +1,102 @@ +#pragma once + +#include <QHexView/model/buffer/qhexbuffer.h> +#include <QHexView/model/qhexmetadata.h> +#include <QUndoStack> + +class QHexCursor; + +class QHexDocument: public QObject { + Q_OBJECT + +public: + enum class ChangeReason { Insert, Remove, Replace }; + enum class FindDirection { Forward, Backward }; + Q_ENUM(ChangeReason); + Q_ENUM(FindDirection); + +private: + explicit QHexDocument(QHexBuffer* buffer, QObject* parent = nullptr); + bool accept(qint64 idx) const; + +public: + bool isEmpty() const; + bool isModified() const; + bool canUndo() const; + bool canRedo() const; + void setData(const QByteArray& ba); + void setData(QHexBuffer* buffer); + qint64 length() const; + qint64 indexOf(const QByteArray& ba, qint64 from = 0); + qint64 lastIndexOf(const QByteArray& ba, qint64 from = 0); + QByteArray read(qint64 offset, int len = 0) const; + uchar at(int offset) const; + +public Q_SLOTS: + void clearModified(); + void undo(); + void redo(); + void insert(qint64 offset, uchar b); + void replace(qint64 offset, uchar b); + void insert(qint64 offset, const QByteArray& data); + void replace(qint64 offset, const QByteArray& data); + void remove(qint64 offset, int len); + bool saveTo(QIODevice* device); + +public: + template<typename T, bool Owned = true> + static QHexDocument* fromDevice(QIODevice* iodevice, + QObject* parent = nullptr); + template<typename T> + static QHexDocument* fromMemory(char* data, int size, + QObject* parent = nullptr); + template<typename T> + static QHexDocument* fromMemory(const QByteArray& ba, + QObject* parent = nullptr); + static QHexDocument* fromBuffer(QHexBuffer* buffer, + QObject* parent = nullptr); + static QHexDocument* fromLargeFile(QString filename, + QObject* parent = nullptr); + static QHexDocument* fromMappedFile(QString filename, + QObject* parent = nullptr); + static QHexDocument* fromFile(QString filename, QObject* parent = nullptr); + static QHexDocument* create(QObject* parent = nullptr); + +Q_SIGNALS: + void modifiedChanged(bool modified); + void canUndoChanged(bool canundo); + void canRedoChanged(bool canredo); + void dataChanged(const QByteArray& data, quint64 offset, + QHexDocument::ChangeReason reason); + void changed(); + void reset(); + +private: + QHexBuffer* m_buffer; + QUndoStack m_undostack; + + friend class QHexView; +}; + +template<typename T, bool Owned> +QHexDocument* QHexDocument::fromDevice(QIODevice* iodevice, QObject* parent) { + QHexBuffer* hexbuffer = new T(parent); + if(Owned) + iodevice->setParent(hexbuffer); + return hexbuffer->read(iodevice) ? new QHexDocument(hexbuffer, parent) + : nullptr; +} + +template<typename T> +QHexDocument* QHexDocument::fromMemory(char* data, int size, QObject* parent) { + QHexBuffer* hexbuffer = new T(); + hexbuffer->read(data, size); + return new QHexDocument(hexbuffer, parent); +} + +template<typename T> +QHexDocument* QHexDocument::fromMemory(const QByteArray& ba, QObject* parent) { + QHexBuffer* hexbuffer = new T(); + hexbuffer->read(ba); + return new QHexDocument(hexbuffer, parent); +} diff --git a/UEFITool/QHexView/include/QHexView/model/qhexmetadata.h b/UEFITool/QHexView/include/QHexView/model/qhexmetadata.h new file mode 100644 index 0000000..f4a1517 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/qhexmetadata.h @@ -0,0 +1,92 @@ +#pragma once + +#include <QColor> +#include <QHash> +#include <QHexView/model/qhexoptions.h> +#include <QList> +#include <QObject> +#include <functional> + +struct QHexMetadataItem { + qint64 begin, end; + QColor foreground, background; + QString comment; +}; + +using QHexMetadataLine = QList<QHexMetadataItem>; + +class QHexMetadata: public QObject { + Q_OBJECT + +private: + using ClearMetadataCallback = std::function<bool(QHexMetadataItem&)>; + +private: + explicit QHexMetadata(const QHexOptions* options, + QObject* parent = nullptr); + +public: + const QHexMetadataLine* find(qint64 line) const; + QString getComment(qint64 line, qint64 column) const; + void removeMetadata(qint64 line); + void removeBackground(qint64 line); + void removeForeground(qint64 line); + void removeComments(qint64 line); + void unhighlight(qint64 line); + void clear(); + +public: + inline void setMetadata(qint64 begin, qint64 end, const QColor& fgcolor, + const QColor& bgcolor, const QString& comment) { + this->setMetadata({begin, end, fgcolor, bgcolor, comment}); + } + + inline void setForeground(qint64 begin, qint64 end, const QColor& fgcolor) { + this->setMetadata(begin, end, fgcolor, QColor(), QString()); + } + + inline void setBackground(qint64 begin, qint64 end, const QColor& bgcolor) { + this->setMetadata(begin, end, QColor(), bgcolor, QString()); + } + + inline void setComment(qint64 begin, qint64 end, const QString& comment) { + this->setMetadata(begin, end, QColor(), QColor(), comment); + }; + + inline void setMetadataSize(qint64 begin, qint64 length, + const QColor& fgcolor, const QColor& bgcolor, + const QString& comment) { + this->setMetadata({begin, begin + length, fgcolor, bgcolor, comment}); + } + + inline void setForegroundSize(qint64 begin, qint64 length, + const QColor& fgcolor) { + this->setForeground(begin, begin + length, fgcolor); + } + + inline void setBackgroundSize(qint64 begin, qint64 length, + const QColor& bgcolor) { + this->setBackground(begin, begin + length, bgcolor); + } + + inline void setCommentSize(qint64 begin, qint64 length, + const QString& comment) { + this->setComment(begin, begin + length, comment); + }; + +private: + void copy(const QHexMetadata* metadata); + void clearMetadata(qint64 line, ClearMetadataCallback&& cb); + void setMetadata(const QHexMetadataItem& mi); + void invalidate(); + +Q_SIGNALS: + void changed(); + void cleared(); + +private: + QHash<qint64, QHexMetadataLine> m_metadata; + const QHexOptions* m_options; + + friend class QHexView; +}; diff --git a/UEFITool/qhexview5/model/qhexoptions.h b/UEFITool/QHexView/include/QHexView/model/qhexoptions.h similarity index 60% rename from UEFITool/qhexview5/model/qhexoptions.h rename to UEFITool/QHexView/include/QHexView/model/qhexoptions.h index 8505a40..07a2a3a 100644 --- a/UEFITool/qhexview5/model/qhexoptions.h +++ b/UEFITool/QHexView/include/QHexView/model/qhexoptions.h @@ -1,35 +1,36 @@ #pragma once -#include <QHash> -#include <QColor> #include <QChar> +#include <QColor> +#include <QHash> namespace QHexFlags { - enum: unsigned int { - None = (1 << 0), - HSeparator = (1 << 1), - VSeparator = (1 << 2), - StyledHeader = (1 << 3), - StyledAddress = (1 << 4), - NoHeader = (1 << 5), - HighlightAddress = (1 << 6), - HighlightColumn = (1 << 7), - Separators = HSeparator | VSeparator, - Styled = StyledHeader | StyledAddress, - }; +enum : unsigned int { + None = (1 << 0), + HSeparator = (1 << 1), + VSeparator = (1 << 2), + StyledHeader = (1 << 3), + StyledAddress = (1 << 4), + NoHeader = (1 << 5), + HighlightAddress = (1 << 6), + HighlightColumn = (1 << 7), + + Separators = HSeparator | VSeparator, + Styled = StyledHeader | StyledAddress, +}; + } -struct QHexColor -{ +struct QHexColor { QColor foreground; QColor background; }; -struct QHexOptions -{ +struct QHexOptions { // Appearance QChar unprintablechar{'.'}; + QChar invalidchar{'?'}; QString addresslabel{""}; QString hexlabel; QString asciilabel; @@ -38,7 +39,7 @@ struct QHexOptions unsigned int linelength{0x10}; unsigned int addresswidth{0}; unsigned int grouplength{1}; - unsigned int scrollsteps{1}; + int scrollsteps{1}; // Colors & Styles QHash<quint8, QHexColor> bytecolors; diff --git a/UEFITool/QHexView/include/QHexView/model/qhexutils.h b/UEFITool/QHexView/include/QHexView/model/qhexutils.h new file mode 100644 index 0000000..b591479 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/model/qhexutils.h @@ -0,0 +1,66 @@ +#pragma once + +#include <QByteArray> +#include <QPair> +#include <QString> +#include <QVariant> + +struct QHexOptions; +class QHexView; + +namespace QHexFindOptions { + +enum : unsigned int { + None = (1 << 0), + CaseSensitive = (1 << 1), + Int8 = (1 << 2), + Int16 = (1 << 3), + Int32 = (1 << 4), + Int64 = (1 << 5), + Float = (1 << 6), + Double = (1 << 7), + + BigEndian = (1 << 11), +}; + +} + +enum class QHexFindMode { Text, Hex, Int, Float }; +enum class QHexFindDirection { All, Forward, Backward }; +enum class QHexArea { Header, Address, Hex, Ascii, Extra }; + +struct QHexPosition { + qint64 line; + qint64 column; + static inline QHexPosition invalid() { return {-1, -1}; } + inline bool isValid() const { return line >= 0 && column >= 0; } + inline bool operator==(const QHexPosition& rhs) const { + return (line == rhs.line) && (column == rhs.column); + } + inline bool operator!=(const QHexPosition& rhs) const { + return (line != rhs.line) || (column != rhs.column); + } +}; + +namespace QHexUtils { + +bool isHex(char ch); +QByteArray toHex(const QByteArray& ba, char sep); +QByteArray toHex(const QByteArray& ba); +qint64 positionToOffset(const QHexOptions* options, QHexPosition pos); +QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset); +bool checkPattern(QString pattern); + +QPair<qint64, qint64> find(const QHexView* hexview, QVariant value, + qint64 startoffset = 0, + QHexFindMode mode = QHexFindMode::Text, + unsigned int options = QHexFindOptions::None, + QHexFindDirection fd = QHexFindDirection::Forward); + +QPair<qint64, qint64> +replace(const QHexView* hexview, QVariant oldvalue, QVariant newvalue, + qint64 startoffset = 0, QHexFindMode mode = QHexFindMode::Text, + unsigned int options = QHexFindOptions::None, + QHexFindDirection fd = QHexFindDirection::Forward); + +} // namespace QHexUtils diff --git a/UEFITool/QHexView/include/QHexView/qhexview.h b/UEFITool/QHexView/include/QHexView/qhexview.h new file mode 100644 index 0000000..0e3c8c8 --- /dev/null +++ b/UEFITool/QHexView/include/QHexView/qhexview.h @@ -0,0 +1,184 @@ +#pragma once + +#define QHEXVIEW_VERSION 5.0 + +#include <QAbstractScrollArea> +#include <QFontMetricsF> +#include <QHexView/model/qhexcursor.h> +#include <QHexView/model/qhexdelegate.h> +#include <QHexView/model/qhexdocument.h> +#include <QList> +#include <QRectF> +#include <QTextCharFormat> + +#if defined(QHEXVIEW_ENABLE_DIALOGS) +class HexFindDialog; +#endif + +class QHexView: public QAbstractScrollArea { + Q_OBJECT + +public: + enum class CopyMode { Visual, HexArraySquare, HexArrayCurly, HexArrayChar }; + Q_ENUM(CopyMode); + +public: + explicit QHexView(QWidget* parent = nullptr); + QRectF headerRect() const; + QRectF addressRect() const; + QRectF hexRect() const; + QRectF asciiRect() const; + QHexDocument* hexDocument() const; + QHexCursor* hexCursor() const; + const QHexMetadata* hexMetadata() const; + QHexOptions options() const; + QColor getReadableColor(QColor c) const; + QByteArray selectedBytes() const; + QByteArray getLine(qint64 line) const; + unsigned int addressWidth() const; + unsigned int lineLength() const; + bool isModified() const; + bool canUndo() const; + bool canRedo() const; + quint64 offset() const; + quint64 address() const; + QHexPosition positionFromOffset(quint64 offset) const; + QHexPosition positionFromAddress(quint64 address) const; + QHexPosition position() const; + QHexPosition selectionStart() const; + QHexPosition selectionEnd() const; + quint64 selectionStartOffset() const; + quint64 selectionEndOffset() const; + quint64 baseAddress() const; + quint64 lines() const; + qint64 replace(const QVariant& oldvalue, const QVariant& newvalue, + qint64 offset, QHexFindMode mode = QHexFindMode::Text, + unsigned int options = QHexFindOptions::None, + QHexFindDirection fd = QHexFindDirection::Forward) const; + qint64 find(const QVariant& value, qint64 offset, + QHexFindMode mode = QHexFindMode::Text, + unsigned int options = QHexFindOptions::None, + QHexFindDirection fd = QHexFindDirection::Forward) const; + void setOptions(const QHexOptions& options); + void setBaseAddress(quint64 baseaddress); + void setDelegate(QHexDelegate* rd); + void setDocument(QHexDocument* doc); + void setData(const QByteArray& ba); + void setData(QHexBuffer* buffer); + void setCursorMode(QHexCursor::Mode mode); + void setByteColor(quint8 b, QHexColor c); + void setByteForeground(quint8 b, QColor c); + void setByteBackground(quint8 b, QColor c); + void setMetadata(qint64 begin, qint64 end, const QColor& fgcolor, + const QColor& bgcolor, const QString& comment); + void setForeground(qint64 begin, qint64 end, const QColor& fgcolor); + void setBackground(qint64 begin, qint64 end, const QColor& bgcolor); + void setComment(qint64 begin, qint64 end, const QString& comment); + void setMetadataSize(qint64 begin, qint64 length, const QColor& fgcolor, + const QColor& bgcolor, const QString& comment); + void setForegroundSize(qint64 begin, qint64 length, const QColor& fgcolor); + void setBackgroundSize(qint64 begin, qint64 length, const QColor& bgcolor); + void setCommentSize(qint64 begin, qint64 length, const QString& comment); + void removeMetadata(qint64 line); + void removeBackground(qint64 line); + void removeForeground(qint64 line); + void removeComments(qint64 line); + void unhighlight(qint64 line); + void clearMetadata(); + +public Q_SLOTS: +#if defined(QHEXVIEW_ENABLE_DIALOGS) + void showFind(); + void showReplace(); +#endif + void undo(); + void redo(); + void cut(bool hex = false); + void copyAs(CopyMode mode = CopyMode::Visual) const; + void copy(bool hex = false) const; + void paste(bool hex = false); + void clearModified(); + void selectAll(); + void removeSelection(); + void switchMode(); + void setAddressWidth(unsigned int w); + void setLineLength(unsigned int l); + void setGroupLength(unsigned int l); + void setScrollSteps(int scrollsteps); + void setReadOnly(bool r); + void setAutoWidth(bool r); + +private: + void paint(QPainter* painter) const; + void checkOptions(); + void checkState(); + void checkAndUpdate(bool calccolumns = false); + void calcColumns(); + void ensureVisible(); + void drawSeparators(QPainter* p) const; + void drawHeader(QTextCursor& c) const; + void drawDocument(QTextCursor& c) const; + QTextCharFormat drawFormat(QTextCursor& c, quint8 b, const QString& s, + QHexArea area, qint64 line, qint64 column, + bool applyformat) const; + unsigned int calcAddressWidth() const; + int visibleLines(bool absolute = false) const; + qint64 getLastColumn(qint64 line) const; + qint64 lastLine() const; + qreal getNCellsWidth(int n) const; + qreal hexColumnWidth() const; + qreal hexColumnX() const; + qreal asciiColumnX() const; + qreal endColumnX() const; + qreal cellWidth() const; + qreal lineHeight() const; + qint64 positionFromLineCol(qint64 line, qint64 col) const; + QHexPosition positionFromPoint(QPoint pt) const; + QPoint absolutePoint(QPoint pt) const; + QHexArea areaFromPoint(QPoint pt) const; + void moveNext(bool select = false); + void movePrevious(bool select = false); + bool keyPressMove(QKeyEvent* e); + bool keyPressTextInput(QKeyEvent* e); + bool keyPressAction(QKeyEvent* e); + +protected: + bool event(QEvent* e) override; + void showEvent(QShowEvent* e) override; + void paintEvent(QPaintEvent*) override; + void resizeEvent(QResizeEvent* e) override; + void focusInEvent(QFocusEvent* e) override; + void focusOutEvent(QFocusEvent* e) override; + void mousePressEvent(QMouseEvent* e) override; + void mouseMoveEvent(QMouseEvent* e) override; + void wheelEvent(QWheelEvent* e) override; + void keyPressEvent(QKeyEvent* e) override; + +private: + static QString reduced(const QString& s, int maxlen); + static bool isColorLight(QColor c); + +Q_SIGNALS: + void dataChanged(const QByteArray& data, quint64 offset, + QHexDocument::ChangeReason reason); + void modifiedChanged(bool modified); + void positionChanged(); + void modeChanged(); + +private: + bool m_readonly{false}, m_writing{false}, m_autowidth{false}; + QHexArea m_currentarea{QHexArea::Ascii}; + QList<QRectF> m_hexcolumns; + QFontMetricsF m_fontmetrics; + QHexOptions m_options; + QHexCursor* m_hexcursor{nullptr}; + QHexDocument* m_hexdocument{nullptr}; + QHexMetadata* m_hexmetadata{nullptr}; + QHexDelegate* m_hexdelegate{nullptr}; +#if defined(QHEXVIEW_ENABLE_DIALOGS) + HexFindDialog *m_hexdlgfind{nullptr}, *m_hexdlgreplace{nullptr}; +#endif + + friend class QHexDelegate; + friend class QHexCursor; +}; diff --git a/UEFITool/QHexView/src/dialogs/hexfinddialog.cpp b/UEFITool/QHexView/src/dialogs/hexfinddialog.cpp new file mode 100644 index 0000000..ce42092 --- /dev/null +++ b/UEFITool/QHexView/src/dialogs/hexfinddialog.cpp @@ -0,0 +1,418 @@ +#include <QCheckBox> +#include <QComboBox> +#include <QDialogButtonBox> +#include <QGridLayout> +#include <QGroupBox> +#include <QHBoxLayout> +#include <QHexView/dialogs/hexfinddialog.h> +#include <QHexView/qhexview.h> +#include <QLabel> +#include <QLineEdit> +#include <QList> +#include <QMessageBox> +#include <QPair> +#include <QPushButton> +#include <QRadioButton> +#include <QRegularExpression> +#include <QRegularExpressionValidator> +#include <QSpacerItem> +#include <QStackedLayout> +#include <QVBoxLayout> +#include <limits> + +const QString HexFindDialog::BUTTONBOX = "qhexview_buttonbox"; +const QString HexFindDialog::CBFINDMODE = "qhexview_cbfindmode"; +const QString HexFindDialog::LEFIND = "qhexview_lefind"; +const QString HexFindDialog::LEREPLACE = "qhexview_lereplace"; +const QString HexFindDialog::HLAYOUT = "qhexview_hlayout"; +const QString HexFindDialog::GBOPTIONS = "qhexview_gboptions"; +const QString HexFindDialog::RBALL = "qhexview_rball"; +const QString HexFindDialog::RBFORWARD = "qhexview_rbforward"; +const QString HexFindDialog::RBBACKWARD = "qhexview_rbbackward"; + +HexFindDialog::HexFindDialog(Type type, QHexView* parent) + : QDialog{parent}, m_type{type} { + m_hexvalidator = new QRegularExpressionValidator( + QRegularExpression{"[0-9A-Fa-f ]+"}, this); + m_hexpvalidator = new QRegularExpressionValidator( + QRegularExpression{"[0-9A-Fa-f \\?]+"}, this); + m_dblvalidator = new QDoubleValidator(this); + m_intvalidator = new QIntValidator(this); + + this->setWindowTitle(type == Type::Replace ? tr("Replace...") + : tr("Find...")); + + auto* vlayout = new QVBoxLayout(this); + auto* gridlayout = new QGridLayout(); + + auto* cbfindmode = new QComboBox(this); + cbfindmode->setObjectName(HexFindDialog::CBFINDMODE); + cbfindmode->addItem("Text", static_cast<int>(QHexFindMode::Text)); + cbfindmode->addItem("Hex", static_cast<int>(QHexFindMode::Hex)); + cbfindmode->addItem("Int", static_cast<int>(QHexFindMode::Int)); + cbfindmode->addItem("Float", static_cast<int>(QHexFindMode::Float)); + + QLineEdit *lereplace = nullptr, *lefind = new QLineEdit(this); + lefind->setObjectName(HexFindDialog::LEFIND); + + gridlayout->addWidget(new QLabel(tr("Mode:"), this), 0, 0, Qt::AlignRight); + gridlayout->addWidget(cbfindmode, 0, 1); + gridlayout->addWidget(new QLabel(tr("Find:"), this), 1, 0, Qt::AlignRight); + gridlayout->addWidget(lefind, 1, 1); + + if(type == Type::Replace) { + lereplace = new QLineEdit(this); + lereplace->setObjectName(HexFindDialog::LEREPLACE); + + gridlayout->addWidget(new QLabel(tr("Replace:"), this), 2, 0, + Qt::AlignRight); + gridlayout->addWidget(lereplace, 2, 1); + } + + vlayout->addLayout(gridlayout); + + auto* gboptions = new QGroupBox(this); + gboptions->setObjectName(HexFindDialog::GBOPTIONS); + gboptions->setTitle(tr("Options")); + gboptions->setLayout(new QStackedLayout()); + + QGroupBox* gbdirection = new QGroupBox(this); + gbdirection->setTitle(tr("Find direction")); + auto* gbvlayout = new QVBoxLayout(gbdirection); + + auto* rball = new QRadioButton("All", gbdirection); + rball->setObjectName(HexFindDialog::RBALL); + auto* rbforward = new QRadioButton("Forward", gbdirection); + rbforward->setObjectName(HexFindDialog::RBFORWARD); + rbforward->setChecked(true); + auto* rbbackward = new QRadioButton("Backward", gbdirection); + rbbackward->setObjectName(HexFindDialog::RBBACKWARD); + + gbvlayout->addWidget(rball); + gbvlayout->addWidget(rbforward); + gbvlayout->addWidget(rbbackward); + gbvlayout->addSpacerItem( + new QSpacerItem(0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + auto* hlayout = new QHBoxLayout(); + hlayout->setObjectName(HexFindDialog::HLAYOUT); + hlayout->addWidget(gboptions, 1); + hlayout->addWidget(gbdirection); + vlayout->addLayout(hlayout, 1); + + auto* buttonbox = new QDialogButtonBox(this); + buttonbox->setOrientation(Qt::Horizontal); + + if(type == Type::Replace) + buttonbox->setStandardButtons(QDialogButtonBox::Ok | + QDialogButtonBox::Apply | + QDialogButtonBox::Cancel); + else + buttonbox->setStandardButtons(QDialogButtonBox::Ok | + QDialogButtonBox::Cancel); + + buttonbox->setObjectName(HexFindDialog::BUTTONBOX); + buttonbox->button(QDialogButtonBox::Ok)->setEnabled(false); + buttonbox->button(QDialogButtonBox::Ok)->setText(tr("Find")); + + if(type == Type::Replace) { + buttonbox->button(QDialogButtonBox::Apply)->setEnabled(false); + buttonbox->button(QDialogButtonBox::Apply)->setText(tr("Replace")); + } + + vlayout->addWidget(buttonbox); + + connect(lefind, &QLineEdit::textChanged, this, + &HexFindDialog::validateActions); + connect(cbfindmode, QOverload<int>::of(&QComboBox::currentIndexChanged), + this, &HexFindDialog::updateFindOptions); + connect(buttonbox, &QDialogButtonBox::accepted, this, &HexFindDialog::find); + connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(parent, &QHexView::positionChanged, this, + [this]() { m_startoffset = -1; }); + + if(lereplace) { + connect(buttonbox->button(QDialogButtonBox::Apply), + &QPushButton::clicked, this, &HexFindDialog::replace); + connect(lereplace, &QLineEdit::textChanged, this, + &HexFindDialog::validateActions); + } + + this->prepareTextMode(gboptions->layout()); + this->prepareHexMode(gboptions->layout()); + this->prepareIntMode(gboptions->layout()); + this->prepareFloatMode(gboptions->layout()); + this->updateFindOptions(-1); +} + +QHexView* HexFindDialog::hexView() const { + return qobject_cast<QHexView*>(this->parentWidget()); +} + +void HexFindDialog::updateFindOptions(int) { + QGroupBox* gboptions = + this->findChild<QGroupBox*>(HexFindDialog::GBOPTIONS); + + QLineEdit* lefind = this->findChild<QLineEdit*>(HexFindDialog::LEFIND); + QLineEdit* lereplace = + this->findChild<QLineEdit*>(HexFindDialog::LEREPLACE); + lefind->clear(); + if(lereplace) + lereplace->clear(); + + bool ok = false; + QHexFindMode mode = static_cast<QHexFindMode>( + this->findChild<QComboBox*>(HexFindDialog::CBFINDMODE) + ->currentData() + .toInt(&ok)); + if(!ok) + return; + + m_findoptions = QHexFindOptions::None; + m_oldidxbits = m_oldidxendian = -1; + + auto* stack = qobject_cast<QStackedLayout*>(gboptions->layout()); + + switch(mode) { + case QHexFindMode::Text: { + lefind->setValidator(nullptr); + if(lereplace) + lereplace->setValidator(nullptr); + + stack->setCurrentIndex(0); + gboptions->setVisible(true); + break; + } + + case QHexFindMode::Hex: { + lefind->setValidator(m_hexpvalidator); + if(lereplace) + lereplace->setValidator(m_hexvalidator); + stack->setCurrentIndex(1); + gboptions->setVisible(false); + break; + } + + case QHexFindMode::Int: { + lefind->setValidator(m_intvalidator); + if(lereplace) + lereplace->setValidator(m_intvalidator); + + stack->setCurrentIndex(2); + gboptions->setVisible(true); + break; + } + + case QHexFindMode::Float: { + lefind->setValidator(m_dblvalidator); + if(lereplace) + lereplace->setValidator(m_dblvalidator); + + stack->setCurrentIndex(3); + gboptions->setVisible(true); + break; + } + } +} + +bool HexFindDialog::validateIntRange(uint v) const { + if(m_findoptions & QHexFindOptions::Int8) + return !(v > std::numeric_limits<quint8>::max()); + if(m_findoptions & QHexFindOptions::Int16) + return !(v > std::numeric_limits<quint16>::max()); + if(m_findoptions & QHexFindOptions::Int32) + return !(v > std::numeric_limits<quint32>::max()); + return true; +} + +void HexFindDialog::checkResult(const QString& q, qint64 offset, + QHexFindDirection fd) { + if(offset == -1) { + QMessageBox::information(this, tr("Not found"), + tr("Cannot find '%1'").arg(q)); + return; + } + + if(fd == QHexFindDirection::Backward) + m_startoffset = this->hexView()->selectionStartOffset() - 1; + else + m_startoffset = this->hexView()->selectionEndOffset() + 1; +} + +void HexFindDialog::validateActions() { + auto mode = static_cast<QHexFindMode>( + this->findChild<QComboBox*>(HexFindDialog::CBFINDMODE) + ->currentData() + .toUInt()); + auto* lefind = this->findChild<QLineEdit*>(HexFindDialog::LEFIND); + auto* lereplace = this->findChild<QLineEdit*>(HexFindDialog::LEREPLACE); + auto* buttonbox = + this->findChild<QDialogButtonBox*>(HexFindDialog::BUTTONBOX); + + bool findenable = false, replaceenable = false; + + switch(mode) { + case QHexFindMode::Hex: + findenable = QHexUtils::checkPattern(lefind->text()); + replaceenable = findenable; + break; + + case QHexFindMode::Float: { + lefind->text().toFloat(&findenable); + if(lereplace && findenable) + lereplace->text().toFloat(&replaceenable); + break; + } + + case QHexFindMode::Int: { + auto v = lefind->text().toUInt(&findenable); + if(findenable && !this->validateIntRange(v)) + findenable = false; + if(lereplace && findenable) + lereplace->text().toUInt(&replaceenable); + break; + } + + default: + findenable = !lefind->text().isEmpty(); + replaceenable = findenable; + break; + } + + if(lereplace) + buttonbox->button(QDialogButtonBox::Apply)->setEnabled(replaceenable); + buttonbox->button(QDialogButtonBox::Ok)->setEnabled(findenable); +} + +void HexFindDialog::replace() { + QString q1; + QHexFindMode mode; + QHexFindDirection fd; + + if(!this->prepareOptions(q1, mode, fd)) + return; + + QString q2 = this->findChild<QLineEdit*>(HexFindDialog::LEREPLACE)->text(); + auto offset = this->hexView()->hexCursor()->replace( + q1, q2, m_startoffset > -1 ? m_startoffset : this->hexView()->offset(), + mode, m_findoptions, fd); + this->checkResult(q1, offset, fd); +} + +void HexFindDialog::find() { + QString q; + QHexFindMode mode; + QHexFindDirection fd; + + if(!this->prepareOptions(q, mode, fd)) + return; + + auto offset = this->hexView()->hexCursor()->find( + q, m_startoffset > -1 ? m_startoffset : this->hexView()->offset(), mode, + m_findoptions, fd); + this->checkResult(q, offset, fd); +} + +bool HexFindDialog::prepareOptions(QString& q, QHexFindMode& mode, + QHexFindDirection& fd) { + q = this->findChild<QLineEdit*>(HexFindDialog::LEFIND)->text(); + mode = static_cast<QHexFindMode>( + this->findChild<QComboBox*>(HexFindDialog::CBFINDMODE) + ->currentData() + .toUInt()); + + if(mode == QHexFindMode::Hex && !QHexUtils::checkPattern(q)) { + QMessageBox::warning(this, tr("Pattern Error"), + tr("Hex pattern '%1' is not valid").arg(q)); + return false; + } + + if(this->findChild<QRadioButton*>(HexFindDialog::RBBACKWARD)->isChecked()) + fd = QHexFindDirection::Backward; + else if(this->findChild<QRadioButton*>(HexFindDialog::RBFORWARD) + ->isChecked()) + fd = QHexFindDirection::Forward; + else + fd = QHexFindDirection::All; + return true; +} + +void HexFindDialog::prepareTextMode(QLayout* l) { + auto* cbcasesensitive = new QCheckBox("Case sensitive"); + + connect(cbcasesensitive, &QCheckBox::stateChanged, this, [this](int state) { + if(state == Qt::Checked) + m_findoptions |= QHexFindOptions::CaseSensitive; + else + m_findoptions &= ~QHexFindOptions::CaseSensitive; + }); + + auto* vlayout = new QVBoxLayout(new QWidget()); + vlayout->addWidget(cbcasesensitive); + l->addWidget(vlayout->parentWidget()); +} + +void HexFindDialog::prepareHexMode(QLayout* l) { l->addWidget(new QWidget()); } + +void HexFindDialog::prepareIntMode(QLayout* l) { + static const QList<QPair<QString, unsigned int>> INT_TYPES = { + qMakePair<QString, unsigned int>("(any)", 0), + qMakePair<QString, unsigned int>("8", QHexFindOptions::Int8), + qMakePair<QString, unsigned int>("16", QHexFindOptions::Int16), + qMakePair<QString, unsigned int>("32", QHexFindOptions::Int32), + qMakePair<QString, unsigned int>("64", QHexFindOptions::Int64)}; + + auto* cbbits = new QComboBox(); + for(const auto& it : INT_TYPES) + cbbits->addItem(it.first, it.second); + + connect(cbbits, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + [this, cbbits](int index) { + if(m_oldidxbits > -1) + m_findoptions &= ~cbbits->itemData(m_oldidxbits).toUInt(); + m_findoptions |= cbbits->itemData(index).toUInt(); + m_oldidxbits = index; + }); + + auto* cbendian = new QComboBox(); + cbendian->addItem("Little Endian", 0); + cbendian->addItem("Big Endian", QHexFindOptions::BigEndian); + + connect(cbendian, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + [this, cbendian](int index) { + if(m_oldidxendian > -1) + m_findoptions &= + ~cbendian->itemData(m_oldidxendian).toUInt(); + m_findoptions |= cbendian->itemData(index).toUInt(); + m_oldidxendian = index; + }); + + auto* vlayout = new QVBoxLayout(new QWidget()); + + QGridLayout* gl = new QGridLayout(); + gl->addWidget(new QLabel("Type:"), 0, 0, Qt::AlignRight); + gl->addWidget(cbbits, 0, 1); + gl->addWidget(new QLabel("Endian:"), 1, 0, Qt::AlignRight); + gl->addWidget(cbendian, 1, 1); + vlayout->addLayout(gl); + + l->addWidget(vlayout->parentWidget()); +} + +void HexFindDialog::prepareFloatMode(QLayout* l) { + static const QList<QPair<QString, unsigned int>> FLOAT_TYPES = { + qMakePair<QString, unsigned int>("float", QHexFindOptions::Float), + qMakePair<QString, unsigned int>("double", QHexFindOptions::Double)}; + + bool first = true; + auto* vlayout = new QVBoxLayout(new QWidget()); + + for(const auto& ft : FLOAT_TYPES) { + auto* rb = new QRadioButton(ft.first); + rb->setChecked(first); + vlayout->addWidget(rb); + first = false; + } + + l->addWidget(vlayout->parentWidget()); +} diff --git a/UEFITool/qhexview5/model/buffer/qdevicebuffer.cpp b/UEFITool/QHexView/src/model/buffer/qdevicebuffer.cpp similarity index 61% rename from UEFITool/qhexview5/model/buffer/qdevicebuffer.cpp rename to UEFITool/QHexView/src/model/buffer/qdevicebuffer.cpp index 1ba59d0..24413e4 100644 --- a/UEFITool/qhexview5/model/buffer/qdevicebuffer.cpp +++ b/UEFITool/QHexView/src/model/buffer/qdevicebuffer.cpp @@ -1,24 +1,23 @@ -#include "qdevicebuffer.h" +#include <QHexView/model/buffer/qdevicebuffer.h> #include <QIODevice> #include <limits> -QDeviceBuffer::QDeviceBuffer(QObject *parent) : QHexBuffer{parent} { } +QDeviceBuffer::QDeviceBuffer(QObject* parent): QHexBuffer{parent} {} -QDeviceBuffer::~QDeviceBuffer() -{ - if(!m_device) return; +QDeviceBuffer::~QDeviceBuffer() { + if(!m_device) + return; - if(m_device->parent() == this) - { - if(m_device->isOpen()) m_device->close(); + if(m_device->parent() == this) { + if(m_device->isOpen()) + m_device->close(); m_device->deleteLater(); } m_device = nullptr; } -uchar QDeviceBuffer::at(qint64 idx) -{ +uchar QDeviceBuffer::at(qint64 idx) { m_device->seek(idx); char c = '\0'; @@ -28,68 +27,61 @@ uchar QDeviceBuffer::at(qint64 idx) qint64 QDeviceBuffer::length() const { return m_device->size(); } -void QDeviceBuffer::insert(qint64 offset, const QByteArray &data) -{ +void QDeviceBuffer::insert(qint64 offset, const QByteArray& data) { Q_UNUSED(offset) Q_UNUSED(data) // Not implemented } -void QDeviceBuffer::replace(qint64 offset, const QByteArray& data) -{ +void QDeviceBuffer::replace(qint64 offset, const QByteArray& data) { m_device->seek(offset); m_device->write(data); } -void QDeviceBuffer::remove(qint64 offset, int length) -{ +void QDeviceBuffer::remove(qint64 offset, int length) { Q_UNUSED(offset) Q_UNUSED(length) // Not implemented } -QByteArray QDeviceBuffer::read(qint64 offset, int length) -{ +QByteArray QDeviceBuffer::read(qint64 offset, int length) { m_device->seek(offset); return m_device->read(length); } -bool QDeviceBuffer::read(QIODevice *device) -{ +bool QDeviceBuffer::read(QIODevice* device) { m_device = device; - if(!m_device) return false; - if(!m_device->isOpen()) m_device->open(QIODevice::ReadWrite); + if(!m_device) + return false; + if(!m_device->isOpen()) + m_device->open(QIODevice::ReadWrite); return m_device->isOpen(); } -void QDeviceBuffer::write(QIODevice *device) -{ +void QDeviceBuffer::write(QIODevice* device) { Q_UNUSED(device) // Not implemented } -qint64 QDeviceBuffer::indexOf(const QByteArray& ba, qint64 from) -{ +qint64 QDeviceBuffer::indexOf(const QByteArray& ba, qint64 from) { const auto MAX = std::numeric_limits<int>::max(); qint64 idx = -1; - if(from < m_device->size()) - { + if(from < m_device->size()) { idx = from; m_device->seek(from); - while(idx < m_device->size()) - { + while(idx < m_device->size()) { QByteArray data = m_device->read(MAX); int sidx = data.indexOf(ba); - if(sidx >= 0) - { + if(sidx >= 0) { idx += sidx; break; } - if(idx + data.size() >= m_device->size()) return -1; + if(idx + data.size() >= m_device->size()) + return -1; m_device->seek(m_device->pos() + data.size() - ba.size()); } } @@ -97,33 +89,29 @@ qint64 QDeviceBuffer::indexOf(const QByteArray& ba, qint64 from) return idx; } -qint64 QDeviceBuffer::lastIndexOf(const QByteArray& ba, qint64 from) -{ +qint64 QDeviceBuffer::lastIndexOf(const QByteArray& ba, qint64 from) { const auto MAX = std::numeric_limits<int>::max(); qint64 idx = -1; - if(from >= 0 && ba.size() < MAX) - { + if(from >= 0 && ba.size() < MAX) { qint64 currpos = from; - while(currpos >= 0) - { + while(currpos >= 0) { qint64 readpos = (currpos < MAX) ? 0 : currpos - MAX; m_device->seek(readpos); QByteArray data = m_device->read(currpos - readpos); int lidx = data.lastIndexOf(ba, from); - if(lidx >= 0) - { + if(lidx >= 0) { idx = readpos + lidx; break; } - if(readpos <= 0) break; + if(readpos <= 0) + break; currpos = readpos + ba.size(); } - } return idx; diff --git a/UEFITool/qhexview5/model/buffer/qhexbuffer.cpp b/UEFITool/QHexView/src/model/buffer/qhexbuffer.cpp similarity index 62% rename from UEFITool/qhexview5/model/buffer/qhexbuffer.cpp rename to UEFITool/QHexView/src/model/buffer/qhexbuffer.cpp index b50081d..1d07b8a 100644 --- a/UEFITool/qhexview5/model/buffer/qhexbuffer.cpp +++ b/UEFITool/QHexView/src/model/buffer/qhexbuffer.cpp @@ -1,18 +1,21 @@ -#include "qhexbuffer.h" #include <QBuffer> +#include <QHexView/model/buffer/qhexbuffer.h> -QHexBuffer::QHexBuffer(QObject *parent) : QObject{parent} { } +QHexBuffer::QHexBuffer(QObject* parent): QObject{parent} {} uchar QHexBuffer::at(qint64 idx) { return this->read(idx, 1).at(0); } bool QHexBuffer::isEmpty() const { return this->length() <= 0; } -void QHexBuffer::replace(qint64 offset, const QByteArray &data) -{ +void QHexBuffer::replace(qint64 offset, const QByteArray& data) { this->remove(offset, data.length()); this->insert(offset, data); } -void QHexBuffer::read(char *data, int size) -{ +bool QHexBuffer::accept(qint64 idx) const { + Q_UNUSED(idx); + return true; +} + +void QHexBuffer::read(char* data, int size) { QBuffer* buffer = new QBuffer(this); buffer->setData(data, size); @@ -22,8 +25,7 @@ void QHexBuffer::read(char *data, int size) this->read(buffer); } -void QHexBuffer::read(const QByteArray &ba) -{ +void QHexBuffer::read(const QByteArray& ba) { QBuffer* buffer = new QBuffer(this); buffer->setData(ba); @@ -32,4 +34,3 @@ void QHexBuffer::read(const QByteArray &ba) this->read(buffer); } - diff --git a/UEFITool/QHexView/src/model/buffer/qmappedfilebuffer.cpp b/UEFITool/QHexView/src/model/buffer/qmappedfilebuffer.cpp new file mode 100644 index 0000000..a870d0a --- /dev/null +++ b/UEFITool/QHexView/src/model/buffer/qmappedfilebuffer.cpp @@ -0,0 +1,51 @@ +#include <QFile> +#include <QHexView/model/buffer/qmappedfilebuffer.h> + +QMappedFileBuffer::QMappedFileBuffer(QObject* parent): QDeviceBuffer{parent} {} + +QMappedFileBuffer::~QMappedFileBuffer() { + if((m_device && (m_device->parent() == this)) && m_mappeddata) { + QFile* f = qobject_cast<QFile*>(m_device); + f->unmap(m_mappeddata); + } + + m_mappeddata = nullptr; +} + +QByteArray QMappedFileBuffer::read(qint64 offset, int length) { + if(offset >= this->length()) + return {}; + + if(offset + length >= this->length()) + length = this->length() - offset; + + return QByteArray::fromRawData( + reinterpret_cast<const char*>(m_mappeddata + offset), length); +} + +bool QMappedFileBuffer::read(QIODevice* iodevice) { + m_device = qobject_cast<QFile*>(iodevice); + if(!m_device || !QDeviceBuffer::read(iodevice)) + return false; + + this->remap(); + return m_mappeddata; +} + +void QMappedFileBuffer::write(QIODevice* iodevice) { + if(iodevice == m_device) + this->remap(); + else + iodevice->write(reinterpret_cast<const char*>(m_mappeddata), + m_device->size()); +} + +void QMappedFileBuffer::remap() { + QFile* f = qobject_cast<QFile*>(m_device); + if(!f) + return; + + if(m_mappeddata) + f->unmap(m_mappeddata); + m_mappeddata = f->map(0, f->size()); +} diff --git a/UEFITool/QHexView/src/model/buffer/qmemorybuffer.cpp b/UEFITool/QHexView/src/model/buffer/qmemorybuffer.cpp new file mode 100644 index 0000000..220cebf --- /dev/null +++ b/UEFITool/QHexView/src/model/buffer/qmemorybuffer.cpp @@ -0,0 +1,39 @@ +#include <QHexView/model/buffer/qmemorybuffer.h> +#include <QIODevice> + +QMemoryBuffer::QMemoryBuffer(QObject* parent): QHexBuffer{parent} {} + +uchar QMemoryBuffer::at(qint64 idx) { + return static_cast<uchar>(m_buffer.at(idx)); +} + +qint64 QMemoryBuffer::length() const { + return static_cast<qint64>(m_buffer.length()); +} + +void QMemoryBuffer::insert(qint64 offset, const QByteArray& data) { + m_buffer.insert(static_cast<int>(offset), data); +} + +void QMemoryBuffer::remove(qint64 offset, int length) { + m_buffer.remove(static_cast<int>(offset), length); +} + +QByteArray QMemoryBuffer::read(qint64 offset, int length) { + return m_buffer.mid(static_cast<int>(offset), length); +} + +bool QMemoryBuffer::read(QIODevice* device) { + m_buffer = device->readAll(); + return true; +} + +void QMemoryBuffer::write(QIODevice* device) { device->write(m_buffer); } + +qint64 QMemoryBuffer::indexOf(const QByteArray& ba, qint64 from) { + return m_buffer.indexOf(ba, static_cast<int>(from)); +} + +qint64 QMemoryBuffer::lastIndexOf(const QByteArray& ba, qint64 from) { + return m_buffer.lastIndexOf(ba, static_cast<int>(from)); +} diff --git a/UEFITool/QHexView/src/model/buffer/qmemoryrefbuffer.cpp b/UEFITool/QHexView/src/model/buffer/qmemoryrefbuffer.cpp new file mode 100644 index 0000000..2598b85 --- /dev/null +++ b/UEFITool/QHexView/src/model/buffer/qmemoryrefbuffer.cpp @@ -0,0 +1,26 @@ +#include <QBuffer> +#include <QHexView/model/buffer/qmemoryrefbuffer.h> + +QMemoryRefBuffer::QMemoryRefBuffer(QObject* parent): QDeviceBuffer{parent} {} + +bool QMemoryRefBuffer::read(QIODevice* device) { + m_device = qobject_cast<QBuffer*>(device); + + if(m_device) { + m_device->setParent(this); + return QDeviceBuffer::read(device); + } + + return false; +} + +void QMemoryRefBuffer::write(QIODevice* device) { + if(!m_device || m_device == device) + return; + + static const int CHUNK_SIZE = 4096; + m_device->seek(0); + + while(!m_device->atEnd()) + device->write(m_device->read(CHUNK_SIZE)); +} diff --git a/UEFITool/QHexView/src/model/commands/hexcommand.cpp b/UEFITool/QHexView/src/model/commands/hexcommand.cpp new file mode 100644 index 0000000..ce27843 --- /dev/null +++ b/UEFITool/QHexView/src/model/commands/hexcommand.cpp @@ -0,0 +1,6 @@ +#include <QHexView/model/commands/hexcommand.h> + +HexCommand::HexCommand(QHexBuffer* buffer, QHexDocument* document, + QUndoCommand* parent) + : QUndoCommand(parent), m_hexdocument(document), m_buffer(buffer), + m_offset(0), m_length(0) {} diff --git a/UEFITool/QHexView/src/model/commands/insertcommand.cpp b/UEFITool/QHexView/src/model/commands/insertcommand.cpp new file mode 100644 index 0000000..eaec5bc --- /dev/null +++ b/UEFITool/QHexView/src/model/commands/insertcommand.cpp @@ -0,0 +1,18 @@ +#include <QHexView/model/commands/insertcommand.h> +#include <QHexView/model/qhexdocument.h> + +InsertCommand::InsertCommand(QHexBuffer* buffer, QHexDocument* document, + qint64 offset, const QByteArray& data, + QUndoCommand* parent) + : HexCommand(buffer, document, parent) { + m_offset = offset; + m_data = data; +} + +void InsertCommand::undo() { + m_buffer->remove(m_offset, m_data.length()); + Q_EMIT m_hexdocument->dataChanged(m_data, m_offset, + QHexDocument::ChangeReason::Remove); +} + +void InsertCommand::redo() { m_buffer->insert(m_offset, m_data); } diff --git a/UEFITool/QHexView/src/model/commands/removecommand.cpp b/UEFITool/QHexView/src/model/commands/removecommand.cpp new file mode 100644 index 0000000..a71b37e --- /dev/null +++ b/UEFITool/QHexView/src/model/commands/removecommand.cpp @@ -0,0 +1,20 @@ +#include <QHexView/model/commands/removecommand.h> +#include <QHexView/model/qhexdocument.h> + +RemoveCommand::RemoveCommand(QHexBuffer* buffer, QHexDocument* document, + qint64 offset, int length, QUndoCommand* parent) + : HexCommand(buffer, document, parent) { + m_offset = offset; + m_length = length; +} + +void RemoveCommand::undo() { + m_buffer->insert(m_offset, m_data); + Q_EMIT m_hexdocument->dataChanged(m_data, m_offset, + QHexDocument::ChangeReason::Insert); +} + +void RemoveCommand::redo() { + m_data = m_buffer->read(m_offset, m_length); // Backup data + m_buffer->remove(m_offset, m_length); +} diff --git a/UEFITool/QHexView/src/model/commands/replacecommand.cpp b/UEFITool/QHexView/src/model/commands/replacecommand.cpp new file mode 100644 index 0000000..6a193ea --- /dev/null +++ b/UEFITool/QHexView/src/model/commands/replacecommand.cpp @@ -0,0 +1,21 @@ +#include <QHexView/model/commands/replacecommand.h> +#include <QHexView/model/qhexdocument.h> + +ReplaceCommand::ReplaceCommand(QHexBuffer* buffer, QHexDocument* document, + qint64 offset, const QByteArray& data, + QUndoCommand* parent) + : HexCommand(buffer, document, parent) { + m_offset = offset; + m_data = data; +} + +void ReplaceCommand::undo() { + m_buffer->replace(m_offset, m_olddata); + Q_EMIT m_hexdocument->dataChanged(m_olddata, m_offset, + QHexDocument::ChangeReason::Replace); +} + +void ReplaceCommand::redo() { + m_olddata = m_buffer->read(m_offset, m_data.length()); + m_buffer->replace(m_offset, m_data); +} diff --git a/UEFITool/QHexView/src/model/qhexcursor.cpp b/UEFITool/QHexView/src/model/qhexcursor.cpp new file mode 100644 index 0000000..1b702cc --- /dev/null +++ b/UEFITool/QHexView/src/model/qhexcursor.cpp @@ -0,0 +1,182 @@ +#include <QHexView/model/qhexcursor.h> +#include <QHexView/model/qhexdocument.h> +#include <QHexView/qhexview.h> + +/* + * https://stackoverflow.com/questions/10803043/inverse-column-row-major-order-transformation + * + * If the index is calculated as: + * offset = row + column*NUMROWS + * then the inverse would be: + * row = offset % NUMROWS + * column = offset / NUMROWS + * where % is modulus, and / is integer division. + */ + +QHexCursor::QHexCursor(const QHexOptions* options, QHexView* parent) + : QObject(parent), m_options(options) {} + +QHexView* QHexCursor::hexView() const { + return qobject_cast<QHexView*>(this->parent()); +} + +QHexCursor::Mode QHexCursor::mode() const { return m_mode; } +qint64 QHexCursor::offset() const { return this->positionToOffset(m_position); } + +qint64 QHexCursor::address() const { + return m_options->baseaddress + this->offset(); +} + +quint64 QHexCursor::lineAddress() const { + return m_options->baseaddress + (m_position.line * m_options->linelength); +} + +qint64 QHexCursor::selectionStartOffset() const { + return this->positionToOffset(this->selectionStart()); +} + +qint64 QHexCursor::selectionEndOffset() const { + return this->positionToOffset(this->selectionEnd()); +} + +qint64 QHexCursor::line() const { return m_position.line; } +qint64 QHexCursor::column() const { return m_position.column; } + +QHexPosition QHexCursor::selectionStart() const { + if(m_position.line < m_selection.line) + return m_position; + + if(m_position.line == m_selection.line) { + if(m_position.column < m_selection.column) + return m_position; + } + + return m_selection; +} + +QHexPosition QHexCursor::selectionEnd() const { + if(m_position.line > m_selection.line) + return m_position; + + if(m_position.line == m_selection.line) { + if(m_position.column > m_selection.column) + return m_position; + } + + return m_selection; +} + +qint64 QHexCursor::selectionLength() const { + auto selstart = this->selectionStartOffset(), + selend = this->selectionEndOffset(); + return selstart == selend ? 0 : selend - selstart + 1; +} + +QHexPosition QHexCursor::position() const { return m_position; } + +QByteArray QHexCursor::selectedBytes() const { + return this->hexView()->selectedBytes(); +} + +bool QHexCursor::hasSelection() const { return m_position != m_selection; } + +bool QHexCursor::isSelected(qint64 line, qint64 column) const { + if(!this->hasSelection()) + return false; + + auto selstart = this->selectionStart(), selend = this->selectionEnd(); + if(line > selstart.line && line < selend.line) + return true; + if(line == selstart.line && line == selend.line) + return column >= selstart.column && column <= selend.column; + if(line == selstart.line) + return column >= selstart.column; + if(line == selend.line) + return column <= selend.column; + return false; +} + +void QHexCursor::setMode(Mode m) { + if(m_mode == m) + return; + m_mode = m; + Q_EMIT modeChanged(); +} + +void QHexCursor::switchMode() { + switch(m_mode) { + case Mode::Insert: this->setMode(Mode::Overwrite); break; + case Mode::Overwrite: this->setMode(Mode::Insert); break; + } +} + +void QHexCursor::move(qint64 offset) { + this->move(this->offsetToPosition(offset)); +} + +void QHexCursor::move(qint64 line, qint64 column) { + return this->move({line, column}); +} + +void QHexCursor::move(QHexPosition pos) { + if(pos.line >= 0) + m_selection.line = pos.line; + if(pos.column >= 0) + m_selection.column = pos.column; + this->select(pos); +} + +void QHexCursor::select(qint64 offset) { + this->select(this->offsetToPosition(offset)); +} + +void QHexCursor::select(qint64 line, qint64 column) { + this->select({line, column}); +} + +void QHexCursor::select(QHexPosition pos) { + if(pos.line >= 0) + m_position.line = pos.line; + if(pos.column >= 0) + m_position.column = pos.column; + Q_EMIT positionChanged(); +} + +void QHexCursor::selectSize(qint64 length) { + if(length > 0) + length--; + else if(length < 0) + length++; + if(length) + this->select(this->offset() + length); +} + +qint64 QHexCursor::replace(const QVariant& oldvalue, const QVariant& newvalue, + qint64 offset, QHexFindMode mode, + unsigned int options, QHexFindDirection fd) const { + return this->hexView()->replace(oldvalue, newvalue, offset, mode, options, + fd); +} +qint64 QHexCursor::find(const QVariant& value, qint64 offset, QHexFindMode mode, + unsigned int options, QHexFindDirection fd) const { + return this->hexView()->find(value, offset, mode, options, fd); +} + +void QHexCursor::cut(bool hex) { this->hexView()->cut(hex); } +void QHexCursor::copy(bool hex) const { this->hexView()->copy(hex); } +void QHexCursor::paste(bool hex) { this->hexView()->paste(hex); } +void QHexCursor::selectAll() { this->hexView()->selectAll(); } +void QHexCursor::removeSelection() { this->hexView()->removeSelection(); } + +void QHexCursor::clearSelection() { + m_position = m_selection; + Q_EMIT positionChanged(); +} + +qint64 QHexCursor::positionToOffset(QHexPosition pos) const { + return QHexUtils::positionToOffset(m_options, pos); +} + +QHexPosition QHexCursor::offsetToPosition(qint64 offset) const { + return QHexUtils::offsetToPosition(m_options, offset); +} diff --git a/UEFITool/qhexview5/model/qhexdelegate.cpp b/UEFITool/QHexView/src/model/qhexdelegate.cpp similarity index 60% rename from UEFITool/qhexview5/model/qhexdelegate.cpp rename to UEFITool/QHexView/src/model/qhexdelegate.cpp index 62114e8..fe2a1d0 100644 --- a/UEFITool/qhexview5/model/qhexdelegate.cpp +++ b/UEFITool/QHexView/src/model/qhexdelegate.cpp @@ -1,50 +1,48 @@ -#include "../qhexview.h" -#include "qhexdelegate.h" +#include <QHexView/model/qhexdelegate.h> +#include <QHexView/qhexview.h> -QHexDelegate::QHexDelegate(QObject* parent): QObject{parent} { } +QHexDelegate::QHexDelegate(QObject* parent): QObject{parent} {} -QString QHexDelegate::addressHeader(const QHexView* hexview) const -{ +QString QHexDelegate::addressHeader(const QHexView* hexview) const { Q_UNUSED(hexview); return QString(); } -QString QHexDelegate::hexHeader(const QHexView* hexview) const -{ +QString QHexDelegate::hexHeader(const QHexView* hexview) const { Q_UNUSED(hexview); return QString(); } -QString QHexDelegate::asciiHeader(const QHexView* hexview) const -{ +QString QHexDelegate::asciiHeader(const QHexView* hexview) const { Q_UNUSED(hexview); return QString(); } -void QHexDelegate::renderAddress(quint64 address, QTextCharFormat& cf, const QHexView* hexview) const -{ +void QHexDelegate::renderAddress(quint64 address, QTextCharFormat& cf, + const QHexView* hexview) const { Q_UNUSED(address); Q_UNUSED(hexview); Q_UNUSED(cf); Q_UNUSED(hexview); } -void QHexDelegate::renderHeader(QTextBlockFormat& bf, const QHexView* hexview) const -{ +void QHexDelegate::renderHeader(QTextBlockFormat& bf, + const QHexView* hexview) const { Q_UNUSED(bf); Q_UNUSED(hexview); } -void QHexDelegate::renderHeaderPart(const QString& s, QHexArea area, QTextCharFormat& cf, const QHexView* hexview) const -{ +void QHexDelegate::renderHeaderPart(const QString& s, QHexArea area, + QTextCharFormat& cf, + const QHexView* hexview) const { Q_UNUSED(s); Q_UNUSED(area); Q_UNUSED(cf); Q_UNUSED(hexview); } -bool QHexDelegate::render(quint64 offset, quint8 b, QTextCharFormat& outcf, const QHexView* hexview) const -{ +bool QHexDelegate::render(quint64 offset, quint8 b, QTextCharFormat& outcf, + const QHexView* hexview) const { Q_UNUSED(offset); Q_UNUSED(b); Q_UNUSED(outcf); @@ -53,16 +51,15 @@ bool QHexDelegate::render(quint64 offset, quint8 b, QTextCharFormat& outcf, cons return false; } -bool QHexDelegate::paintSeparator(QPainter* painter, QLineF line, const QHexView* hexview) const -{ +bool QHexDelegate::paintSeparator(QPainter* painter, QLineF line, + const QHexView* hexview) const { Q_UNUSED(painter); Q_UNUSED(line); Q_UNUSED(hexview); return false; } -void QHexDelegate::paint(QPainter* painter, const QHexView* hexview) const -{ +void QHexDelegate::paint(QPainter* painter, const QHexView* hexview) const { Q_UNUSED(hexview); hexview->paint(painter); } diff --git a/UEFITool/QHexView/src/model/qhexdocument.cpp b/UEFITool/QHexView/src/model/qhexdocument.cpp new file mode 100644 index 0000000..0933b6b --- /dev/null +++ b/UEFITool/QHexView/src/model/qhexdocument.cpp @@ -0,0 +1,142 @@ +#include <QBuffer> +#include <QFile> +#include <QHexView/model/buffer/qdevicebuffer.h> +#include <QHexView/model/buffer/qmappedfilebuffer.h> +#include <QHexView/model/buffer/qmemorybuffer.h> +#include <QHexView/model/commands/insertcommand.h> +#include <QHexView/model/commands/removecommand.h> +#include <QHexView/model/commands/replacecommand.h> +#include <QHexView/model/qhexdocument.h> +#include <cmath> + +QHexDocument::QHexDocument(QHexBuffer* buffer, QObject* parent) + : QObject(parent) { + m_buffer = buffer; + m_buffer->setParent(this); // Take Ownership + + connect(&m_undostack, &QUndoStack::canUndoChanged, this, + &QHexDocument::canUndoChanged); + connect(&m_undostack, &QUndoStack::canRedoChanged, this, + &QHexDocument::canRedoChanged); + connect(&m_undostack, &QUndoStack::cleanChanged, this, + [&](bool clean) { Q_EMIT modifiedChanged(!clean); }); +} + +qint64 QHexDocument::indexOf(const QByteArray& ba, qint64 from) { + return m_buffer->indexOf(ba, from); +} + +qint64 QHexDocument::lastIndexOf(const QByteArray& ba, qint64 from) { + return m_buffer->lastIndexOf(ba, from); +} + +bool QHexDocument::accept(qint64 idx) const { return m_buffer->accept(idx); } +bool QHexDocument::isEmpty() const { return m_buffer->isEmpty(); } +bool QHexDocument::isModified() const { return !m_undostack.isClean(); } +bool QHexDocument::canUndo() const { return m_undostack.canUndo(); } +bool QHexDocument::canRedo() const { return m_undostack.canRedo(); } + +void QHexDocument::setData(const QByteArray& ba) { + QHexBuffer* mb = new QMemoryBuffer(); + mb->read(ba); + this->setData(mb); +} + +void QHexDocument::setData(QHexBuffer* buffer) { + if(!buffer) + return; + + m_undostack.clear(); + buffer->setParent(this); + + auto* oldbuffer = m_buffer; + m_buffer = buffer; + if(oldbuffer) + oldbuffer->deleteLater(); + + Q_EMIT canUndoChanged(false); + Q_EMIT canRedoChanged(false); + Q_EMIT changed(); + Q_EMIT reset(); +} + +void QHexDocument::clearModified() { m_undostack.setClean(); } + +qint64 QHexDocument::length() const { + return m_buffer ? m_buffer->length() : 0; +} + +uchar QHexDocument::at(int offset) const { return m_buffer->at(offset); } + +QHexDocument* QHexDocument::fromFile(QString filename, QObject* parent) { + QFile f(filename); + f.open(QFile::ReadOnly); + return QHexDocument::fromMemory<QMemoryBuffer>(f.readAll(), parent); +} + +void QHexDocument::undo() { + m_undostack.undo(); + Q_EMIT changed(); +} + +void QHexDocument::redo() { + m_undostack.redo(); + Q_EMIT changed(); +} + +void QHexDocument::insert(qint64 offset, uchar b) { + this->insert(offset, QByteArray(1, b)); +} + +void QHexDocument::replace(qint64 offset, uchar b) { + this->replace(offset, QByteArray(1, b)); +} + +void QHexDocument::insert(qint64 offset, const QByteArray& data) { + m_undostack.push(new InsertCommand(m_buffer, this, offset, data)); + + Q_EMIT changed(); + Q_EMIT dataChanged(data, offset, ChangeReason::Insert); +} + +void QHexDocument::replace(qint64 offset, const QByteArray& data) { + m_undostack.push(new ReplaceCommand(m_buffer, this, offset, data)); + Q_EMIT changed(); + Q_EMIT dataChanged(data, offset, ChangeReason::Replace); +} + +void QHexDocument::remove(qint64 offset, int len) { + QByteArray data = m_buffer->read(offset, len); + + m_undostack.push(new RemoveCommand(m_buffer, this, offset, len)); + Q_EMIT changed(); + Q_EMIT dataChanged(data, offset, ChangeReason::Remove); +} + +QByteArray QHexDocument::read(qint64 offset, int len) const { + return m_buffer->read(offset, len); +} + +bool QHexDocument::saveTo(QIODevice* device) { + if(!device->isWritable()) + return false; + m_buffer->write(device); + return true; +} + +QHexDocument* QHexDocument::fromBuffer(QHexBuffer* buffer, QObject* parent) { + return new QHexDocument(buffer, parent); +} + +QHexDocument* QHexDocument::fromLargeFile(QString filename, QObject* parent) { + return QHexDocument::fromDevice<QDeviceBuffer>(new QFile(filename), parent); +} + +QHexDocument* QHexDocument::fromMappedFile(QString filename, QObject* parent) { + return QHexDocument::fromDevice<QMappedFileBuffer>(new QFile(filename), + parent); +} + +QHexDocument* QHexDocument::create(QObject* parent) { + return QHexDocument::fromMemory<QMemoryBuffer>({}, parent); +} diff --git a/UEFITool/qhexview5/model/qhexmetadata.cpp b/UEFITool/QHexView/src/model/qhexmetadata.cpp similarity index 56% rename from UEFITool/qhexview5/model/qhexmetadata.cpp rename to UEFITool/QHexView/src/model/qhexmetadata.cpp index a65f95a..8fa4864 100644 --- a/UEFITool/qhexview5/model/qhexmetadata.cpp +++ b/UEFITool/QHexView/src/model/qhexmetadata.cpp @@ -1,44 +1,44 @@ -#include "qhexmetadata.h" -#include "qhexcursor.h" +#include <QHexView/model/qhexcursor.h> +#include <QHexView/model/qhexmetadata.h> -QHexMetadata::QHexMetadata(const QHexOptions* options, QObject *parent) : QObject(parent), m_options(options) { } +QHexMetadata::QHexMetadata(const QHexOptions* options, QObject* parent) + : QObject(parent), m_options(options) {} -const QHexMetadataLine* QHexMetadata::find(qint64 line) const -{ +const QHexMetadataLine* QHexMetadata::find(qint64 line) const { auto it = m_metadata.find(line); return it != m_metadata.end() ? std::addressof(it.value()) : nullptr; } -QString QHexMetadata::getComment(qint64 line, qint64 column) const -{ +QString QHexMetadata::getComment(qint64 line, qint64 column) const { auto* metadataline = this->find(line); - if(!metadataline) return QString(); + if(!metadataline) + return QString(); auto offset = QHexUtils::positionToOffset(m_options, {line, column}); QStringList comments; - for(auto& mi : *metadataline) - { - if((offset < mi.begin || offset > mi.end) || mi.comment.isEmpty()) continue; + for(auto& mi : *metadataline) { + if((offset < mi.begin || offset > mi.end) || mi.comment.isEmpty()) + continue; comments.push_back(mi.comment); } return comments.join("\n"); } -void QHexMetadata::removeMetadata(qint64 line) -{ +void QHexMetadata::removeMetadata(qint64 line) { auto it = m_metadata.find(line); - if(it == m_metadata.end()) return; + if(it == m_metadata.end()) + return; m_metadata.erase(it); Q_EMIT changed(); } -void QHexMetadata::removeBackground(qint64 line) -{ +void QHexMetadata::removeBackground(qint64 line) { this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool { - if(!mi.background.isValid()) return false; + if(!mi.background.isValid()) + return false; if(mi.foreground.isValid() || !mi.comment.isEmpty()) { mi.background = QColor(); @@ -49,10 +49,10 @@ void QHexMetadata::removeBackground(qint64 line) }); } -void QHexMetadata::removeForeground(qint64 line) -{ +void QHexMetadata::removeForeground(qint64 line) { this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool { - if(!mi.foreground.isValid()) return false; + if(!mi.foreground.isValid()) + return false; if(mi.background.isValid() || !mi.comment.isEmpty()) { mi.foreground = QColor(); @@ -63,10 +63,10 @@ void QHexMetadata::removeForeground(qint64 line) }); } -void QHexMetadata::removeComments(qint64 line) -{ +void QHexMetadata::removeComments(qint64 line) { this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool { - if(mi.comment.isEmpty()) return false; + if(mi.comment.isEmpty()) + return false; if(mi.foreground.isValid() || mi.background.isValid()) { mi.comment.clear(); @@ -77,10 +77,10 @@ void QHexMetadata::removeComments(qint64 line) }); } -void QHexMetadata::unhighlight(qint64 line) -{ +void QHexMetadata::unhighlight(qint64 line) { this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool { - if(!mi.foreground.isValid() && !mi.background.isValid()) return false; + if(!mi.foreground.isValid() && !mi.background.isValid()) + return false; if(!mi.comment.isEmpty()) { mi.foreground = QColor(); @@ -92,54 +92,63 @@ void QHexMetadata::unhighlight(qint64 line) }); } -void QHexMetadata::clear() { m_metadata.clear(); Q_EMIT changed(); } -void QHexMetadata::copy(const QHexMetadata* metadata) { m_metadata = metadata->m_metadata; } +void QHexMetadata::clear() { + m_metadata.clear(); + Q_EMIT changed(); +} -void QHexMetadata::clearMetadata(qint64 line, ClearMetadataCallback&& cb) -{ +void QHexMetadata::copy(const QHexMetadata* metadata) { + m_metadata = metadata->m_metadata; +} + +void QHexMetadata::clearMetadata(qint64 line, ClearMetadataCallback&& cb) { auto iit = m_metadata.find(line); - if(iit == m_metadata.end()) return; + if(iit == m_metadata.end()) + return; auto oldsize = iit->size(); - for(auto it = iit->begin(); it != iit->end(); ) - { - if(cb(*it)) it = iit->erase(it); - else it++; + for(auto it = iit->begin(); it != iit->end();) { + if(cb(*it)) + it = iit->erase(it); + else + it++; } - if(iit->empty()) - { + if(iit->empty()) { this->removeMetadata(line); return; } - if(oldsize != iit->size()) Q_EMIT changed(); + if(oldsize != iit->size()) + Q_EMIT changed(); } -void QHexMetadata::setMetadata(const QHexMetadataItem& mi) -{ - if(!m_options->linelength) return; +void QHexMetadata::setMetadata(const QHexMetadataItem& mi) { + if(!m_options->linelength) + return; const qint64 firstline = mi.begin / m_options->linelength; const qint64 lastline = mi.end / m_options->linelength; bool notify = false; - for(auto line = firstline; line <= lastline; line++) - { + for(auto line = firstline; line <= lastline; line++) { auto start = line == firstline ? mi.begin % m_options->linelength : 0; - auto length = line == lastline ? (mi.end % m_options->linelength) - start : m_options->linelength; - if(length <= 0) continue; + auto length = line == lastline + ? (mi.end % m_options->linelength) - start + : m_options->linelength; + if(length <= 0) + continue; notify = true; m_metadata[line].push_back(mi); } - if(notify) Q_EMIT changed(); + if(notify) + Q_EMIT changed(); } -void QHexMetadata::invalidate() -{ +void QHexMetadata::invalidate() { auto oldmetadata = m_metadata; m_metadata.clear(); diff --git a/UEFITool/QHexView/src/model/qhexutils.cpp b/UEFITool/QHexView/src/model/qhexutils.cpp new file mode 100644 index 0000000..13350ba --- /dev/null +++ b/UEFITool/QHexView/src/model/qhexutils.cpp @@ -0,0 +1,384 @@ +#include <QDataStream> +#include <QGlobalStatic> +#include <QHash> +#include <QHexView/model/qhexoptions.h> +#include <QHexView/model/qhexutils.h> +#include <QHexView/qhexview.h> +#include <QList> +#include <QtEndian> +#include <limits> + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#define QHEXVIEW_VARIANT_EQ(x, t) ((x).metaType().id() == QMetaType::Q##t) +#else +#define QHEXVIEW_VARIANT_EQ(x, t) ((x).type() == QVariant::t) +#endif + +#if defined(_WIN32) && _MSC_VER <= 1916 // v141_xp +#include <ctype.h> +namespace std { +using ::tolower; +} +#else +#include <cctype> +#endif + +namespace QHexUtils { + +Q_GLOBAL_STATIC_WITH_ARGS(QList<char>, HEXMAP, + ({'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'})); + +bool isHex(char ch) { + return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f'); +} + +namespace PatternUtils { + +Q_GLOBAL_STATIC_WITH_ARGS(QString, WILDCARD_BYTE, ("??")) + +bool check(QString& p, qint64& len) { + static QHash<QString, QPair<QString, size_t>> + processed; // Cache processed patterns + + auto it = processed.find(p); + + if(it != processed.end()) { + p = it.value().first; + len = it.value().second; + return true; + } + + QString op = p; // Store unprocessed pattern + p = p.simplified().replace(" ", ""); + if(p.isEmpty() || (p.size() % 2)) + return false; + + int wccount = 0; + + for(auto i = 0; i < p.size() - 2; i += 2) { + const auto& hexb = p.mid(i, 2); + + if(hexb == *WILDCARD_BYTE) { + wccount++; + continue; + } + + if(!QHexUtils::isHex(hexb.at(0).toLatin1()) || + !QHexUtils::isHex(hexb.at(1).toLatin1())) + return false; + } + + if(wccount >= p.size()) + return false; + len = p.size() / 2; + processed[op] = qMakePair(p, len); // Cache processed pattern + return true; +} + +bool match(const QByteArray& data, const QString& pattern) { + for(qint64 i = 0, idx = 0; (i <= (pattern.size() - 2)); i += 2, idx++) { + if(idx >= data.size()) + return false; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + QStringView hexb = QStringView{pattern}.mid(i, 2); +#else + const QStringRef& hexb = pattern.midRef(i, 2); +#endif + + if(hexb == *WILDCARD_BYTE) + continue; + + bool ok = false; + auto b = static_cast<char>(hexb.toUInt(&ok, 16)); + if(!ok || (b != data.at(idx))) + return false; + } + + return true; +} + +} // namespace PatternUtils + +namespace { + +unsigned int countBits(uint val) { + if(val <= std::numeric_limits<quint8>::max()) + return QHexFindOptions::Int8; + if(val <= std::numeric_limits<quint16>::max()) + return QHexFindOptions::Int16; + if(val <= std::numeric_limits<quint32>::max()) + return QHexFindOptions::Int32; + + return QHexFindOptions::Int64; +} + +template<typename Function> +qint64 findIter(qint64 startoffset, QHexFindDirection fd, + const QHexView* hexview, Function&& f) { + QHexDocument* hexdocument = hexview->hexDocument(); + qint64 offset = -1; + + QHexFindDirection cfd = fd; + if(cfd == QHexFindDirection::All) + cfd = QHexFindDirection::Forward; + + qint64 i = startoffset; + + bool restartLoopOnce = true; + + while(offset == -1 && + (cfd == QHexFindDirection::Backward ? (i >= 0) + : (i < hexdocument->length()))) { + if(!f(i, offset)) + break; + + if(cfd == QHexFindDirection::Backward) + i--; + else + i++; + + if(fd == QHexFindDirection::All && i >= hexdocument->length() && + restartLoopOnce) { + i = 0; + restartLoopOnce = false; + } + } + + return offset; +} + +qint64 findDefault(const QByteArray& value, qint64 startoffset, + const QHexView* hexview, unsigned int options, + QHexFindDirection fd) { + QHexDocument* hexdocument = hexview->hexDocument(); + if(value.size() > hexdocument->length()) + return -1; + + return findIter( + startoffset, fd, hexview, + [options, value, hexdocument](qint64 idx, qint64& offset) -> bool { + for(auto i = 0; i < value.size(); i++) { + qint64 curroffset = idx + i; + + if(curroffset >= hexdocument->length()) { + offset = -1; + return false; + } + + uchar ch1 = hexdocument->at(curroffset); + uchar ch2 = value.at(i); + + if(!(options & QHexFindOptions::CaseSensitive)) { + ch1 = std::tolower(ch1); + ch2 = std::tolower(ch2); + } + + if(ch1 != ch2) + break; + if(i == value.size() - 1) + offset = idx; + } + + return true; + }); +} + +qint64 findWildcard(QString pattern, qint64 startoffset, + const QHexView* hexview, QHexFindDirection fd, + qint64& patternlen) { + QHexDocument* hexdocument = hexview->hexDocument(); + if(!PatternUtils::check(pattern, patternlen) || + (patternlen >= hexdocument->length())) + return -1; + + return findIter( + startoffset, fd, hexview, + [hexdocument, pattern, patternlen](qint64 idx, qint64& offset) -> bool { + if(PatternUtils::match(hexdocument->read(idx, patternlen), pattern)) + offset = idx; + return true; + }); +} + +QByteArray variantToByteArray(QVariant value, QHexFindMode mode, + unsigned int options) { + QByteArray v; + + switch(mode) { + case QHexFindMode::Text: + if(QHEXVIEW_VARIANT_EQ(value, String)) + v = value.toString().toUtf8(); + else if(QHEXVIEW_VARIANT_EQ(value, ByteArray)) + v = value.toByteArray(); + break; + + case QHexFindMode::Hex: { + if(QHEXVIEW_VARIANT_EQ(value, String)) { + qint64 len = 0; + auto s = value.toString(); + if(!PatternUtils::check(s, len)) + return {}; + + bool ok = true; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + for(auto i = 0; ok && i < s.size(); i += 2) + v.push_back(static_cast<char>( + QStringView{s}.mid(i, 2).toUInt(&ok, 16))); +#else + for(auto i = 0; ok && i < s.size(); i += 2) + v.push_back( + static_cast<char>(s.midRef(i, 2).toUInt(&ok, 16))); +#endif + + if(!ok) + return {}; + } + else if(QHEXVIEW_VARIANT_EQ(value, ByteArray)) + v = value.toByteArray(); + break; + } + + case QHexFindMode::Int: { + bool ok = false; + uint val = value.toUInt(&ok); + if(!ok) + return QByteArray{}; + + QDataStream ds(&v, QIODevice::WriteOnly); + + if(options & QHexFindOptions::BigEndian) { + if(options & QHexFindOptions::Int8) + ds << qToBigEndian<quint8>(val); + else if(options & QHexFindOptions::Int16) + ds << qToBigEndian<quint16>(val); + else if(options & QHexFindOptions::Int32) + ds << qToBigEndian<quint32>(val); + else if(options & QHexFindOptions::Int64) + ds << qToBigEndian<quint64>(val); + else + return variantToByteArray(value, mode, + options | countBits(val)); + } + else { + if(options & QHexFindOptions::Int8) + ds << static_cast<quint8>(val); + else if(options & QHexFindOptions::Int16) + ds << static_cast<quint16>(val); + else if(options & QHexFindOptions::Int32) + ds << static_cast<quint32>(val); + else if(options & QHexFindOptions::Int64) + ds << static_cast<quint64>(val); + else + return variantToByteArray(value, mode, + options | countBits(val)); + } + + break; + } + + case QHexFindMode::Float: { + bool ok = false; + QDataStream ds(&v, QIODevice::WriteOnly); + if(options & QHexFindOptions::Float) + ds << value.toFloat(&ok); + else if(options & QHexFindOptions::Double) + ds << value.toDouble(&ok); + if(!ok) + return {}; + } + + default: break; + } + + return v; +} + +} // namespace + +QByteArray toHex(const QByteArray& ba, char sep) { + if(ba.isEmpty()) { + return QByteArray(); + } + + QByteArray hex(sep ? (ba.size() * 3 - 1) : (ba.size() * 2), + Qt::Uninitialized); + + for(auto i = 0, o = 0; i < ba.size(); i++) { + if(sep && i) + hex[o++] = static_cast<uchar>(sep); + hex[o++] = HEXMAP->at((ba.at(i) & 0xf0) >> 4); + hex[o++] = HEXMAP->at(ba.at(i) & 0x0f); + } + + return hex; +} + +QByteArray toHex(const QByteArray& ba) { return QHexUtils::toHex(ba, '\0'); } +qint64 positionToOffset(const QHexOptions* options, QHexPosition pos) { + return options->linelength * pos.line + pos.column; +} +QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset) { + return {offset / options->linelength, offset % options->linelength}; +} + +QPair<qint64, qint64> find(const QHexView* hexview, QVariant value, + qint64 startoffset, QHexFindMode mode, + unsigned int options, QHexFindDirection fd) { + qint64 offset = -1, size = 0; + if(startoffset == -1) + startoffset = static_cast<qint64>(hexview->offset()); + + if(mode == QHexFindMode::Hex && QHEXVIEW_VARIANT_EQ(value, String)) { + offset = QHexUtils::findWildcard(value.toString(), startoffset, hexview, + fd, size); + } + else { + auto ba = variantToByteArray(value, mode, options); + + if(!ba.isEmpty()) { + offset = + QHexUtils::findDefault(ba, startoffset, hexview, options, fd); + size = ba.size(); + } + else + offset = -1; + } + + return {offset, offset > -1 ? size : 0}; +} + +bool checkPattern(QString pattern) { + qint64 len = 0; + return PatternUtils::check(pattern, len); +} + +QPair<qint64, qint64> replace(const QHexView* hexview, QVariant oldvalue, + QVariant newvalue, qint64 startoffset, + QHexFindMode mode, unsigned int options, + QHexFindDirection fd) { + auto res = + QHexUtils::find(hexview, oldvalue, startoffset, mode, options, fd); + + if(res.first != -1 && res.second > 0) { + QHexDocument* hexdocument = hexview->hexDocument(); + auto ba = variantToByteArray(newvalue, mode, options); + + if(!ba.isEmpty()) { + hexdocument->remove(res.first, res.second); + hexdocument->insert(res.first, ba); + res.second = ba.size(); + } + else { + res.first = -1; + res.second = 0; + } + } + + return res; +} + +} // namespace QHexUtils diff --git a/UEFITool/QHexView/src/qhexview.cpp b/UEFITool/QHexView/src/qhexview.cpp new file mode 100644 index 0000000..334ccef --- /dev/null +++ b/UEFITool/QHexView/src/qhexview.cpp @@ -0,0 +1,1582 @@ +#include <QApplication> +#include <QClipboard> +#include <QFontDatabase> +#include <QHexView/model/buffer/qmemorybuffer.h> +#include <QHexView/model/qhexcursor.h> +#include <QHexView/model/qhexutils.h> +#include <QHexView/qhexview.h> +#include <QMouseEvent> +#include <QPainter> +#include <QPalette> +#include <QScrollBar> +#include <QTextCursor> +#include <QTextDocument> +#include <QToolTip> +#include <QWheelEvent> +#include <QtGlobal> +#include <QtMath> +#include <limits> + +#if defined(QHEXVIEW_ENABLE_DIALOGS) +#include <QHexView/dialogs/hexfinddialog.h> +#endif + +#if defined(QHEXVIEW_DEBUG) +#include <QDebug> +#define qhexview_fmtprint(fmt, ...) qDebug("%s " fmt, __func__, __VA_ARGS__) +#else +#define qhexview_fmtprint(fmt, ...) +#endif + +QHexView::QHexView(QWidget* parent) + : QAbstractScrollArea(parent), m_fontmetrics(this->font()) { + QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont); + + if(f.styleHint() != QFont::TypeWriter) { + f.setFamily("Monospace"); // Force Monospaced font + f.setStyleHint(QFont::TypeWriter); + } + + this->setFont(f); + this->setMouseTracking(true); + this->setFocusPolicy(Qt::StrongFocus); + this->viewport()->setCursor(Qt::IBeamCursor); + + QPalette p = this->palette(); + p.setBrush(QPalette::Window, p.base()); + + connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, + [=](int) { this->viewport()->update(); }); + + m_hexmetadata = new QHexMetadata(&m_options, this); + connect(m_hexmetadata, &QHexMetadata::changed, this, + [=]() { this->viewport()->update(); }); + + m_hexcursor = new QHexCursor(&m_options, this); + this->setDocument( + QHexDocument::fromMemory<QMemoryBuffer>(QByteArray(), this)); + this->checkState(); + + connect(m_hexcursor, &QHexCursor::positionChanged, this, [=]() { + m_writing = false; + this->ensureVisible(); + Q_EMIT positionChanged(); + }); + + connect(m_hexcursor, &QHexCursor::modeChanged, this, [=]() { + m_writing = false; + this->viewport()->update(); + Q_EMIT modeChanged(); + }); +} + +QRectF QHexView::headerRect() const { + if(m_options.hasFlag(QHexFlags::NoHeader)) + return QRectF(); + + return QRectF(0, 0, this->endColumnX(), this->lineHeight()); +} + +QRectF QHexView::addressRect() const { + qreal y = m_options.hasFlag(QHexFlags::NoHeader) ? 0 : this->lineHeight(); + + return QRectF(0, y, this->endColumnX(), this->height() - y); +} + +QRectF QHexView::hexRect() const { + qreal y = m_options.hasFlag(QHexFlags::NoHeader) ? 0 : this->lineHeight(); + + return QRectF(this->hexColumnX(), y, + this->asciiColumnX() - this->hexColumnX(), + this->height() - y); +} + +QRectF QHexView::asciiRect() const { + qreal y = m_options.hasFlag(QHexFlags::NoHeader) ? 0 : this->lineHeight(); + + return QRectF(this->asciiColumnX(), y, + this->endColumnX() - this->asciiColumnX(), + this->height() - y); +} + +QHexDocument* QHexView::hexDocument() const { return m_hexdocument; } +QHexCursor* QHexView::hexCursor() const { + return m_hexdocument ? m_hexcursor : nullptr; +} +const QHexMetadata* QHexView::hexMetadata() const { return m_hexmetadata; } +QHexOptions QHexView::options() const { return m_options; } + +void QHexView::setOptions(const QHexOptions& options) { + auto oldlinelength = m_options.linelength; + m_options = options; + + if(oldlinelength != m_options.linelength) + m_hexmetadata->invalidate(); + + this->checkAndUpdate(); +} + +void QHexView::setBaseAddress(quint64 baseaddress) { + if(m_options.baseaddress == baseaddress) + return; + + m_options.baseaddress = baseaddress; + this->checkAndUpdate(); +} + +void QHexView::setDelegate(QHexDelegate* rd) { + if(m_hexdelegate == rd) + return; + m_hexdelegate = rd; + this->checkAndUpdate(); +} + +void QHexView::setDocument(QHexDocument* doc) { + if(!doc) + doc = QHexDocument::fromMemory<QMemoryBuffer>(QByteArray(), this); + if(!doc->parent()) + doc->setParent(this); + + m_writing = false; + m_hexmetadata->clear(); + m_hexcursor->move(0); + + if(m_hexdocument) { + disconnect(m_hexdocument, &QHexDocument::changed, this, nullptr); + disconnect(m_hexdocument, &QHexDocument::dataChanged, this, nullptr); + disconnect(m_hexdocument, &QHexDocument::reset, this, nullptr); + disconnect(m_hexdocument, &QHexDocument::modifiedChanged, this, + nullptr); + } + + m_hexdocument = doc; + + connect(m_hexdocument, &QHexDocument::reset, this, [=]() { + m_writing = false; + m_hexcursor->move(0); + this->checkAndUpdate(true); + }); + + connect(m_hexdocument, &QHexDocument::dataChanged, this, + &QHexView::dataChanged); + + connect(m_hexdocument, &QHexDocument::modifiedChanged, this, + &QHexView::modifiedChanged); + + connect(m_hexdocument, &QHexDocument::changed, this, + [=]() { this->checkAndUpdate(true); }); + + this->checkAndUpdate(true); +} + +void QHexView::setData(const QByteArray& ba) { m_hexdocument->setData(ba); } +void QHexView::setData(QHexBuffer* buffer) { m_hexdocument->setData(buffer); } + +void QHexView::setCursorMode(QHexCursor::Mode mode) { + m_hexcursor->setMode(mode); +} + +void QHexView::setByteColor(quint8 b, QHexColor c) { + m_options.bytecolors[b] = c; + this->checkAndUpdate(); +} + +void QHexView::setByteForeground(quint8 b, QColor c) { + m_options.bytecolors[b].foreground = c; + this->checkAndUpdate(); +} + +void QHexView::setByteBackground(quint8 b, QColor c) { + m_options.bytecolors[b].background = c; + this->checkAndUpdate(); +} + +void QHexView::setMetadata(qint64 begin, qint64 end, const QColor& fgcolor, + const QColor& bgcolor, const QString& comment) { + m_hexmetadata->setMetadata(begin, end, fgcolor, bgcolor, comment); +} +void QHexView::setForeground(qint64 begin, qint64 end, const QColor& fgcolor) { + m_hexmetadata->setForeground(begin, end, fgcolor); +} +void QHexView::setBackground(qint64 begin, qint64 end, const QColor& bgcolor) { + m_hexmetadata->setBackground(begin, end, bgcolor); +} +void QHexView::setComment(qint64 begin, qint64 end, const QString& comment) { + m_hexmetadata->setComment(begin, end, comment); +} +void QHexView::setMetadataSize(qint64 begin, qint64 length, + const QColor& fgcolor, const QColor& bgcolor, + const QString& comment) { + m_hexmetadata->setMetadataSize(begin, length, fgcolor, bgcolor, comment); +} +void QHexView::setForegroundSize(qint64 begin, qint64 length, + const QColor& fgcolor) { + m_hexmetadata->setForegroundSize(begin, length, fgcolor); +} +void QHexView::setBackgroundSize(qint64 begin, qint64 length, + const QColor& bgcolor) { + m_hexmetadata->setBackgroundSize(begin, length, bgcolor); +} +void QHexView::setCommentSize(qint64 begin, qint64 length, + const QString& comment) { + m_hexmetadata->setCommentSize(begin, length, comment); +} +void QHexView::removeMetadata(qint64 line) { + m_hexmetadata->removeMetadata(line); +} +void QHexView::removeBackground(qint64 line) { + m_hexmetadata->removeBackground(line); +} +void QHexView::removeForeground(qint64 line) { + m_hexmetadata->removeForeground(line); +} +void QHexView::removeComments(qint64 line) { + m_hexmetadata->removeComments(line); +} +void QHexView::unhighlight(qint64 line) { m_hexmetadata->unhighlight(line); } +void QHexView::clearMetadata() { m_hexmetadata->clear(); } + +#if defined(QHEXVIEW_ENABLE_DIALOGS) +void QHexView::showFind() { + if(!m_hexdlgfind) + m_hexdlgfind = new HexFindDialog(HexFindDialog::Type::Find, this); + m_hexdlgfind->show(); +} + +void QHexView::showReplace() { + if(!m_hexdlgreplace) + m_hexdlgreplace = new HexFindDialog(HexFindDialog::Type::Replace, this); + m_hexdlgreplace->show(); +} +#endif + +void QHexView::undo() { + if(m_hexdocument) + m_hexdocument->undo(); +} +void QHexView::redo() { + if(m_hexdocument) + m_hexdocument->redo(); +} + +void QHexView::cut(bool hex) { + this->copy(hex); + if(m_readonly) + return; + + if(m_hexcursor->hasSelection()) + this->removeSelection(); + else + m_hexdocument->remove(m_hexcursor->offset(), 1); +} + +void QHexView::copyAs(CopyMode mode) const { + QClipboard* c = qApp->clipboard(); + + QByteArray bytes = m_hexcursor->hasSelection() + ? m_hexcursor->selectedBytes() + : m_hexdocument->read(m_hexcursor->offset(), 1); + + switch(mode) { + case CopyMode::HexArrayCurly: + case CopyMode::HexArraySquare: { + QString hexchar; + int i = 0; + + for(char b : bytes) { + if(!hexchar.isEmpty()) { + hexchar += ", "; + if(m_options.copybreak && !(++i % m_options.linelength)) + hexchar += "\n"; + } + + hexchar += + "0x" + QString::number(static_cast<uint>(b), 16).toUpper(); + } + + c->setText( + QString(mode == CopyMode::HexArraySquare ? "[%1]" : "{%1}") + .arg(hexchar)); + break; + } + + case CopyMode::HexArrayChar: { + QString hexchar; + + for(char b : bytes) + hexchar += + "\\x" + QString::number(static_cast<uint>(b), 16).toUpper(); + + c->setText(QString("\"%1\"").arg(hexchar)); + break; + } + + default: { + QString hexchar; + + for(int i = 0; i < bytes.size(); i++) { + if(!(i % m_options.grouplength)) { + if(!hexchar.isEmpty()) { + hexchar += ", "; + if(m_options.copybreak && !(i % m_options.linelength)) + hexchar += "\n"; + } + + hexchar += "0x"; + } + + hexchar += QString("%1") + .arg(static_cast<uint>(bytes[i]), 2, 16, + QLatin1Char('0')) + .toUpper(); + } + + c->setText(hexchar); + break; + } + } +} + +void QHexView::copy(bool hex) const { + QClipboard* c = qApp->clipboard(); + + QByteArray bytes = m_hexcursor->hasSelection() + ? m_hexcursor->selectedBytes() + : m_hexdocument->read(m_hexcursor->offset(), 1); + + if(hex) + bytes = QHexUtils::toHex(bytes, ' ').toUpper(); + c->setText(bytes); +} + +void QHexView::paste(bool hex) { + if(m_readonly) + return; + + QClipboard* c = qApp->clipboard(); + QByteArray pastedata = c->text().toUtf8(); + if(pastedata.isEmpty()) + return; + + this->removeSelection(); + if(hex) + pastedata = QByteArray::fromHex(pastedata); + + if(m_hexcursor->mode() == QHexCursor::Mode::Insert) + m_hexdocument->insert(m_hexcursor->offset(), pastedata); + else + m_hexdocument->replace(m_hexcursor->offset(), pastedata); +} + +void QHexView::clearModified() { + if(m_hexdocument) + m_hexdocument->clearModified(); +} + +void QHexView::selectAll() { + m_hexcursor->move(0); + m_hexcursor->select(m_hexdocument->length()); +} + +void QHexView::removeSelection() { + if(!m_hexcursor->hasSelection()) + return; + if(!m_readonly) + m_hexdocument->remove(m_hexcursor->selectionStartOffset(), + m_hexcursor->selectionLength() - 1); + m_hexcursor->clearSelection(); +} + +void QHexView::switchMode() { m_hexcursor->switchMode(); } + +void QHexView::setAddressWidth(unsigned int w) { + if(w == m_options.addresswidth) + return; + m_options.addresswidth = w; + this->checkState(); +} + +void QHexView::setScrollSteps(int scrollsteps) { + m_options.scrollsteps = scrollsteps; +} + +void QHexView::setReadOnly(bool r) { m_readonly = r; } + +void QHexView::setAutoWidth(bool r) { + if(m_autowidth == r) + return; + m_autowidth = r; + this->checkState(); +} + +void QHexView::paint(QPainter* painter) const { + QTextDocument doc; + doc.setDocumentMargin(0); + doc.setUndoRedoEnabled(false); + doc.setDefaultFont(this->font()); + + QTextCursor c(&doc); + + this->drawHeader(c); + this->drawDocument(c); + + painter->translate(-this->horizontalScrollBar()->value(), 0); + doc.drawContents(painter); + this->drawSeparators(painter); +} + +void QHexView::checkOptions() { + if(m_options.grouplength > m_options.linelength) + m_options.grouplength = m_options.linelength; + + m_options.addresswidth = + qMax<unsigned int>(m_options.addresswidth, this->calcAddressWidth()); + + // Round to nearest multiple of 2 + m_options.grouplength = + 1u << (static_cast<unsigned int>(qFloor(m_options.grouplength / 2.0))); + + if(m_options.grouplength <= 1) + m_options.grouplength = 1; + + if(!m_options.headercolor.isValid()) + m_options.headercolor = + this->palette().color(QPalette::Normal, QPalette::Highlight); +} + +void QHexView::setLineLength(unsigned int l) { + if(l == m_options.linelength) + return; + m_options.linelength = l; + m_hexmetadata->invalidate(); + this->checkAndUpdate(true); +} + +void QHexView::setGroupLength(unsigned int l) { + if(l == m_options.grouplength) + return; + m_options.grouplength = l; + this->checkAndUpdate(true); +} + +void QHexView::checkState() { + if(!m_hexdocument) + return; + this->checkOptions(); + + int doclines = static_cast<int>(this->lines()), + vislines = this->visibleLines(true); + qint64 vscrollmax = doclines - vislines; + if(doclines >= vislines) + vscrollmax++; + + this->verticalScrollBar()->setRange(0, qMax<qint64>(0, vscrollmax)); + this->verticalScrollBar()->setPageStep(vislines - 1); + this->verticalScrollBar()->setSingleStep(m_options.scrollsteps); + + int vw = this->verticalScrollBar()->isVisible() + ? this->verticalScrollBar()->width() + : 0; + + static int oldmw = 0; + if(!oldmw) + oldmw = this->maximumWidth(); + this->setMaximumWidth(m_autowidth ? qCeil(this->endColumnX() + vw + 3) + : oldmw); + + this->horizontalScrollBar()->setRange( + 0, qMax<int>(0, this->endColumnX() - this->width() + vw + 3)); + this->horizontalScrollBar()->setPageStep(this->width()); +} + +void QHexView::checkAndUpdate(bool calccolumns) { + this->checkState(); + if(calccolumns) + this->calcColumns(); + this->viewport()->update(); +} + +void QHexView::calcColumns() { + if(!m_hexdocument) + return; + + m_hexcolumns.clear(); + m_hexcolumns.reserve(m_options.linelength); + + auto x = this->hexColumnX(), cw = this->cellWidth() * 2; + + for(auto i = 0u; i < m_options.linelength; i++) { + for(auto j = 0u; j < m_options.grouplength; j++, x += cw) + m_hexcolumns.push_back(QRect(x, 0, cw, 0)); + + x += this->cellWidth(); + } +} + +void QHexView::ensureVisible() { + if(!m_hexdocument) + return; + + auto pos = m_hexcursor->position(); + auto vlines = this->visibleLines(); + + if(pos.line >= (this->verticalScrollBar()->value() + vlines)) + this->verticalScrollBar()->setValue(pos.line - vlines + 1); + else if(pos.line < this->verticalScrollBar()->value()) + this->verticalScrollBar()->setValue(pos.line); + else + this->viewport()->update(); +} + +void QHexView::drawSeparators(QPainter* p) const { + if(!m_options.hasFlag(QHexFlags::Separators)) + return; + + auto oldpen = p->pen(); + p->setPen(m_options.separatorcolor.isValid() + ? m_options.separatorcolor + : this->palette().color(QPalette::Dark)); + + if(m_options.hasFlag(QHexFlags::HSeparator)) { + QLineF l(0, m_fontmetrics.lineSpacing(), this->endColumnX(), + m_fontmetrics.lineSpacing()); + if(!m_hexdelegate || !m_hexdelegate->paintSeparator(p, l, this)) + p->drawLine(l); + } + + if(m_options.hasFlag(QHexFlags::VSeparator)) { + QLineF l1(this->hexColumnX(), 0, this->hexColumnX(), this->height()); + QLineF l2(this->asciiColumnX(), 0, this->asciiColumnX(), + this->height()); + + if(!m_hexdelegate || + (m_hexdelegate && !m_hexdelegate->paintSeparator(p, l1, this))) + p->drawLine(l1); + + if(!m_hexdelegate || + (m_hexdelegate && !m_hexdelegate->paintSeparator(p, l2, this))) + p->drawLine(l2); + } + + p->setPen(oldpen); +} + +void QHexView::drawHeader(QTextCursor& c) const { + if(m_options.hasFlag(QHexFlags::NoHeader)) + return; + + static const auto RESET_FORMAT = [](const QHexOptions& options, + QTextCharFormat& cf) { + cf = {}; + cf.setForeground(options.headercolor); + }; + + QString addresslabel; + if(m_hexdelegate) + addresslabel = m_hexdelegate->addressHeader(this); + if(addresslabel.isEmpty() && !m_options.addresslabel.isEmpty()) + addresslabel = m_options.addresslabel; + + QTextCharFormat cf; + RESET_FORMAT(m_options, cf); + if(m_hexdelegate) + m_hexdelegate->renderHeaderPart(addresslabel, QHexArea::Address, cf, + this); + c.insertText( + " " + QHexView::reduced(addresslabel, this->addressWidth()) + " ", cf); + + if(m_hexdelegate) + RESET_FORMAT(m_options, cf); + + QString hexlabel; + if(m_hexdelegate) + hexlabel = m_hexdelegate->hexHeader(this); + if(hexlabel.isEmpty()) + hexlabel = m_options.hexlabel; + + if(hexlabel.isNull()) { + c.insertText(" ", {}); + + for(auto i = 0u; i < m_options.linelength; i += m_options.grouplength) { + QString h = QString::number(i, 16) + .rightJustified(m_options.grouplength * 2, '0') + .toUpper(); + + if(m_hexdelegate) { + RESET_FORMAT(m_options, cf); + m_hexdelegate->renderHeaderPart(h, QHexArea::Hex, cf, this); + } + + if(m_hexcursor->column() == static_cast<qint64>(i) && + m_options.hasFlag(QHexFlags::HighlightColumn)) { + cf.setBackground(this->palette().color(QPalette::Highlight)); + cf.setForeground( + this->palette().color(QPalette::HighlightedText)); + } + + c.insertText(h, cf); + c.insertText(" ", {}); + RESET_FORMAT(m_options, cf); + } + } + else { + if(m_hexdelegate) + m_hexdelegate->renderHeaderPart(hexlabel, QHexArea::Hex, cf, this); + c.insertText( + " " + + QHexView::reduced( + hexlabel, (this->hexColumnWidth() / this->cellWidth()) - 1) + + " "); + } + + if(m_hexdelegate) + RESET_FORMAT(m_options, cf); + + QString asciilabel; + if(m_hexdelegate) + asciilabel = m_hexdelegate->asciiHeader(this); + if(asciilabel.isEmpty()) + asciilabel = m_options.asciilabel; + + if(asciilabel.isNull()) { + c.insertText(" ", {}); + + for(unsigned int i = 0; i < m_options.linelength; i++) { + QString a = QString::number(i, 16).toUpper(); + + if(m_hexdelegate) { + RESET_FORMAT(m_options, cf); + m_hexdelegate->renderHeaderPart(a, QHexArea::Ascii, cf, this); + } + + if(m_hexcursor->column() == static_cast<qint64>(i) && + m_options.hasFlag(QHexFlags::HighlightColumn)) { + cf.setBackground(this->palette().color(QPalette::Highlight)); + cf.setForeground( + this->palette().color(QPalette::HighlightedText)); + } + + c.insertText(a, cf); + RESET_FORMAT(m_options, cf); + } + + c.insertText(" ", {}); + } + else { + if(m_hexdelegate) + m_hexdelegate->renderHeaderPart(asciilabel, QHexArea::Ascii, cf, + this); + c.insertText(" " + + QHexView::reduced(asciilabel, ((this->endColumnX() - + this->asciiColumnX() - + this->cellWidth()) / + this->cellWidth()) - + 1) + + " "); + } + + QTextBlockFormat bf; + if(m_options.hasFlag(QHexFlags::StyledHeader)) + bf.setBackground(this->palette().color(QPalette::Window)); + if(m_hexdelegate) + m_hexdelegate->renderHeader(bf, this); + c.setBlockFormat(bf); + c.insertBlock(); +} + +void QHexView::drawDocument(QTextCursor& c) const { + if(!m_hexdocument) + return; + + qreal y = !m_options.hasFlag(QHexFlags::NoHeader) ? this->lineHeight() : 0; + quint64 line = static_cast<quint64>(this->verticalScrollBar()->value()); + + QTextCharFormat addrformat; + addrformat.setForeground( + this->palette().color(QPalette::Normal, QPalette::Highlight)); + + for(qint64 l = 0; m_hexdocument->isEmpty() || + (line < this->lines() && l < this->visibleLines()); + l++, line++, y += this->lineHeight()) { + quint64 address = line * m_options.linelength + this->baseAddress(); + QString addrstr = QString::number(address, 16) + .rightJustified(this->addressWidth(), '0') + .toUpper(); + + // Address Part + QTextCharFormat acf; + acf.setForeground(m_options.headercolor); + + if(m_options.hasFlag(QHexFlags::StyledAddress)) + acf.setBackground(this->palette().color(QPalette::Window)); + + if(m_hexdelegate) + m_hexdelegate->renderAddress(address, acf, this); + + if(m_hexcursor->line() == static_cast<qint64>(line) && + m_options.hasFlag(QHexFlags::HighlightAddress)) { + acf.setBackground(this->palette().color(QPalette::Highlight)); + acf.setForeground(this->palette().color(QPalette::HighlightedText)); + } + + c.insertText(" " + addrstr + " ", acf); + + QByteArray linebytes = this->getLine(line); + c.insertText(" ", {}); + + // Hex Part + for(unsigned int column = 0u; column < m_options.linelength;) { + QTextCharFormat cf; + + for(unsigned int byteidx = 0u; byteidx < m_options.grouplength; + byteidx++, column++) { + QString s; + quint8 b{}; + + if(m_hexdocument->accept( + this->positionFromLineCol(line, column))) { + s = linebytes.isEmpty() || + column >= static_cast<qint64>(linebytes.size()) + ? " " + : QString(QHexUtils::toHex(linebytes.mid(column, 1)) + .toUpper()); + b = static_cast<int>(column) < linebytes.size() + ? linebytes.at(column) + : 0x00; + } + else + s = QString(m_options.invalidchar).repeated(2); + + cf = this->drawFormat(c, b, s, QHexArea::Hex, line, column, + static_cast<int>(column) < + linebytes.size()); + } + + c.insertText(" ", cf); + } + + c.insertText(" ", {}); + + // Ascii Part + for(unsigned int column = 0u; column < m_options.linelength; column++) { + QString s; + quint8 b{}; + + if(m_hexdocument->accept(this->positionFromLineCol(line, column))) { + s = linebytes.isEmpty() || + column >= static_cast<qint64>(linebytes.size()) + ? QChar(' ') + : (QChar::isPrint(linebytes.at(column)) + ? QChar(linebytes.at(column)) + : m_options.unprintablechar); + + b = static_cast<int>(column) < linebytes.size() + ? linebytes.at(column) + : 0x00; + } + else + s = m_options.invalidchar; + + this->drawFormat(c, b, s, QHexArea::Ascii, line, column, + static_cast<int>(column) < linebytes.size()); + } + + QTextBlockFormat bf; + + if(m_options.linealternatebackground.isValid() && line % 2) + bf.setBackground(m_options.linealternatebackground); + else if(m_options.linebackground.isValid() && !(line % 2)) + bf.setBackground(m_options.linebackground); + + c.setBlockFormat(bf); + c.insertBlock({}); + if(m_hexdocument->isEmpty()) + break; + } +} + +unsigned int QHexView::calcAddressWidth() const { + if(!m_hexdocument) + return 0; + + auto maxaddr = + static_cast<quint64>(m_options.baseaddress + m_hexdocument->length()); + if(maxaddr <= std::numeric_limits<quint32>::max()) + return 8; + return QString::number(maxaddr, 16).size(); +} + +int QHexView::visibleLines(bool absolute) const { + int vl = static_cast<int>( + qCeil(this->viewport()->height() / this->lineHeight())); + if(!m_options.hasFlag(QHexFlags::NoHeader)) + vl--; + return absolute ? vl : qMin<int>(this->lines(), vl); +} + +qint64 QHexView::getLastColumn(qint64 line) const { + return this->getLine(line).size() - 1; +} +qint64 QHexView::lastLine() const { return qMax<qint64>(0, this->lines() - 1); } + +qreal QHexView::hexColumnWidth() const { + int l = 0; + + for(auto i = 0u; i < m_options.linelength; i += m_options.grouplength) + l += (2 * m_options.grouplength) + 1; + + return this->getNCellsWidth(l); +} + +unsigned int QHexView::addressWidth() const { + if(!m_hexdocument || m_options.addresswidth) + return m_options.addresswidth; + return this->calcAddressWidth(); +} + +unsigned int QHexView::lineLength() const { return m_options.linelength; } + +bool QHexView::isModified() const { + return m_hexdocument && m_hexdocument->isModified(); +} + +bool QHexView::canUndo() const { + return m_hexdocument && m_hexdocument->canUndo(); +} + +bool QHexView::canRedo() const { + return m_hexdocument && m_hexdocument->canRedo(); +} + +quint64 QHexView::offset() const { return m_hexcursor->offset(); } +quint64 QHexView::address() const { return m_hexcursor->address(); } + +QHexPosition QHexView::positionFromOffset(quint64 offset) const { + QHexPosition opt = QHexPosition::invalid(); + + if(offset < static_cast<quint64>(m_hexdocument->length())) { + opt.line = offset / m_options.linelength; + opt.column = offset % m_options.linelength; + } + + return opt; +} + +QHexPosition QHexView::positionFromAddress(quint64 address) const { + return this->positionFromOffset(address - m_options.baseaddress); +} + +QHexPosition QHexView::position() const { return m_hexcursor->position(); } + +QHexPosition QHexView::selectionStart() const { + return m_hexcursor->selectionStart(); +} + +QHexPosition QHexView::selectionEnd() const { + return m_hexcursor->selectionEnd(); +} + +quint64 QHexView::selectionStartOffset() const { + return m_hexcursor->selectionStartOffset(); +} + +quint64 QHexView::selectionEndOffset() const { + return m_hexcursor->selectionEndOffset(); +} + +quint64 QHexView::baseAddress() const { return m_options.baseaddress; } + +quint64 QHexView::lines() const { + if(!m_hexdocument) + return 0; + + auto lines = static_cast<quint64>(qCeil( + m_hexdocument->length() / static_cast<double>(m_options.linelength))); + return !m_hexdocument->isEmpty() && !lines ? 1 : lines; +} + +qint64 QHexView::replace(const QVariant& oldvalue, const QVariant& newvalue, + qint64 offset, QHexFindMode mode, unsigned int options, + QHexFindDirection fd) const { + auto res = + QHexUtils::replace(this, oldvalue, newvalue, offset, mode, options, fd); + + if(res.first > -1) { + m_hexcursor->move(res.first); + m_hexcursor->selectSize(res.second); + } + + return res.first; +} + +qint64 QHexView::find(const QVariant& value, qint64 offset, QHexFindMode mode, + unsigned int options, QHexFindDirection fd) const { + auto res = QHexUtils::find(this, value, offset, mode, options, fd); + + if(res.first > -1) { + m_hexcursor->move(res.first); + m_hexcursor->selectSize(res.second); + } + + return res.first; +} + +qreal QHexView::hexColumnX() const { + return this->getNCellsWidth(this->addressWidth() + 2); +} +qreal QHexView::asciiColumnX() const { + return this->hexColumnX() + this->hexColumnWidth() + this->cellWidth(); +} +qreal QHexView::endColumnX() const { + return this->asciiColumnX() + + this->getNCellsWidth(m_options.linelength + 1) + this->cellWidth(); +} +qreal QHexView::getNCellsWidth(int n) const { return n * this->cellWidth(); } + +qreal QHexView::cellWidth() const { +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + return m_fontmetrics.horizontalAdvance(" "); +#else + return m_fontmetrics.width(" "); +#endif +} + +qreal QHexView::lineHeight() const { return m_fontmetrics.height(); } + +qint64 QHexView::positionFromLineCol(qint64 line, qint64 col) const { + if(m_hexdocument) { + return qMin((line * m_options.linelength) + col, + m_hexdocument->length()); + } + + return 0; +} + +QHexPosition QHexView::positionFromPoint(QPoint pt) const { + QHexPosition pos = QHexPosition::invalid(); + auto abspt = this->absolutePoint(pt); + + switch(this->areaFromPoint(pt)) { + case QHexArea::Hex: { + pos.column = -1; + + for(qint64 i = 0; i < m_hexcolumns.size(); i++) { + if(m_hexcolumns.at(i).left() > abspt.x()) + break; + pos.column = i; + } + + break; + } + + case QHexArea::Ascii: + pos.column = qMax<qint64>( + qFloor((abspt.x() - this->asciiColumnX()) / this->cellWidth()) - + 1, + 0); + break; + case QHexArea::Address: pos.column = 0; break; + case QHexArea::Header: return QHexPosition::invalid(); + default: break; + } + + pos.line = qMin<qint64>(this->verticalScrollBar()->value() + + (abspt.y() / this->lineHeight()), + this->lines()); + if(!m_options.hasFlag(QHexFlags::NoHeader)) + pos.line = qMax<qint64>(0, pos.line - 1); + + auto docline = this->getLine(pos.line); + pos.column = + qMin<qint64>(pos.column, docline.isEmpty() ? 0 : docline.size()); + + qhexview_fmtprint("line: %lld, col: %lld", pos.line, pos.column); + return pos; +} + +QPoint QHexView::absolutePoint(QPoint pt) const { + return pt + QPoint(this->horizontalScrollBar()->value(), 0); +} + +QHexArea QHexView::areaFromPoint(QPoint pt) const { + pt = this->absolutePoint(pt); + qreal line = + this->verticalScrollBar()->value() + pt.y() / this->lineHeight(); + + if(!m_options.hasFlag(QHexFlags::NoHeader) && !qFloor(line)) + return QHexArea::Header; + if(pt.x() < this->hexColumnX()) + return QHexArea::Address; + if(pt.x() < this->asciiColumnX()) + return QHexArea::Hex; + if(pt.x() < this->endColumnX()) + return QHexArea::Ascii; + return QHexArea::Extra; +} + +QTextCharFormat QHexView::drawFormat(QTextCursor& c, quint8 b, const QString& s, + QHexArea area, qint64 line, qint64 column, + bool applyformat) const { + QTextCharFormat cf, selcf; + QHexPosition pos{line, column}; + + if(applyformat) { + auto offset = m_hexcursor->positionToOffset(pos); + bool hasdelegate = + m_hexdelegate && m_hexdelegate->render(offset, b, cf, this); + + if(!hasdelegate) { + auto it = m_options.bytecolors.find(b); + + if(it != m_options.bytecolors.end()) { + if(it->background.isValid()) + cf.setBackground(it->background); + if(it->foreground.isValid()) + cf.setForeground(it->foreground); + } + } + + const auto* metadataline = m_hexmetadata->find(line); + + if(metadataline) { + for(const auto& metadata : *metadataline) { + if(offset < metadata.begin || offset >= metadata.end) + continue; + + if(!hasdelegate) { + if(metadata.foreground.isValid()) + cf.setForeground(metadata.foreground); + + if(metadata.background.isValid()) { + cf.setBackground(metadata.background); + + if(!metadata.foreground.isValid()) + cf.setForeground( + this->getReadableColor(metadata.background)); + } + } + + if(!metadata.comment.isEmpty()) { + cf.setUnderlineColor( + m_options.commentcolor.isValid() + ? m_options.commentcolor + : this->palette().color(QPalette::WindowText)); + cf.setUnderlineStyle( + QTextCharFormat::UnderlineStyle::SingleUnderline); + } + + if(offset == metadata.begin) // Remove previous metadata's + // style, if needed + { + if(metadata.comment.isEmpty()) + selcf.setUnderlineStyle( + QTextCharFormat::UnderlineStyle::NoUnderline); + if(!metadata.foreground.isValid()) + selcf.setForeground(Qt::color1); + if(!metadata.background.isValid()) + selcf.setBackground(Qt::transparent); + } + + if(offset < metadata.end - 1 && + column < this->getLastColumn(line)) + selcf = cf; + } + } + + if(hasdelegate && column < this->getLastColumn(line)) + selcf = cf; + } + + if(this->hexCursor()->isSelected(line, column)) { + auto offset = this->hexCursor()->positionToOffset(pos); + auto selend = this->hexCursor()->selectionEndOffset(); + + cf.setBackground( + this->palette().color(QPalette::Normal, QPalette::Highlight)); + cf.setForeground( + this->palette().color(QPalette::Normal, QPalette::HighlightedText)); + if(offset < selend && column < this->getLastColumn(line)) + selcf = cf; + } + + if(this->hexCursor()->position() == pos) { + auto cursorbg = this->palette().color( + this->hasFocus() ? QPalette::Normal : QPalette::Disabled, + QPalette::WindowText); + auto cursorfg = this->palette().color( + this->hasFocus() ? QPalette::Normal : QPalette::Disabled, + QPalette::Base); + auto discursorbg = + this->palette().color(QPalette::Disabled, QPalette::WindowText); + auto discursorfg = + this->palette().color(QPalette::Disabled, QPalette::Base); + + switch(m_hexcursor->mode()) { + case QHexCursor::Mode::Insert: + cf.setUnderlineColor(m_currentarea == area ? cursorbg + : discursorbg); + cf.setUnderlineStyle( + QTextCharFormat::UnderlineStyle::SingleUnderline); + break; + + case QHexCursor::Mode::Overwrite: + cf.setBackground(m_currentarea == area ? cursorbg + : discursorbg); + cf.setForeground(m_currentarea == area ? cursorfg + : discursorfg); + break; + } + } + + c.insertText(s, cf); + return selcf; +} + +void QHexView::moveNext(bool select) { + auto line = this->hexCursor()->line(), column = this->hexCursor()->column(); + + if(column >= m_options.linelength - 1) { + line++; + column = 0; + } + else + column++; + + qint64 offset = + this->hexCursor()->mode() == QHexCursor::Mode::Insert ? 1 : 0; + if(select) + this->hexCursor()->select( + qMin<qint64>(line, this->lines()), + qMin<qint64>(column, this->getLastColumn(line) + offset)); + else + this->hexCursor()->move( + qMin<qint64>(line, this->lines()), + qMin<qint64>(column, this->getLastColumn(line) + offset)); +} + +void QHexView::movePrevious(bool select) { + auto line = this->hexCursor()->line(), column = this->hexCursor()->column(); + + if(column <= 0) { + if(!line) + return; + column = this->getLine(--line).size() - 1; + } + else + column--; + + if(select) + this->hexCursor()->select( + qMin<qint64>(line, this->lines()), + qMin<qint64>(column, this->getLastColumn(line))); + else + this->hexCursor()->move( + qMin<qint64>(line, this->lines()), + qMin<qint64>(column, this->getLastColumn(line))); +} + +bool QHexView::keyPressMove(QKeyEvent* e) { + if(e->matches(QKeySequence::MoveToNextChar) || + e->matches(QKeySequence::SelectNextChar)) + this->moveNext(e->matches(QKeySequence::SelectNextChar)); + else if(e->matches(QKeySequence::MoveToPreviousChar) || + e->matches(QKeySequence::SelectPreviousChar)) + this->movePrevious(e->matches(QKeySequence::SelectPreviousChar)); + else if(e->matches(QKeySequence::MoveToNextLine) || + e->matches(QKeySequence::SelectNextLine)) { + if(this->hexCursor()->line() == this->lastLine()) + return true; + auto nextline = this->hexCursor()->line() + 1; + if(e->matches(QKeySequence::MoveToNextLine)) + this->hexCursor()->move(nextline, this->hexCursor()->column()); + else + this->hexCursor()->select(nextline, this->hexCursor()->column()); + } + else if(e->matches(QKeySequence::MoveToPreviousLine) || + e->matches(QKeySequence::SelectPreviousLine)) { + if(!this->hexCursor()->line()) + return true; + auto prevline = this->hexCursor()->line() - 1; + if(e->matches(QKeySequence::MoveToPreviousLine)) + this->hexCursor()->move(prevline, this->hexCursor()->column()); + else + this->hexCursor()->select(prevline, this->hexCursor()->column()); + } + else if(e->matches(QKeySequence::MoveToNextPage) || + e->matches(QKeySequence::SelectNextPage)) { + if(this->lastLine() == this->hexCursor()->line()) + return true; + auto pageline = qMin(this->lastLine(), + this->hexCursor()->line() + this->visibleLines()); + if(e->matches(QKeySequence::MoveToNextPage)) + this->hexCursor()->move(pageline, this->hexCursor()->column()); + else + this->hexCursor()->select(pageline, this->hexCursor()->column()); + } + else if(e->matches(QKeySequence::MoveToPreviousPage) || + e->matches(QKeySequence::SelectPreviousPage)) { + if(!this->hexCursor()->line()) + return true; + auto pageline = + qMax<qint64>(0, this->hexCursor()->line() - this->visibleLines()); + if(e->matches(QKeySequence::MoveToPreviousPage)) + this->hexCursor()->move(pageline, this->hexCursor()->column()); + else + this->hexCursor()->select(pageline, this->hexCursor()->column()); + } + else if(e->matches(QKeySequence::MoveToStartOfDocument) || + e->matches(QKeySequence::SelectStartOfDocument)) { + if(!this->hexCursor()->line()) + return true; + if(e->matches(QKeySequence::MoveToStartOfDocument)) + this->hexCursor()->move(0, 0); + else + this->hexCursor()->select(0, 0); + } + else if(e->matches(QKeySequence::MoveToEndOfDocument) || + e->matches(QKeySequence::SelectEndOfDocument)) { + if(this->lastLine() == this->hexCursor()->line()) + return true; + if(e->matches(QKeySequence::MoveToEndOfDocument)) + this->hexCursor()->move( + this->lastLine(), + this->getLastColumn(this->hexCursor()->line())); + else + this->hexCursor()->select(this->lastLine(), + this->getLastColumn(this->lastLine())); + } + else if(e->matches(QKeySequence::MoveToStartOfLine) || + e->matches(QKeySequence::SelectStartOfLine)) { + auto offset = + this->hexCursor()->positionToOffset({this->hexCursor()->line(), 0}); + if(e->matches(QKeySequence::MoveToStartOfLine)) + this->hexCursor()->move(offset); + else + this->hexCursor()->select(offset); + } + else if(e->matches(QKeySequence::SelectEndOfLine) || + e->matches(QKeySequence::MoveToEndOfLine)) { + auto offset = this->hexCursor()->positionToOffset( + {this->hexCursor()->line(), + this->getLastColumn(this->hexCursor()->line())}); + if(e->matches(QKeySequence::SelectEndOfLine)) + this->hexCursor()->select(offset); + else + this->hexCursor()->move(offset); + } + else + return false; + + return true; +} + +bool QHexView::keyPressTextInput(QKeyEvent* e) { + if(m_readonly || e->text().isEmpty() || + (e->modifiers() & Qt::ControlModifier)) + return false; + + bool atend = m_hexcursor->offset() >= m_hexdocument->length(); + if(atend && m_hexcursor->mode() == QHexCursor::Mode::Overwrite) + return false; + + char key = e->text().at(0).toLatin1(); + + switch(m_currentarea) { + case QHexArea::Hex: { + if(!QHexUtils::isHex(key)) + return false; + + bool ok = false; + auto val = static_cast<quint8>(QString(key).toUInt(&ok, 16)); + if(!ok) + return false; + m_hexcursor->removeSelection(); + + quint8 ch = m_hexdocument->isEmpty() || + m_hexcursor->offset() >= m_hexdocument->length() + ? '\x00' + : m_hexdocument->at(m_hexcursor->offset()); + ch = m_writing ? (ch << 4) | val : val; + + if(!m_writing && (m_hexcursor->mode() == QHexCursor::Mode::Insert)) + m_hexdocument->insert(m_hexcursor->offset(), val); + else + m_hexdocument->replace(m_hexcursor->offset(), ch); + + m_writing = !m_writing; + if(!m_writing) + this->moveNext(); + + break; + } + + case QHexArea::Ascii: { + if(!QChar::isPrint(key)) + return false; + m_hexcursor->removeSelection(); + if(m_hexcursor->mode() == QHexCursor::Mode::Insert) + m_hexdocument->insert(m_hexcursor->offset(), key); + else + m_hexdocument->replace(m_hexcursor->offset(), key); + this->moveNext(); + break; + } + + default: return false; + } + + return true; +} + +bool QHexView::keyPressAction(QKeyEvent* e) { + if(e->modifiers() != Qt::NoModifier) { + if(e->matches(QKeySequence::SelectAll)) + this->selectAll(); + else if(!m_readonly && e->matches(QKeySequence::Undo)) + this->undo(); + else if(!m_readonly && e->matches(QKeySequence::Redo)) + this->redo(); + else if(!m_readonly && e->matches(QKeySequence::Cut)) + this->cut(m_currentarea != QHexArea::Ascii); + else if(e->matches(QKeySequence::Copy)) + this->copy(m_currentarea != QHexArea::Ascii); + else if(!m_readonly && e->matches(QKeySequence::Paste)) + this->paste(m_currentarea != QHexArea::Ascii); + else + return false; + + return true; + } + + if(m_readonly) + return false; + + switch(e->key()) { + case Qt::Key_Backspace: + case Qt::Key_Delete: { + if(!m_hexcursor->hasSelection()) { + auto offset = m_hexcursor->offset(); + if(offset <= 0) + return true; + + if(e->key() == Qt::Key_Backspace) + m_hexdocument->remove(offset - 1, 1); + else + m_hexdocument->remove(offset, 1); + } + else { + auto oldpos = m_hexcursor->selectionStart(); + m_hexcursor->removeSelection(); + m_hexcursor->move(oldpos); + } + + if(e->key() == Qt::Key_Backspace) + this->movePrevious(); + m_writing = false; + break; + } + + case Qt::Key_Insert: + m_writing = false; + m_hexcursor->switchMode(); + break; + + default: return false; + } + + return true; +} + +bool QHexView::event(QEvent* e) { + switch(e->type()) { + case QEvent::FontChange: + m_fontmetrics = QFontMetricsF(this->font()); + this->checkAndUpdate(true); + return true; + + case QEvent::ToolTip: { + if(m_hexdocument && (m_currentarea == QHexArea::Hex || + m_currentarea == QHexArea::Ascii)) { + auto* helpevent = static_cast<QHelpEvent*>(e); + auto pos = this->positionFromPoint(helpevent->pos()); + auto comment = m_hexmetadata->getComment(pos.line, pos.column); + if(!comment.isEmpty()) + QToolTip::showText(helpevent->globalPos(), comment); + return true; + } + + break; + } + + default: break; + } + + return QAbstractScrollArea::event(e); +} + +void QHexView::showEvent(QShowEvent* e) { + QAbstractScrollArea::showEvent(e); + this->checkAndUpdate(true); +} + +void QHexView::paintEvent(QPaintEvent*) { + if(!m_hexdocument) + return; + + QPainter painter(this->viewport()); + if(m_hexdelegate) + m_hexdelegate->paint(&painter, this); + else + this->paint(&painter); +} + +void QHexView::resizeEvent(QResizeEvent* e) { + this->checkState(); + QAbstractScrollArea::resizeEvent(e); +} + +void QHexView::focusInEvent(QFocusEvent* e) { + QAbstractScrollArea::focusInEvent(e); + if(m_hexdocument) + this->viewport()->update(); +} + +void QHexView::focusOutEvent(QFocusEvent* e) { + QAbstractScrollArea::focusOutEvent(e); + if(m_hexdocument) + this->viewport()->update(); +} + +void QHexView::mousePressEvent(QMouseEvent* e) { + QAbstractScrollArea::mousePressEvent(e); + if(!m_hexdocument || e->button() != Qt::LeftButton) + return; + + auto pos = this->positionFromPoint(e->pos()); + if(!pos.isValid()) + return; + + auto area = this->areaFromPoint(e->pos()); + qhexview_fmtprint("%d", static_cast<int>(area)); + + switch(area) { + case QHexArea::Address: this->hexCursor()->move(pos.line, 0); break; + case QHexArea::Hex: + m_currentarea = area; + this->hexCursor()->move(pos); + break; + case QHexArea::Ascii: + m_currentarea = area; + this->hexCursor()->move(pos.line, pos.column); + break; + default: return; + } + + this->viewport()->update(); +} + +void QHexView::mouseMoveEvent(QMouseEvent* e) { + QAbstractScrollArea::mouseMoveEvent(e); + if(!this->hexCursor()) + return; + + e->accept(); + auto area = this->areaFromPoint(e->pos()); + + switch(area) { + case QHexArea::Header: + this->viewport()->setCursor(Qt::ArrowCursor); + return; + case QHexArea::Address: + this->viewport()->setCursor(Qt::ArrowCursor); + break; + default: this->viewport()->setCursor(Qt::IBeamCursor); break; + } + + if(e->buttons() == Qt::LeftButton) { + auto pos = this->positionFromPoint(e->pos()); + if(!pos.isValid()) + return; + if(area == QHexArea::Ascii || area == QHexArea::Hex) + m_currentarea = area; + this->hexCursor()->select(pos); + } +} + +void QHexView::wheelEvent(QWheelEvent* e) { + e->ignore(); + +#if defined(Q_OS_OSX) + // In macOS scrollbar invisibility should not prevent scrolling from working + if(!m_hexdocument) + return; +#else + if(!m_hexdocument || !this->verticalScrollBar()->isVisible()) + return; +#endif + + // https://doc.qt.io/qt-6/qwheelevent.html + // "Returns the relative amount that the wheel was rotated, in eighths of a + // degree." "Most mouse types work in steps of 15 degrees, in which case the + // delta value is a multiple of 120; i.e., 120 units * 1/8 = 15 degrees." + int const ydelta = e->angleDelta().y(); + if(0 != ydelta) { + int const ydeltaAbsolute = qAbs(ydelta); + int const numberOfLinesToMove = + (ydeltaAbsolute * m_options.scrollsteps + 119) / + 120; // always move at least 1 line + int const ydeltaSign = ydelta / ydeltaAbsolute; + + int const oldValue = this->verticalScrollBar()->value(); + int const newValue = oldValue - ydeltaSign * numberOfLinesToMove; + this->verticalScrollBar()->setValue(newValue); + } +} + +void QHexView::keyPressEvent(QKeyEvent* e) { + bool handled = false; + + if(this->hexCursor()) { + handled = this->keyPressMove(e); + if(!handled) + handled = this->keyPressAction(e); + if(!handled) + handled = this->keyPressTextInput(e); + } + + if(handled) + e->accept(); + else + QAbstractScrollArea::keyPressEvent(e); +} + +QString QHexView::reduced(const QString& s, int maxlen) { + if(s.length() <= maxlen) + return s.leftJustified(maxlen); + return s.mid(0, maxlen - 1) + "\u2026"; +} + +bool QHexView::isColorLight(QColor c) { + return std::sqrt(0.299 * std::pow(c.red(), 2) + + 0.587 * std::pow(c.green(), 2) + + 0.114 * std::pow(c.blue(), 2)) > 127.5; +} + +QColor QHexView::getReadableColor(QColor c) const { + QPalette palette = this->palette(); + return QHexView::isColorLight(c) + ? palette.color(QPalette::Normal, QPalette::WindowText) + : palette.color(QPalette::Normal, QPalette::HighlightedText); +} + +QByteArray QHexView::selectedBytes() const { + return m_hexcursor->hasSelection() + ? m_hexdocument->read(m_hexcursor->selectionStartOffset(), + m_hexcursor->selectionLength()) + : QByteArray{}; +} +QByteArray QHexView::getLine(qint64 line) const { + return m_hexdocument ? m_hexdocument->read(line * m_options.linelength, + m_options.linelength) + : QByteArray{}; +} diff --git a/UEFITool/hexviewdialog.h b/UEFITool/hexviewdialog.h index 9a0e138..18eaacc 100644 --- a/UEFITool/hexviewdialog.h +++ b/UEFITool/hexviewdialog.h @@ -15,8 +15,8 @@ #define HEXVIEWDIALOG_H #include <QDialog> +#include <QHexView/qhexview.h> #include "../common/treemodel.h" -#include "qhexview5/qhexview.h" #include "ui_hexviewdialog.h" class HexViewDialog : public QDialog diff --git a/UEFITool/qhexview5/model/buffer/qdevicebuffer.h b/UEFITool/qhexview5/model/buffer/qdevicebuffer.h deleted file mode 100644 index 0115c67..0000000 --- a/UEFITool/qhexview5/model/buffer/qdevicebuffer.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "qhexbuffer.h" - -class QDeviceBuffer : public QHexBuffer -{ - Q_OBJECT - - public: - explicit QDeviceBuffer(QObject *parent = nullptr); - virtual ~QDeviceBuffer(); - uchar at(qint64 idx) override; - qint64 length() const override; - void insert(qint64 offset, const QByteArray& data) override; - void replace(qint64 offset, const QByteArray& data) override; - void remove(qint64 offset, int length) override; - QByteArray read(qint64 offset, int length) override; - bool read(QIODevice* device) override; - void write(QIODevice* device) override; - qint64 indexOf(const QByteArray& ba, qint64 from) override; - qint64 lastIndexOf(const QByteArray& ba, qint64 from) override; - - protected: - QIODevice* m_device{nullptr}; -}; diff --git a/UEFITool/qhexview5/model/buffer/qhexbuffer.h b/UEFITool/qhexview5/model/buffer/qhexbuffer.h deleted file mode 100644 index c00bbbd..0000000 --- a/UEFITool/qhexview5/model/buffer/qhexbuffer.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include <QObject> -#include <QIODevice> - -class QHexBuffer : public QObject -{ - Q_OBJECT - - public: - explicit QHexBuffer(QObject *parent = nullptr); - bool isEmpty() const; - - public: - virtual uchar at(qint64 idx); - virtual void replace(qint64 offset, const QByteArray& data); - virtual void read(char* data, int size); - virtual void read(const QByteArray& ba); - - public: - virtual qint64 length() const = 0; - virtual void insert(qint64 offset, const QByteArray& data) = 0; - virtual void remove(qint64 offset, int length) = 0; - virtual QByteArray read(qint64 offset, int length) = 0; - virtual bool read(QIODevice* iodevice) = 0; - virtual void write(QIODevice* iodevice) = 0; - virtual qint64 indexOf(const QByteArray& ba, qint64 from) = 0; - virtual qint64 lastIndexOf(const QByteArray& ba, qint64 from) = 0; - -}; diff --git a/UEFITool/qhexview5/model/buffer/qmemorybuffer.cpp b/UEFITool/qhexview5/model/buffer/qmemorybuffer.cpp deleted file mode 100644 index b0d6a02..0000000 --- a/UEFITool/qhexview5/model/buffer/qmemorybuffer.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "qmemorybuffer.h" -#include <QIODevice> - -QMemoryBuffer::QMemoryBuffer(QObject *parent) : QHexBuffer{parent} { } -uchar QMemoryBuffer::at(qint64 idx) { return static_cast<uchar>(m_buffer.at(idx)); } -qint64 QMemoryBuffer::length() const { return static_cast<qint64>(m_buffer.length()); } -void QMemoryBuffer::insert(qint64 offset, const QByteArray &data) { m_buffer.insert(static_cast<int>(offset), data); } -void QMemoryBuffer::remove(qint64 offset, int length) { m_buffer.remove(static_cast<int>(offset), length); } -QByteArray QMemoryBuffer::read(qint64 offset, int length) { return m_buffer.mid(static_cast<int>(offset), length); } - -bool QMemoryBuffer::read(QIODevice *device) -{ - m_buffer = device->readAll(); - return true; -} - -void QMemoryBuffer::write(QIODevice *device) { device->write(m_buffer); } -qint64 QMemoryBuffer::indexOf(const QByteArray& ba, qint64 from) { return m_buffer.indexOf(ba, static_cast<int>(from)); } -qint64 QMemoryBuffer::lastIndexOf(const QByteArray& ba, qint64 from) { return m_buffer.lastIndexOf(ba, static_cast<int>(from)); } diff --git a/UEFITool/qhexview5/model/buffer/qmemorybuffer.h b/UEFITool/qhexview5/model/buffer/qmemorybuffer.h deleted file mode 100644 index 4e096d2..0000000 --- a/UEFITool/qhexview5/model/buffer/qmemorybuffer.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "qhexbuffer.h" - -class QMemoryBuffer : public QHexBuffer -{ - Q_OBJECT - - public: - explicit QMemoryBuffer(QObject *parent = nullptr); - uchar at(qint64 idx) override; - qint64 length() const override; - void insert(qint64 offset, const QByteArray& data) override; - void remove(qint64 offset, int length) override; - QByteArray read(qint64 offset, int length) override; - bool read(QIODevice* device) override; - void write(QIODevice* device) override; - qint64 indexOf(const QByteArray& ba, qint64 from) override; - qint64 lastIndexOf(const QByteArray& ba, qint64 from) override; - - private: - QByteArray m_buffer; -}; diff --git a/UEFITool/qhexview5/model/commands/hexcommand.cpp b/UEFITool/qhexview5/model/commands/hexcommand.cpp deleted file mode 100644 index c4ca0ff..0000000 --- a/UEFITool/qhexview5/model/commands/hexcommand.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "hexcommand.h" - -HexCommand::HexCommand(QHexBuffer *buffer, QHexDocument* document, QUndoCommand *parent): QUndoCommand(parent), m_hexdocument(document), m_buffer(buffer), m_offset(0), m_length(0) { } diff --git a/UEFITool/qhexview5/model/commands/hexcommand.h b/UEFITool/qhexview5/model/commands/hexcommand.h deleted file mode 100644 index f43c758..0000000 --- a/UEFITool/qhexview5/model/commands/hexcommand.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include <QUndoCommand> -#include "../buffer/qhexbuffer.h" - -class QHexDocument; - -class HexCommand: public QUndoCommand -{ - public: - HexCommand(QHexBuffer* buffer, QHexDocument* document, QUndoCommand* parent = nullptr); - - protected: - QHexDocument* m_hexdocument; - QHexBuffer* m_buffer; - qint64 m_offset; - int m_length; - QByteArray m_data; -}; diff --git a/UEFITool/qhexview5/model/commands/insertcommand.cpp b/UEFITool/qhexview5/model/commands/insertcommand.cpp deleted file mode 100644 index 122dbb8..0000000 --- a/UEFITool/qhexview5/model/commands/insertcommand.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "insertcommand.h" -#include "../qhexdocument.h" - -InsertCommand::InsertCommand(QHexBuffer *buffer, QHexDocument* document, qint64 offset, const QByteArray &data, QUndoCommand *parent): HexCommand(buffer, document, parent) -{ - m_offset = offset; - m_data = data; -} - -void InsertCommand::undo() -{ - m_buffer->remove(m_offset, m_data.length()); - Q_EMIT m_hexdocument->dataChanged(m_data, m_offset, QHexDocument::ChangeReason::Remove); -} - -void InsertCommand::redo() { m_buffer->insert(m_offset, m_data); } diff --git a/UEFITool/qhexview5/model/commands/insertcommand.h b/UEFITool/qhexview5/model/commands/insertcommand.h deleted file mode 100644 index f1394a8..0000000 --- a/UEFITool/qhexview5/model/commands/insertcommand.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "hexcommand.h" - -class InsertCommand: public HexCommand -{ - public: - InsertCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, const QByteArray& data, QUndoCommand* parent = nullptr); - void undo() override; - void redo() override; -}; diff --git a/UEFITool/qhexview5/model/commands/removecommand.cpp b/UEFITool/qhexview5/model/commands/removecommand.cpp deleted file mode 100644 index 42fe553..0000000 --- a/UEFITool/qhexview5/model/commands/removecommand.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "removecommand.h" -#include "../qhexdocument.h" - -RemoveCommand::RemoveCommand(QHexBuffer *buffer, QHexDocument* document, qint64 offset, int length, QUndoCommand *parent): HexCommand(buffer, document, parent) -{ - m_offset = offset; - m_length = length; -} - -void RemoveCommand::undo() -{ - m_buffer->insert(m_offset, m_data); - Q_EMIT m_hexdocument->dataChanged(m_data, m_offset, QHexDocument::ChangeReason::Insert); -} - -void RemoveCommand::redo() -{ - m_data = m_buffer->read(m_offset, m_length); // Backup data - m_buffer->remove(m_offset, m_length); -} diff --git a/UEFITool/qhexview5/model/commands/removecommand.h b/UEFITool/qhexview5/model/commands/removecommand.h deleted file mode 100644 index e707e6c..0000000 --- a/UEFITool/qhexview5/model/commands/removecommand.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "hexcommand.h" - -class RemoveCommand: public HexCommand -{ - public: - RemoveCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, int length, QUndoCommand* parent = nullptr); - void undo() override; - void redo() override; -}; diff --git a/UEFITool/qhexview5/model/commands/replacecommand.cpp b/UEFITool/qhexview5/model/commands/replacecommand.cpp deleted file mode 100644 index 6e0ec93..0000000 --- a/UEFITool/qhexview5/model/commands/replacecommand.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "replacecommand.h" -#include "../qhexdocument.h" - -ReplaceCommand::ReplaceCommand(QHexBuffer *buffer, QHexDocument* document, qint64 offset, const QByteArray &data, QUndoCommand *parent): HexCommand(buffer, document, parent) -{ - m_offset = offset; - m_data = data; -} - -void ReplaceCommand::undo() -{ - m_buffer->replace(m_offset, m_olddata); - Q_EMIT m_hexdocument->dataChanged(m_olddata, m_offset, QHexDocument::ChangeReason::Replace); -} - -void ReplaceCommand::redo() -{ - m_olddata = m_buffer->read(m_offset, m_data.length()); - m_buffer->replace(m_offset, m_data); -} diff --git a/UEFITool/qhexview5/model/commands/replacecommand.h b/UEFITool/qhexview5/model/commands/replacecommand.h deleted file mode 100644 index c4a2418..0000000 --- a/UEFITool/qhexview5/model/commands/replacecommand.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "hexcommand.h" - -class ReplaceCommand: public HexCommand -{ - public: - ReplaceCommand(QHexBuffer* buffer, QHexDocument* document, qint64 offset, const QByteArray& data, QUndoCommand* parent = nullptr); - void undo() override; - void redo() override; - - private: - QByteArray m_olddata; -}; diff --git a/UEFITool/qhexview5/model/qhexcursor.cpp b/UEFITool/qhexview5/model/qhexcursor.cpp deleted file mode 100644 index 6042128..0000000 --- a/UEFITool/qhexview5/model/qhexcursor.cpp +++ /dev/null @@ -1,129 +0,0 @@ -#include "../qhexview.h" -#include "qhexcursor.h" -#include "qhexdocument.h" - -/* - * https://stackoverflow.com/questions/10803043/inverse-column-row-major-order-transformation - * - * If the index is calculated as: - * offset = row + column*NUMROWS - * then the inverse would be: - * row = offset % NUMROWS - * column = offset / NUMROWS - * where % is modulus, and / is integer division. - */ - -QHexCursor::QHexCursor(const QHexOptions* options, QHexView* parent) : QObject(parent), m_options(options) { } -QHexView* QHexCursor::hexView() const { return qobject_cast<QHexView*>(this->parent()); } -QHexCursor::Mode QHexCursor::mode() const { return m_mode; } -qint64 QHexCursor::offset() const { return this->positionToOffset(m_position); } -qint64 QHexCursor::address() const { return m_options->baseaddress + this->offset(); } -quint64 QHexCursor::lineAddress() const { return m_options->baseaddress + (m_position.line * m_options->linelength); } -qint64 QHexCursor::selectionStartOffset() const { return this->positionToOffset(this->selectionStart()); } -qint64 QHexCursor::selectionEndOffset() const { return this->positionToOffset(this->selectionEnd()); } -qint64 QHexCursor::line() const { return m_position.line; } -qint64 QHexCursor::column() const { return m_position.column; } - -QHexPosition QHexCursor::selectionStart() const -{ - if(m_position.line < m_selection.line) - return m_position; - - if(m_position.line == m_selection.line) - { - if(m_position.column < m_selection.column) - return m_position; - } - - return m_selection; -} - -QHexPosition QHexCursor::selectionEnd() const -{ - if(m_position.line > m_selection.line) - return m_position; - - if(m_position.line == m_selection.line) - { - if(m_position.column > m_selection.column) - return m_position; - } - - return m_selection; -} - -qint64 QHexCursor::selectionLength() const -{ - auto selstart = this->selectionStartOffset(), selend = this->selectionEndOffset(); - return selstart == selend ? 0 : selend - selstart + 1; -} - -QHexPosition QHexCursor::position() const { return m_position; } -QByteArray QHexCursor::selectedBytes() const { return this->hexView()->selectedBytes(); } -bool QHexCursor::hasSelection() const { return m_position != m_selection; } - -bool QHexCursor::isSelected(qint64 line, qint64 column) const -{ - if(!this->hasSelection()) return false; - - auto selstart = this->selectionStart(), selend = this->selectionEnd(); - if(line > selstart.line && line < selend.line) return true; - if(line == selstart.line && line == selend.line) return column >= selstart.column && column <= selend.column; - if(line == selstart.line) return column >= selstart.column; - if(line == selend.line) return column <= selend.column; - return false; -} - -void QHexCursor::setMode(Mode m) -{ - if(m_mode == m) return; - m_mode = m; - Q_EMIT modeChanged(); -} - -void QHexCursor::switchMode() -{ - switch(m_mode) - { - case Mode::Insert: this->setMode(Mode::Overwrite); break; - case Mode::Overwrite: this->setMode(Mode::Insert); break; - } -} - -void QHexCursor::move(qint64 offset) { this->move(this->offsetToPosition(offset)); } -void QHexCursor::move(qint64 line, qint64 column) { return this->move({line, column}); } - -void QHexCursor::move(QHexPosition pos) -{ - if(pos.line >= 0) m_selection.line = pos.line; - if(pos.column >= 0) m_selection.column = pos.column; - this->select(pos); -} - -void QHexCursor::select(qint64 offset) { this->select(this->offsetToPosition(offset)); } -void QHexCursor::select(qint64 line, qint64 column) { this->select({line, column}); } - -void QHexCursor::select(QHexPosition pos) -{ - if(pos.line >= 0) m_position.line = pos.line; - if(pos.column >= 0) m_position.column = pos.column; - Q_EMIT positionChanged(); -} - -void QHexCursor::selectSize(qint64 length) -{ - if(length > 0) length--; - else if(length < 0) length++; - if(length) this->select(this->offset() + length); -} - -qint64 QHexCursor::replace(const QVariant& oldvalue, const QVariant& newvalue, qint64 offset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) const { return this->hexView()->replace(oldvalue, newvalue, offset, mode, options, fd); } -qint64 QHexCursor::find(const QVariant& value, qint64 offset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) const { return this->hexView()->find(value, offset, mode, options, fd); } -void QHexCursor::cut(bool hex) { this->hexView()->cut(hex); } -void QHexCursor::copy(bool hex) const { this->hexView()->copy(hex); } -void QHexCursor::paste(bool hex) { this->hexView()->paste(hex); } -void QHexCursor::selectAll() { this->hexView()->selectAll(); } -void QHexCursor::removeSelection() { this->hexView()->removeSelection(); } -void QHexCursor::clearSelection() { m_position = m_selection; Q_EMIT positionChanged(); } -qint64 QHexCursor::positionToOffset(QHexPosition pos) const { return QHexUtils::positionToOffset(m_options, pos); } -QHexPosition QHexCursor::offsetToPosition(qint64 offset) const { return QHexUtils::offsetToPosition(m_options, offset); } diff --git a/UEFITool/qhexview5/model/qhexcursor.h b/UEFITool/qhexview5/model/qhexcursor.h deleted file mode 100644 index 46f1067..0000000 --- a/UEFITool/qhexview5/model/qhexcursor.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include <QObject> -#include "qhexoptions.h" -#include "qhexutils.h" - -class QHexView; - -class QHexCursor : public QObject -{ - Q_OBJECT - - public: - enum class Mode { Overwrite, Insert }; - - private: - explicit QHexCursor(const QHexOptions* options, QHexView *parent = nullptr); - - public: - QHexView* hexView() const; - Mode mode() const; - qint64 line() const; - qint64 column() const; - qint64 offset() const; - qint64 address() const; - quint64 lineAddress() const; - qint64 selectionStartOffset() const; - qint64 selectionEndOffset() const; - qint64 selectionLength() const; - QHexPosition position() const; - QHexPosition selectionStart() const; - QHexPosition selectionEnd() const; - QByteArray selectedBytes() const; - bool hasSelection() const; - bool isSelected(qint64 line, qint64 column) const; - void setMode(Mode m); - void move(qint64 offset); - void move(qint64 line, qint64 column); - void move(QHexPosition pos); - void select(qint64 offset); - void select(qint64 line, qint64 column); - void select(QHexPosition pos); - void selectSize(qint64 length); - qint64 replace(const QVariant& oldvalue, const QVariant& newvalue, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const; - qint64 find(const QVariant& value, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const; - qint64 positionToOffset(QHexPosition pos) const; - QHexPosition offsetToPosition(qint64 offset) const; - - public Q_SLOTS: - void cut(bool hex = false); - void copy(bool hex = false) const; - void paste(bool hex = false); - void selectAll(); - void removeSelection(); - void clearSelection(); - void switchMode(); - - Q_SIGNALS: - void positionChanged(); - void modeChanged(); - - private: - const QHexOptions* m_options; - Mode m_mode{Mode::Overwrite}; - QHexPosition m_position{}, m_selection{}; - - friend class QHexView; -}; - diff --git a/UEFITool/qhexview5/model/qhexdelegate.h b/UEFITool/qhexview5/model/qhexdelegate.h deleted file mode 100644 index b122890..0000000 --- a/UEFITool/qhexview5/model/qhexdelegate.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include <QTextCharFormat> -#include <QObject> -#include "qhexutils.h" - -class QHexView; - -class QHexDelegate: public QObject -{ - Q_OBJECT - - public: - explicit QHexDelegate(QObject* parent = nullptr); - virtual ~QHexDelegate() = default; - virtual QString addressHeader(const QHexView* hexview) const; - virtual QString hexHeader(const QHexView* hexview) const; - virtual QString asciiHeader(const QHexView* hexview) const; - virtual void renderAddress(quint64 address, QTextCharFormat& cf, const QHexView* hexview) const; - virtual void renderHeader(QTextBlockFormat& bf, const QHexView* hexview) const; - virtual void renderHeaderPart(const QString& s, QHexArea area, QTextCharFormat& cf, const QHexView* hexview) const; - virtual bool render(quint64 offset, quint8 b, QTextCharFormat& outcf, const QHexView* hexview) const; - virtual bool paintSeparator(QPainter* painter, QLineF line, const QHexView* hexview) const; - virtual void paint(QPainter* painter, const QHexView* hexview) const; -}; diff --git a/UEFITool/qhexview5/model/qhexdocument.cpp b/UEFITool/qhexview5/model/qhexdocument.cpp deleted file mode 100644 index a4f1a76..0000000 --- a/UEFITool/qhexview5/model/qhexdocument.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "qhexdocument.h" -#include "buffer/qmemorybuffer.h" -#include "commands/insertcommand.h" -#include "commands/replacecommand.h" -#include "commands/removecommand.h" -#include "qhexutils.h" -#include <QBuffer> -#include <QFile> -#include <cmath> - -QHexDocument::QHexDocument(QHexBuffer *buffer, QObject* parent): QObject(parent) -{ - m_buffer = buffer; - m_buffer->setParent(this); // Take Ownership - - connect(&m_undostack, &QUndoStack::canUndoChanged, this, &QHexDocument::canUndoChanged); - connect(&m_undostack, &QUndoStack::canRedoChanged, this, &QHexDocument::canRedoChanged); -} - -qint64 QHexDocument::indexOf(const QByteArray& ba, qint64 from) { return m_buffer->indexOf(ba, from); } -qint64 QHexDocument::lastIndexOf(const QByteArray& ba, qint64 from) { return m_buffer->lastIndexOf(ba, from); } -bool QHexDocument::isEmpty() const { return m_buffer->isEmpty(); } -bool QHexDocument::canUndo() const { return m_undostack.canUndo(); } -bool QHexDocument::canRedo() const { return m_undostack.canRedo(); } - -void QHexDocument::setData(const QByteArray& ba) -{ - QHexBuffer* mb = new QMemoryBuffer(); - mb->read(ba); - this->setData(mb); -} - -void QHexDocument::setData(QHexBuffer* buffer) -{ - if(!buffer) return; - - m_undostack.clear(); - buffer->setParent(this); - - auto* oldbuffer = m_buffer; - m_buffer = buffer; - if(oldbuffer) oldbuffer->deleteLater(); - - Q_EMIT canUndoChanged(false); - Q_EMIT canRedoChanged(false); - Q_EMIT changed(); - Q_EMIT reset(); -} - -qint64 QHexDocument::length() const { return m_buffer ? m_buffer->length() : 0; } -uchar QHexDocument::at(int offset) const { return m_buffer->at(offset); } - -void QHexDocument::undo() { m_undostack.undo(); Q_EMIT changed(); } -void QHexDocument::redo() { m_undostack.redo(); Q_EMIT changed(); } -void QHexDocument::insert(qint64 offset, uchar b) { this->insert(offset, QByteArray(1, b)); } -void QHexDocument::replace(qint64 offset, uchar b) { this->replace(offset, QByteArray(1, b)); } - -void QHexDocument::insert(qint64 offset, const QByteArray &data) -{ - m_undostack.push(new InsertCommand(m_buffer, this, offset, data)); - - Q_EMIT changed(); - Q_EMIT dataChanged(data, offset, ChangeReason::Insert); -} - -void QHexDocument::replace(qint64 offset, const QByteArray &data) -{ - m_undostack.push(new ReplaceCommand(m_buffer, this, offset, data)); - Q_EMIT changed(); - Q_EMIT dataChanged(data, offset, ChangeReason::Replace); -} - -void QHexDocument::remove(qint64 offset, int len) -{ - QByteArray data = m_buffer->read(offset, len); - - m_undostack.push(new RemoveCommand(m_buffer, this, offset, len)); - Q_EMIT changed(); - Q_EMIT dataChanged(data, offset, ChangeReason::Remove); -} - -QByteArray QHexDocument::read(qint64 offset, int len) const { return m_buffer->read(offset, len); } - -bool QHexDocument::saveTo(QIODevice *device) -{ - if(!device->isWritable()) return false; - m_buffer->write(device); - return true; -} - -QHexDocument* QHexDocument::fromBuffer(QHexBuffer* buffer, QObject* parent) { return new QHexDocument(buffer, parent); } -QHexDocument* QHexDocument::create(QObject* parent) { return QHexDocument::fromMemory<QMemoryBuffer>({}, parent); } diff --git a/UEFITool/qhexview5/model/qhexdocument.h b/UEFITool/qhexview5/model/qhexdocument.h deleted file mode 100644 index bc05b6d..0000000 --- a/UEFITool/qhexview5/model/qhexdocument.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include <QUndoStack> -#include "buffer/qhexbuffer.h" -#include "qhexmetadata.h" -#include "qhexoptions.h" - -class QHexCursor; - -class QHexDocument: public QObject -{ - Q_OBJECT - - public: - enum class ChangeReason { Insert, Remove, Replace }; - enum class FindDirection { Forward, Backward }; - Q_ENUM(ChangeReason); - Q_ENUM(FindDirection); - - private: - explicit QHexDocument(QHexBuffer* buffer, QObject *parent = nullptr); - - public: - bool isEmpty() const; - bool canUndo() const; - bool canRedo() const; - void setData(const QByteArray& ba); - void setData(QHexBuffer* buffer); - qint64 length() const; - qint64 indexOf(const QByteArray& ba, qint64 from = 0); - qint64 lastIndexOf(const QByteArray& ba, qint64 from = 0); - QByteArray read(qint64 offset, int len = 0) const; - uchar at(int offset) const; - - public Q_SLOTS: - void undo(); - void redo(); - void insert(qint64 offset, uchar b); - void replace(qint64 offset, uchar b); - void insert(qint64 offset, const QByteArray& data); - void replace(qint64 offset, const QByteArray& data); - void remove(qint64 offset, int len); - bool saveTo(QIODevice* device); - - public: - template<typename T, bool Owned = true> static QHexDocument* fromDevice(QIODevice* iodevice, QObject* parent = nullptr); - template<typename T> static QHexDocument* fromMemory(char *data, int size, QObject* parent = nullptr); - template<typename T> static QHexDocument* fromMemory(const QByteArray& ba, QObject* parent = nullptr); - static QHexDocument* fromBuffer(QHexBuffer* buffer, QObject* parent = nullptr); - static QHexDocument* create(QObject* parent = nullptr); - - Q_SIGNALS: - void canUndoChanged(bool canundo); - void canRedoChanged(bool canredo); - void dataChanged(const QByteArray& data, quint64 offset, QHexDocument::ChangeReason reason); - void changed(); - void reset(); - - private: - QHexBuffer* m_buffer; - QUndoStack m_undostack; - - friend class QHexView; -}; - -template<typename T, bool Owned> -QHexDocument* QHexDocument::fromDevice(QIODevice* iodevice, QObject *parent) -{ - QHexBuffer* hexbuffer = new T(parent); - if(Owned) iodevice->setParent(hexbuffer); - return hexbuffer->read(iodevice) ? new QHexDocument(hexbuffer, parent) : nullptr; -} - -template<typename T> -QHexDocument* QHexDocument::fromMemory(char *data, int size, QObject *parent) -{ - QHexBuffer* hexbuffer = new T(); - hexbuffer->read(data, size); - return new QHexDocument(hexbuffer, parent); -} - -template<typename T> -QHexDocument* QHexDocument::fromMemory(const QByteArray& ba, QObject *parent) -{ - QHexBuffer* hexbuffer = new T(); - hexbuffer->read(ba); - return new QHexDocument(hexbuffer, parent); -} diff --git a/UEFITool/qhexview5/model/qhexmetadata.h b/UEFITool/qhexview5/model/qhexmetadata.h deleted file mode 100644 index 70f4fb2..0000000 --- a/UEFITool/qhexview5/model/qhexmetadata.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include <functional> -#include <QObject> -#include <QHash> -#include <QList> -#include <QColor> -#include "qhexoptions.h" - -struct QHexMetadataItem -{ - qint64 begin, end; - QColor foreground, background; - QString comment; -}; - -using QHexMetadataLine = QList<QHexMetadataItem>; - -class QHexMetadata : public QObject -{ - Q_OBJECT - - private: - using ClearMetadataCallback = std::function<bool(QHexMetadataItem&)>; - - private: - explicit QHexMetadata(const QHexOptions* options, QObject *parent = nullptr); - - public: - const QHexMetadataLine* find(qint64 line) const; - QString getComment(qint64 line, qint64 column) const; - void removeMetadata(qint64 line); - void removeBackground(qint64 line); - void removeForeground(qint64 line); - void removeComments(qint64 line); - void unhighlight(qint64 line); - void clear(); - - public: - inline void setMetadata(qint64 begin, qint64 end, const QColor &fgcolor, const QColor &bgcolor, const QString &comment) { this->setMetadata({begin, end, fgcolor, bgcolor, comment}); } - inline void setForeground(qint64 begin, qint64 end, const QColor &fgcolor) { this->setMetadata(begin, end, fgcolor, QColor(), QString()); } - inline void setBackground(qint64 begin, qint64 end, const QColor &bgcolor) { this->setMetadata(begin, end, QColor(), bgcolor, QString()); } - inline void setComment(qint64 begin, qint64 end, const QString& comment) { this->setMetadata(begin, end, QColor(), QColor(), comment); }; - inline void setMetadataSize(qint64 begin, qint64 length, const QColor &fgcolor, const QColor &bgcolor, const QString &comment) { this->setMetadata({begin, begin + length, fgcolor, bgcolor, comment}); } - inline void setForegroundSize(qint64 begin, qint64 length, const QColor &fgcolor) { this->setForeground(begin, begin + length, fgcolor); } - inline void setBackgroundSize(qint64 begin, qint64 length, const QColor &bgcolor) { this->setBackground(begin, begin + length, bgcolor); } - inline void setCommentSize(qint64 begin, qint64 length, const QString& comment) { this->setComment(begin, begin + length, comment); }; - - private: - void copy(const QHexMetadata* metadata); - void clearMetadata(qint64 line, ClearMetadataCallback&& cb); - void setMetadata(const QHexMetadataItem& mi); - void invalidate(); - - Q_SIGNALS: - void changed(); - void cleared(); - - private: - QHash<qint64, QHexMetadataLine> m_metadata; - const QHexOptions* m_options; - - friend class QHexView; -}; diff --git a/UEFITool/qhexview5/model/qhexutils.cpp b/UEFITool/qhexview5/model/qhexutils.cpp deleted file mode 100644 index 0fab0c9..0000000 --- a/UEFITool/qhexview5/model/qhexutils.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include "qhexutils.h" -#include "qhexoptions.h" -#include "../qhexview.h" -#include <QGlobalStatic> -#include <QDataStream> -#include <QtEndian> -#include <QList> -#include <QHash> -#include <limits> -#include <cctype> - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - #define QHEXVIEW_VARIANT_EQ(x, t) ((x).metaType().id() == QMetaType::Q##t) -#else - #define QHEXVIEW_VARIANT_EQ(x, t) ((x).type() == QVariant::t) -#endif - -namespace QHexUtils { - -Q_GLOBAL_STATIC_WITH_ARGS(QList<char>, HEXMAP, ({ - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' -})); - -namespace PatternUtils { - -Q_GLOBAL_STATIC_WITH_ARGS(QString, WILDCARD_BYTE, ("??")) - -bool check(QString& p, qint64& len) -{ - static QHash<QString, QPair<QString, size_t>> processed; // Cache processed patterns - - auto it = processed.find(p); - - if(it != processed.end()) - { - p = it.value().first; - len = it.value().second; - return true; - } - - QString op = p; // Store unprocessed pattern - p = p.simplified().replace(" ", ""); - if(p.isEmpty() || (p.size() % 2)) return false; - - int wccount = 0; - - for(auto i = 0; i < p.size() - 2; i += 2) - { - const auto& hexb = p.mid(i, 2); - - if(hexb == *WILDCARD_BYTE) - { - wccount++; - continue; - } - - if(!isxdigit(hexb.at(0).toLatin1()) || !isxdigit(hexb.at(1).toLatin1())) - return false; - } - - if(wccount >= p.size()) return false; - len = p.size() / 2; - processed[op] = qMakePair(p, len); // Cache processed pattern - return true; -} - -bool match(const QByteArray& data, const QString& pattern) -{ - for(qint64 i = 0, idx = 0; (i <= (pattern.size() - 2)); i += 2, idx++) - { - if(idx >= data.size()) return false; - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - QStringView hexb = QStringView{pattern}.mid(i, 2); -#else - const QStringRef& hexb = pattern.midRef(i, 2); -#endif - - if(hexb == *WILDCARD_BYTE) continue; - - bool ok = false; - auto b = static_cast<char>(hexb.toUInt(&ok, 16)); - if(!ok || (b != data.at(idx))) return false; - } - - return true; -} - -} - -namespace { - -unsigned int countBits(quint64 val) -{ - if(val <= std::numeric_limits<quint8>::max()) return QHexFindOptions::Int8; - if(val <= std::numeric_limits<quint16>::max()) return QHexFindOptions::Int16; - if(val <= std::numeric_limits<quint32>::max()) return QHexFindOptions::Int32; - - return QHexFindOptions::Int64; -} - -template<typename Function> -qint64 findIter(qint64 startoffset, QHexFindDirection fd, const QHexView* hexview, Function&& f) -{ - QHexDocument* hexdocument = hexview->hexDocument(); - qint64 offset = -1; - - QHexFindDirection cfd = fd; - if(cfd == QHexFindDirection::All) cfd = QHexFindDirection::Forward; - - qint64 i = startoffset; - - while(offset == -1 && (cfd == QHexFindDirection::Backward ? (i >= 0) : (i < hexdocument->length()))) - { - if(!f(i, offset)) break; - - if(cfd == QHexFindDirection::Backward) i--; - else i++; - - if(fd == QHexFindDirection::All && i >= hexdocument->length()) i = 0; - } - - return offset; -} - -qint64 findDefault(const QByteArray& value, qint64 startoffset, const QHexView* hexview, unsigned int options, QHexFindDirection fd) -{ - QHexDocument* hexdocument = hexview->hexDocument(); - if(value.size() > hexdocument->length()) return -1; - - return findIter(startoffset, fd, hexview, [options, value, hexdocument](qint64 idx, qint64& offset) -> bool { - for(auto i = 0; i < value.size(); i++) { - qint64 curroffset = idx + i; - - if(curroffset >= hexdocument->length()) { - offset = -1; - return false; - } - - uchar ch1 = hexdocument->at(curroffset); - uchar ch2 = value.at(i); - - if(!(options & QHexFindOptions::CaseSensitive)) { - ch1 = std::tolower(ch1); - ch2 = std::tolower(ch2); - } - - if(ch1 != ch2) break; - if(i == value.size() - 1) offset = idx; - } - - return true; - }); -} - -qint64 findWildcard(QString pattern, qint64 startoffset, const QHexView* hexview, QHexFindDirection fd, qint64& patternlen) -{ - QHexDocument* hexdocument = hexview->hexDocument(); - if(!PatternUtils::check(pattern, patternlen) || (patternlen >= hexdocument->length())) return -1; - - return findIter(startoffset, fd, hexview, [hexdocument, pattern, patternlen](qint64 idx, qint64& offset) -> bool { - if(PatternUtils::match(hexdocument->read(idx, patternlen), pattern)) offset = idx; - return true; - }); -} - -QByteArray variantToByteArray(QVariant value, QHexFindMode mode, unsigned int options) -{ - QByteArray v; - - switch(mode) - { - case QHexFindMode::Text: - if(QHEXVIEW_VARIANT_EQ(value, String)) v = value.toString().toUtf8(); - else if(QHEXVIEW_VARIANT_EQ(value, ByteArray)) v = value.toByteArray(); - break; - - case QHexFindMode::Hex: { - if(QHEXVIEW_VARIANT_EQ(value, String)) { - qint64 len = 0; - auto s = value.toString(); - if(!PatternUtils::check(s, len)) return { }; - - bool ok = true; - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - for(auto i = 0; ok && i < s.size(); i += 2) v.push_back(static_cast<char>(QStringView{s}.mid(i, 2).toUInt(&ok, 16))); -#else - for(auto i = 0; ok && i < s.size(); i += 2) v.push_back(static_cast<char>(s.midRef(i, 2).toUInt(&ok, 16))); -#endif - - if(!ok) return { }; - } - else if(QHEXVIEW_VARIANT_EQ(value, ByteArray)) v = value.toByteArray(); - break; - } - - case QHexFindMode::Int: { - bool ok = false; - uint val = value.toUInt(&ok); - if(!ok) return QByteArray{ }; - - QDataStream ds(&v, QIODevice::WriteOnly); - - if(options & QHexFindOptions::BigEndian) { - if(options & QHexFindOptions::Int8) ds << qToBigEndian<quint8>(val); - else if(options & QHexFindOptions::Int16) ds << qToBigEndian<quint16>(val); - else if(options & QHexFindOptions::Int32) ds << qToBigEndian<quint32>(val); - else if(options & QHexFindOptions::Int64) ds << qToBigEndian<quint64>(val); - else return variantToByteArray(value, mode, options | countBits(val)); - } - else { - if(options & QHexFindOptions::Int8) ds << static_cast<quint8>(val); - else if(options & QHexFindOptions::Int16) ds << static_cast<quint16>(val); - else if(options & QHexFindOptions::Int32) ds << static_cast<quint32>(val); - else if(options & QHexFindOptions::Int64) ds << static_cast<quint64>(val); - else return variantToByteArray(value, mode, options | countBits(val)); - } - - break; - } - - case QHexFindMode::Float: { - bool ok = false; - QDataStream ds(&v, QIODevice::WriteOnly); - if(options & QHexFindOptions::Float) ds << value.toFloat(&ok); - else if(options & QHexFindOptions::Double) ds << value.toDouble(&ok); - if(!ok) return { }; - } - - default: break; - } - - return v; -} - -} // namespace - -QByteArray toHex(const QByteArray& ba, char sep) -{ - QByteArray hex(sep ? (ba.size() * 3 - 1) : (ba.size() * 2), Qt::Uninitialized); - - for(auto i = 0, o = 0; i < ba.size(); i++) - { - if(sep && i) hex[o++] = static_cast<uchar>(sep); - hex[o++] = HEXMAP->at((ba.at(i) & 0xf0) >> 4); - hex[o++] = HEXMAP->at(ba.at(i) & 0x0f); - } - - return hex; -} - -QByteArray toHex(const QByteArray& ba) { return QHexUtils::toHex(ba, '\0'); } -qint64 positionToOffset(const QHexOptions* options, QHexPosition pos) { return options->linelength * pos.line + pos.column; } -QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset) { return { offset / options->linelength, offset % options->linelength }; } - -QPair<qint64, qint64> find(const QHexView* hexview, QVariant value, qint64 startoffset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) -{ - qint64 offset, size = 0; - if(startoffset == -1) startoffset = static_cast<qint64>(hexview->offset()); - - if(mode == QHexFindMode::Hex && QHEXVIEW_VARIANT_EQ(value, String)) - { - offset = QHexUtils::findWildcard(value.toString(), startoffset, hexview, fd, size); - } - else - { - auto ba = variantToByteArray(value, mode, options); - - if(!ba.isEmpty()) - { - offset = QHexUtils::findDefault(ba, startoffset, hexview, options, fd); - size = ba.size(); - } - else - offset = -1; - } - - return {offset, offset > -1 ? size : 0}; -} - -bool checkPattern(QString pattern) -{ - qint64 len = 0; - return PatternUtils::check(pattern, len); -} - -QPair<qint64, qint64> replace(const QHexView* hexview, QVariant oldvalue, QVariant newvalue, qint64 startoffset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) -{ - auto res = QHexUtils::find(hexview, oldvalue, startoffset, mode, options, fd); - - if(res.first != -1 && res.second > 0) - { - QHexDocument* hexdocument = hexview->hexDocument(); - auto ba = variantToByteArray(newvalue, mode, options); - - if(!ba.isEmpty()) - { - hexdocument->remove(res.first, res.second); - hexdocument->insert(res.first, ba); - res.second = ba.size(); - } - else - { - res.first = -1; - res.second = 0; - } - } - - return res; -} - -} diff --git a/UEFITool/qhexview5/model/qhexutils.h b/UEFITool/qhexview5/model/qhexutils.h deleted file mode 100644 index 170e9e1..0000000 --- a/UEFITool/qhexview5/model/qhexutils.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include <QByteArray> -#include <QVariant> -#include <QString> -#include <QPair> - -struct QHexOptions; -class QHexView; - -namespace QHexFindOptions { - enum: unsigned int { - None = (1 << 0), - CaseSensitive = (1 << 1), - Int8 = (1 << 2), - Int16 = (1 << 3), - Int32 = (1 << 4), - Int64 = (1 << 5), - Float = (1 << 6), - Double = (1 << 7), - - BigEndian = (1 << 11), - }; -} - -enum class QHexFindMode { Text, Hex, Int, Float }; -enum class QHexFindDirection { All, Forward, Backward }; -enum class QHexArea { Header, Address, Hex, Ascii, Extra }; - -struct QHexPosition { - qint64 line; qint64 column; - static inline QHexPosition invalid() { return {-1, -1}; } - inline bool isValid() const { return line >= 0 && column >= 0; } - inline bool operator==(const QHexPosition& rhs) const { return (line == rhs.line) && (column == rhs.column); } - inline bool operator!=(const QHexPosition& rhs) const { return (line != rhs.line) || (column != rhs.column); } -}; - -namespace QHexUtils { - -QByteArray toHex(const QByteArray& ba, char sep); -QByteArray toHex(const QByteArray& ba); -qint64 positionToOffset(const QHexOptions* options, QHexPosition pos); -QPair<qint64, qint64> find(const QHexView* hexview, QVariant value, qint64 startoffset = 0, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward); -QPair<qint64, qint64> replace(const QHexView* hexview, QVariant oldvalue, QVariant newvalue, qint64 startoffset = 0, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward); -QHexPosition offsetToPosition(const QHexOptions* options, qint64 offset); -bool checkPattern(QString pattern); - -} diff --git a/UEFITool/qhexview5/qhexview.cpp b/UEFITool/qhexview5/qhexview.cpp deleted file mode 100644 index d5b82b6..0000000 --- a/UEFITool/qhexview5/qhexview.cpp +++ /dev/null @@ -1,1264 +0,0 @@ -#include "qhexview.h" -#include "model/buffer/qmemorybuffer.h" -#include "model/qhexcursor.h" -#include "model/qhexutils.h" -#include <QtGlobal> -#include <QtMath> -#include <QMouseEvent> -#include <QWheelEvent> -#include <QTextDocument> -#include <QFontDatabase> -#include <QApplication> -#include <QClipboard> -#include <QTextDocument> -#include <QTextCursor> -#include <QScrollBar> -#include <QToolTip> -#include <QPalette> -#include <QPainter> -#include <limits> - -#if defined(QHEXVIEW_ENABLE_DIALOGS) - #include "dialogs/hexfinddialog.h" -#endif - -#if defined(QHEXVIEW_DEBUG) - #include <QDebug> - #define qhexview_fmtprint(fmt, ...) qDebug("%s " fmt, __func__, __VA_ARGS__) -#else - #define qhexview_fmtprint(fmt, ...) -#endif - -QHexView::QHexView(QWidget *parent) : QAbstractScrollArea(parent), m_fontmetrics(this->font()) -{ - QFont f = QFontDatabase::systemFont(QFontDatabase::FixedFont); - - if (f.styleHint() != QFont::TypeWriter) { - f.setFamily("Monospace"); // Force Monospaced font - f.setStyleHint(QFont::TypeWriter); - } - - this->setFont(f); - this->setMouseTracking(true); - this->setFocusPolicy(Qt::StrongFocus); - this->viewport()->setCursor(Qt::IBeamCursor); - - QPalette p = this->palette(); - p.setBrush(QPalette::Window, p.base()); - - connect(this->verticalScrollBar(), &QScrollBar::valueChanged, this, [=](int) { this->viewport()->update(); }); - - m_hexmetadata = new QHexMetadata(&m_options, this); - connect(m_hexmetadata, &QHexMetadata::changed, this, [=]() { this->viewport()->update(); }); - - m_hexcursor = new QHexCursor(&m_options, this); - this->setDocument(QHexDocument::fromMemory<QMemoryBuffer>(QByteArray(), this)); - this->checkState(); - - connect(m_hexcursor, &QHexCursor::positionChanged, this, [=]() { - m_writing = false; - this->ensureVisible(); - Q_EMIT positionChanged(); - }); - - connect(m_hexcursor, &QHexCursor::modeChanged, this, [=]() { - m_writing = false; - this->viewport()->update(); - Q_EMIT modeChanged(); - }); -} - -QRectF QHexView::headerRect() const -{ - if(m_options.hasFlag(QHexFlags::NoHeader)) return QRectF(); - - return QRectF(0, - 0, - this->endColumnX(), - this->lineHeight()); -} - -QRectF QHexView::addressRect() const -{ - qreal y = m_options.hasFlag(QHexFlags::NoHeader) ? 0 : this->lineHeight(); - - return QRectF(0, - y, - this->endColumnX(), - this->height() - y); -} - -QRectF QHexView::hexRect() const -{ - qreal y = m_options.hasFlag(QHexFlags::NoHeader) ? 0 : this->lineHeight(); - - return QRectF(this->hexColumnX(), - y, - this->asciiColumnX() - this->hexColumnX(), - this->height() - y); -} - -QRectF QHexView::asciiRect() const -{ - qreal y = m_options.hasFlag(QHexFlags::NoHeader) ? 0 : this->lineHeight(); - - return QRectF(this->asciiColumnX(), - y, - this->endColumnX() - this->asciiColumnX(), - this->height() - y); -} - -QHexDocument* QHexView::hexDocument() const { return m_hexdocument; } -QHexCursor* QHexView::hexCursor() const { return m_hexdocument ? m_hexcursor : nullptr; } -const QHexMetadata* QHexView::hexMetadata() const { return m_hexmetadata; } -QHexOptions QHexView::options() const { return m_options; } - -void QHexView::setOptions(const QHexOptions& options) -{ - auto oldlinelength = m_options.linelength; - m_options = options; - - if(oldlinelength != m_options.linelength) - m_hexmetadata->invalidate(); - - this->checkAndUpdate(); -} - -void QHexView::setBaseAddress(quint64 baseaddress) -{ - if(m_options.baseaddress == baseaddress) return; - - m_options.baseaddress = baseaddress; - this->checkAndUpdate(); -} - -void QHexView::setDelegate(QHexDelegate* rd) -{ - if(m_hexdelegate == rd) return; - m_hexdelegate = rd; - this->checkAndUpdate(); -} - -void QHexView::setDocument(QHexDocument* doc) -{ - if(!doc) doc = QHexDocument::fromMemory<QMemoryBuffer>(QByteArray(), this); - if(!doc->parent()) doc->setParent(this); - - m_writing = false; - m_hexmetadata->clear(); - m_hexcursor->move(0); - - if(m_hexdocument) - { - disconnect(m_hexdocument, &QHexDocument::changed, this, nullptr); - disconnect(m_hexdocument, &QHexDocument::dataChanged, this, nullptr); - disconnect(m_hexdocument, &QHexDocument::reset, this, nullptr); - } - - m_hexdocument = doc; - - connect(m_hexdocument, &QHexDocument::reset, this, [=]() { - m_writing = false; - m_hexcursor->move(0); - this->checkAndUpdate(true); - }); - - connect(m_hexdocument, &QHexDocument::dataChanged, this, &QHexView::dataChanged); - connect(m_hexdocument, &QHexDocument::changed, this, [=]() { this->checkAndUpdate(true); }); - this->checkAndUpdate(true); -} - -void QHexView::setData(const QByteArray& ba) { m_hexdocument->setData(ba); } -void QHexView::setData(QHexBuffer* buffer) { m_hexdocument->setData(buffer); } -void QHexView::setCursorMode(QHexCursor::Mode mode) { m_hexcursor->setMode(mode); } - -void QHexView::setByteColor(quint8 b, QHexColor c) -{ - m_options.bytecolors[b] = c; - this->checkAndUpdate(); -} - -void QHexView::setByteForeground(quint8 b, QColor c) -{ - m_options.bytecolors[b].foreground = c; - this->checkAndUpdate(); -} - -void QHexView::setByteBackground(quint8 b, QColor c) -{ - m_options.bytecolors[b].background = c; - this->checkAndUpdate(); -} - -void QHexView::setMetadata(qint64 begin, qint64 end, const QColor& fgcolor, const QColor& bgcolor, const QString& comment) { m_hexmetadata->setMetadata(begin, end, fgcolor, bgcolor, comment); } -void QHexView::setForeground(qint64 begin, qint64 end, const QColor& fgcolor) { m_hexmetadata->setForeground(begin, end, fgcolor); } -void QHexView::setBackground(qint64 begin, qint64 end, const QColor& bgcolor) { m_hexmetadata->setBackground(begin, end, bgcolor); } -void QHexView::setComment(qint64 begin, qint64 end, const QString& comment) { m_hexmetadata->setComment(begin, end, comment); } -void QHexView::setMetadataSize(qint64 begin, qint64 length, const QColor& fgcolor, const QColor& bgcolor, const QString& comment) { m_hexmetadata->setMetadataSize(begin, length, fgcolor, bgcolor, comment); } -void QHexView::setForegroundSize(qint64 begin, qint64 length, const QColor& fgcolor) { m_hexmetadata->setForegroundSize(begin, length, fgcolor); } -void QHexView::setBackgroundSize(qint64 begin, qint64 length, const QColor& bgcolor) { m_hexmetadata->setBackgroundSize(begin, length, bgcolor); } -void QHexView::setCommentSize(qint64 begin, qint64 length, const QString& comment) { m_hexmetadata->setCommentSize(begin, length, comment); } -void QHexView::removeMetadata(qint64 line) { m_hexmetadata->removeMetadata(line); } -void QHexView::removeBackground(qint64 line) { m_hexmetadata->removeBackground(line); } -void QHexView::removeForeground(qint64 line) { m_hexmetadata->removeForeground(line); } -void QHexView::removeComments(qint64 line) { m_hexmetadata->removeComments(line); } -void QHexView::unhighlight(qint64 line) { m_hexmetadata->unhighlight(line); } -void QHexView::clearMetadata() { m_hexmetadata->clear(); } - -#if defined(QHEXVIEW_ENABLE_DIALOGS) -void QHexView::showFind() -{ - if(!m_hexdlgfind) m_hexdlgfind = new HexFindDialog(HexFindDialog::Type::Find, this); - m_hexdlgfind->show(); -} - -void QHexView::showReplace() -{ - if(!m_hexdlgreplace) m_hexdlgreplace = new HexFindDialog(HexFindDialog::Type::Replace, this); - m_hexdlgreplace->show(); -} -#endif - -void QHexView::undo() { if(m_hexdocument) m_hexdocument->undo(); } -void QHexView::redo() { if(m_hexdocument) m_hexdocument->redo(); } - -void QHexView::cut(bool hex) -{ - this->copy(hex); - if(m_readonly) return; - - if(m_hexcursor->hasSelection()) this->removeSelection(); - else m_hexdocument->remove(m_hexcursor->offset(), 1); -} - -void QHexView::copyAs(CopyMode mode) const -{ - QClipboard* c = qApp->clipboard(); - - QByteArray bytes = m_hexcursor->hasSelection() ? m_hexcursor->selectedBytes() : - m_hexdocument->read(m_hexcursor->offset(), 1); - - switch(mode) - { - case CopyMode::HexArrayCurly: - case CopyMode::HexArraySquare: { - QString hexchar; - int i = 0; - - for(char b : bytes) { - if(!hexchar.isEmpty()) { - hexchar += ", "; - if(m_options.copybreak && !(++i % m_options.linelength)) hexchar += "\n"; - } - - hexchar += "0x" + QString::number(static_cast<uint>(b), 16).toUpper(); - } - - c->setText(QString(mode == CopyMode::HexArraySquare ? "[%1]" : "{%1}").arg(hexchar)); - break; - } - - case CopyMode::HexArrayChar: { - QString hexchar; - - for(char b : bytes) - hexchar += "\\x" + QString::number(static_cast<uint>(b), 16).toUpper(); - - c->setText(QString("\"%1\"").arg(hexchar)); - break; - } - - default: { - QString hexchar; - - for(int i = 0; i < bytes.size(); i++) { - if(!(i % m_options.grouplength)) { - if(!hexchar.isEmpty()) { - hexchar += ", "; - if(m_options.copybreak && !(i % m_options.linelength)) hexchar += "\n"; - } - - hexchar += "0x"; - } - - hexchar += QString("%1").arg(static_cast<uint>(bytes[i]), 2, 16, QLatin1Char('0')).toUpper(); - } - - c->setText(hexchar); - break; - } - } -} - -void QHexView::copy(bool hex) const -{ - QClipboard* c = qApp->clipboard(); - - QByteArray bytes = m_hexcursor->hasSelection() ? m_hexcursor->selectedBytes() : - m_hexdocument->read(m_hexcursor->offset(), 1); - - if(hex) bytes = QHexUtils::toHex(bytes, ' ').toUpper(); - c->setText(bytes); -} - -void QHexView::paste(bool hex) -{ - if(m_readonly) return; - - QClipboard* c = qApp->clipboard(); - QByteArray pastedata = c->text().toUtf8(); - if(pastedata.isEmpty()) return; - - this->removeSelection(); - if(hex) pastedata = QByteArray::fromHex(pastedata); - - if(m_hexcursor->mode() == QHexCursor::Mode::Insert) m_hexdocument->insert(m_hexcursor->offset(), pastedata); - else m_hexdocument->replace(m_hexcursor->offset(), pastedata); -} - -void QHexView::selectAll() -{ - m_hexcursor->move(0); - m_hexcursor->select(m_hexdocument->length()); -} - -void QHexView::removeSelection() -{ - if(!m_hexcursor->hasSelection()) return; - if(!m_readonly) m_hexdocument->remove(m_hexcursor->selectionStartOffset(), m_hexcursor->selectionLength() - 1); - m_hexcursor->clearSelection(); -} - -void QHexView::switchMode() { m_hexcursor->switchMode(); } - -void QHexView::setAddressWidth(unsigned int w) -{ - if(w == m_options.addresswidth) return; - m_options.addresswidth = w; - this->checkState(); -} - -void QHexView::setScrollSteps(unsigned int l) -{ - if(l == m_options.scrollsteps) return; - m_options.scrollsteps = qMax(1u, l); -} - -void QHexView::setReadOnly(bool r) { m_readonly = r; } - -void QHexView::setAutoWidth(bool r) -{ - if(m_autowidth == r) return; - m_autowidth = r; - this->checkState(); -} - -void QHexView::paint(QPainter* painter) const -{ - QTextDocument doc; - doc.setDocumentMargin(0); - doc.setUndoRedoEnabled(false); - doc.setDefaultFont(this->font()); - - QTextCursor c(&doc); - - this->drawHeader(c); - this->drawDocument(c); - - painter->translate(-this->horizontalScrollBar()->value(), 0); - doc.drawContents(painter); - this->drawSeparators(painter); -} - -void QHexView::checkOptions() -{ - if(m_options.grouplength > m_options.linelength) m_options.grouplength = m_options.linelength; - if(!m_options.scrollsteps) m_options.scrollsteps = 1; - - m_options.addresswidth = qMax<unsigned int>(m_options.addresswidth, this->calcAddressWidth()); - - // Round to nearest multiple of 2 - m_options.grouplength = 1u << (static_cast<unsigned int>(qFloor(m_options.grouplength / 2.0))); - - if(m_options.grouplength <= 1) m_options.grouplength = 1; - - if(!m_options.headercolor.isValid()) - m_options.headercolor = this->palette().color(QPalette::Normal, QPalette::Highlight); -} - -void QHexView::setLineLength(unsigned int l) -{ - if(l == m_options.linelength) return; - m_options.linelength = l; - m_hexmetadata->invalidate(); - this->checkAndUpdate(true); -} - -void QHexView::setGroupLength(unsigned int l) -{ - if(l == m_options.grouplength) return; - m_options.grouplength = l; - this->checkAndUpdate(true); -} - -void QHexView::checkState() -{ - if(!m_hexdocument) return; - this->checkOptions(); - - int doclines = static_cast<int>(this->lines()), vislines = this->visibleLines(true); - qint64 vscrollmax = doclines - vislines; - if(doclines >= vislines) vscrollmax++; - - this->verticalScrollBar()->setRange(0, qMax<qint64>(0, vscrollmax)); - this->verticalScrollBar()->setPageStep(vislines - 1); - this->verticalScrollBar()->setSingleStep(m_options.scrollsteps); - - int vw = this->verticalScrollBar()->isVisible() ? this->verticalScrollBar()->width() : 0; - - static int oldmw = 0; - if(!oldmw) oldmw = this->maximumWidth(); - this->setMaximumWidth(m_autowidth ? qCeil(this->endColumnX() + vw + 3) : oldmw); - - this->horizontalScrollBar()->setRange(0, qMax<int>(0, this->endColumnX() - this->width() + vw + 3)); - this->horizontalScrollBar()->setPageStep(this->width()); -} - -void QHexView::checkAndUpdate(bool calccolumns) -{ - this->checkState(); - if(calccolumns) this->calcColumns(); - this->viewport()->update(); -} - -void QHexView::calcColumns() -{ - if(!m_hexdocument) return; - - m_hexcolumns.clear(); - m_hexcolumns.reserve(m_options.linelength); - - auto x = this->hexColumnX(), cw = this->cellWidth() * 2; - - for(auto i = 0u; i < m_options.linelength; i++) - { - for(auto j = 0u; j < m_options.grouplength; j++, x += cw) - m_hexcolumns.push_back(QRect(x, 0, cw, 0)); - - x += this->cellWidth(); - } -} - -void QHexView::ensureVisible() -{ - if(!m_hexdocument) return; - - auto pos = m_hexcursor->position(); - auto vlines = this->visibleLines(); - - if(pos.line >= (this->verticalScrollBar()->value() + vlines)) - this->verticalScrollBar()->setValue(pos.line - vlines + 1); - else if(pos.line < this->verticalScrollBar()->value()) - this->verticalScrollBar()->setValue(pos.line); - else - this->viewport()->update(); -} - -void QHexView::drawSeparators(QPainter* p) const -{ - if(!m_options.hasFlag(QHexFlags::Separators)) return; - - auto oldpen = p->pen(); - p->setPen(m_options.separatorcolor.isValid() ? m_options.separatorcolor : this->palette().color(QPalette::Dark)); - - if(m_options.hasFlag(QHexFlags::HSeparator)) - { - QLineF l(0, m_fontmetrics.lineSpacing(), this->endColumnX(), m_fontmetrics.lineSpacing()); - if(!m_hexdelegate || !m_hexdelegate->paintSeparator(p, l, this)) p->drawLine(l); - } - - if(m_options.hasFlag(QHexFlags::VSeparator)) - { - QLineF l1(this->hexColumnX(), 0, this->hexColumnX(), this->height()); - QLineF l2(this->asciiColumnX(), 0, this->asciiColumnX(), this->height()); - - if(!m_hexdelegate || !m_hexdelegate->paintSeparator(p, l1, this)) - p->drawLine(l1); - - if(!m_hexdelegate || !m_hexdelegate->paintSeparator(p, l2, this)) - p->drawLine(l2); - } - - p->setPen(oldpen); -} - -void QHexView::drawHeader(QTextCursor& c) const -{ - if(m_options.hasFlag(QHexFlags::NoHeader)) return; - - static const auto RESET_FORMAT = [](const QHexOptions& options, QTextCharFormat& cf) { - cf = { }; - cf.setForeground(options.headercolor); - }; - - QString addresslabel; - if(m_hexdelegate) addresslabel = m_hexdelegate->addressHeader(this); - if(addresslabel.isEmpty() && !m_options.addresslabel.isEmpty()) addresslabel = m_options.addresslabel; - - QTextCharFormat cf; - RESET_FORMAT(m_options, cf); - if(m_hexdelegate) m_hexdelegate->renderHeaderPart(addresslabel, QHexArea::Address, cf, this); - c.insertText(" " + QHexView::reduced(addresslabel, this->addressWidth()) + " ", cf); - - if(m_hexdelegate) RESET_FORMAT(m_options, cf); - - QString hexlabel; - if(m_hexdelegate) hexlabel = m_hexdelegate->hexHeader(this); - if(hexlabel.isEmpty()) hexlabel = m_options.hexlabel; - - if(hexlabel.isNull()) - { - c.insertText(" ", { }); - - for(auto i = 0u; i < m_options.linelength; i += m_options.grouplength) - { - QString h = QString::number(i, 16).rightJustified(m_options.grouplength * 2, '0').toUpper(); - - if(m_hexdelegate) - { - RESET_FORMAT(m_options, cf); - m_hexdelegate->renderHeaderPart(h, QHexArea::Hex, cf, this); - } - - if(m_hexcursor->column() == static_cast<qint64>(i) && m_options.hasFlag(QHexFlags::HighlightColumn)) - { - cf.setBackground(this->palette().color(QPalette::Highlight)); - cf.setForeground(this->palette().color(QPalette::HighlightedText)); - } - - c.insertText(h, cf); - c.insertText(" ", { }); - RESET_FORMAT(m_options, cf); - } - } - else - { - if(m_hexdelegate) m_hexdelegate->renderHeaderPart(hexlabel, QHexArea::Hex, cf, this); - c.insertText(" " + QHexView::reduced(hexlabel, (this->hexColumnWidth() / this->cellWidth()) - 1) + " "); - } - - if(m_hexdelegate) RESET_FORMAT(m_options, cf); - - QString asciilabel; - if(m_hexdelegate) asciilabel = m_hexdelegate->asciiHeader(this); - if(asciilabel.isEmpty()) asciilabel = m_options.asciilabel; - - if(asciilabel.isNull()) - { - c.insertText(" ", { }); - - for(unsigned int i = 0; i < m_options.linelength; i++) - { - QString a = QString::number(i, 16).toUpper(); - - if(m_hexdelegate) - { - RESET_FORMAT(m_options, cf); - m_hexdelegate->renderHeaderPart(a, QHexArea::Ascii, cf, this); - } - - if(m_hexcursor->column() == static_cast<qint64>(i) && m_options.hasFlag(QHexFlags::HighlightColumn)) - { - cf.setBackground(this->palette().color(QPalette::Highlight)); - cf.setForeground(this->palette().color(QPalette::HighlightedText)); - } - - c.insertText(a, cf); - RESET_FORMAT(m_options, cf); - } - - c.insertText(" ", { }); - } - else - { - if(m_hexdelegate) m_hexdelegate->renderHeaderPart(asciilabel, QHexArea::Ascii, cf, this); - c.insertText(" " + QHexView::reduced(asciilabel, ((this->endColumnX() - this->asciiColumnX() - this->cellWidth()) / this->cellWidth()) - 1) + " "); - } - - QTextBlockFormat bf; - if(m_options.hasFlag(QHexFlags::StyledHeader)) bf.setBackground(this->palette().color(QPalette::Window)); - if(m_hexdelegate) m_hexdelegate->renderHeader(bf, this); - c.setBlockFormat(bf); - c.insertBlock(); -} - -void QHexView::drawDocument(QTextCursor& c) const -{ - if(!m_hexdocument) return; - - qreal y = !m_options.hasFlag(QHexFlags::NoHeader) ? this->lineHeight() : 0; - quint64 line = static_cast<quint64>(this->verticalScrollBar()->value()); - - QTextCharFormat addrformat; - addrformat.setForeground(this->palette().color(QPalette::Normal, QPalette::Highlight)); - - for(qint64 l = 0; m_hexdocument->isEmpty() || (line < this->lines() && l < this->visibleLines()); l++, line++, y += this->lineHeight()) - { - quint64 address = line * m_options.linelength + this->baseAddress(); - QString addrstr = QString::number(address, 16).rightJustified(this->addressWidth(), '0').toUpper(); - - // Address Part - QTextCharFormat acf; - acf.setForeground(m_options.headercolor); - - if(m_options.hasFlag(QHexFlags::StyledAddress)) - acf.setBackground(this->palette().color(QPalette::Window)); - - if(m_hexdelegate) m_hexdelegate->renderAddress(address, acf, this); - - if(m_hexcursor->line() == static_cast<qint64>(line) && m_options.hasFlag(QHexFlags::HighlightAddress)) - { - acf.setBackground(this->palette().color(QPalette::Highlight)); - acf.setForeground(this->palette().color(QPalette::HighlightedText)); - } - - c.insertText(" " + addrstr + " ", acf); - - auto linebytes = this->getLine(line); - c.insertText(" ", { }); - - // Hex Part - for(auto column = 0u; column < m_options.linelength; ) - { - QTextCharFormat cf; - - for(auto byteidx = 0u; byteidx < m_options.grouplength; byteidx++, column++) - { - QString s = linebytes.isEmpty() || column >= static_cast<qint64>(linebytes.size()) ? " " : QString(QHexUtils::toHex(linebytes.mid(column, 1)).toUpper()); - quint8 b = static_cast<int>(column) < linebytes.size() ? linebytes.at(column) : 0x00; - cf = this->drawFormat(c, b, s, QHexArea::Hex, line, column, static_cast<int>(column) < linebytes.size()); - } - - c.insertText(" ", cf); - } - - c.insertText(" ", { }); - - // Ascii Part - for(auto column = 0u; column < m_options.linelength; column++) - { - auto s = linebytes.isEmpty() || - column >= static_cast<qint64>(linebytes.size()) ? QChar(' ') : - (QChar::isPrint(linebytes.at(column)) ? QChar(linebytes.at(column)) : m_options.unprintablechar); - - quint8 b = static_cast<int>(column) < linebytes.size() ? linebytes.at(column) : 0x00; - this->drawFormat(c, b, s, QHexArea::Ascii, line, column, static_cast<int>(column) < linebytes.size()); - } - - QTextBlockFormat bf; - - if(m_options.linealternatebackground.isValid() && line % 2) - bf.setBackground(m_options.linealternatebackground); - else if(m_options.linebackground.isValid() && !(line % 2)) - bf.setBackground(m_options.linebackground); - - c.setBlockFormat(bf); - c.insertBlock({}); - if(m_hexdocument->isEmpty()) break; - } -} - -unsigned int QHexView::calcAddressWidth() const -{ - if(!m_hexdocument) return 0; - - auto maxaddr = static_cast<quint64>(m_options.baseaddress + m_hexdocument->length()); - if(maxaddr <= std::numeric_limits<quint32>::max()) return 8; - return QString::number(maxaddr, 16).size(); -} - -int QHexView::visibleLines(bool absolute) const -{ - int vl = static_cast<int>(qCeil(this->viewport()->height() / this->lineHeight())); - if(!m_options.hasFlag(QHexFlags::NoHeader)) vl--; - return absolute ? vl : qMin<int>(this->lines(), vl); -} - -qint64 QHexView::getLastColumn(qint64 line) const { return this->getLine(line).size() - 1; } -qint64 QHexView::lastLine() const { return qMax<qint64>(0, this->lines() - 1); } - -qreal QHexView::hexColumnWidth() const -{ - int l = 0; - - for(auto i = 0u; i < m_options.linelength; i += m_options.grouplength) - l += (2 * m_options.grouplength) + 1; - - return this->getNCellsWidth(l); -} - -unsigned int QHexView::addressWidth() const -{ - if(!m_hexdocument || m_options.addresswidth) return m_options.addresswidth; - return this->calcAddressWidth(); -} - -unsigned int QHexView::lineLength() const { return m_options.linelength; } -bool QHexView::canUndo() const { return m_hexdocument && m_hexdocument->canUndo(); } -bool QHexView::canRedo() const { return m_hexdocument && m_hexdocument->canRedo(); } -quint64 QHexView::offset() const { return m_hexcursor->offset(); } -quint64 QHexView::address() const { return m_hexcursor->address(); } -QHexPosition QHexView::position() const { return m_hexcursor->position(); } -QHexPosition QHexView::selectionStart() const { return m_hexcursor->selectionStart(); } -QHexPosition QHexView::selectionEnd() const { return m_hexcursor->selectionEnd(); } -quint64 QHexView::selectionStartOffset() const { return m_hexcursor->selectionStartOffset(); } -quint64 QHexView::selectionEndOffset() const { return m_hexcursor->selectionEndOffset(); } -quint64 QHexView::baseAddress() const { return m_options.baseaddress; } - -quint64 QHexView::lines() const -{ - if(!m_hexdocument) return 0; - - auto lines = static_cast<quint64>(qCeil(m_hexdocument->length() / static_cast<double>(m_options.linelength))); - return !m_hexdocument->isEmpty() && !lines ? 1 : lines; -} - -qint64 QHexView::replace(const QVariant& oldvalue, const QVariant& newvalue, qint64 offset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) const -{ - auto res = QHexUtils::replace(this, oldvalue, newvalue, offset, mode, options, fd); - - if(res.first > -1) - { - m_hexcursor->move(res.first); - m_hexcursor->selectSize(res.second); - } - - return res.first; -} - -qint64 QHexView::find(const QVariant& value, qint64 offset, QHexFindMode mode, unsigned int options, QHexFindDirection fd) const -{ - auto res = QHexUtils::find(this, value, offset, mode, options, fd); - - if(res.first > -1) - { - m_hexcursor->move(res.first); - m_hexcursor->selectSize(res.second); - } - - return res.first; -} - -qreal QHexView::hexColumnX() const { return this->getNCellsWidth(this->addressWidth() + 2); } -qreal QHexView::asciiColumnX() const { return this->hexColumnX() + this->hexColumnWidth() + this->cellWidth(); } -qreal QHexView::endColumnX() const { return this->asciiColumnX() + this->getNCellsWidth(m_options.linelength + 1) + this->cellWidth(); } -qreal QHexView::getNCellsWidth(int n) const { return n * this->cellWidth(); } - -qreal QHexView::cellWidth() const -{ -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) - return m_fontmetrics.horizontalAdvance(" "); -#else - return m_fontmetrics.width(" "); -#endif -} - -qreal QHexView::lineHeight() const { return m_fontmetrics.height(); } - -QHexPosition QHexView::positionFromPoint(QPoint pt) const -{ - QHexPosition pos = QHexPosition::invalid(); - auto abspt = this->absolutePoint(pt); - - switch(this->areaFromPoint(pt)) - { - case QHexArea::Hex: { - pos.column = -1; - - for(qint64 i = 0; i < m_hexcolumns.size(); i++) { - if(m_hexcolumns.at(i).left() > abspt.x()) break; - pos.column = i; - } - - break; - } - - case QHexArea::Ascii: pos.column = qMax<qint64>(qFloor((abspt.x() - this->asciiColumnX()) / this->cellWidth()) - 1, 0); break; - case QHexArea::Address: pos.column = 0; break; - case QHexArea::Header: return QHexPosition::invalid(); - default: break; - } - - pos.line = qMin<qint64>(this->verticalScrollBar()->value() + (abspt.y() / this->lineHeight()), this->lines()); - if(!m_options.hasFlag(QHexFlags::NoHeader)) pos.line = qMax<qint64>(0, pos.line - 1); - - auto docline = this->getLine(pos.line); - pos.column = qMin<qint64>(pos.column, docline.isEmpty() ? 0 : docline.size()); - - qhexview_fmtprint("line: %lld, col: %lld", pos.line, pos.column); - return pos; -} - -QPoint QHexView::absolutePoint(QPoint pt) const { return pt + QPoint(this->horizontalScrollBar()->value(), 0); } - -QHexArea QHexView::areaFromPoint(QPoint pt) const -{ - pt = this->absolutePoint(pt); - qreal line = this->verticalScrollBar()->value() + pt.y() / this->lineHeight(); - - if(!m_options.hasFlag(QHexFlags::NoHeader) && !qFloor(line)) return QHexArea::Header; - if(pt.x() < this->hexColumnX()) return QHexArea::Address; - if(pt.x() < this->asciiColumnX()) return QHexArea::Hex; - if(pt.x() < this->endColumnX()) return QHexArea::Ascii; - return QHexArea::Extra; -} - -QTextCharFormat QHexView::drawFormat(QTextCursor& c, quint8 b, const QString& s, QHexArea area, qint64 line, qint64 column, bool applyformat) const -{ - QTextCharFormat cf, selcf; - QHexPosition pos{line, column}; - - if(applyformat) - { - auto offset = m_hexcursor->positionToOffset(pos); - bool hasdelegate = m_hexdelegate && m_hexdelegate->render(offset, b, cf, this); - - if(!hasdelegate) - { - auto it = m_options.bytecolors.find(b); - - if(it != m_options.bytecolors.end()) - { - if(it->background.isValid()) cf.setBackground(it->background); - if(it->foreground.isValid()) cf.setForeground(it->foreground); - } - } - - const auto* metadataline = m_hexmetadata->find(line); - - if(metadataline) - { - for(const auto& metadata : *metadataline) - { - if(offset < metadata.begin || offset >= metadata.end) continue; - - if(!hasdelegate) - { - if(metadata.foreground.isValid()) cf.setForeground(metadata.foreground); - - if(metadata.background.isValid()) - { - cf.setBackground(metadata.background); - - if(!metadata.foreground.isValid()) - cf.setForeground(this->getReadableColor(metadata.background)); - } - } - - if(!metadata.comment.isEmpty()) - { - cf.setUnderlineColor(m_options.commentcolor.isValid() ? m_options.commentcolor : this->palette().color(QPalette::WindowText)); - cf.setUnderlineStyle(QTextCharFormat::UnderlineStyle::SingleUnderline); - } - - if(offset == metadata.begin) // Remove previous metadata's style, if needed - { - if(metadata.comment.isEmpty()) selcf.setUnderlineStyle(QTextCharFormat::UnderlineStyle::NoUnderline); - if(!metadata.foreground.isValid()) selcf.setForeground(Qt::color1); - if(!metadata.background.isValid()) selcf.setBackground(Qt::transparent); - } - - if(offset < metadata.end - 1 && column < this->getLastColumn(line)) - selcf = cf; - } - } - - if(hasdelegate && column < this->getLastColumn(line)) selcf = cf; - } - - if(this->hexCursor()->isSelected(line, column)) - { - auto offset = this->hexCursor()->positionToOffset(pos); - auto selend = this->hexCursor()->selectionEndOffset(); - - cf.setBackground(this->palette().color(QPalette::Normal, QPalette::Highlight)); - cf.setForeground(this->palette().color(QPalette::Normal, QPalette::HighlightedText)); - if(offset < selend && column < this->getLastColumn(line)) selcf = cf; - } - - if(this->hexCursor()->position() == pos) - { - auto cursorbg = this->palette().color(this->hasFocus() ? QPalette::Normal : QPalette::Disabled, QPalette::WindowText); - auto cursorfg = this->palette().color(this->hasFocus() ? QPalette::Normal : QPalette::Disabled, QPalette::Base); - auto discursorbg = this->palette().color(QPalette::Disabled, QPalette::WindowText); - auto discursorfg = this->palette().color(QPalette::Disabled, QPalette::Base); - - switch(m_hexcursor->mode()) - { - case QHexCursor::Mode::Insert: - cf.setUnderlineColor(m_currentarea == area ? cursorbg : discursorbg); - cf.setUnderlineStyle(QTextCharFormat::UnderlineStyle::SingleUnderline); - break; - - case QHexCursor::Mode::Overwrite: - cf.setBackground(m_currentarea == area ? cursorbg : discursorbg); - cf.setForeground(m_currentarea == area ? cursorfg : discursorfg); - break; - } - } - - c.insertText(s, cf); - return selcf; -} - -void QHexView::moveNext(bool select) -{ - auto line = this->hexCursor()->line(), column = this->hexCursor()->column(); - - if(column >= m_options.linelength - 1) - { - line++; - column = 0; - } - else - column++; - - qint64 offset = this->hexCursor()->mode() == QHexCursor::Mode::Insert ? 1 : 0; - if(select) this->hexCursor()->select(qMin<qint64>(line, this->lines()), qMin<qint64>(column, this->getLastColumn(line) + offset)); - else this->hexCursor()->move(qMin<qint64>(line, this->lines()), qMin<qint64>(column, this->getLastColumn(line) + offset)); -} - -void QHexView::movePrevious(bool select) -{ - auto line = this->hexCursor()->line(), column = this->hexCursor()->column(); - - if(column <= 0) - { - if(!line) return; - column = this->getLine(--line).size() - 1; - } - else - column--; - - if(select) this->hexCursor()->select(qMin<qint64>(line, this->lines()), qMin<qint64>(column, this->getLastColumn(line))); - else this->hexCursor()->move(qMin<qint64>(line, this->lines()), qMin<qint64>(column, this->getLastColumn(line))); -} - -bool QHexView::keyPressMove(QKeyEvent* e) -{ - if(e->matches(QKeySequence::MoveToNextChar) || e->matches(QKeySequence::SelectNextChar)) - this->moveNext(e->matches(QKeySequence::SelectNextChar)); - else if(e->matches(QKeySequence::MoveToPreviousChar) || e->matches(QKeySequence::SelectPreviousChar)) - this->movePrevious(e->matches(QKeySequence::SelectPreviousChar)); - else if(e->matches(QKeySequence::MoveToNextLine) || e->matches(QKeySequence::SelectNextLine)) - { - if(this->hexCursor()->line() == this->lastLine()) return true; - auto nextline = this->hexCursor()->line() + 1; - if(e->matches(QKeySequence::MoveToNextLine)) this->hexCursor()->move(nextline, this->hexCursor()->column()); - else this->hexCursor()->select(nextline, this->hexCursor()->column()); - } - else if(e->matches(QKeySequence::MoveToPreviousLine) || e->matches(QKeySequence::SelectPreviousLine)) - { - if(!this->hexCursor()->line()) return true; - auto prevline = this->hexCursor()->line() - 1; - if(e->matches(QKeySequence::MoveToPreviousLine)) this->hexCursor()->move(prevline, this->hexCursor()->column()); - else this->hexCursor()->select(prevline, this->hexCursor()->column()); - } - else if(e->matches(QKeySequence::MoveToNextPage) || e->matches(QKeySequence::SelectNextPage)) - { - if(this->lastLine() == this->hexCursor()->line()) return true; - auto pageline = qMin(this->lastLine(), this->hexCursor()->line() + this->visibleLines()); - if(e->matches(QKeySequence::MoveToNextPage)) this->hexCursor()->move(pageline, this->hexCursor()->column()); - else this->hexCursor()->select(pageline, this->hexCursor()->column()); - } - else if(e->matches(QKeySequence::MoveToPreviousPage) || e->matches(QKeySequence::SelectPreviousPage)) - { - if(!this->hexCursor()->line()) return true; - auto pageline = qMax<qint64>(0, this->hexCursor()->line() - this->visibleLines()); - if(e->matches(QKeySequence::MoveToPreviousPage)) this->hexCursor()->move(pageline, this->hexCursor()->column()); - else this->hexCursor()->select(pageline, this->hexCursor()->column()); - } - else if(e->matches(QKeySequence::MoveToStartOfDocument) || e->matches(QKeySequence::SelectStartOfDocument)) - { - if(!this->hexCursor()->line()) return true; - if(e->matches(QKeySequence::MoveToStartOfDocument)) this->hexCursor()->move(0, 0); - else this->hexCursor()->select(0, 0); - } - else if(e->matches(QKeySequence::MoveToEndOfDocument) || e->matches(QKeySequence::SelectEndOfDocument)) - { - if(this->lastLine() == this->hexCursor()->line()) return true; - if(e->matches(QKeySequence::MoveToEndOfDocument)) this->hexCursor()->move(this->lastLine(), this->getLastColumn(this->hexCursor()->line())); - else this->hexCursor()->select(this->lastLine(), this->getLastColumn(this->lastLine())); - } - else if(e->matches(QKeySequence::MoveToStartOfLine) || e->matches(QKeySequence::SelectStartOfLine)) - { - auto offset = this->hexCursor()->positionToOffset({this->hexCursor()->line(), 0}); - if(e->matches(QKeySequence::MoveToStartOfLine)) this->hexCursor()->move(offset); - else this->hexCursor()->select(offset); - } - else if(e->matches(QKeySequence::SelectEndOfLine) || e->matches(QKeySequence::MoveToEndOfLine)) - { - auto offset = this->hexCursor()->positionToOffset({this->hexCursor()->line(), this->getLastColumn(this->hexCursor()->line())}); - if(e->matches(QKeySequence::SelectEndOfLine)) this->hexCursor()->select(offset); - else this->hexCursor()->move(offset); - } - else - return false; - - return true; -} - -bool QHexView::keyPressTextInput(QKeyEvent* e) -{ - if(m_readonly || e->text().isEmpty() || (e->modifiers() & Qt::ControlModifier)) return false; - - bool atend = m_hexcursor->offset() >= m_hexdocument->length(); - if(atend && m_hexcursor->mode() == QHexCursor::Mode::Overwrite) return false; - - char key = e->text().at(0).toLatin1(); - - switch(m_currentarea) - { - case QHexArea::Hex: { - if(!isxdigit(key)) return false; - - bool ok = false; - auto val = static_cast<quint8>(QString(key).toUInt(&ok, 16)); - if(!ok) return false; - m_hexcursor->removeSelection(); - - quint8 ch = m_hexdocument->isEmpty() || m_hexcursor->offset() >= m_hexdocument->length() ? '\x00' : m_hexdocument->at(m_hexcursor->offset()); - ch = m_writing ? (ch << 4) | val : val; - - if(!m_writing && (m_hexcursor->mode() == QHexCursor::Mode::Insert)) m_hexdocument->insert(m_hexcursor->offset(), val); - else m_hexdocument->replace(m_hexcursor->offset(), ch); - - m_writing = !m_writing; - if(!m_writing) - this->moveNext(); - - break; - } - - case QHexArea::Ascii: { - if(!QChar::isPrint(key)) return false; - m_hexcursor->removeSelection(); - if(m_hexcursor->mode() == QHexCursor::Mode::Insert) m_hexdocument->insert(m_hexcursor->offset(), key); - else m_hexdocument->replace(m_hexcursor->offset(), key); - this->moveNext(); - break; - } - - default: return false; - } - - return true; -} - -bool QHexView::keyPressAction(QKeyEvent* e) -{ - if(e->modifiers() != Qt::NoModifier) - { - if(e->matches(QKeySequence::SelectAll)) this->selectAll(); - else if(!m_readonly && e->matches(QKeySequence::Undo)) this->undo(); - else if(!m_readonly && e->matches(QKeySequence::Redo)) this->redo(); - else if(!m_readonly && e->matches(QKeySequence::Cut)) this->cut(m_currentarea != QHexArea::Ascii); - else if(e->matches(QKeySequence::Copy)) this->copy(m_currentarea != QHexArea::Ascii); - else if(!m_readonly && e->matches(QKeySequence::Paste)) this->paste(m_currentarea != QHexArea::Ascii); - else return false; - - return true; - } - - if(m_readonly) return false; - - switch(e->key()) - { - case Qt::Key_Backspace: - case Qt::Key_Delete: { - if(!m_hexcursor->hasSelection()) { - auto offset = m_hexcursor->offset(); - if(offset <= 0) return true; - - if(e->key() == Qt::Key_Backspace) m_hexdocument->remove(offset - 1, 1); - else m_hexdocument->remove(offset, 1); - } - else - { - auto oldpos = m_hexcursor->selectionStart(); - m_hexcursor->removeSelection(); - m_hexcursor->move(oldpos); - } - - if(e->key() == Qt::Key_Backspace) this->movePrevious(); - m_writing = false; - break; - } - - case Qt::Key_Insert: - m_writing = false; - m_hexcursor->switchMode(); - break; - - default: return false; - } - - return true; -} - -bool QHexView::event(QEvent* e) -{ - switch(e->type()) - { - case QEvent::FontChange: - m_fontmetrics = QFontMetricsF(this->font()); - this->checkAndUpdate(true); - return true; - - case QEvent::ToolTip: { - if(m_hexdocument && (m_currentarea == QHexArea::Hex || m_currentarea == QHexArea::Ascii)) { - auto* helpevent = static_cast<QHelpEvent*>(e); - auto pos = this->positionFromPoint(helpevent->pos()); - auto comment = m_hexmetadata->getComment(pos.line, pos.column); - if(!comment.isEmpty()) QToolTip::showText(helpevent->globalPos(), comment); - return true; - } - - break; - } - - default: break; - } - - return QAbstractScrollArea::event(e); -} - -void QHexView::showEvent(QShowEvent* e) -{ - QAbstractScrollArea::showEvent(e); - this->checkAndUpdate(true); -} - -void QHexView::paintEvent(QPaintEvent*) -{ - if(!m_hexdocument) return; - - QPainter painter(this->viewport()); - if(m_hexdelegate) m_hexdelegate->paint(&painter, this); - else this->paint(&painter); -} - -void QHexView::resizeEvent(QResizeEvent* e) -{ - this->checkState(); - QAbstractScrollArea::resizeEvent(e); -} - -void QHexView::focusInEvent(QFocusEvent* e) -{ - QAbstractScrollArea::focusInEvent(e); - if(m_hexdocument) this->viewport()->update(); -} - -void QHexView::focusOutEvent(QFocusEvent* e) -{ - QAbstractScrollArea::focusOutEvent(e); - if(m_hexdocument) this->viewport()->update(); -} - -void QHexView::mousePressEvent(QMouseEvent* e) -{ - QAbstractScrollArea::mousePressEvent(e); - if(!m_hexdocument || e->button() != Qt::LeftButton) return; - - auto pos = this->positionFromPoint(e->pos()); - if(!pos.isValid()) return; - - auto area = this->areaFromPoint(e->pos()); - qhexview_fmtprint("%d", static_cast<int>(area)); - - switch(area) - { - case QHexArea::Address: this->hexCursor()->move(pos.line, 0); break; - case QHexArea::Hex: m_currentarea = area; this->hexCursor()->move(pos); break; - case QHexArea::Ascii: m_currentarea = area; this->hexCursor()->move(pos.line, pos.column); break; - default: return; - } - - this->viewport()->update(); -} - -void QHexView::mouseMoveEvent(QMouseEvent* e) -{ - QAbstractScrollArea::mouseMoveEvent(e); - if(!this->hexCursor()) return; - - e->accept(); - auto area = this->areaFromPoint(e->pos()); - - switch(area) - { - case QHexArea::Header: this->viewport()->setCursor(Qt::ArrowCursor); return; - case QHexArea::Address: this->viewport()->setCursor(Qt::ArrowCursor); break; - default: this->viewport()->setCursor(Qt::IBeamCursor); break; - } - - if(e->buttons() == Qt::LeftButton) - { - auto pos = this->positionFromPoint(e->pos()); - if(!pos.isValid()) return; - if(area == QHexArea::Ascii || area == QHexArea::Hex) m_currentarea = area; - this->hexCursor()->select(pos); - } -} - -void QHexView::wheelEvent(QWheelEvent* e) -{ - e->ignore(); -#if defined Q_OS_OSX - // In macOS scrollbar invisibility should not prevent scrolling from working - if(!m_hexdocument) return; -#else - if(!m_hexdocument || !this->verticalScrollBar()->isVisible()) return; -#endif - auto ydelta = e->angleDelta().y(); - if(ydelta > 0) this->verticalScrollBar()->setValue(this->verticalScrollBar()->value() - m_options.scrollsteps); - else if(ydelta < 0) this->verticalScrollBar()->setValue(this->verticalScrollBar()->value() + m_options.scrollsteps); -} - -void QHexView::keyPressEvent(QKeyEvent* e) -{ - bool handled = false; - - if(this->hexCursor()) - { - handled = this->keyPressMove(e); - if(!handled) handled = this->keyPressAction(e); - if(!handled) handled = this->keyPressTextInput(e); - } - - if(handled) e->accept(); - else QAbstractScrollArea::keyPressEvent(e); -} - -QString QHexView::reduced(const QString& s, int maxlen) -{ - if(s.length() <= maxlen) return s.leftJustified(maxlen); - return s.mid(0, maxlen - 1) + "\u2026"; -} - -bool QHexView::isColorLight(QColor c) -{ - return std::sqrt(0.299 * std::pow(c.red(), 2) + - 0.587 * std::pow(c.green(), 2) + - 0.114 * std::pow(c.blue(), 2)) > 127.5; -} - -QColor QHexView::getReadableColor(QColor c) const -{ - QPalette palette = this->palette(); - return QHexView::isColorLight(c) ? palette.color(QPalette::Normal, QPalette::WindowText) : palette.color(QPalette::Normal, QPalette::HighlightedText); -} - -QByteArray QHexView::selectedBytes() const { return m_hexcursor->hasSelection() ? m_hexdocument->read(m_hexcursor->selectionStartOffset(), m_hexcursor->selectionLength()) : QByteArray{ }; } -QByteArray QHexView::getLine(qint64 line) const { return m_hexdocument ? m_hexdocument->read(line * m_options.linelength, m_options.linelength) : QByteArray{ }; } diff --git a/UEFITool/qhexview5/qhexview.h b/UEFITool/qhexview5/qhexview.h deleted file mode 100644 index 6ecafa7..0000000 --- a/UEFITool/qhexview5/qhexview.h +++ /dev/null @@ -1,169 +0,0 @@ -#pragma once - -#define QHEXVIEW_VERSION 5.0 - -#include <QAbstractScrollArea> -#include <QTextCharFormat> -#include <QFontMetricsF> -#include <QRectF> -#include <QList> -#include "model/qhexdelegate.h" -#include "model/qhexdocument.h" -#include "model/qhexcursor.h" - -#if defined(QHEXVIEW_ENABLE_DIALOGS) -class HexFindDialog; -#endif - -class QHexView : public QAbstractScrollArea -{ - Q_OBJECT - - public: - enum class CopyMode { Visual, HexArraySquare, HexArrayCurly, HexArrayChar }; - Q_ENUM(CopyMode); - - public: - explicit QHexView(QWidget *parent = nullptr); - QRectF headerRect() const; - QRectF addressRect() const; - QRectF hexRect() const; - QRectF asciiRect() const; - QHexDocument* hexDocument() const; - QHexCursor* hexCursor() const; - const QHexMetadata* hexMetadata() const; - QHexOptions options() const; - QColor getReadableColor(QColor c) const; - QByteArray selectedBytes() const; - QByteArray getLine(qint64 line) const; - unsigned int addressWidth() const; - unsigned int lineLength() const; - bool canUndo() const; - bool canRedo() const; - quint64 offset() const; - quint64 address() const; - QHexPosition position() const; - QHexPosition selectionStart() const; - QHexPosition selectionEnd() const; - quint64 selectionStartOffset() const; - quint64 selectionEndOffset() const; - quint64 baseAddress() const; - quint64 lines() const; - qint64 replace(const QVariant& oldvalue, const QVariant& newvalue, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const; - qint64 find(const QVariant& value, qint64 offset, QHexFindMode mode = QHexFindMode::Text, unsigned int options = QHexFindOptions::None, QHexFindDirection fd = QHexFindDirection::Forward) const; - void setOptions(const QHexOptions& options); - void setBaseAddress(quint64 baseaddress); - void setDelegate(QHexDelegate* rd); - void setDocument(QHexDocument* doc); - void setData(const QByteArray& ba); - void setData(QHexBuffer* buffer); - void setCursorMode(QHexCursor::Mode mode); - void setByteColor(quint8 b, QHexColor c); - void setByteForeground(quint8 b, QColor c); - void setByteBackground(quint8 b, QColor c); - void setMetadata(qint64 begin, qint64 end, const QColor &fgcolor, const QColor &bgcolor, const QString &comment); - void setForeground(qint64 begin, qint64 end, const QColor &fgcolor); - void setBackground(qint64 begin, qint64 end, const QColor &bgcolor); - void setComment(qint64 begin, qint64 end, const QString& comment); - void setMetadataSize(qint64 begin, qint64 length, const QColor &fgcolor, const QColor &bgcolor, const QString &comment); - void setForegroundSize(qint64 begin, qint64 length, const QColor &fgcolor); - void setBackgroundSize(qint64 begin, qint64 length, const QColor &bgcolor); - void setCommentSize(qint64 begin, qint64 length, const QString& comment); - void removeMetadata(qint64 line); - void removeBackground(qint64 line); - void removeForeground(qint64 line); - void removeComments(qint64 line); - void unhighlight(qint64 line); - void clearMetadata(); - - public Q_SLOTS: -#if defined(QHEXVIEW_ENABLE_DIALOGS) - void showFind(); - void showReplace(); -#endif - void undo(); - void redo(); - void cut(bool hex = false); - void copyAs(CopyMode mode = CopyMode::Visual) const; - void copy(bool hex = false) const; - void paste(bool hex = false); - void selectAll(); - void removeSelection(); - void switchMode(); - void setAddressWidth(unsigned int w); - void setLineLength(unsigned int l); - void setGroupLength(unsigned int l); - void setScrollSteps(unsigned int l); - void setReadOnly(bool r); - void setAutoWidth(bool r); - - private: - void paint(QPainter* painter) const; - void checkOptions(); - void checkState(); - void checkAndUpdate(bool calccolumns = false); - void calcColumns(); - void ensureVisible(); - void drawSeparators(QPainter* p) const; - void drawHeader(QTextCursor& c) const; - void drawDocument(QTextCursor& c) const; - QTextCharFormat drawFormat(QTextCursor& c, quint8 b, const QString& s, QHexArea area, qint64 line, qint64 column, bool applyformat) const; - unsigned int calcAddressWidth() const; - int visibleLines(bool absolute = false) const; - qint64 getLastColumn(qint64 line) const; - qint64 lastLine() const; - qreal getNCellsWidth(int n) const; - qreal hexColumnWidth() const; - qreal hexColumnX() const; - qreal asciiColumnX() const; - qreal endColumnX() const; - qreal cellWidth() const; - qreal lineHeight() const; - QHexPosition positionFromPoint(QPoint pt) const; - QPoint absolutePoint(QPoint pt) const; - QHexArea areaFromPoint(QPoint pt) const; - void moveNext(bool select = false); - void movePrevious(bool select = false); - bool keyPressMove(QKeyEvent* e); - bool keyPressTextInput(QKeyEvent* e); - bool keyPressAction(QKeyEvent* e); - - protected: - bool event(QEvent* e) override; - void showEvent(QShowEvent* e) override; - void paintEvent(QPaintEvent*) override; - void resizeEvent(QResizeEvent* e) override; - void focusInEvent(QFocusEvent* e) override; - void focusOutEvent(QFocusEvent* e) override; - void mousePressEvent(QMouseEvent* e) override; - void mouseMoveEvent(QMouseEvent* e) override; - void wheelEvent(QWheelEvent* e) override; - void keyPressEvent(QKeyEvent *e) override; - - private: - static QString reduced(const QString& s, int maxlen); - static bool isColorLight(QColor c); - - Q_SIGNALS: - void dataChanged(const QByteArray& data, quint64 offset, QHexDocument::ChangeReason reason); - void positionChanged(); - void modeChanged(); - - private: - bool m_readonly{false}, m_writing{false}, m_autowidth{false}; - QHexArea m_currentarea{QHexArea::Ascii}; - QList<QRectF> m_hexcolumns; - QFontMetricsF m_fontmetrics; - QHexOptions m_options; - QHexCursor* m_hexcursor{nullptr}; - QHexDocument* m_hexdocument{nullptr}; - QHexMetadata* m_hexmetadata{nullptr}; - QHexDelegate* m_hexdelegate{nullptr}; -#if defined(QHEXVIEW_ENABLE_DIALOGS) - HexFindDialog *m_hexdlgfind{nullptr}, *m_hexdlgreplace{nullptr}; -#endif - - friend class QHexDelegate; - friend class QHexCursor; -}; - diff --git a/UEFITool/uefitool.pro b/UEFITool/uefitool.pro index 44f23ce..7e8699b 100644 --- a/UEFITool/uefitool.pro +++ b/UEFITool/uefitool.pro @@ -62,20 +62,21 @@ HEADERS += uefitool.h \ ../common/zlib/zlib.h \ ../common/zlib/crc32.h \ ../version.h \ - qhexview5/model/buffer/qhexbuffer.h \ - qhexview5/model/buffer/qdevicebuffer.h \ - qhexview5/model/buffer/qmemorybuffer.h \ - qhexview5/model/commands/hexcommand.h \ - qhexview5/model/commands/insertcommand.h \ - qhexview5/model/commands/removecommand.h \ - qhexview5/model/commands/replacecommand.h \ - qhexview5/model/qhexcursor.h \ - qhexview5/model/qhexdelegate.h \ - qhexview5/model/qhexdocument.h \ - qhexview5/model/qhexmetadata.h \ - qhexview5/model/qhexoptions.h \ - qhexview5/model/qhexutils.h \ - qhexview5/qhexview.h + QHexView/include/QHexView/model/buffer/qhexbuffer.h \ + QHexView/include/QHexView/model/buffer/qdevicebuffer.h \ + QHexView/include/QHexView/model/buffer/qmemorybuffer.h \ + QHexView/include/QHexView/model/buffer/qmappedfilebuffer.h \ + QHexView/include/QHexView/model/commands/hexcommand.h \ + QHexView/include/QHexView/model/commands/insertcommand.h \ + QHexView/include/QHexView/model/commands/removecommand.h \ + QHexView/include/QHexView/model/commands/replacecommand.h \ + QHexView/include/QHexView/model/qhexcursor.h \ + QHexView/include/QHexView/model/qhexdelegate.h \ + QHexView/include/QHexView/model/qhexdocument.h \ + QHexView/include/QHexView/model/qhexmetadata.h \ + QHexView/include/QHexView/model/qhexoptions.h \ + QHexView/include/QHexView/model/qhexutils.h \ + QHexView/include/QHexView/qhexview.h SOURCES += uefitool_main.cpp \ uefitool.cpp \ @@ -138,19 +139,22 @@ SOURCES += uefitool_main.cpp \ ../common/zlib/trees.c \ ../common/zlib/uncompr.c \ ../common/zlib/zutil.c \ - qhexview5/model/buffer/qhexbuffer.cpp \ - qhexview5/model/buffer/qdevicebuffer.cpp \ - qhexview5/model/buffer/qmemorybuffer.cpp \ - qhexview5/model/commands/hexcommand.cpp \ - qhexview5/model/commands/insertcommand.cpp \ - qhexview5/model/commands/removecommand.cpp \ - qhexview5/model/commands/replacecommand.cpp \ - qhexview5/model/qhexcursor.cpp \ - qhexview5/model/qhexdelegate.cpp \ - qhexview5/model/qhexdocument.cpp \ - qhexview5/model/qhexmetadata.cpp \ - qhexview5/model/qhexutils.cpp \ - qhexview5/qhexview.cpp + QHexView/src/model/buffer/qhexbuffer.cpp \ + QHexView/src/model/buffer/qdevicebuffer.cpp \ + QHexView/src/model/buffer/qmemorybuffer.cpp \ + QHexView/src/model/buffer/qmappedfilebuffer.cpp \ + QHexView/src/model/commands/hexcommand.cpp \ + QHexView/src/model/commands/insertcommand.cpp \ + QHexView/src/model/commands/removecommand.cpp \ + QHexView/src/model/commands/replacecommand.cpp \ + QHexView/src/model/qhexcursor.cpp \ + QHexView/src/model/qhexdelegate.cpp \ + QHexView/src/model/qhexdocument.cpp \ + QHexView/src/model/qhexmetadata.cpp \ + QHexView/src/model/qhexutils.cpp \ + QHexView/src/qhexview.cpp + +INCLUDEPATH += QHexView/include/ FORMS += uefitool.ui \ searchdialog.ui \ diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 5a9f9a4..6d89299 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR) +CMAKE_MINIMUM_REQUIRED(VERSION 3.22) PROJECT(ffsparser_fuzzer LANGUAGES C CXX)