2021-02-10 18:17:09 +01:00
# include <hex.hpp>
2021-08-29 22:15:18 +02:00
# include <hex/helpers/logger.hpp>
2020-11-10 15:26:38 +01:00
# include "window.hpp"
2023-06-01 18:35:41 +02:00
# include "crash_handlers.hpp"
2023-07-13 14:08:23 +02:00
# include "messaging.hpp"
2020-11-10 15:26:38 +01:00
2021-04-20 21:46:48 +02:00
# include "init/splash_window.hpp"
# include "init/tasks.hpp"
2023-11-18 14:50:43 +01:00
# include <hex/api/task_manager.hpp>
2022-08-08 21:23:52 +02:00
# include <hex/api/project_file_manager.hpp>
2023-07-13 14:08:23 +02:00
# include <hex/api/plugin_manager.hpp>
2023-07-22 21:30:22 +02:00
2023-07-13 14:08:23 +02:00
# include <hex/helpers/fs.hpp>
# include "hex/subcommands/subcommands.hpp"
2022-08-08 21:23:52 +02:00
2023-03-12 18:27:29 +01:00
# include <wolv/io/fs.hpp>
# include <wolv/utils/guards.hpp>
2023-10-21 20:40:24 +02:00
# include <fcntl.h>
2023-03-12 18:27:29 +01:00
2023-10-04 12:00:32 +02:00
# if defined(OS_WEB)
# include <emscripten.h>
# include <emscripten/html5.h>
# endif
2023-07-13 14:08:23 +02:00
using namespace hex ;
2023-07-22 21:30:22 +02:00
namespace {
2023-07-13 14:08:23 +02:00
2023-07-22 21:30:22 +02:00
/**
* @ brief Handles commands passed to ImHex via the command line
* @ param argc Argument count
* @ param argv Argument values
*/
void handleCommandLineInterface ( int argc , char * * argv ) {
2023-11-19 12:21:59 +01:00
std : : vector < std : : string > args ;
# if defined (OS_WINDOWS)
hex : : unused ( argv ) ;
// On Windows, argv contains UTF-16 encoded strings, so we need to convert them to UTF-8
auto convertedCommandLine = : : CommandLineToArgvW ( : : GetCommandLineW ( ) , & argc ) ;
if ( convertedCommandLine = = nullptr ) {
log : : error ( " Failed to convert command line arguments to UTF-8 " ) ;
std : : exit ( EXIT_FAILURE ) ;
}
for ( int i = 1 ; i < argc ; i + = 1 ) {
std : : wstring wcharArg = convertedCommandLine [ i ] ;
std : : string utf8Arg = std : : wstring_convert < std : : codecvt_utf8_utf16 < wchar_t > > ( ) . to_bytes ( wcharArg ) ;
args . push_back ( utf8Arg ) ;
}
: : LocalFree ( convertedCommandLine ) ;
# else
// Skip the first argument (the executable path) and convert the rest to a vector of strings
args = { argv + 1 , argv + argc } ;
# endif
2023-07-13 14:08:23 +02:00
2023-07-22 21:30:22 +02:00
// Load all plugins but don't initialize them
2023-07-22 18:38:14 +02:00
for ( const auto & dir : fs : : getDefaultPaths ( fs : : ImHexPath : : Plugins ) ) {
PluginManager : : load ( dir ) ;
}
2023-07-13 14:08:23 +02:00
2023-07-22 21:30:22 +02:00
// Setup messaging system to allow sending commands to the main ImHex instance
2023-07-22 18:38:14 +02:00
hex : : messaging : : setupMessaging ( ) ;
2023-07-22 21:30:22 +02:00
// Process the arguments
2023-07-22 18:38:14 +02:00
hex : : subcommands : : processArguments ( args ) ;
2023-07-22 21:30:22 +02:00
// Unload plugins again
2023-07-22 18:38:14 +02:00
PluginManager : : unload ( ) ;
}
2021-01-13 17:28:27 +01:00
2023-07-22 21:30:22 +02:00
/**
* @ brief Checks if the portable version of ImHex is installed
* @ note The portable version is detected by the presence of a file named " PORTABLE " in the same directory as the executable
* @ return True if ImHex is running in portable mode , false otherwise
*/
bool isPortableVersion ( ) {
2023-03-12 18:27:29 +01:00
if ( const auto executablePath = wolv : : io : : fs : : getExecutablePath ( ) ; executablePath . has_value ( ) ) {
2023-01-16 19:39:00 +01:00
const auto flagFile = executablePath - > parent_path ( ) / " PORTABLE " ;
2023-03-12 18:27:29 +01:00
if ( wolv : : io : : fs : : exists ( flagFile ) & & wolv : : io : : fs : : isRegularFile ( flagFile ) )
2023-07-22 21:30:22 +02:00
return true ;
2023-01-16 19:39:00 +01:00
}
2023-07-22 21:30:22 +02:00
return false ;
2023-01-16 19:39:00 +01:00
}
2023-07-22 21:30:22 +02:00
/**
* @ brief Displays ImHex ' s splash screen and runs all initialization tasks . The splash screen will be displayed until all tasks have finished .
*/
2023-10-04 12:00:32 +02:00
[[maybe_unused]]
2023-07-22 21:30:22 +02:00
void initializeImHex ( ) {
init : : WindowSplash splashWindow ;
2023-07-13 14:08:23 +02:00
2023-07-22 21:30:22 +02:00
log : : info ( " Using '{}' GPU " , ImHexApi : : System : : getGPUVendor ( ) ) ;
// Add initialization tasks to run
TaskManager : : init ( ) ;
for ( const auto & [ name , task , async ] : init : : getInitTasks ( ) )
splashWindow . addStartupTask ( name , task , async ) ;
2022-08-16 11:48:37 +02:00
2023-09-07 20:33:49 +02:00
splashWindow . startStartupTasks ( ) ;
2023-07-22 21:30:22 +02:00
// Draw the splash window while tasks are running
if ( ! splashWindow . loop ( ) )
ImHexApi : : System : : getInitArguments ( ) . insert ( { " tasks-failed " , { } } ) ;
}
2022-08-16 11:48:37 +02:00
2023-07-22 21:30:22 +02:00
/**
* @ brief Deinitializes ImHex by running all exit tasks and terminating all asynchronous tasks
*/
void deinitializeImHex ( ) {
// Run exit tasks
2023-10-11 22:38:54 +02:00
init : : runExitTasks ( ) ;
2023-07-22 21:30:22 +02:00
// Terminate all asynchronous tasks
TaskManager : : exit ( ) ;
}
/**
* @ brief Handles a file open request by opening the file specified by OS - specific means
*/
void handleFileOpenRequest ( ) {
if ( auto path = hex : : getInitialFilePath ( ) ; path . has_value ( ) ) {
EventManager : : post < RequestOpenFile > ( path . value ( ) ) ;
2022-08-16 11:48:37 +02:00
}
2023-07-22 21:30:22 +02:00
}
2022-08-16 11:48:37 +02:00
2023-10-04 12:00:32 +02:00
# if defined(OS_WEB)
2023-10-04 21:45:43 +02:00
2023-10-04 12:00:32 +02:00
using namespace hex : : init ;
void saveFsData ( ) {
EM_ASM ( {
FS . syncfs ( function ( err ) {
if ( ! err )
return ;
alert ( " Failed to save permanent file system: " + err ) ;
} ) ;
} ) ;
}
int runImHex ( ) {
auto splashWindow = new WindowSplash ( ) ;
log : : info ( " Using '{}' GPU " , ImHexApi : : System : : getGPUVendor ( ) ) ;
// Add initialization tasks to run
TaskManager : : init ( ) ;
for ( const auto & [ name , task , async ] : init : : getInitTasks ( ) )
splashWindow - > addStartupTask ( name , task , async ) ;
splashWindow - > startStartupTasks ( ) ;
2023-10-04 21:45:43 +02:00
EventManager : : subscribe < RequestRestartImHex > ( [ & ] {
MAIN_THREAD_EM_ASM ( {
location . reload ( ) ;
} ) ;
} ) ;
2023-10-04 12:00:32 +02:00
// Draw the splash window while tasks are running
emscripten_set_main_loop_arg ( [ ] ( void * arg ) {
auto splashWindow = reinterpret_cast < WindowSplash * > ( arg ) ;
FrameResult res = splashWindow - > fullFrame ( ) ;
if ( res = = FrameResult : : success ) {
handleFileOpenRequest ( ) ;
// Clean up everything after the main window is closed
emscripten_set_beforeunload_callback ( nullptr , [ ] ( int eventType , const void * reserved , void * userData ) {
hex : : unused ( eventType , reserved , userData ) ;
try {
saveFsData ( ) ;
deinitializeImHex ( ) ;
return " " ;
} catch ( const std : : exception & ex ) {
std : : string * msg = new std : : string ( " Failed to deinitialize ImHex. This is just a message warning you of this, the application has already closed, you probably can't do anything about it. Message: " ) ;
msg - > append ( std : : string ( ex . what ( ) ) ) ;
log : : fatal ( " {} " , * msg ) ;
return msg - > c_str ( ) ;
}
} ) ;
// Delete splash window (do it before creating the main window so glfw destroys the window)
delete splashWindow ;
emscripten_cancel_main_loop ( ) ;
// Main window
static Window window ;
emscripten_set_main_loop ( [ ] ( ) {
window . fullFrame ( ) ;
} , 60 , 0 ) ;
}
} , splashWindow , 60 , 0 ) ;
return - 1 ;
}
# else
int runImHex ( ) {
bool shouldRestart = false ;
do {
// Register an event handler that will make ImHex restart when requested
shouldRestart = false ;
EventManager : : subscribe < RequestRestartImHex > ( [ & ] {
shouldRestart = true ;
} ) ;
initializeImHex ( ) ;
handleFileOpenRequest ( ) ;
// Clean up everything after the main window is closed
ON_SCOPE_EXIT {
deinitializeImHex ( ) ;
} ;
// Main window
Window window ;
window . loop ( ) ;
} while ( shouldRestart ) ;
return EXIT_SUCCESS ;
}
# endif
2023-07-22 21:30:22 +02:00
}
2023-06-20 11:55:56 +02:00
2023-07-22 21:30:22 +02:00
/**
* @ brief Main entry point of ImHex
* @ param argc Argument count
* @ param argv Argument values
* @ return Exit code
*/
int main ( int argc , char * * argv ) {
Window : : initNative ( ) ;
hex : : crash : : setupCrashHandlers ( ) ;
2023-07-21 11:53:37 +02:00
2023-07-22 21:30:22 +02:00
if ( argc > 1 ) {
handleCommandLineInterface ( argc , argv ) ;
}
2022-08-16 11:48:37 +02:00
2023-07-22 21:30:22 +02:00
log : : info ( " Welcome to ImHex {}! " , ImHexApi : : System : : getImHexVersion ( ) ) ;
log : : info ( " Compiled using commit {}@{} " , ImHexApi : : System : : getCommitBranch ( ) , ImHexApi : : System : : getCommitHash ( ) ) ;
log : : info ( " Running on {} {} ({}) " , ImHexApi : : System : : getOSName ( ) , ImHexApi : : System : : getOSVersion ( ) , ImHexApi : : System : : getArchitecture ( ) ) ;
ImHexApi : : System : : impl : : setPortableVersion ( isPortableVersion ( ) ) ;
2022-08-16 11:48:37 +02:00
2023-10-04 12:00:32 +02:00
return runImHex ( ) ;
2023-11-10 20:47:08 +01:00
}