C++ Plugins (#550)

* Added Cutter plugins listing
* Added SetupInterface callback
* Added seekChanged signal handling to plugin
This commit is contained in:
xarkes 2018-06-26 09:40:08 +02:00 committed by GitHub
parent 83c6fd5d22
commit bfa495321a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 273 additions and 4 deletions

View File

@ -1696,9 +1696,6 @@ QString CutterCore::getVersionInformation()
return ret;
}
QJsonArray CutterCore::getOpenedFiles()
{
QJsonDocument files = cmdj("oj");
@ -1729,3 +1726,13 @@ void CutterCore::deleteTask(RCoreTask *task)
{
r_core_task_del(core_, task->id);
}
void CutterCore::setCutterPlugins(QList<CutterPlugin*> plugins)
{
this->plugins = plugins;
}
QList<CutterPlugin*> CutterCore::getCutterPlugins()
{
return plugins;
}

View File

@ -45,6 +45,8 @@ typedef ut64 RVA;
#define RVA_INVALID RVA_MAX
class AsyncTaskManager;
class CutterCore;
#include "plugins/CutterPlugin.h"
class RCoreLocked
{
@ -506,6 +508,9 @@ public:
void joinTask(RCoreTask *task);
void deleteTask(RCoreTask *task);
void setCutterPlugins(QList<CutterPlugin*> plugins);
QList<CutterPlugin*> getCutterPlugins();
RCoreLocked core() const;
signals:
@ -548,6 +553,8 @@ private:
RCore *core_;
AsyncTaskManager *asyncTaskManager;
QList<CutterPlugin*> plugins;
};
class ccClass : public CutterCore

View File

@ -55,6 +55,9 @@ macx {
unix:exists(/usr/local/include/libr) {
INCLUDEPATH += /usr/local/include/libr
}
unix {
QMAKE_LFLAGS += -rdynamic # Export dynamic symbols for plugins
}
# Libraries
include(lib_radare2.pri)
@ -253,7 +256,8 @@ HEADERS += \
utils/StringsTask.h \
utils/FunctionsTask.h \
utils/CommandTask.h \
utils/ProgressIndicator.h
utils/ProgressIndicator.h \
plugins/CutterPlugin.h
FORMS += \
dialogs/AboutDialog.ui \

View File

@ -8,10 +8,13 @@
#include <QTextCodec>
#include <QStringList>
#include <QProcess>
#include <QPluginLoader>
#include <QDir>
#ifdef CUTTER_ENABLE_JUPYTER
#include "utils/JupyterConnection.h"
#endif
#include "plugins/CutterPlugin.h"
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
mainWindow->openNewFile(args[0], analLevelSpecified ? analLevel : -1);
}
// Load plugins
loadPlugins();
}
CutterApplication::~CutterApplication()
@ -126,3 +132,33 @@ bool CutterApplication::event(QEvent *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);
}

View File

@ -3,6 +3,7 @@
#include <QEvent>
#include <QApplication>
#include <QList>
#include "MainWindow.h"
@ -20,6 +21,8 @@ public:
return mainWindow;
}
void loadPlugins();
protected:
bool event(QEvent *e);

View File

@ -239,6 +239,13 @@ void MainWindow::initUI()
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()

View File

@ -50,6 +50,15 @@ R2PluginsDialog::R2PluginsDialog(QWidget *parent) :
ui->RAsmTreeWidget->addTopLevelItem(item);
}
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()

View File

@ -2,12 +2,23 @@
<ui version="4.0">
<class>R2PluginsDialog</class>
<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">
<string>radare2 plugin information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>4</number>
</property>
<widget class="QWidget" name="RBinTab">
<attribute name="title">
<string>RBin</string>
@ -168,6 +179,44 @@
</item>
</layout>
</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>
</item>
<item>

View 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

View 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);
}

View 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

View 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