2018-02-10 18:04:31 +00:00
# include "CutterApplication.h"
# include <QApplication>
# include <QFileOpenEvent>
# include <QEvent>
# include <QMessageBox>
# include <QCommandLineParser>
# include <QTextCodec>
# include <QStringList>
# include <QProcess>
2018-06-26 07:40:08 +00:00
# include <QPluginLoader>
# include <QDir>
2018-10-31 16:07:53 +00:00
# include <QTranslator>
# include <QLibraryInfo>
2018-02-10 18:04:31 +00:00
2018-03-06 17:21:42 +00:00
# ifdef CUTTER_ENABLE_JUPYTER
2018-10-17 07:55:53 +00:00
# include "common/JupyterConnection.h"
2018-03-06 17:21:42 +00:00
# endif
2018-06-26 07:40:08 +00:00
# include "plugins/CutterPlugin.h"
2018-03-06 17:21:42 +00:00
2018-08-26 18:37:11 +00:00
# include "CutterConfig.h"
2018-10-21 16:23:35 +00:00
# include <cstdlib>
2018-03-21 20:32:32 +00:00
CutterApplication : : CutterApplication ( int & argc , char * * argv ) : QApplication ( argc , argv )
{
2018-11-02 16:49:15 +00:00
// Setup application information
setOrganizationName ( " Cutter " ) ;
setApplicationName ( " Cutter " ) ;
setApplicationVersion ( CUTTER_VERSION_FULL ) ;
setWindowIcon ( QIcon ( " :/img/cutter.svg " ) ) ;
setAttribute ( Qt : : AA_DontShowIconsInMenus ) ;
// WARN!!! Put initialization code below this line. Code above this line is mandatory to be run First
2018-11-01 22:23:01 +00:00
// Load translations
2018-10-31 16:07:53 +00:00
QTranslator * t = new QTranslator ;
QTranslator * qtBaseTranslator = new QTranslator ;
QTranslator * qtTranslator = new QTranslator ;
QString language = Config ( ) - > getCurrLocale ( ) . bcp47Name ( ) ;
auto allLocales = QLocale : : matchingLocales ( QLocale : : AnyLanguage , QLocale : : AnyScript ,
QLocale : : AnyCountry ) ;
QString langPrefix ;
if ( language ! = " en " ) {
for ( auto & it : allLocales ) {
langPrefix = it . bcp47Name ( ) ;
if ( langPrefix = = language ) {
2018-11-02 16:49:15 +00:00
const QString & cutterTranslationPath = QCoreApplication : : applicationDirPath ( ) + QDir : : separator ( )
+ " translations " + QDir : : separator ( ) + QString ( " cutter_%1.qm " ) . arg ( langPrefix ) ;
if ( t - > load ( cutterTranslationPath ) ) {
installTranslator ( t ) ;
}
2018-10-31 16:07:53 +00:00
QApplication : : setLayoutDirection ( it . textDirection ( ) ) ;
QLocale : : setDefault ( it ) ;
QString translationsPath ( QLibraryInfo : : location ( QLibraryInfo : : TranslationsPath ) ) ;
if ( qtTranslator - > load ( it , " qt " , " _ " , translationsPath ) ) {
installTranslator ( qtTranslator ) ;
} else {
delete qtTranslator ;
}
if ( qtBaseTranslator - > load ( it , " qtbase " , " _ " , translationsPath ) ) {
installTranslator ( qtBaseTranslator ) ;
} else {
delete qtBaseTranslator ;
}
break ;
}
}
}
2018-11-02 16:49:15 +00:00
2018-11-01 22:23:01 +00:00
// Load fonts
int ret = QFontDatabase : : addApplicationFont ( " :/fonts/Anonymous Pro.ttf " ) ;
if ( ret = = - 1 ) {
qWarning ( ) < < " Cannot load Anonymous Pro font. " ;
}
ret = QFontDatabase : : addApplicationFont ( " :/fonts/Inconsolata-Regular.ttf " ) ;
if ( ret = = - 1 ) {
qWarning ( ) < < " Cannot load Incosolata-Regular font. " ;
}
2018-02-10 18:04:31 +00:00
// Set QString codec to UTF-8
QTextCodec : : setCodecForLocale ( QTextCodec : : codecForName ( " UTF-8 " ) ) ;
# if QT_VERSION < QT_VERSION_CHECK(5,0,0)
QTextCodec : : setCodecForCStrings ( QTextCodec : : codecForName ( " UTF-8 " ) ) ;
QTextCodec : : setCodecForTr ( QTextCodec : : codecForName ( " UTF-8 " ) ) ;
# endif
QCommandLineParser cmd_parser ;
2018-03-21 20:32:32 +00:00
cmd_parser . setApplicationDescription (
QObject : : tr ( " A Qt and C++ GUI for radare2 reverse engineering framework " ) ) ;
2018-02-10 18:04:31 +00:00
cmd_parser . addHelpOption ( ) ;
cmd_parser . addVersionOption ( ) ;
cmd_parser . addPositionalArgument ( " filename " , QObject : : tr ( " Filename to open. " ) ) ;
QCommandLineOption analOption ( { " A " , " anal " } ,
2018-03-21 20:32:32 +00:00
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) " ) ,
QObject : : tr ( " level " ) ) ;
2018-02-10 18:04:31 +00:00
cmd_parser . addOption ( analOption ) ;
2018-08-18 16:09:49 +00:00
QCommandLineOption scriptOption ( " i " ,
QObject : : tr ( " Run script file " ) ,
QObject : : tr ( " file " ) ) ;
cmd_parser . addOption ( scriptOption ) ;
2018-03-06 17:21:42 +00:00
# ifdef CUTTER_ENABLE_JUPYTER
2018-03-21 20:32:32 +00:00
QCommandLineOption pythonHomeOption ( " pythonhome " , QObject : : tr ( " PYTHONHOME to use for Jupyter " ) ,
" PYTHONHOME " ) ;
2018-03-06 17:21:42 +00:00
cmd_parser . addOption ( pythonHomeOption ) ;
# endif
2018-02-10 18:04:31 +00:00
cmd_parser . process ( * this ) ;
QStringList args = cmd_parser . positionalArguments ( ) ;
// Check r2 version
QString r2version = r_core_version ( ) ;
QString localVersion = " " R2_GITTAP ;
2018-03-21 20:32:32 +00:00
if ( r2version ! = localVersion ) {
2018-02-10 18:04:31 +00:00
QMessageBox msg ;
msg . setIcon ( QMessageBox : : Critical ) ;
msg . setStandardButtons ( QMessageBox : : Yes | QMessageBox : : No ) ;
msg . setWindowTitle ( QObject : : tr ( " Version mismatch! " ) ) ;
2018-03-21 20:32:32 +00:00
msg . setText ( QString (
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 (
localVersion , r2version ) ) ;
2018-10-21 16:23:35 +00:00
if ( msg . exec ( ) = = QMessageBox : : No ) {
std : : exit ( 1 ) ;
}
2018-02-10 18:04:31 +00:00
}
2018-03-06 17:21:42 +00:00
# ifdef CUTTER_ENABLE_JUPYTER
2018-03-21 20:32:32 +00:00
if ( cmd_parser . isSet ( pythonHomeOption ) ) {
2018-03-06 17:21:42 +00:00
Jupyter ( ) - > setPythonHome ( cmd_parser . value ( pythonHomeOption ) ) ;
}
# endif
2018-02-10 18:04:31 +00:00
bool analLevelSpecified = false ;
2018-03-21 20:32:32 +00:00
int analLevel = 0 ;
2018-02-10 18:04:31 +00:00
2018-07-12 13:04:33 +00:00
// Initialize CutterCore and set default settings
Core ( ) - > setSettings ( ) ;
2018-03-21 20:32:32 +00:00
if ( cmd_parser . isSet ( analOption ) ) {
2018-02-10 18:04:31 +00:00
analLevel = cmd_parser . value ( analOption ) . toInt ( & analLevelSpecified ) ;
2018-03-21 20:32:32 +00:00
if ( ! analLevelSpecified | | analLevel < 0 | | analLevel > 2 ) {
printf ( " %s \n " ,
QObject : : tr ( " Invalid Analysis Level. May be a value between 0 and 2. " ) . toLocal8Bit ( ) . constData ( ) ) ;
2018-10-21 16:23:35 +00:00
std : : exit ( 1 ) ;
2018-02-10 18:04:31 +00:00
}
}
2018-02-27 13:06:04 +00:00
mainWindow = new MainWindow ( ) ;
2018-05-13 07:50:01 +00:00
installEventFilter ( mainWindow ) ;
2018-02-10 18:04:31 +00:00
2018-03-21 20:32:32 +00:00
if ( args . empty ( ) ) {
if ( analLevelSpecified ) {
printf ( " %s \n " ,
QObject : : tr ( " Filename must be specified to start analysis automatically. " ) . toLocal8Bit ( ) . constData ( ) ) ;
2018-10-21 16:23:35 +00:00
std : : exit ( 1 ) ;
2018-02-10 18:04:31 +00:00
}
2018-02-27 13:06:04 +00:00
mainWindow - > displayNewFileDialog ( ) ;
2018-03-21 20:32:32 +00:00
} else { // filename specified as positional argument
2018-08-18 16:04:45 +00:00
InitialOptions options ;
options . filename = args [ 0 ] ;
if ( analLevelSpecified ) {
switch ( analLevel ) {
case 0 :
default :
options . analCmd = { } ;
break ;
case 1 :
options . analCmd = { " aaa " } ;
break ;
case 2 :
options . analCmd = { " aaaa " } ;
break ;
}
}
2018-08-18 16:09:49 +00:00
options . script = cmd_parser . value ( scriptOption ) ;
2018-08-18 16:04:45 +00:00
mainWindow - > openNewFile ( options , analLevelSpecified ) ;
2018-02-10 18:04:31 +00:00
}
2018-06-26 07:40:08 +00:00
// Load plugins
loadPlugins ( ) ;
2018-02-10 18:04:31 +00:00
}
2018-02-27 13:06:04 +00:00
CutterApplication : : ~ CutterApplication ( )
{
delete mainWindow ;
}
bool CutterApplication : : event ( QEvent * e )
{
2018-03-21 20:32:32 +00:00
if ( e - > type ( ) = = QEvent : : FileOpen ) {
2018-02-10 18:04:31 +00:00
QFileOpenEvent * openEvent = static_cast < QFileOpenEvent * > ( e ) ;
2018-03-21 20:32:32 +00:00
if ( openEvent ) {
if ( m_FileAlreadyDropped ) {
2018-05-08 20:44:53 +00:00
// We already dropped a file in macOS, let's spawn another instance
2018-02-10 18:04:31 +00:00
// (Like the File -> Open)
QString fileName = openEvent - > file ( ) ;
QProcess process ( this ) ;
process . setEnvironment ( QProcess : : systemEnvironment ( ) ) ;
QStringList args = QStringList ( fileName ) ;
process . startDetached ( qApp - > applicationFilePath ( ) , args ) ;
2018-03-21 20:32:32 +00:00
} else {
2018-02-10 18:04:31 +00:00
QString fileName = openEvent - > file ( ) ;
m_FileAlreadyDropped = true ;
2018-02-27 13:06:04 +00:00
mainWindow - > closeNewFileDialog ( ) ;
2018-08-18 16:04:45 +00:00
InitialOptions options ;
options . filename = fileName ;
mainWindow - > openNewFile ( options ) ;
2018-02-10 18:04:31 +00:00
}
}
}
return QApplication : : event ( e ) ;
}
2018-06-26 07:40:08 +00:00
void CutterApplication : : loadPlugins ( )
{
2018-09-30 20:00:53 +00:00
QList < CutterPlugin * > plugins ;
2018-06-26 07:40:08 +00:00
QDir pluginsDir ( qApp - > applicationDirPath ( ) ) ;
2018-09-30 20:00:53 +00:00
# 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
2018-10-15 04:11:47 +00:00
if ( ! pluginsDir . cd ( " plugins " ) )
return ;
2018-06-26 07:40:08 +00:00
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 ) ;
}