"Fossies" - the Fresh Open Source Software Archive

Member "cutter-1.9.0/src/CutterApplication.cpp" (6 Sep 2019, 11357 Bytes) of package /linux/privat/cutter-1.9.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "CutterApplication.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.8.3_vs_1.9.0.

    1 #include "common/PythonManager.h"
    2 #include "common/CrashHandler.h"
    3 #include "CutterApplication.h"
    4 #include "plugins/PluginManager.h"
    5 #include "CutterConfig.h"
    6 #include "common/Decompiler.h"
    7 
    8 #include <QApplication>
    9 #include <QFileOpenEvent>
   10 #include <QEvent>
   11 #include <QMenu>
   12 #include <QMessageBox>
   13 #include <QCommandLineParser>
   14 #include <QTextCodec>
   15 #include <QStringList>
   16 #include <QProcess>
   17 #include <QPluginLoader>
   18 #include <QDir>
   19 #include <QTranslator>
   20 #include <QLibraryInfo>
   21 #include <QFontDatabase>
   22 #ifdef Q_OS_WIN
   23 #include <QtNetwork/QtNetwork>
   24 #endif // Q_OS_WIN
   25 
   26 #include <cstdlib>
   27 
   28 #if CUTTER_R2GHIDRA_STATIC
   29 #include <R2GhidraDecompiler.h>
   30 #endif
   31 
   32 CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv)
   33 {
   34     // Setup application information
   35     setApplicationVersion(CUTTER_VERSION_FULL);
   36     setWindowIcon(QIcon(":/img/cutter.svg"));
   37     setAttribute(Qt::AA_DontShowIconsInMenus);
   38     setAttribute(Qt::AA_UseHighDpiPixmaps);
   39     setLayoutDirection(Qt::LeftToRight);
   40 
   41     // WARN!!! Put initialization code below this line. Code above this line is mandatory to be run First
   42 
   43 #ifdef Q_OS_WIN
   44     // Hack to force Cutter load internet connection related DLL's
   45     QSslSocket s;
   46     s.sslConfiguration();
   47 #endif // Q_OS_WIN
   48 
   49     // Load translations
   50     if (!loadTranslations()) {
   51         qWarning() << "Cannot load translations";
   52     }
   53 
   54     // Load fonts
   55     int ret = QFontDatabase::addApplicationFont(":/fonts/Anonymous Pro.ttf");
   56     if (ret == -1) {
   57         qWarning() << "Cannot load Anonymous Pro font.";
   58     }
   59 
   60     ret = QFontDatabase::addApplicationFont(":/fonts/Inconsolata-Regular.ttf");
   61     if (ret == -1) {
   62         qWarning() << "Cannot load Incosolata-Regular font.";
   63     }
   64 
   65 
   66     // Set QString codec to UTF-8
   67     QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
   68 #if QT_VERSION < QT_VERSION_CHECK(5,0,0)
   69     QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
   70     QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
   71 #endif
   72     QCommandLineParser cmd_parser;
   73     cmd_parser.setApplicationDescription(
   74         QObject::tr("A Qt and C++ GUI for radare2 reverse engineering framework"));
   75     cmd_parser.addHelpOption();
   76     cmd_parser.addVersionOption();
   77     cmd_parser.addPositionalArgument("filename", QObject::tr("Filename to open."));
   78 
   79     QCommandLineOption analOption({"A", "anal"},
   80                                   QObject::tr("Automatically open file and optionally start analysis. Needs filename to be specified. May be a value between 0 and 2: 0 = no analysis, 1 = aaa, 2 = aaaa (experimental)"),
   81                                   QObject::tr("level"));
   82     cmd_parser.addOption(analOption);
   83 
   84     QCommandLineOption scriptOption("i",
   85                                     QObject::tr("Run script file"),
   86                                     QObject::tr("file"));
   87     cmd_parser.addOption(scriptOption);
   88 
   89     QCommandLineOption pythonHomeOption("pythonhome", QObject::tr("PYTHONHOME to use for embeded python interpreter"),
   90                                         "PYTHONHOME");
   91     cmd_parser.addOption(pythonHomeOption);
   92 
   93     cmd_parser.process(*this);
   94 
   95     QStringList args = cmd_parser.positionalArguments();
   96 
   97     // Check r2 version
   98     QString r2version = r_core_version();
   99     QString localVersion = "" R2_GITTAP;
  100     if (r2version != localVersion) {
  101         QMessageBox msg;
  102         msg.setIcon(QMessageBox::Critical);
  103         msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  104         msg.setWindowTitle(QObject::tr("Version mismatch!"));
  105         msg.setText(QString(
  106                         QObject::tr("The version used to compile Cutter (%1) does not match the binary version of radare2 (%2). This could result in unexpected behaviour. Are you sure you want to continue?")).arg(
  107                         localVersion, r2version));
  108         if (msg.exec() == QMessageBox::No) {
  109             std::exit(1);
  110         }
  111     }
  112 
  113 #ifdef CUTTER_ENABLE_PYTHON
  114     // Init python
  115     if (cmd_parser.isSet(pythonHomeOption)) {
  116         Python()->setPythonHome(cmd_parser.value(pythonHomeOption));
  117     }
  118     Python()->initialize();
  119 #endif
  120 
  121     Core()->initialize();
  122     Core()->setSettings();
  123     Config()->loadInitial();
  124     Core()->loadCutterRC();
  125 
  126     if (R2DecDecompiler::isAvailable()) {
  127         Core()->registerDecompiler(new R2DecDecompiler(Core()));
  128     }
  129 
  130 #if CUTTER_R2GHIDRA_STATIC
  131     Core()->registerDecompiler(new R2GhidraDecompiler(Core()));
  132 #endif
  133 
  134     bool analLevelSpecified = false;
  135     int analLevel = 0;
  136 
  137     if (cmd_parser.isSet(analOption)) {
  138         analLevel = cmd_parser.value(analOption).toInt(&analLevelSpecified);
  139 
  140         if (!analLevelSpecified || analLevel < 0 || analLevel > 2) {
  141             printf("%s\n",
  142                    QObject::tr("Invalid Analysis Level. May be a value between 0 and 2.").toLocal8Bit().constData());
  143             std::exit(1);
  144         }
  145     }
  146 
  147     Plugins()->loadPlugins();
  148 
  149     for (auto *plugin : Plugins()->getPlugins()) {
  150         plugin->registerDecompilers();
  151     }
  152 
  153     mainWindow = new MainWindow();
  154     installEventFilter(mainWindow);
  155 
  156     // set up context menu shortcut display fix
  157 #if QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
  158     setStyle(new CutterProxyStyle());
  159 #endif // QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
  160 
  161     if (args.empty()) {
  162         if (analLevelSpecified) {
  163             printf("%s\n",
  164                    QObject::tr("Filename must be specified to start analysis automatically.").toLocal8Bit().constData());
  165             std::exit(1);
  166         }
  167 
  168         // check if this is the first execution of Cutter in this computer
  169         // Note: the execution after the preferences benn reset, will be considered as first-execution
  170         if (Config()->isFirstExecution()) {
  171             mainWindow->displayWelcomeDialog();
  172         }
  173         mainWindow->displayNewFileDialog();
  174     } else { // filename specified as positional argument
  175         InitialOptions options;
  176         options.filename = args[0];
  177         if (analLevelSpecified) {
  178             switch (analLevel) {
  179             case 0:
  180             default:
  181                 options.analCmd = {};
  182                 break;
  183             case 1:
  184                 options.analCmd = { {"aaa", "Auto analysis"} };
  185                 break;
  186             case 2:
  187                 options.analCmd = { {"aaaa", "Auto analysis (experimental)"} };
  188                 break;
  189             }
  190         }
  191         options.script = cmd_parser.value(scriptOption);
  192         mainWindow->openNewFile(options, analLevelSpecified);
  193     }
  194 
  195 #ifdef CUTTER_APPVEYOR_R2DEC
  196     qputenv("R2DEC_HOME", "radare2\\lib\\plugins\\r2dec-js");
  197 #endif
  198 
  199 #ifdef APPIMAGE
  200     {
  201         auto sleighHome = QDir(QCoreApplication::applicationDirPath()); // appdir/bin
  202         sleighHome.cdUp(); // appdir
  203         sleighHome.cd("share/radare2/plugins/r2ghidra_sleigh"); // appdir/share/radare2/plugins/r2ghidra_sleigh
  204         Core()->setConfig("r2ghidra.sleighhome", sleighHome.absolutePath());
  205     }
  206 #endif
  207 
  208 #ifdef Q_OS_MACOS
  209     {
  210         auto sleighHome = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS
  211         sleighHome.cdUp(); // Contents
  212         sleighHome.cd("Resources/r2/share/radare2/plugins/r2ghidra_sleigh"); // Contents/Resources/r2/share/radare2/plugins/r2ghidra_sleigh
  213         Core()->setConfig("r2ghidra.sleighhome", sleighHome.absolutePath());
  214     }
  215 #endif
  216 
  217 #ifdef Q_OS_WIN
  218     {
  219         auto sleighHome = QDir(QCoreApplication::applicationDirPath());
  220         sleighHome.cd("radare2/lib/plugins/r2ghidra_sleigh");
  221         Core()->setConfig("r2ghidra.sleighhome", sleighHome.absolutePath());
  222     }
  223 #endif
  224 }
  225 
  226 CutterApplication::~CutterApplication()
  227 {
  228 #ifdef CUTTER_ENABLE_PYTHON
  229     Plugins()->destroyPlugins();
  230 #endif
  231     delete mainWindow;
  232 #ifdef CUTTER_ENABLE_PYTHON
  233     Python()->shutdown();
  234 #endif
  235 }
  236 
  237 bool CutterApplication::event(QEvent *e)
  238 {
  239     if (e->type() == QEvent::FileOpen) {
  240         QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(e);
  241         if (openEvent) {
  242             if (m_FileAlreadyDropped) {
  243                 // We already dropped a file in macOS, let's spawn another instance
  244                 // (Like the File -> Open)
  245                 QString fileName = openEvent->file();
  246                 QProcess process(this);
  247                 process.setEnvironment(QProcess::systemEnvironment());
  248                 QStringList args = QStringList(fileName);
  249                 process.startDetached(qApp->applicationFilePath(), args);
  250             } else {
  251                 QString fileName = openEvent->file();
  252                 m_FileAlreadyDropped = true;
  253                 mainWindow->closeNewFileDialog();
  254                 InitialOptions options;
  255                 options.filename = fileName;
  256                 mainWindow->openNewFile(options);
  257             }
  258         }
  259     }
  260     return QApplication::event(e);
  261 }
  262 
  263 bool CutterApplication::loadTranslations()
  264 {
  265     const QString &language = Config()->getCurrLocale().bcp47Name();
  266     if (language == QStringLiteral("en") || language.startsWith(QStringLiteral("en-"))) {
  267         return true;
  268     }
  269     const auto &allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript,
  270         QLocale::AnyCountry);
  271 
  272     bool cutterTrLoaded = false;
  273 
  274     for (const QLocale &it : allLocales) {
  275         const QString &langPrefix = it.bcp47Name();
  276         if (langPrefix == language) {
  277             QApplication::setLayoutDirection(it.textDirection());
  278             QLocale::setDefault(it);
  279 
  280             QTranslator *trCutter = new QTranslator;
  281             QTranslator *trQtBase = new QTranslator;
  282             QTranslator *trQt = new QTranslator;
  283 
  284             const QStringList &cutterTrPaths = Config()->getTranslationsDirectories();
  285 
  286             for (const auto &trPath : cutterTrPaths) {
  287                 if (trCutter && trCutter->load(it, QLatin1String("cutter"), QLatin1String("_"), trPath)) {
  288                     installTranslator(trCutter);
  289                     cutterTrLoaded = true;
  290                     trCutter = nullptr;
  291                 }
  292                 if (trQt && trQt->load(it, "qt", "_", trPath)) {
  293                     installTranslator(trQt);
  294                     trQt = nullptr;
  295                 }
  296 
  297                 if (trQtBase && trQtBase->load(it, "qtbase", "_", trPath)) {
  298                     installTranslator(trQtBase);
  299                     trQtBase = nullptr;
  300                 }
  301             }
  302             
  303             if (trCutter) {
  304                 delete trCutter;
  305             }
  306             if (trQt) {
  307                 delete trQt;
  308             }
  309             if (trQtBase) {
  310                 delete trQtBase;
  311             }
  312             return true;
  313         }
  314     }
  315     if (!cutterTrLoaded) {
  316         qWarning() << "Cannot load Cutter's translation for " << language;
  317     }
  318     return false;
  319 }
  320 
  321 
  322 void CutterProxyStyle::polish(QWidget *widget)
  323 {
  324     QProxyStyle::polish(widget);
  325 #if QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
  326     // HACK: This is the only way I've found to force Qt (5.10 and newer) to
  327     //       display shortcuts in context menus on all platforms. It's ugly,
  328     //       but it gets the job done.
  329     if (auto menu = qobject_cast<QMenu*>(widget)) {
  330         const auto &actions = menu->actions();
  331         for (auto action : actions) {
  332             action->setShortcutVisibleInContextMenu(true);
  333         }
  334     }
  335 #endif // QT_VERSION_CHECK(5, 10, 0) < QT_VERSION
  336 }
  337