mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-19 10:58:51 +00:00
C++ Plugins (#550)
* Added Cutter plugins listing * Added SetupInterface callback * Added seekChanged signal handling to plugin
This commit is contained in:
parent
83c6fd5d22
commit
bfa495321a
@ -1696,9 +1696,6 @@ QString CutterCore::getVersionInformation()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QJsonArray CutterCore::getOpenedFiles()
|
QJsonArray CutterCore::getOpenedFiles()
|
||||||
{
|
{
|
||||||
QJsonDocument files = cmdj("oj");
|
QJsonDocument files = cmdj("oj");
|
||||||
@ -1729,3 +1726,13 @@ void CutterCore::deleteTask(RCoreTask *task)
|
|||||||
{
|
{
|
||||||
r_core_task_del(core_, task->id);
|
r_core_task_del(core_, task->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CutterCore::setCutterPlugins(QList<CutterPlugin*> plugins)
|
||||||
|
{
|
||||||
|
this->plugins = plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<CutterPlugin*> CutterCore::getCutterPlugins()
|
||||||
|
{
|
||||||
|
return plugins;
|
||||||
|
}
|
||||||
|
@ -45,6 +45,8 @@ typedef ut64 RVA;
|
|||||||
#define RVA_INVALID RVA_MAX
|
#define RVA_INVALID RVA_MAX
|
||||||
|
|
||||||
class AsyncTaskManager;
|
class AsyncTaskManager;
|
||||||
|
class CutterCore;
|
||||||
|
#include "plugins/CutterPlugin.h"
|
||||||
|
|
||||||
class RCoreLocked
|
class RCoreLocked
|
||||||
{
|
{
|
||||||
@ -506,6 +508,9 @@ public:
|
|||||||
void joinTask(RCoreTask *task);
|
void joinTask(RCoreTask *task);
|
||||||
void deleteTask(RCoreTask *task);
|
void deleteTask(RCoreTask *task);
|
||||||
|
|
||||||
|
void setCutterPlugins(QList<CutterPlugin*> plugins);
|
||||||
|
QList<CutterPlugin*> getCutterPlugins();
|
||||||
|
|
||||||
RCoreLocked core() const;
|
RCoreLocked core() const;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -548,6 +553,8 @@ private:
|
|||||||
|
|
||||||
RCore *core_;
|
RCore *core_;
|
||||||
AsyncTaskManager *asyncTaskManager;
|
AsyncTaskManager *asyncTaskManager;
|
||||||
|
|
||||||
|
QList<CutterPlugin*> plugins;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ccClass : public CutterCore
|
class ccClass : public CutterCore
|
||||||
|
@ -55,6 +55,9 @@ macx {
|
|||||||
unix:exists(/usr/local/include/libr) {
|
unix:exists(/usr/local/include/libr) {
|
||||||
INCLUDEPATH += /usr/local/include/libr
|
INCLUDEPATH += /usr/local/include/libr
|
||||||
}
|
}
|
||||||
|
unix {
|
||||||
|
QMAKE_LFLAGS += -rdynamic # Export dynamic symbols for plugins
|
||||||
|
}
|
||||||
|
|
||||||
# Libraries
|
# Libraries
|
||||||
include(lib_radare2.pri)
|
include(lib_radare2.pri)
|
||||||
@ -253,7 +256,8 @@ HEADERS += \
|
|||||||
utils/StringsTask.h \
|
utils/StringsTask.h \
|
||||||
utils/FunctionsTask.h \
|
utils/FunctionsTask.h \
|
||||||
utils/CommandTask.h \
|
utils/CommandTask.h \
|
||||||
utils/ProgressIndicator.h
|
utils/ProgressIndicator.h \
|
||||||
|
plugins/CutterPlugin.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
dialogs/AboutDialog.ui \
|
dialogs/AboutDialog.ui \
|
||||||
|
@ -8,10 +8,13 @@
|
|||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QPluginLoader>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
#ifdef CUTTER_ENABLE_JUPYTER
|
#ifdef CUTTER_ENABLE_JUPYTER
|
||||||
#include "utils/JupyterConnection.h"
|
#include "utils/JupyterConnection.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "plugins/CutterPlugin.h"
|
||||||
|
|
||||||
CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv)
|
CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv)
|
||||||
{
|
{
|
||||||
@ -96,6 +99,9 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc
|
|||||||
} else { // filename specified as positional argument
|
} else { // filename specified as positional argument
|
||||||
mainWindow->openNewFile(args[0], analLevelSpecified ? analLevel : -1);
|
mainWindow->openNewFile(args[0], analLevelSpecified ? analLevel : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load plugins
|
||||||
|
loadPlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
CutterApplication::~CutterApplication()
|
CutterApplication::~CutterApplication()
|
||||||
@ -126,3 +132,33 @@ bool CutterApplication::event(QEvent *e)
|
|||||||
}
|
}
|
||||||
return QApplication::event(e);
|
return QApplication::event(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CutterApplication::loadPlugins()
|
||||||
|
{
|
||||||
|
QList<CutterPlugin*> plugins;
|
||||||
|
QDir pluginsDir(qApp->applicationDirPath());
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release")
|
||||||
|
pluginsDir.cdUp();
|
||||||
|
#elif defined(Q_OS_MAC)
|
||||||
|
if (pluginsDir.dirName() == "MacOS") {
|
||||||
|
pluginsDir.cdUp();
|
||||||
|
pluginsDir.cdUp();
|
||||||
|
pluginsDir.cdUp();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
pluginsDir.cd("plugins");
|
||||||
|
foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
|
||||||
|
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
|
||||||
|
QObject *plugin = pluginLoader.instance();
|
||||||
|
if (plugin) {
|
||||||
|
CutterPlugin *cutterPlugin = qobject_cast<CutterPlugin *>(plugin);
|
||||||
|
if (cutterPlugin) {
|
||||||
|
cutterPlugin->setupPlugin(Core());
|
||||||
|
plugins.append(cutterPlugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Core()->setCutterPlugins(plugins);
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
@ -20,6 +21,8 @@ public:
|
|||||||
return mainWindow;
|
return mainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadPlugins();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool event(QEvent *e);
|
bool event(QEvent *e);
|
||||||
|
|
||||||
|
@ -239,6 +239,13 @@ void MainWindow::initUI()
|
|||||||
|
|
||||||
updateTasksIndicator();
|
updateTasksIndicator();
|
||||||
connect(core->getAsyncTaskManager(), &AsyncTaskManager::tasksChanged, this, &MainWindow::updateTasksIndicator);
|
connect(core->getAsyncTaskManager(), &AsyncTaskManager::tasksChanged, this, &MainWindow::updateTasksIndicator);
|
||||||
|
|
||||||
|
/* Load plugins */
|
||||||
|
QList<CutterPlugin*> plugins = Core()->getCutterPlugins();
|
||||||
|
for (auto plugin : plugins) {
|
||||||
|
CutterDockWidget *pluginDock = plugin->setupInterface(this);
|
||||||
|
tabifyDockWidget(dashboardDock, pluginDock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateTasksIndicator()
|
void MainWindow::updateTasksIndicator()
|
||||||
|
@ -50,6 +50,15 @@ R2PluginsDialog::R2PluginsDialog(QWidget *parent) :
|
|||||||
ui->RAsmTreeWidget->addTopLevelItem(item);
|
ui->RAsmTreeWidget->addTopLevelItem(item);
|
||||||
}
|
}
|
||||||
qhelpers::adjustColumns(ui->RAsmTreeWidget, 0);
|
qhelpers::adjustColumns(ui->RAsmTreeWidget, 0);
|
||||||
|
|
||||||
|
for (CutterPlugin *plugin : Core()->getCutterPlugins()) {
|
||||||
|
QTreeWidgetItem *item = new QTreeWidgetItem();
|
||||||
|
item->setText(0, plugin->name);
|
||||||
|
item->setText(1, plugin->description);
|
||||||
|
item->setText(2, plugin->version);
|
||||||
|
item->setText(3, plugin->author);
|
||||||
|
ui->CutterTreeWidget->addTopLevelItem(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R2PluginsDialog::~R2PluginsDialog()
|
R2PluginsDialog::~R2PluginsDialog()
|
||||||
|
@ -2,12 +2,23 @@
|
|||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>R2PluginsDialog</class>
|
<class>R2PluginsDialog</class>
|
||||||
<widget class="QDialog" name="R2PluginsDialog">
|
<widget class="QDialog" name="R2PluginsDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>296</width>
|
||||||
|
<height>310</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>radare2 plugin information</string>
|
<string>radare2 plugin information</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>4</number>
|
||||||
|
</property>
|
||||||
<widget class="QWidget" name="RBinTab">
|
<widget class="QWidget" name="RBinTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>RBin</string>
|
<string>RBin</string>
|
||||||
@ -168,6 +179,44 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="CutterTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Cutter</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="CutterLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Cutter plugins</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeWidget" name="CutterTreeWidget">
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Description</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Version</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>Author</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
31
src/plugins/CutterPlugin.h
Normal file
31
src/plugins/CutterPlugin.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef CUTTERPLUGIN_H
|
||||||
|
#define CUTTERPLUGIN_H
|
||||||
|
|
||||||
|
class CutterPlugin;
|
||||||
|
class MainWindow;
|
||||||
|
|
||||||
|
#include "Cutter.h"
|
||||||
|
#include "widgets/CutterDockWidget.h"
|
||||||
|
|
||||||
|
class CutterPlugin
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~CutterPlugin() {}
|
||||||
|
virtual void setupPlugin(CutterCore *core) = 0;
|
||||||
|
virtual CutterDockWidget* setupInterface(MainWindow *main, QAction *action = nullptr) = 0;
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
QString description;
|
||||||
|
QString version;
|
||||||
|
QString author;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CutterCore *core;
|
||||||
|
CutterDockWidget *dockable;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CutterPlugin_iid "org.radare.cutter.plugins.CutterPlugin"
|
||||||
|
|
||||||
|
Q_DECLARE_INTERFACE(CutterPlugin, CutterPlugin_iid)
|
||||||
|
|
||||||
|
#endif // CUTTERPLUGIN_H
|
68
src/plugins/CutterSamplePlugin.cpp
Normal file
68
src/plugins/CutterSamplePlugin.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include <QLabel>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include "CutterSamplePlugin.h"
|
||||||
|
#include "utils/TempConfig.h"
|
||||||
|
#include "utils/Configuration.h"
|
||||||
|
|
||||||
|
void CutterSamplePlugin::setupPlugin(CutterCore *core)
|
||||||
|
{
|
||||||
|
this->core = core;
|
||||||
|
this->name = "SamplePlugin";
|
||||||
|
this->description = "Just a sample plugin.";
|
||||||
|
this->version = "1.0";
|
||||||
|
this->author = "xarkes";
|
||||||
|
}
|
||||||
|
|
||||||
|
CutterDockWidget* CutterSamplePlugin::setupInterface(MainWindow *main, QAction* actions)
|
||||||
|
{
|
||||||
|
// Instantiate dock widget
|
||||||
|
dockable = new CutterSamplePluginWidget(main, actions);
|
||||||
|
return dockable;
|
||||||
|
}
|
||||||
|
|
||||||
|
CutterSamplePluginWidget::CutterSamplePluginWidget(MainWindow *main, QAction *action) :
|
||||||
|
CutterDockWidget(main, action)
|
||||||
|
{
|
||||||
|
this->setObjectName("CutterSamplePluginWidget");
|
||||||
|
this->setWindowTitle("Sample Plugin");
|
||||||
|
QWidget *content = new QWidget();
|
||||||
|
this->setWidget(content);
|
||||||
|
|
||||||
|
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||||
|
content->setLayout(layout);
|
||||||
|
text = new QLabel(content);
|
||||||
|
text->setFont(Config()->getFont());
|
||||||
|
text->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||||
|
layout->addWidget(text);
|
||||||
|
|
||||||
|
QPushButton *button = new QPushButton(content);
|
||||||
|
button->setText("Want a fortune?");
|
||||||
|
button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||||
|
button->setMaximumHeight(50);
|
||||||
|
button->setMaximumWidth(200);
|
||||||
|
layout->addWidget(button);
|
||||||
|
layout->setAlignment(button, Qt::AlignHCenter);
|
||||||
|
|
||||||
|
connect(Core(), &CutterCore::seekChanged, this, &CutterSamplePluginWidget::on_seekChanged);
|
||||||
|
connect(button, &QPushButton::clicked, this, &CutterSamplePluginWidget::on_buttonClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterSamplePluginWidget::on_seekChanged(RVA addr)
|
||||||
|
{
|
||||||
|
Q_UNUSED(addr);
|
||||||
|
QString res;
|
||||||
|
{
|
||||||
|
TempConfig tempConfig;
|
||||||
|
tempConfig.set("scr.color", 0);
|
||||||
|
res = Core()->cmd("?E `pi 1`");
|
||||||
|
}
|
||||||
|
text->setText(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CutterSamplePluginWidget::on_buttonClicked()
|
||||||
|
{
|
||||||
|
QString res = Core()->cmd("?E `fo`");
|
||||||
|
text->setText(res);
|
||||||
|
}
|
35
src/plugins/CutterSamplePlugin.h
Normal file
35
src/plugins/CutterSamplePlugin.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef CUTTERSAMPLEPLUGIN_H
|
||||||
|
#define CUTTERSAMPLEPLUGIN_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QtPlugin>
|
||||||
|
#include "CutterPlugin.h"
|
||||||
|
|
||||||
|
class CutterSamplePlugin : public QObject, CutterPlugin
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PLUGIN_METADATA(IID "org.radare.cutter.plugins.CutterPlugin")
|
||||||
|
Q_INTERFACES(CutterPlugin)
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setupPlugin(CutterCore *core) override;
|
||||||
|
CutterDockWidget* setupInterface(MainWindow *main, QAction *action = nullptr) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CutterSamplePluginWidget : public CutterDockWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CutterSamplePluginWidget(MainWindow *main, QAction *action);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLabel* text;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_seekChanged(RVA addr);
|
||||||
|
void on_buttonClicked();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CUTTERSAMPLEPLUGIN_H
|
13
src/plugins/PluginSample.pro
Normal file
13
src/plugins/PluginSample.pro
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
HEADERS += CutterSamplePlugin.h CutterPlugin.h
|
||||||
|
INCLUDEPATH += ../
|
||||||
|
SOURCES += CutterSamplePlugin.cpp
|
||||||
|
|
||||||
|
# Needed for r_core include TODO cross platform
|
||||||
|
unix:exists(/usr/include/libr) {
|
||||||
|
INCLUDEPATH += /usr/include/libr
|
||||||
|
}
|
||||||
|
|
||||||
|
TEMPLATE = lib
|
||||||
|
CONFIG += plugin
|
||||||
|
QT += widgets
|
||||||
|
TARGET = PluginSample
|
Loading…
Reference in New Issue
Block a user