diff --git a/docs/source/user-docs/menus/information-windows-menu.rst b/docs/source/user-docs/menus/information-windows-menu.rst index 070fdfc6..ee35bbff 100644 --- a/docs/source/user-docs/menus/information-windows-menu.rst +++ b/docs/source/user-docs/menus/information-windows-menu.rst @@ -89,8 +89,8 @@ Show VTables **Steps:** Windows -> Info... -> VTables -Show Zignatures +Show Signatures ---------------------------------------- -**Description:** Cutter has its own format of signatures, called Zignatures. This widget lists all the loaded Zignatures. +**Description:** Cutter supports the creation and the utilization of signatures. This widget lists all the signatures available to cutter. -**Steps:** Windows -> Info... -> Zignatures \ No newline at end of file +**Steps:** Windows -> Info... -> Signatures \ No newline at end of file diff --git a/rizin b/rizin index 0e87fbd8..789a283d 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 0e87fbd8107dfe463924b498c84687cfc5fe2b7f +Subproject commit 789a283dd565dadebd17ab33cbfb5ec06d87323b diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8aae0d5d..eb556529 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(SOURCES widgets/SymbolsWidget.cpp menus/DisassemblyContextMenu.cpp menus/DecompilerContextMenu.cpp + menus/FlirtContextMenu.cpp widgets/DisassemblyWidget.cpp widgets/HexdumpWidget.cpp common/Configuration.cpp @@ -73,7 +74,7 @@ set(SOURCES common/JsonTreeItem.cpp common/JsonModel.cpp dialogs/VersionInfoDialog.cpp - widgets/ZignaturesWidget.cpp + widgets/FlirtWidget.cpp common/AsyncTask.cpp dialogs/AsyncTaskDialog.cpp widgets/StackWidget.cpp @@ -190,6 +191,7 @@ set(HEADER_FILES widgets/SymbolsWidget.h menus/DisassemblyContextMenu.h menus/DecompilerContextMenu.h + menus/FlirtContextMenu.h widgets/DisassemblyWidget.h widgets/HexdumpWidget.h common/Configuration.h @@ -221,7 +223,7 @@ set(HEADER_FILES common/JsonTreeItem.h common/JsonModel.h dialogs/VersionInfoDialog.h - widgets/ZignaturesWidget.h + widgets/FlirtWidget.h common/AsyncTask.h dialogs/AsyncTaskDialog.h widgets/StackWidget.h @@ -341,7 +343,7 @@ set(UI_FILES widgets/SearchWidget.ui dialogs/RizinPluginsDialog.ui dialogs/VersionInfoDialog.ui - widgets/ZignaturesWidget.ui + widgets/FlirtWidget.ui dialogs/AsyncTaskDialog.ui dialogs/RizinTaskDialog.ui widgets/StackWidget.ui diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 87d52b15..adf0d0e9 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1016,6 +1016,40 @@ RVA CutterCore::getOffset() return core_->offset; } +void CutterCore::applySignature(const QString &filepath) +{ + CORE_LOCK(); + int old_cnt, new_cnt; + const char *arch = rz_config_get(core->config, "asm.arch"); + ut8 expected_arch = rz_core_flirt_arch_from_name(arch); + if (expected_arch == RZ_FLIRT_SIG_ARCH_ANY && filepath.endsWith(".sig", Qt::CaseInsensitive)) { + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Cannot apply signature because the requested arch is not supported by .sig " + "files\n")); + return; + } + old_cnt = rz_flag_count(core->flags, "flirt"); + rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch); + new_cnt = rz_flag_count(core->flags, "flirt"); + QMessageBox::information(nullptr, tr("Signatures"), + tr("Found %1 signatures!").arg(new_cnt - old_cnt)); +} + +void CutterCore::createSignature(const QString &filepath) +{ + CORE_LOCK(); + ut32 n_modules = 0; + if (!rz_core_flirt_create_file(core, filepath.toStdString().c_str(), &n_modules)) { + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Cannot create signature file (check the console for more details).\n")); + return; + } + QMessageBox::information(nullptr, tr("Signatures"), + tr("Written %1 signatures to %2").arg(n_modules).arg(filepath)); +} + ut64 CutterCore::math(const QString &expr) { CORE_LOCK(); @@ -2967,35 +3001,34 @@ QList CutterCore::getAllHeaders() return ret; } -QList CutterCore::getAllZignatures() +QList CutterCore::getSignaturesDB() { CORE_LOCK(); - QList zignatures; - - QJsonArray zignaturesArray = cmdj("zj").array(); - - for (const QJsonValue &value : zignaturesArray) { - QJsonObject zignatureObject = value.toObject(); - - ZignatureDescription zignature; - - zignature.name = zignatureObject[RJsonKey::name].toString(); - zignature.bytes = zignatureObject[RJsonKey::bytes].toString(); - zignature.offset = zignatureObject[RJsonKey::offset].toVariant().toULongLong(); - for (const QJsonValue &ref : zignatureObject[RJsonKey::refs].toArray()) { - zignature.refs << ref.toString(); - } - - QJsonObject graphObject = zignatureObject[RJsonKey::graph].toObject(); - zignature.cc = graphObject[RJsonKey::cc].toVariant().toULongLong(); - zignature.nbbs = graphObject[RJsonKey::nbbs].toVariant().toULongLong(); - zignature.edges = graphObject[RJsonKey::edges].toVariant().toULongLong(); - zignature.ebbs = graphObject[RJsonKey::ebbs].toVariant().toULongLong(); - - zignatures << zignature; + QList sigdb; + const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); + if (RZ_STR_ISEMPTY(sigdb_path)) { + return sigdb; } - return zignatures; + RzList *list = rz_sign_sigdb_load_database(sigdb_path, true); + void *ptr = NULL; + RzListIter *iter = NULL; + + rz_list_foreach(list, iter, ptr) + { + RzSigDBEntry *sig = static_cast(ptr); + FlirtDescription flirt; + flirt.bin_name = sig->bin_name; + flirt.arch_name = sig->arch_name; + flirt.base_name = sig->base_name; + flirt.short_path = sig->short_path; + flirt.file_path = sig->file_path; + flirt.details = sig->details; + flirt.n_modules = QString::number(sig->n_modules); + flirt.arch_bits = QString::number(sig->arch_bits); + sigdb << flirt; + } + return sigdb; } QList CutterCore::getAllComments(const QString &filterType) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index fbd73b6e..8671b73a 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -316,6 +316,10 @@ public: RVA prevOpAddr(RVA startAddr, int count); RVA nextOpAddr(RVA startAddr, int count); + /* SigDB / Flirt functions */ + void applySignature(const QString &filepath); + void createSignature(const QString &filepath); + /* Math functions */ ut64 math(const QString &expr); ut64 num(const QString &expr); @@ -553,7 +557,7 @@ public: QList getAllExports(); QList getAllSymbols(); QList getAllHeaders(); - QList getAllZignatures(); + QList getSignaturesDB(); QList getAllComments(const QString &filterType); QList getAllRelocs(); QList getAllStrings(); diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 941be488..e28894ee 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -60,16 +60,16 @@ struct HeaderDescription QString name; }; -struct ZignatureDescription +struct FlirtDescription { - QString name; - QString bytes; - RVA cc; - RVA nbbs; - RVA edges; - RVA ebbs; - RVA offset; - QStringList refs; + QString bin_name; + QString arch_name; + QString arch_bits; + QString base_name; + QString short_path; + QString file_path; + QString details; + QString n_modules; }; struct TypeDescription @@ -413,7 +413,7 @@ Q_DECLARE_METATYPE(ResourcesDescription) Q_DECLARE_METATYPE(VTableDescription) Q_DECLARE_METATYPE(TypeDescription) Q_DECLARE_METATYPE(HeaderDescription) -Q_DECLARE_METATYPE(ZignatureDescription) +Q_DECLARE_METATYPE(FlirtDescription) Q_DECLARE_METATYPE(SearchDescription) Q_DECLARE_METATYPE(SectionDescription) Q_DECLARE_METATYPE(SegmentDescription) diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 7d254031..6e796a8c 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -55,7 +55,7 @@ #include "widgets/ResourcesWidget.h" #include "widgets/VTablesWidget.h" #include "widgets/HeadersWidget.h" -#include "widgets/ZignaturesWidget.h" +#include "widgets/FlirtWidget.h" #include "widgets/DebugActions.h" #include "widgets/MemoryMapWidget.h" #include "widgets/BreakpointWidget.h" @@ -399,7 +399,7 @@ void MainWindow::initDocks() segmentsDock = new SegmentsWidget(this), symbolsDock = new SymbolsWidget(this), vTablesDock = new VTablesWidget(this), - zignaturesDock = new ZignaturesWidget(this), + flirtDock = new FlirtWidget(this), rzGraphDock = new RizinGraphWidget(this), callGraphDock = new CallGraphWidget(this, false), globalCallGraphDock = new CallGraphWidget(this, true), @@ -896,7 +896,7 @@ void MainWindow::restoreDocks() tabifyDockWidget(dashboardDock, typesDock); tabifyDockWidget(dashboardDock, searchDock); tabifyDockWidget(dashboardDock, headersDock); - tabifyDockWidget(dashboardDock, zignaturesDock); + tabifyDockWidget(dashboardDock, flirtDock); tabifyDockWidget(dashboardDock, symbolsDock); tabifyDockWidget(dashboardDock, classesDock); tabifyDockWidget(dashboardDock, resourcesDock); @@ -1741,6 +1741,50 @@ void MainWindow::on_actionExport_as_code_triggered() fileOut << Core()->cmd(cmd + " $s @ 0"); } +void MainWindow::on_actionApplySigFromFile_triggered() +{ + QStringList filters; + filters << tr("Signature File (*.sig)"); + filters << tr("Pattern File (*.pat)"); + + QFileDialog dialog(this); + dialog.setWindowTitle(tr("Apply Signature From File")); + dialog.setNameFilters(filters); + + if (!dialog.exec()) { + return; + } + + const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first()); + + if (!sigfile.isEmpty()) { + core->applySignature(sigfile); + this->refreshAll(); + } +} + +void MainWindow::on_actionCreateNewSig_triggered() +{ + QStringList filters; + filters << tr("Signature File (*.sig)"); + filters << tr("Pattern File (*.pat)"); + + QFileDialog dialog(this, tr("Create New Signature File")); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.selectFile(""); + dialog.setDefaultSuffix("sig"); + if (!dialog.exec()) + return; + + const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first()); + + if (!sigfile.isEmpty()) { + core->createSignature(sigfile); + } +} + void MainWindow::on_actionGrouped_dock_dragging_triggered(bool checked) { #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index 312350cd..dd878062 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -44,7 +44,7 @@ class ResourcesWidget; class VTablesWidget; class TypesWidget; class HeadersWidget; -class ZignaturesWidget; +class FlirtWidget; class SearchWidget; class QDockWidget; class DisassemblyWidget; @@ -190,6 +190,10 @@ private slots: void on_actionExport_as_code_triggered(); + void on_actionApplySigFromFile_triggered(); + + void on_actionCreateNewSig_triggered(); + void on_actionGrouped_dock_dragging_triggered(bool checked); void updateTasksIndicator(); @@ -243,7 +247,7 @@ private: SdbWidget *sdbDock = nullptr; SectionsWidget *sectionsDock = nullptr; SegmentsWidget *segmentsDock = nullptr; - ZignaturesWidget *zignaturesDock = nullptr; + FlirtWidget *flirtDock = nullptr; ConsoleWidget *consoleDock = nullptr; ClassesWidget *classesDock = nullptr; ResourcesWidget *resourcesDock = nullptr; diff --git a/src/core/MainWindow.ui b/src/core/MainWindow.ui index dc9e4f1e..2af046cc 100644 --- a/src/core/MainWindow.ui +++ b/src/core/MainWindow.ui @@ -77,6 +77,9 @@ + + + @@ -740,6 +743,16 @@ Export as code + + + Apply Signature From File + + + + + Create New Signature File + + Add Hexdump diff --git a/src/menus/FlirtContextMenu.cpp b/src/menus/FlirtContextMenu.cpp new file mode 100644 index 00000000..cd573af0 --- /dev/null +++ b/src/menus/FlirtContextMenu.cpp @@ -0,0 +1,62 @@ +#include "FlirtContextMenu.h" +#include "MainWindow.h" + +#include +#include +#include +#include +#include +#include + +FlirtContextMenu::FlirtContextMenu(QWidget *parent, MainWindow *mainWindow) + : QMenu(parent), mainWindow(mainWindow) +{ + actionCopyLine = new QAction(tr("Copy Line"), this); + actionApplySignature = new QAction(tr("Apply Signature File"), this); + + connect(actionCopyLine, &QAction::triggered, this, &FlirtContextMenu::onActionCopyLine); + connect(actionApplySignature, &QAction::triggered, this, + &FlirtContextMenu::onActionApplySignature); + + addAction(actionCopyLine); + addSeparator(); + addAction(actionApplySignature); + + setHasTarget(false); +} + +FlirtContextMenu::~FlirtContextMenu() {} + +void FlirtContextMenu::setTarget(const FlirtDescription &flirt) +{ + this->entry = flirt; + setHasTarget(true); +} + +void FlirtContextMenu::clearTarget() +{ + setHasTarget(false); +} + +void FlirtContextMenu::onActionCopyLine() +{ + auto clipboard = QApplication::clipboard(); + QString text = entry.bin_name + "\t" + entry.arch_name + "\t" + entry.arch_bits + "\t" + + entry.n_modules + "\t" + entry.base_name + "\t" + entry.details; + clipboard->setText(text); +} + +void FlirtContextMenu::onActionApplySignature() +{ + if (this->hasTarget) { + Core()->applySignature(entry.file_path); + } +} + +void FlirtContextMenu::setHasTarget(bool hasTarget) +{ + this->hasTarget = hasTarget; + for (const auto &action : this->actions()) { + action->setEnabled(hasTarget); + } +} diff --git a/src/menus/FlirtContextMenu.h b/src/menus/FlirtContextMenu.h new file mode 100644 index 00000000..6cf12cae --- /dev/null +++ b/src/menus/FlirtContextMenu.h @@ -0,0 +1,40 @@ +#ifndef FLIRT_CONTEXTMENU_H +#define FLIRT_CONTEXTMENU_H + +#include "core/Cutter.h" +#include +#include + +class MainWindow; + +class CUTTER_EXPORT FlirtContextMenu : public QMenu +{ + Q_OBJECT + +public: + FlirtContextMenu(QWidget *parent, MainWindow *mainWindow); + ~FlirtContextMenu(); + +public slots: + void setTarget(const FlirtDescription &flirt); + void clearTarget(); + +private: + void onActionCopyLine(); + void onActionApplySignature(); + + QMenu *pluginMenu; + QAction *pluginMenuAction; + MainWindow *mainWindow; + + bool hasTarget = false; + +protected: + void setHasTarget(bool hasTarget); + QAction *actionApplySignature; + QAction *actionCopyLine; + QAction *actionShowContents; + + FlirtDescription entry; +}; +#endif // FlirtCONTEXTMENU_H diff --git a/src/widgets/FlirtWidget.cpp b/src/widgets/FlirtWidget.cpp new file mode 100644 index 00000000..61d43d87 --- /dev/null +++ b/src/widgets/FlirtWidget.cpp @@ -0,0 +1,188 @@ +#include "FlirtWidget.h" +#include "ui_FlirtWidget.h" +#include "core/MainWindow.h" +#include "common/Helpers.h" + +FlirtModel::FlirtModel(QList *sigdb, QObject *parent) + : QAbstractListModel(parent), sigdb(sigdb) +{ +} + +int FlirtModel::rowCount(const QModelIndex &) const +{ + return sigdb->count(); +} + +int FlirtModel::columnCount(const QModelIndex &) const +{ + return FlirtModel::ColumnCount; +} + +QVariant FlirtModel::data(const QModelIndex &index, int role) const +{ + if (index.row() >= sigdb->count()) + return QVariant(); + + const FlirtDescription &entry = sigdb->at(index.row()); + + switch (role) { + case Qt::DisplayRole: + switch (index.column()) { + case BinTypeColumn: + return entry.bin_name; + case ArchNameColumn: + return entry.arch_name; + case ArchBitsColumn: + return entry.arch_bits; + case NumModulesColumn: + return entry.n_modules; + case NameColumn: + return entry.base_name; + case DetailsColumn: + return entry.details; + default: + return QVariant(); + } + + case FlirtDescriptionRole: + return QVariant::fromValue(entry); + + case Qt::ToolTipRole: { + return entry.short_path; + } + + default: + return QVariant(); + } +} + +QVariant FlirtModel::headerData(int section, Qt::Orientation, int role) const +{ + switch (role) { + case Qt::DisplayRole: + switch (section) { + case BinTypeColumn: + return tr("Bin"); + case ArchNameColumn: + return tr("Arch"); + case ArchBitsColumn: + return tr("Bits"); + case NumModulesColumn: + return tr("# Funcs"); + case NameColumn: + return tr("Name"); + case DetailsColumn: + return tr("Details"); + default: + return QVariant(); + } + default: + return QVariant(); + } +} + +FlirtProxyModel::FlirtProxyModel(FlirtModel *sourceModel, QObject *parent) + : QSortFilterProxyModel(parent) +{ + setSourceModel(sourceModel); +} + +bool FlirtProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + QModelIndex index = sourceModel()->index(row, 0, parent); + FlirtDescription entry = index.data(FlirtModel::FlirtDescriptionRole).value(); + return qhelpers::filterStringContains(entry.base_name, this); +} + +bool FlirtProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + FlirtDescription leftEntry = + left.data(FlirtModel::FlirtDescriptionRole).value(); + FlirtDescription rightEntry = + right.data(FlirtModel::FlirtDescriptionRole).value(); + + switch (left.column()) { + case FlirtModel::BinTypeColumn: + return leftEntry.bin_name < rightEntry.bin_name; + case FlirtModel::ArchNameColumn: + return leftEntry.arch_name < rightEntry.arch_name; + case FlirtModel::ArchBitsColumn: + return leftEntry.arch_bits < rightEntry.arch_bits; + case FlirtModel::NumModulesColumn: + return leftEntry.n_modules < rightEntry.n_modules; + case FlirtModel::NameColumn: + return leftEntry.base_name < rightEntry.base_name; + case FlirtModel::DetailsColumn: + return leftEntry.details < rightEntry.details; + default: + break; + } + + return leftEntry.bin_name < rightEntry.bin_name; +} + +FlirtWidget::FlirtWidget(MainWindow *main) + : CutterDockWidget(main), + ui(new Ui::FlirtWidget), + blockMenu(new FlirtContextMenu(this, mainWindow)) +{ + ui->setupUi(this); + + model = new FlirtModel(&sigdb, this); + proxyModel = new FlirtProxyModel(model, this); + ui->flirtTreeView->setModel(proxyModel); + ui->flirtTreeView->sortByColumn(FlirtModel::BinTypeColumn, Qt::AscendingOrder); + + setScrollMode(); + + this->connect(this, &QWidget::customContextMenuRequested, this, + &FlirtWidget::showItemContextMenu); + this->setContextMenuPolicy(Qt::CustomContextMenu); + + this->connect(ui->flirtTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, + &FlirtWidget::onSelectedItemChanged); + connect(Core(), &CutterCore::refreshAll, this, &FlirtWidget::refreshFlirt); + + this->addActions(this->blockMenu->actions()); +} + +FlirtWidget::~FlirtWidget() {} + +void FlirtWidget::refreshFlirt() +{ + model->beginResetModel(); + sigdb = Core()->getSignaturesDB(); + model->endResetModel(); + + ui->flirtTreeView->resizeColumnToContents(0); + ui->flirtTreeView->resizeColumnToContents(1); + ui->flirtTreeView->resizeColumnToContents(2); + ui->flirtTreeView->resizeColumnToContents(3); + ui->flirtTreeView->resizeColumnToContents(4); + ui->flirtTreeView->resizeColumnToContents(5); +} + +void FlirtWidget::setScrollMode() +{ + qhelpers::setVerticalScrollMode(ui->flirtTreeView); +} + +void FlirtWidget::onSelectedItemChanged(const QModelIndex &index) +{ + if (index.isValid()) { + const FlirtDescription &entry = sigdb.at(index.row()); + blockMenu->setTarget(entry); + } else { + blockMenu->clearTarget(); + } +} + +void FlirtWidget::showItemContextMenu(const QPoint &pt) +{ + auto index = ui->flirtTreeView->currentIndex(); + if (index.isValid()) { + const FlirtDescription &entry = sigdb.at(index.row()); + blockMenu->setTarget(entry); + blockMenu->exec(this->mapToGlobal(pt)); + } +} \ No newline at end of file diff --git a/src/widgets/FlirtWidget.h b/src/widgets/FlirtWidget.h new file mode 100644 index 00000000..937e91f5 --- /dev/null +++ b/src/widgets/FlirtWidget.h @@ -0,0 +1,88 @@ +#ifndef FLIRT_WIDGET_H +#define FLIRT_WIDGET_H + +#include + +#include "core/Cutter.h" +#include "CutterDockWidget.h" +#include "menus/FlirtContextMenu.h" + +#include +#include + +class MainWindow; +class QTreeWidget; +class QTreeWidgetItem; +class FlirtWidget; + +namespace Ui { +class FlirtWidget; +} + +class FlirtModel : public QAbstractListModel +{ + Q_OBJECT + + friend FlirtWidget; + +public: + enum Column { + BinTypeColumn = 0, + ArchNameColumn, + ArchBitsColumn, + NumModulesColumn, + NameColumn, + DetailsColumn, + ColumnCount + }; + enum Role { FlirtDescriptionRole = Qt::UserRole }; + + FlirtModel(QList *sigdb, QObject *parent = 0); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +private: + QList *sigdb; +}; + +class FlirtProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + FlirtProxyModel(FlirtModel *sourceModel, QObject *parent = nullptr); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +}; + +class FlirtWidget : public CutterDockWidget +{ + Q_OBJECT + +public: + explicit FlirtWidget(MainWindow *main); + ~FlirtWidget(); + +private slots: + void refreshFlirt(); + void onSelectedItemChanged(const QModelIndex &index); + void showItemContextMenu(const QPoint &pt); + +private: + std::unique_ptr ui; + + FlirtModel *model; + FlirtProxyModel *proxyModel; + QList sigdb; + FlirtContextMenu *blockMenu; + + void setScrollMode(); +}; + +#endif // FLIRT_WIDGET_H diff --git a/src/widgets/ZignaturesWidget.ui b/src/widgets/FlirtWidget.ui similarity index 90% rename from src/widgets/ZignaturesWidget.ui rename to src/widgets/FlirtWidget.ui index 4db82885..19b922e1 100644 --- a/src/widgets/ZignaturesWidget.ui +++ b/src/widgets/FlirtWidget.ui @@ -1,7 +1,7 @@ - ZignaturesWidget - + FlirtWidget + 0 @@ -11,7 +11,7 @@ - Zignatures + Signatures @@ -28,7 +28,7 @@ 0 - + CutterTreeView::item { diff --git a/src/widgets/ZignaturesWidget.cpp b/src/widgets/ZignaturesWidget.cpp deleted file mode 100644 index 222a4d09..00000000 --- a/src/widgets/ZignaturesWidget.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "ZignaturesWidget.h" -#include "ui_ZignaturesWidget.h" -#include "core/MainWindow.h" -#include "common/Helpers.h" - -ZignaturesModel::ZignaturesModel(QList *zignatures, QObject *parent) - : QAbstractListModel(parent), zignatures(zignatures) -{ -} - -int ZignaturesModel::rowCount(const QModelIndex &) const -{ - return zignatures->count(); -} - -int ZignaturesModel::columnCount(const QModelIndex &) const -{ - return ZignaturesModel::ColumnCount; -} - -QVariant ZignaturesModel::data(const QModelIndex &index, int role) const -{ - if (index.row() >= zignatures->count()) - return QVariant(); - - const ZignatureDescription &zignature = zignatures->at(index.row()); - - switch (role) { - case Qt::DisplayRole: - switch (index.column()) { - case OffsetColumn: - return RzAddressString(zignature.offset); - case NameColumn: - return zignature.name; - case ValueColumn: - return zignature.bytes; - default: - return QVariant(); - } - - case ZignatureDescriptionRole: - return QVariant::fromValue(zignature); - - case Qt::ToolTipRole: { - QString tmp = QString("Graph:\n\n Cyclomatic complexity: " + RzSizeString(zignature.cc) - + "\n Nodes / basicblocks: " + RzSizeString(zignature.nbbs) - + "\n Edges: " + RzSizeString(zignature.edges) - + "\n Ebbs: " + RzSizeString(zignature.ebbs) + "\n\nRefs:\n"); - for (const QString &ref : zignature.refs) { - tmp.append("\n " + ref); - } - return tmp; - } - - default: - return QVariant(); - } -} - -QVariant ZignaturesModel::headerData(int section, Qt::Orientation, int role) const -{ - switch (role) { - case Qt::DisplayRole: - switch (section) { - case OffsetColumn: - return tr("Offset"); - case NameColumn: - return tr("Name"); - case ValueColumn: - return tr("Bytes"); - default: - return QVariant(); - } - default: - return QVariant(); - } -} - -ZignaturesProxyModel::ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent) - : QSortFilterProxyModel(parent) -{ - setSourceModel(sourceModel); -} - -bool ZignaturesProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const -{ - QModelIndex index = sourceModel()->index(row, 0, parent); - ZignatureDescription item = - index.data(ZignaturesModel::ZignatureDescriptionRole).value(); - return qhelpers::filterStringContains(item.name, this); -} - -bool ZignaturesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - ZignatureDescription leftZignature = - left.data(ZignaturesModel::ZignatureDescriptionRole).value(); - ZignatureDescription rightZignature = - right.data(ZignaturesModel::ZignatureDescriptionRole).value(); - - switch (left.column()) { - case ZignaturesModel::OffsetColumn: - return leftZignature.offset < rightZignature.offset; - case ZignaturesModel::NameColumn: - return leftZignature.name < rightZignature.name; - case ZignaturesModel::ValueColumn: - return leftZignature.bytes < rightZignature.bytes; - default: - break; - } - - return leftZignature.offset < rightZignature.offset; -} - -ZignaturesWidget::ZignaturesWidget(MainWindow *main) - : CutterDockWidget(main), ui(new Ui::ZignaturesWidget) -{ - ui->setupUi(this); - - zignaturesModel = new ZignaturesModel(&zignatures, this); - zignaturesProxyModel = new ZignaturesProxyModel(zignaturesModel, this); - ui->zignaturesTreeView->setModel(zignaturesProxyModel); - ui->zignaturesTreeView->sortByColumn(ZignaturesModel::OffsetColumn, Qt::AscendingOrder); - - setScrollMode(); - - connect(Core(), &CutterCore::refreshAll, this, &ZignaturesWidget::refreshZignatures); -} - -ZignaturesWidget::~ZignaturesWidget() {} - -void ZignaturesWidget::refreshZignatures() -{ - zignaturesModel->beginResetModel(); - zignatures = Core()->getAllZignatures(); - zignaturesModel->endResetModel(); - - ui->zignaturesTreeView->resizeColumnToContents(0); - ui->zignaturesTreeView->resizeColumnToContents(1); - ui->zignaturesTreeView->resizeColumnToContents(2); -} - -void ZignaturesWidget::setScrollMode() -{ - qhelpers::setVerticalScrollMode(ui->zignaturesTreeView); -} - -void ZignaturesWidget::on_zignaturesTreeView_doubleClicked(const QModelIndex &index) -{ - ZignatureDescription item = - index.data(ZignaturesModel::ZignatureDescriptionRole).value(); - Core()->seekAndShow(item.offset); -} diff --git a/src/widgets/ZignaturesWidget.h b/src/widgets/ZignaturesWidget.h deleted file mode 100644 index 88a6d945..00000000 --- a/src/widgets/ZignaturesWidget.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef ZIGNATURESWIDGET_H -#define ZIGNATURESWIDGET_H - -#include - -#include "core/Cutter.h" -#include "CutterDockWidget.h" - -#include -#include - -class MainWindow; -class QTreeWidget; -class QTreeWidgetItem; -class ZignaturesWidget; - -namespace Ui { -class ZignaturesWidget; -} - -class ZignaturesModel : public QAbstractListModel -{ - Q_OBJECT - - friend ZignaturesWidget; - -public: - enum Column { OffsetColumn = 0, NameColumn, ValueColumn, ColumnCount }; - enum Role { ZignatureDescriptionRole = Qt::UserRole }; - - ZignaturesModel(QList *zignatures, QObject *parent = 0); - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - -private: - QList *zignatures; -}; - -class ZignaturesProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT - -public: - ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent = nullptr); - -protected: - bool filterAcceptsRow(int row, const QModelIndex &parent) const override; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; -}; - -class ZignaturesWidget : public CutterDockWidget -{ - Q_OBJECT - -public: - explicit ZignaturesWidget(MainWindow *main); - ~ZignaturesWidget(); - -private slots: - void on_zignaturesTreeView_doubleClicked(const QModelIndex &index); - - void refreshZignatures(); - -private: - std::unique_ptr ui; - - ZignaturesModel *zignaturesModel; - ZignaturesProxyModel *zignaturesProxyModel; - QList zignatures; - - void setScrollMode(); -}; - -#endif // ZIGNATURESWIDGET_H