mirror of
https://github.com/LongSoft/UEFITool.git
synced 2025-05-31 23:38:22 -04:00
Update QHexView, build it as a library for Qt6 builds
This commit is contained in:
parent
369f10188c
commit
4e3fa5899c
63 changed files with 3919 additions and 2658 deletions
UEFIExtract
UEFIFind
UEFITool
CMakeLists.txtqhexview.cppqhexview.huefitool.pro
QHexView
CMakeLists.txtLICENSE
hexviewdialog.hinclude/QHexView
dialogs
model
qhexview.hsrc
qhexview5
model
buffer
commands
hexcommand.cpphexcommand.hinsertcommand.cppinsertcommand.hremovecommand.cppremovecommand.hreplacecommand.cppreplacecommand.h
qhexcursor.cppqhexcursor.hqhexdelegate.hqhexdocument.cppqhexdocument.hqhexmetadata.hqhexutils.cppqhexutils.hfuzzing
|
@ -1,4 +1,4 @@
|
||||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR)
|
CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
|
||||||
|
|
||||||
PROJECT(UEFIExtract)
|
PROJECT(UEFIExtract)
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR)
|
CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
|
||||||
|
|
||||||
PROJECT(UEFIFind)
|
PROJECT(UEFIFind)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ SET(PROJECT_HEADERS
|
||||||
hexviewdialog.h
|
hexviewdialog.h
|
||||||
gotobasedialog.h
|
gotobasedialog.h
|
||||||
gotoaddressdialog.h
|
gotoaddressdialog.h
|
||||||
qhexview5/qhexview.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(PROJECT_SOURCES
|
SET(PROJECT_SOURCES
|
||||||
|
@ -36,19 +35,6 @@ SET(PROJECT_SOURCES
|
||||||
hexlineedit.cpp
|
hexlineedit.cpp
|
||||||
ffsfinder.cpp
|
ffsfinder.cpp
|
||||||
hexspinbox.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/fitparser.cpp
|
||||||
../common/guiddatabase.cpp
|
../common/guiddatabase.cpp
|
||||||
../common/nvram.cpp
|
../common/nvram.cpp
|
||||||
|
@ -124,6 +110,9 @@ TARGET_INCLUDE_DIRECTORIES(UEFITool PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
TARGET_LINK_LIBRARIES(UEFITool PRIVATE Qt6::Widgets)
|
TARGET_LINK_LIBRARIES(UEFITool PRIVATE Qt6::Widgets)
|
||||||
|
|
||||||
|
ADD_SUBDIRECTORY(QHexView)
|
||||||
|
TARGET_LINK_LIBRARIES(UEFITool PRIVATE QHexView)
|
||||||
|
|
||||||
SET_TARGET_PROPERTIES(UEFITool PROPERTIES
|
SET_TARGET_PROPERTIES(UEFITool PROPERTIES
|
||||||
WIN32_EXECUTABLE ON
|
WIN32_EXECUTABLE ON
|
||||||
MACOSX_BUNDLE ON
|
MACOSX_BUNDLE ON
|
||||||
|
|
91
UEFITool/QHexView/CMakeLists.txt
Normal file
91
UEFITool/QHexView/CMakeLists.txt
Normal file
|
@ -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()
|
56
UEFITool/QHexView/include/QHexView/dialogs/hexfinddialog.h
Normal file
56
UEFITool/QHexView/include/QHexView/dialogs/hexfinddialog.h
Normal file
|
@ -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;
|
||||||
|
};
|
|
@ -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};
|
||||||
|
};
|
29
UEFITool/QHexView/include/QHexView/model/buffer/qhexbuffer.h
Normal file
29
UEFITool/QHexView/include/QHexView/model/buffer/qhexbuffer.h
Normal file
|
@ -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;
|
||||||
|
};
|
|
@ -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};
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
73
UEFITool/QHexView/include/QHexView/model/qhexcursor.h
Normal file
73
UEFITool/QHexView/include/QHexView/model/qhexcursor.h
Normal file
|
@ -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;
|
||||||
|
};
|
30
UEFITool/QHexView/include/QHexView/model/qhexdelegate.h
Normal file
30
UEFITool/QHexView/include/QHexView/model/qhexdelegate.h
Normal file
|
@ -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;
|
||||||
|
};
|
102
UEFITool/QHexView/include/QHexView/model/qhexdocument.h
Normal file
102
UEFITool/QHexView/include/QHexView/model/qhexdocument.h
Normal file
|
@ -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);
|
||||||
|
}
|
92
UEFITool/QHexView/include/QHexView/model/qhexmetadata.h
Normal file
92
UEFITool/QHexView/include/QHexView/model/qhexmetadata.h
Normal file
|
@ -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;
|
||||||
|
};
|
|
@ -1,35 +1,36 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QColor>
|
|
||||||
#include <QChar>
|
#include <QChar>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
namespace QHexFlags {
|
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,
|
enum : unsigned int {
|
||||||
Styled = StyledHeader | StyledAddress,
|
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 foreground;
|
||||||
QColor background;
|
QColor background;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QHexOptions
|
struct QHexOptions {
|
||||||
{
|
|
||||||
// Appearance
|
// Appearance
|
||||||
QChar unprintablechar{'.'};
|
QChar unprintablechar{'.'};
|
||||||
|
QChar invalidchar{'?'};
|
||||||
QString addresslabel{""};
|
QString addresslabel{""};
|
||||||
QString hexlabel;
|
QString hexlabel;
|
||||||
QString asciilabel;
|
QString asciilabel;
|
||||||
|
@ -38,7 +39,7 @@ struct QHexOptions
|
||||||
unsigned int linelength{0x10};
|
unsigned int linelength{0x10};
|
||||||
unsigned int addresswidth{0};
|
unsigned int addresswidth{0};
|
||||||
unsigned int grouplength{1};
|
unsigned int grouplength{1};
|
||||||
unsigned int scrollsteps{1};
|
int scrollsteps{1};
|
||||||
|
|
||||||
// Colors & Styles
|
// Colors & Styles
|
||||||
QHash<quint8, QHexColor> bytecolors;
|
QHash<quint8, QHexColor> bytecolors;
|
66
UEFITool/QHexView/include/QHexView/model/qhexutils.h
Normal file
66
UEFITool/QHexView/include/QHexView/model/qhexutils.h
Normal file
|
@ -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
|
184
UEFITool/QHexView/include/QHexView/qhexview.h
Normal file
184
UEFITool/QHexView/include/QHexView/qhexview.h
Normal file
|
@ -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;
|
||||||
|
};
|
418
UEFITool/QHexView/src/dialogs/hexfinddialog.cpp
Normal file
418
UEFITool/QHexView/src/dialogs/hexfinddialog.cpp
Normal file
|
@ -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());
|
||||||
|
}
|
|
@ -1,24 +1,23 @@
|
||||||
#include "qdevicebuffer.h"
|
#include <QHexView/model/buffer/qdevicebuffer.h>
|
||||||
#include <QIODevice>
|
#include <QIODevice>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
QDeviceBuffer::QDeviceBuffer(QObject *parent) : QHexBuffer{parent} { }
|
QDeviceBuffer::QDeviceBuffer(QObject* parent): QHexBuffer{parent} {}
|
||||||
|
|
||||||
QDeviceBuffer::~QDeviceBuffer()
|
QDeviceBuffer::~QDeviceBuffer() {
|
||||||
{
|
if(!m_device)
|
||||||
if(!m_device) return;
|
return;
|
||||||
|
|
||||||
if(m_device->parent() == this)
|
if(m_device->parent() == this) {
|
||||||
{
|
if(m_device->isOpen())
|
||||||
if(m_device->isOpen()) m_device->close();
|
m_device->close();
|
||||||
m_device->deleteLater();
|
m_device->deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_device = nullptr;
|
m_device = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uchar QDeviceBuffer::at(qint64 idx)
|
uchar QDeviceBuffer::at(qint64 idx) {
|
||||||
{
|
|
||||||
m_device->seek(idx);
|
m_device->seek(idx);
|
||||||
|
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
|
@ -28,68 +27,61 @@ uchar QDeviceBuffer::at(qint64 idx)
|
||||||
|
|
||||||
qint64 QDeviceBuffer::length() const { return m_device->size(); }
|
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(offset)
|
||||||
Q_UNUSED(data)
|
Q_UNUSED(data)
|
||||||
// Not implemented
|
// Not implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
void QDeviceBuffer::replace(qint64 offset, const QByteArray& data)
|
void QDeviceBuffer::replace(qint64 offset, const QByteArray& data) {
|
||||||
{
|
|
||||||
m_device->seek(offset);
|
m_device->seek(offset);
|
||||||
m_device->write(data);
|
m_device->write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QDeviceBuffer::remove(qint64 offset, int length)
|
void QDeviceBuffer::remove(qint64 offset, int length) {
|
||||||
{
|
|
||||||
Q_UNUSED(offset)
|
Q_UNUSED(offset)
|
||||||
Q_UNUSED(length)
|
Q_UNUSED(length)
|
||||||
// Not implemented
|
// Not implemented
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray QDeviceBuffer::read(qint64 offset, int length)
|
QByteArray QDeviceBuffer::read(qint64 offset, int length) {
|
||||||
{
|
|
||||||
m_device->seek(offset);
|
m_device->seek(offset);
|
||||||
return m_device->read(length);
|
return m_device->read(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QDeviceBuffer::read(QIODevice *device)
|
bool QDeviceBuffer::read(QIODevice* device) {
|
||||||
{
|
|
||||||
m_device = device;
|
m_device = device;
|
||||||
if(!m_device) return false;
|
if(!m_device)
|
||||||
if(!m_device->isOpen()) m_device->open(QIODevice::ReadWrite);
|
return false;
|
||||||
|
if(!m_device->isOpen())
|
||||||
|
m_device->open(QIODevice::ReadWrite);
|
||||||
return m_device->isOpen();
|
return m_device->isOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QDeviceBuffer::write(QIODevice *device)
|
void QDeviceBuffer::write(QIODevice* device) {
|
||||||
{
|
|
||||||
Q_UNUSED(device)
|
Q_UNUSED(device)
|
||||||
// Not implemented
|
// 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();
|
const auto MAX = std::numeric_limits<int>::max();
|
||||||
qint64 idx = -1;
|
qint64 idx = -1;
|
||||||
|
|
||||||
if(from < m_device->size())
|
if(from < m_device->size()) {
|
||||||
{
|
|
||||||
idx = from;
|
idx = from;
|
||||||
m_device->seek(from);
|
m_device->seek(from);
|
||||||
|
|
||||||
while(idx < m_device->size())
|
while(idx < m_device->size()) {
|
||||||
{
|
|
||||||
QByteArray data = m_device->read(MAX);
|
QByteArray data = m_device->read(MAX);
|
||||||
int sidx = data.indexOf(ba);
|
int sidx = data.indexOf(ba);
|
||||||
|
|
||||||
if(sidx >= 0)
|
if(sidx >= 0) {
|
||||||
{
|
|
||||||
idx += sidx;
|
idx += sidx;
|
||||||
break;
|
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());
|
m_device->seek(m_device->pos() + data.size() - ba.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,33 +89,29 @@ qint64 QDeviceBuffer::indexOf(const QByteArray& ba, qint64 from)
|
||||||
return idx;
|
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();
|
const auto MAX = std::numeric_limits<int>::max();
|
||||||
qint64 idx = -1;
|
qint64 idx = -1;
|
||||||
|
|
||||||
if(from >= 0 && ba.size() < MAX)
|
if(from >= 0 && ba.size() < MAX) {
|
||||||
{
|
|
||||||
qint64 currpos = from;
|
qint64 currpos = from;
|
||||||
|
|
||||||
while(currpos >= 0)
|
while(currpos >= 0) {
|
||||||
{
|
|
||||||
qint64 readpos = (currpos < MAX) ? 0 : currpos - MAX;
|
qint64 readpos = (currpos < MAX) ? 0 : currpos - MAX;
|
||||||
m_device->seek(readpos);
|
m_device->seek(readpos);
|
||||||
|
|
||||||
QByteArray data = m_device->read(currpos - readpos);
|
QByteArray data = m_device->read(currpos - readpos);
|
||||||
int lidx = data.lastIndexOf(ba, from);
|
int lidx = data.lastIndexOf(ba, from);
|
||||||
|
|
||||||
if(lidx >= 0)
|
if(lidx >= 0) {
|
||||||
{
|
|
||||||
idx = readpos + lidx;
|
idx = readpos + lidx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(readpos <= 0) break;
|
if(readpos <= 0)
|
||||||
|
break;
|
||||||
currpos = readpos + ba.size();
|
currpos = readpos + ba.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx;
|
return idx;
|
|
@ -1,18 +1,21 @@
|
||||||
#include "qhexbuffer.h"
|
|
||||||
#include <QBuffer>
|
#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); }
|
uchar QHexBuffer::at(qint64 idx) { return this->read(idx, 1).at(0); }
|
||||||
bool QHexBuffer::isEmpty() const { return this->length() <= 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->remove(offset, data.length());
|
||||||
this->insert(offset, data);
|
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);
|
QBuffer* buffer = new QBuffer(this);
|
||||||
buffer->setData(data, size);
|
buffer->setData(data, size);
|
||||||
|
|
||||||
|
@ -22,8 +25,7 @@ void QHexBuffer::read(char *data, int size)
|
||||||
this->read(buffer);
|
this->read(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QHexBuffer::read(const QByteArray &ba)
|
void QHexBuffer::read(const QByteArray& ba) {
|
||||||
{
|
|
||||||
QBuffer* buffer = new QBuffer(this);
|
QBuffer* buffer = new QBuffer(this);
|
||||||
|
|
||||||
buffer->setData(ba);
|
buffer->setData(ba);
|
||||||
|
@ -32,4 +34,3 @@ void QHexBuffer::read(const QByteArray &ba)
|
||||||
|
|
||||||
this->read(buffer);
|
this->read(buffer);
|
||||||
}
|
}
|
||||||
|
|
51
UEFITool/QHexView/src/model/buffer/qmappedfilebuffer.cpp
Normal file
51
UEFITool/QHexView/src/model/buffer/qmappedfilebuffer.cpp
Normal file
|
@ -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());
|
||||||
|
}
|
39
UEFITool/QHexView/src/model/buffer/qmemorybuffer.cpp
Normal file
39
UEFITool/QHexView/src/model/buffer/qmemorybuffer.cpp
Normal file
|
@ -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));
|
||||||
|
}
|
26
UEFITool/QHexView/src/model/buffer/qmemoryrefbuffer.cpp
Normal file
26
UEFITool/QHexView/src/model/buffer/qmemoryrefbuffer.cpp
Normal file
|
@ -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));
|
||||||
|
}
|
6
UEFITool/QHexView/src/model/commands/hexcommand.cpp
Normal file
6
UEFITool/QHexView/src/model/commands/hexcommand.cpp
Normal file
|
@ -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) {}
|
18
UEFITool/QHexView/src/model/commands/insertcommand.cpp
Normal file
18
UEFITool/QHexView/src/model/commands/insertcommand.cpp
Normal file
|
@ -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); }
|
20
UEFITool/QHexView/src/model/commands/removecommand.cpp
Normal file
20
UEFITool/QHexView/src/model/commands/removecommand.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
21
UEFITool/QHexView/src/model/commands/replacecommand.cpp
Normal file
21
UEFITool/QHexView/src/model/commands/replacecommand.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
182
UEFITool/QHexView/src/model/qhexcursor.cpp
Normal file
182
UEFITool/QHexView/src/model/qhexcursor.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -1,50 +1,48 @@
|
||||||
#include "../qhexview.h"
|
#include <QHexView/model/qhexdelegate.h>
|
||||||
#include "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);
|
Q_UNUSED(hexview);
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QHexDelegate::hexHeader(const QHexView* hexview) const
|
QString QHexDelegate::hexHeader(const QHexView* hexview) const {
|
||||||
{
|
|
||||||
Q_UNUSED(hexview);
|
Q_UNUSED(hexview);
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QHexDelegate::asciiHeader(const QHexView* hexview) const
|
QString QHexDelegate::asciiHeader(const QHexView* hexview) const {
|
||||||
{
|
|
||||||
Q_UNUSED(hexview);
|
Q_UNUSED(hexview);
|
||||||
return QString();
|
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(address);
|
||||||
Q_UNUSED(hexview);
|
Q_UNUSED(hexview);
|
||||||
Q_UNUSED(cf);
|
Q_UNUSED(cf);
|
||||||
Q_UNUSED(hexview);
|
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(bf);
|
||||||
Q_UNUSED(hexview);
|
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(s);
|
||||||
Q_UNUSED(area);
|
Q_UNUSED(area);
|
||||||
Q_UNUSED(cf);
|
Q_UNUSED(cf);
|
||||||
Q_UNUSED(hexview);
|
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(offset);
|
||||||
Q_UNUSED(b);
|
Q_UNUSED(b);
|
||||||
Q_UNUSED(outcf);
|
Q_UNUSED(outcf);
|
||||||
|
@ -53,16 +51,15 @@ bool QHexDelegate::render(quint64 offset, quint8 b, QTextCharFormat& outcf, cons
|
||||||
return false;
|
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(painter);
|
||||||
Q_UNUSED(line);
|
Q_UNUSED(line);
|
||||||
Q_UNUSED(hexview);
|
Q_UNUSED(hexview);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QHexDelegate::paint(QPainter* painter, const QHexView* hexview) const
|
void QHexDelegate::paint(QPainter* painter, const QHexView* hexview) const {
|
||||||
{
|
|
||||||
Q_UNUSED(hexview);
|
Q_UNUSED(hexview);
|
||||||
hexview->paint(painter);
|
hexview->paint(painter);
|
||||||
}
|
}
|
142
UEFITool/QHexView/src/model/qhexdocument.cpp
Normal file
142
UEFITool/QHexView/src/model/qhexdocument.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -1,44 +1,44 @@
|
||||||
#include "qhexmetadata.h"
|
#include <QHexView/model/qhexcursor.h>
|
||||||
#include "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);
|
auto it = m_metadata.find(line);
|
||||||
return it != m_metadata.end() ? std::addressof(it.value()) : nullptr;
|
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);
|
auto* metadataline = this->find(line);
|
||||||
if(!metadataline) return QString();
|
if(!metadataline)
|
||||||
|
return QString();
|
||||||
|
|
||||||
auto offset = QHexUtils::positionToOffset(m_options, {line, column});
|
auto offset = QHexUtils::positionToOffset(m_options, {line, column});
|
||||||
QStringList comments;
|
QStringList comments;
|
||||||
|
|
||||||
for(auto& mi : *metadataline)
|
for(auto& mi : *metadataline) {
|
||||||
{
|
if((offset < mi.begin || offset > mi.end) || mi.comment.isEmpty())
|
||||||
if((offset < mi.begin || offset > mi.end) || mi.comment.isEmpty()) continue;
|
continue;
|
||||||
comments.push_back(mi.comment);
|
comments.push_back(mi.comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
return comments.join("\n");
|
return comments.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void QHexMetadata::removeMetadata(qint64 line)
|
void QHexMetadata::removeMetadata(qint64 line) {
|
||||||
{
|
|
||||||
auto it = m_metadata.find(line);
|
auto it = m_metadata.find(line);
|
||||||
if(it == m_metadata.end()) return;
|
if(it == m_metadata.end())
|
||||||
|
return;
|
||||||
|
|
||||||
m_metadata.erase(it);
|
m_metadata.erase(it);
|
||||||
Q_EMIT changed();
|
Q_EMIT changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QHexMetadata::removeBackground(qint64 line)
|
void QHexMetadata::removeBackground(qint64 line) {
|
||||||
{
|
|
||||||
this->clearMetadata(line, [](QHexMetadataItem& mi) -> bool {
|
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()) {
|
if(mi.foreground.isValid() || !mi.comment.isEmpty()) {
|
||||||
mi.background = QColor();
|
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 {
|
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()) {
|
if(mi.background.isValid() || !mi.comment.isEmpty()) {
|
||||||
mi.foreground = QColor();
|
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 {
|
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()) {
|
if(mi.foreground.isValid() || mi.background.isValid()) {
|
||||||
mi.comment.clear();
|
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 {
|
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()) {
|
if(!mi.comment.isEmpty()) {
|
||||||
mi.foreground = QColor();
|
mi.foreground = QColor();
|
||||||
|
@ -92,54 +92,63 @@ void QHexMetadata::unhighlight(qint64 line)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void QHexMetadata::clear() { m_metadata.clear(); Q_EMIT changed(); }
|
void QHexMetadata::clear() {
|
||||||
void QHexMetadata::copy(const QHexMetadata* metadata) { m_metadata = metadata->m_metadata; }
|
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);
|
auto iit = m_metadata.find(line);
|
||||||
if(iit == m_metadata.end()) return;
|
if(iit == m_metadata.end())
|
||||||
|
return;
|
||||||
|
|
||||||
auto oldsize = iit->size();
|
auto oldsize = iit->size();
|
||||||
|
|
||||||
for(auto it = iit->begin(); it != iit->end(); )
|
for(auto it = iit->begin(); it != iit->end();) {
|
||||||
{
|
if(cb(*it))
|
||||||
if(cb(*it)) it = iit->erase(it);
|
it = iit->erase(it);
|
||||||
else it++;
|
else
|
||||||
|
it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(iit->empty())
|
if(iit->empty()) {
|
||||||
{
|
|
||||||
this->removeMetadata(line);
|
this->removeMetadata(line);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(oldsize != iit->size()) Q_EMIT changed();
|
if(oldsize != iit->size())
|
||||||
|
Q_EMIT changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QHexMetadata::setMetadata(const QHexMetadataItem& mi)
|
void QHexMetadata::setMetadata(const QHexMetadataItem& mi) {
|
||||||
{
|
if(!m_options->linelength)
|
||||||
if(!m_options->linelength) return;
|
return;
|
||||||
|
|
||||||
const qint64 firstline = mi.begin / m_options->linelength;
|
const qint64 firstline = mi.begin / m_options->linelength;
|
||||||
const qint64 lastline = mi.end / m_options->linelength;
|
const qint64 lastline = mi.end / m_options->linelength;
|
||||||
bool notify = false;
|
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 start = line == firstline ? mi.begin % m_options->linelength : 0;
|
||||||
auto length = line == lastline ? (mi.end % m_options->linelength) - start : m_options->linelength;
|
auto length = line == lastline
|
||||||
if(length <= 0) continue;
|
? (mi.end % m_options->linelength) - start
|
||||||
|
: m_options->linelength;
|
||||||
|
if(length <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
notify = true;
|
notify = true;
|
||||||
m_metadata[line].push_back(mi);
|
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;
|
auto oldmetadata = m_metadata;
|
||||||
m_metadata.clear();
|
m_metadata.clear();
|
||||||
|
|
384
UEFITool/QHexView/src/model/qhexutils.cpp
Normal file
384
UEFITool/QHexView/src/model/qhexutils.cpp
Normal file
|
@ -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
|
1582
UEFITool/QHexView/src/qhexview.cpp
Normal file
1582
UEFITool/QHexView/src/qhexview.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -15,8 +15,8 @@
|
||||||
#define HEXVIEWDIALOG_H
|
#define HEXVIEWDIALOG_H
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <QHexView/qhexview.h>
|
||||||
#include "../common/treemodel.h"
|
#include "../common/treemodel.h"
|
||||||
#include "qhexview5/qhexview.h"
|
|
||||||
#include "ui_hexviewdialog.h"
|
#include "ui_hexviewdialog.h"
|
||||||
|
|
||||||
class HexViewDialog : public QDialog
|
class HexViewDialog : public QDialog
|
||||||
|
|
|
@ -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};
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
|
|
||||||
};
|
|
|
@ -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)); }
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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) { }
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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); }
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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); }
|
|
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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); }
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -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;
|
|
||||||
};
|
|
||||||
|
|
|
@ -62,20 +62,21 @@ HEADERS += uefitool.h \
|
||||||
../common/zlib/zlib.h \
|
../common/zlib/zlib.h \
|
||||||
../common/zlib/crc32.h \
|
../common/zlib/crc32.h \
|
||||||
../version.h \
|
../version.h \
|
||||||
qhexview5/model/buffer/qhexbuffer.h \
|
QHexView/include/QHexView/model/buffer/qhexbuffer.h \
|
||||||
qhexview5/model/buffer/qdevicebuffer.h \
|
QHexView/include/QHexView/model/buffer/qdevicebuffer.h \
|
||||||
qhexview5/model/buffer/qmemorybuffer.h \
|
QHexView/include/QHexView/model/buffer/qmemorybuffer.h \
|
||||||
qhexview5/model/commands/hexcommand.h \
|
QHexView/include/QHexView/model/buffer/qmappedfilebuffer.h \
|
||||||
qhexview5/model/commands/insertcommand.h \
|
QHexView/include/QHexView/model/commands/hexcommand.h \
|
||||||
qhexview5/model/commands/removecommand.h \
|
QHexView/include/QHexView/model/commands/insertcommand.h \
|
||||||
qhexview5/model/commands/replacecommand.h \
|
QHexView/include/QHexView/model/commands/removecommand.h \
|
||||||
qhexview5/model/qhexcursor.h \
|
QHexView/include/QHexView/model/commands/replacecommand.h \
|
||||||
qhexview5/model/qhexdelegate.h \
|
QHexView/include/QHexView/model/qhexcursor.h \
|
||||||
qhexview5/model/qhexdocument.h \
|
QHexView/include/QHexView/model/qhexdelegate.h \
|
||||||
qhexview5/model/qhexmetadata.h \
|
QHexView/include/QHexView/model/qhexdocument.h \
|
||||||
qhexview5/model/qhexoptions.h \
|
QHexView/include/QHexView/model/qhexmetadata.h \
|
||||||
qhexview5/model/qhexutils.h \
|
QHexView/include/QHexView/model/qhexoptions.h \
|
||||||
qhexview5/qhexview.h
|
QHexView/include/QHexView/model/qhexutils.h \
|
||||||
|
QHexView/include/QHexView/qhexview.h
|
||||||
|
|
||||||
SOURCES += uefitool_main.cpp \
|
SOURCES += uefitool_main.cpp \
|
||||||
uefitool.cpp \
|
uefitool.cpp \
|
||||||
|
@ -138,19 +139,22 @@ SOURCES += uefitool_main.cpp \
|
||||||
../common/zlib/trees.c \
|
../common/zlib/trees.c \
|
||||||
../common/zlib/uncompr.c \
|
../common/zlib/uncompr.c \
|
||||||
../common/zlib/zutil.c \
|
../common/zlib/zutil.c \
|
||||||
qhexview5/model/buffer/qhexbuffer.cpp \
|
QHexView/src/model/buffer/qhexbuffer.cpp \
|
||||||
qhexview5/model/buffer/qdevicebuffer.cpp \
|
QHexView/src/model/buffer/qdevicebuffer.cpp \
|
||||||
qhexview5/model/buffer/qmemorybuffer.cpp \
|
QHexView/src/model/buffer/qmemorybuffer.cpp \
|
||||||
qhexview5/model/commands/hexcommand.cpp \
|
QHexView/src/model/buffer/qmappedfilebuffer.cpp \
|
||||||
qhexview5/model/commands/insertcommand.cpp \
|
QHexView/src/model/commands/hexcommand.cpp \
|
||||||
qhexview5/model/commands/removecommand.cpp \
|
QHexView/src/model/commands/insertcommand.cpp \
|
||||||
qhexview5/model/commands/replacecommand.cpp \
|
QHexView/src/model/commands/removecommand.cpp \
|
||||||
qhexview5/model/qhexcursor.cpp \
|
QHexView/src/model/commands/replacecommand.cpp \
|
||||||
qhexview5/model/qhexdelegate.cpp \
|
QHexView/src/model/qhexcursor.cpp \
|
||||||
qhexview5/model/qhexdocument.cpp \
|
QHexView/src/model/qhexdelegate.cpp \
|
||||||
qhexview5/model/qhexmetadata.cpp \
|
QHexView/src/model/qhexdocument.cpp \
|
||||||
qhexview5/model/qhexutils.cpp \
|
QHexView/src/model/qhexmetadata.cpp \
|
||||||
qhexview5/qhexview.cpp
|
QHexView/src/model/qhexutils.cpp \
|
||||||
|
QHexView/src/qhexview.cpp
|
||||||
|
|
||||||
|
INCLUDEPATH += QHexView/include/
|
||||||
|
|
||||||
FORMS += uefitool.ui \
|
FORMS += uefitool.ui \
|
||||||
searchdialog.ui \
|
searchdialog.ui \
|
||||||
|
|
|
@ -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)
|
PROJECT(ffsparser_fuzzer LANGUAGES C CXX)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue