22 #include <sys/types.h> 
   33 #       include <sys/utsname.h> 
   36 #ifdef XEMU_MISSING_BIGGEST_ALIGNMENT_WORKAROUND 
   37 #       warning "System did not define __BIGGEST_ALIGNMENT__ Xemu assumes some default value." 
   39 #ifdef XEMU_OVERSIZED_BIGGEST_ALIGNMENT_WORKAROUND 
   40 #       warning "System deifned __BIGGEST_ALIGNMENT__ just too big Xemu will use a smaller default." 
   43 #       warning "Compiling for ARM CPU. Some features of Xemu won't be avaialble because of usual limits of OSes (MacOS, Linux) on the ARM architecture." 
   45 #               warning "WOW! Are you on Apple M1?! Call me now!" 
   61 #ifndef XEMU_NO_SDL_DIALOG_OVERRIDE 
   67 int macos_gui_started = 0;
 
   71 static int atexit_callback_for_console_registered = 0;
 
   82 static Uint32 sdl_pixel_format_id;
 
   83 static const char default_window_title[] = 
"XEMU";
 
   87 static const char *emscripten_sdl_base_dir = EMSCRIPTEN_SDL_BASE_DIR;
 
   96 static int win_xsize, win_ysize;
 
   99 static Uint32 black_colour;
 
  100 static void (*shutdown_user_function)(void) = NULL;
 
  103 static char *window_title_buffer, *window_title_buffer_end;
 
  104 static struct timeval unix_time_tv;
 
  105 static Uint64 et_old;
 
  106 static int td_balancer, td_em_ALL, td_pc_ALL;
 
  107 static Uint64 td_stat_counter = 0, td_stat_sum = 0;
 
  108 static int td_stat_min = INT_MAX, td_stat_max = INT_MIN;
 
  114 static SDL_Rect sdl_viewport, *sdl_viewport_ptr = NULL;
 
  115 static unsigned int sdl_texture_x_size, sdl_texture_y_size;
 
  117 static SDL_bool grabbed_mouse = SDL_FALSE, grabbed_mouse_saved = SDL_FALSE;
 
  119 static int sdl_viewport_changed;
 
  120 static int follow_win_size;
 
  122 #if !SDL_VERSION_ATLEAST(2, 0, 4) 
  123 #error "At least SDL version 2.0.4 is needed!" 
  126 #ifdef XEMU_OSD_SUPPORT 
  135         else if (state != grabbed_mouse) {
 
  136                 grabbed_mouse = state;
 
  137                 SDL_SetRelativeMouseMode(state);
 
  138                 SDL_SetWindowGrab(
sdl_win, state);
 
  147         return grabbed_mouse;
 
  153         grabbed_mouse_saved = grabbed_mouse;
 
  164 static inline int get_elapsed_time ( Uint64 t_old, Uint64 *t_new, 
struct timeval *store_time )
 
  166 #ifdef XEMU_OLD_TIMING 
  167 #define __TIMING_METHOD_DESC "gettimeofday" 
  169         gettimeofday(&tv, NULL);
 
  171                 store_time->tv_sec = tv.tv_sec;
 
  172                 store_time->tv_usec = tv.tv_usec;
 
  174         *t_new = tv.tv_sec * 1000000UL + tv.tv_usec;
 
  175         return *t_new - t_old;
 
  177 #define __TIMING_METHOD_DESC "SDL_GetPerformanceCounter" 
  179                 gettimeofday(store_time, NULL);
 
  180         *t_new = SDL_GetPerformanceCounter();
 
  181         return 1000000UL * (*t_new - t_old) / SDL_GetPerformanceFrequency();
 
  189 #ifdef XEMU_ARCH_WIN64 
  191         const time_t temp = unix_time_tv.tv_sec;
 
  192         return localtime(&temp);
 
  194         return localtime(&unix_time_tv.tv_sec);
 
  201         return unix_time_tv.tv_sec;
 
  207         return unix_time_tv.tv_usec;
 
  214         hours = abs((
int)hours + hour_offset) % 24;
 
  218                 return XEMU_BYTE_TO_BCD(hours);             
 
  219         else if (hours == 12)
 
  222                 return XEMU_BYTE_TO_BCD(hours - 12) + 0x80; 
 
  228         void *p = malloc(
size);
 
  230                 FATAL(
"Cannot allocate %d bytes of memory.", (
int)
size);
 
  237         p = realloc(p, 
size);
 
  239                 FATAL(
"Cannot re-allocate %d bytes of memory.", (
int)
size);
 
  252                 DEBUGPRINT(
"ALIGNED-ALLOC: malloc() alignment-workaround: correcting alignment %p -> %p (reminder: %u, need_alignment_of: %u)" NL, p_old, p, reminder, 
__BIGGEST_ALIGNMENT__);
 
  254                 DEBUG(
"ALIGNED-ALLOC: malloc() alignment-workaround: alignment was OK already" NL);
 
  257 #ifdef HAVE_MM_MALLOC 
  259 extern void *_mm_malloc ( 
size_t size, 
size_t alignment );      
 
  268                 DEBUGPRINT(
"ALIGNED-ALLOC: _mm_malloc() failed, errno=%d[%s] ... defaulting to malloc()" NL, errno, strerror(errno));
 
  274 #warning "No _mm_malloc() for this architecture ..." 
  282                 FATAL(
"Cannot allocate memory for strdup()");
 
  288         size_t len = strlen(str) + 1;
 
  290         memcpy(*ptr, str, len);
 
  297         SDL_FlushEvent(SDL_KEYDOWN);
 
  298         SDL_FlushEvent(SDL_KEYUP);
 
  299         SDL_FlushEvent(SDL_MOUSEMOTION);
 
  300         SDL_FlushEvent(SDL_MOUSEWHEEL);
 
  301         SDL_FlushEvent(SDL_MOUSEBUTTONDOWN);
 
  302         SDL_FlushEvent(SDL_MOUSEBUTTONUP);
 
  321                 SDL_GetWindowSize(
sdl_win, &win_xsize, &win_ysize); 
 
  322                 if (SDL_SetWindowFullscreen(
sdl_win, SDL_WINDOW_FULLSCREEN_DESKTOP)) {
 
  323                         fprintf(stderr, 
"Cannot enter full screen mode: %s" NL, SDL_GetError());
 
  330                 if (SDL_SetWindowFullscreen(
sdl_win, 0)) {
 
  331                         fprintf(stderr, 
"Cannot leave full screen mode: %s" NL, SDL_GetError());
 
  335                         SDL_SetWindowSize(
sdl_win, win_xsize, win_ysize); 
 
  355 static inline void do_sleep ( 
int td )
 
  357 #ifdef XEMU_ARCH_HTML 
  358 #define __SLEEP_METHOD_DESC "emscripten_set_main_loop_timing" 
  365         emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, td > 999 ? td / 1000 : 1);
 
  366 #elif defined(XEMU_SLEEP_IS_SDL_DELAY) 
  367 #define __SLEEP_METHOD_DESC "SDL_Delay" 
  369                 SDL_Delay(td / 1000);
 
  370 #elif defined(XEMU_SLEEP_IS_USLEEP) 
  371 #define __SLEEP_METHOD_DESC "usleep" 
  374 #elif defined(XEMU_SLEEP_IS_NANOSLEEP) 
  375 #define __SLEEP_METHOD_DESC "nanosleep" 
  376         struct timespec req, rem;
 
  380         req.tv_sec  = td / 1000000000UL;
 
  381         req.tv_nsec = td % 1000000000UL;
 
  383                 if (nanosleep(&req, &rem)) {
 
  384                         if (errno == EINTR) {
 
  385                                 req.tv_sec = rem.tv_sec;
 
  386                                 req.tv_nsec = rem.tv_nsec;
 
  388                                 FATAL(
"nanosleep() returned with unhandable error");
 
  393 #error "No SLEEP method is defined with XEMU_SLEEP_IS_* macros!" 
  408         time_t old_unix_time = unix_time_tv.tv_sec;
 
  410         td_pc = get_elapsed_time(et_old, &et_new, NULL);        
 
  411         if (td_pc < 0) 
return; 
 
  415                 do_sleep(td_balancer);
 
  421         td = get_elapsed_time(et_new, &et_old, &unix_time_tv);
 
  424                 snprintf(window_title_buffer_end, 64, 
"  [%d%% %d%%] %s %s",
 
  425                         ((td_em_ALL < td_pc_ALL) && td_pc_ALL) ? td_em_ALL * 100 / td_pc_ALL : 100,
 
  426                         td_em_ALL ? (td_pc_ALL * 100 / td_em_ALL) : -1,
 
  430                 SDL_SetWindowTitle(
sdl_win, window_title_buffer);
 
  438         if (td_em_ALL > 0 && td_pc_ALL > 0) {
 
  439                 int stat = td_pc_ALL * 100 / td_em_ALL;
 
  442                 if (stat > td_stat_max)
 
  444                 if (stat < td_stat_min && stat)
 
  453         if (td_balancer >  1000000)
 
  455         else if (td_balancer < -1000000) {
 
  462 static void atexit_callback_for_console ( 
void )
 
  464         sysconsole_close(
"Please review the console content (if you need it) before exiting!");
 
  470 #ifdef XEMU_ARCH_UNIX 
  471         static const char *result = NULL;
 
  476                 if (snprintf(
buf, 
sizeof buf, 
"%s %s %s %s %s",
 
  477                         uts.sysname, uts.nodename,
 
  478                         uts.release, uts.version, uts.machine
 
  480                         strcpy(
buf, 
"<buffer-is-too-small>");
 
  485 #elif defined(XEMU_ARCH_WIN) 
  486         static const char *result = NULL;
 
  491                 if (!GetComputerNameA(
host_name, &size_used))
 
  497                 ZeroMemory(&info, 
sizeof info);
 
  498                 info.dwOSVersionInfoSize = 
sizeof info;
 
  502                 GetNativeSystemInfo(&sysinfo);
 
  504                 const char *isa_name = 
"(Xemu-unknown-ISA)";
 
  505                 switch (sysinfo.wProcessorArchitecture) {
 
  507                                 isa_name = 
"x86_64";    
break;
 
  509                                 isa_name = 
"ARM";       
break;
 
  511                                 isa_name = 
"ARM64";     
break;
 
  513                                 isa_name = 
"Itanium";   
break;
 
  515                                 isa_name = 
"x86";       
break;
 
  517                                 isa_name = 
"(Windows-unknown-ISA)";
 
  521                 if (snprintf(
buf, 
sizeof buf, 
"Windows %s %u.%u %s",
 
  523                         (
unsigned int)info.dwMajorVersion, (
unsigned int)info.dwMinorVersion,
 
  526                         strcpy(
buf, 
"<buffer-is-too-small>");
 
  532         static const char result[] = XEMU_ARCH_NAME 
" (Xemu-no-uname)";
 
  540         if (td_stat_counter) {
 
  541                 Uint32 ticks = SDL_GetTicks() / 1000;
 
  543                         "avg=%.2f%%, min=%d%%, max=%d%% (%u counts), uptime=%02d:%02d",
 
  544                         td_stat_sum / (
double)td_stat_counter,
 
  545                         td_stat_min == INT_MAX ? 0 : td_stat_min,
 
  547                         (
unsigned int)td_stat_counter,
 
  548                         ticks / 60, ticks % 60
 
  551                 snprintf(
buf, 
size, 
"Currently unavailable");
 
  555 static void shutdown_emulator ( 
void )
 
  557         DEBUG(
"XEMU: Shutdown callback function has been called." NL);
 
  558         if (shutdown_user_function)
 
  559                 shutdown_user_function();
 
  564         atexit_callback_for_console();
 
  566         if (td_stat_counter) {
 
  569                 DEBUGPRINT(
NL "TIMING: Xemu CPU usage: %s" NL "XEMU: good by(T)e." NL, td_stat_str);
 
  585         printf(
"Logging is disabled at compile-time." NL);
 
  588                 ERROR_WINDOW(
"Debug file %s already used, you can't call emu_init_debug() twice!\nUse it before emu_init_sdl() if you need it!", 
fn);
 
  605 #ifndef XEMU_ARCH_HTML 
  606 static char *GetHackedPrefDir ( 
const char *base_path, 
const char *
name )
 
  608         static const char prefdir_is_here_marker[] = 
"prefdir-is-here.txt";
 
  611         char file[PATH_MAX + 
sizeof(prefdir_is_here_marker)];
 
  612         sprintf(file, 
"%s%s", path, prefdir_is_here_marker);
 
  625         static int is_first_time_user = -1;
 
  626         if (is_first_time_user >= 0)
 
  627                 return is_first_time_user;
 
  630         SDL_RWops *file = SDL_RWFromFile(
fn, 
"rb");
 
  633                 is_first_time_user = 0; 
 
  634                 return is_first_time_user;
 
  638         file = SDL_RWFromFile(
fn, 
"wb");
 
  640                 ERROR_WINDOW(
"Xemu cannot write the preferences directory!\nFile: %s\nError: %s", 
fn, SDL_GetError());
 
  643         static const char message[] = 
"DO NOT DELETE. Xemu uses this file to tell, if Xemu has been already run on this system at all.";
 
  644         SDL_RWwrite(file, message, strlen(message), 1); 
 
  646         is_first_time_user = 1;
 
  647         return is_first_time_user;      
 
  651 void xemu_pre_init ( 
const char *app_organization, 
const char *app_name, 
const char *slogan )
 
  653 #ifdef XEMU_ARCH_UNIX 
  654 #ifndef XEMU_DO_NOT_DISALLOW_ROOT 
  656         if (getuid() == 0 || geteuid() == 0)
 
  657                 FATAL(
"Xemu must not be run as user root");
 
  658         if (getgid() == 0 || getegid() == 0)
 
  659                 FATAL(
"Xemu must not be run as group root");
 
  662         signal(SIGHUP, SIG_IGN);        
 
  670 #if defined(XEMU_ARCH_WIN) && !defined(XEMU_DO_NOT_DISALLOW_ROOT) 
  672         HANDLE hToken = NULL;
 
  673         if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
 
  674                 TOKEN_ELEVATION Elevation;
 
  675                 DWORD cbSize = 
sizeof(TOKEN_ELEVATION);
 
  676                 if (GetTokenInformation(hToken, TokenElevation, &Elevation, 
sizeof(Elevation), &cbSize)) {
 
  677                         fRet = Elevation.TokenIsElevated;
 
  684                 WARNING_WINDOW(
"Do not run Xemu with administrator rights!\nXemu is not OS security audited and can access network, filesystem, etc.\nIt can be easily used to exploit your system.\nAs always, never run anything as adminstrator, unless you really need to\nadministrate your OS, as the name suggest!");
 
  688 #ifdef XEMU_ARCH_HTML 
  691         MKDIR(emscripten_sdl_base_dir);
 
  698         if (SDL_Init(SDL_INIT_EVERYTHING & ~(SDL_INIT_TIMER | SDL_INIT_HAPTIC)))
 
  699                 FATAL(
"Cannot initialize SDL: %s", SDL_GetError());
 
  700         atexit(shutdown_emulator);
 
  714                 FATAL(
"Cannot pre-initialize SDL without any subsystem: %s", SDL_GetError());
 
  715         atexit(shutdown_emulator);
 
  716         p = SDL_GetBasePath();
 
  721                 FATAL(
"Cannot query SDL base directory: %s", SDL_GetError());
 
  724                 p = SDL_GetPrefPath(app_organization, app_name);
 
  731                 FATAL(
"Cannot query SDL preference directory: %s", SDL_GetError());
 
  735 #ifdef XEMU_CONFIGDB_SUPPORT 
  746 #ifndef XEMU_ARCH_HTML 
  747         const Uint32 XEMU_SDL_INIT_EVERYTHING =
 
  748 #if defined(XEMU_ARCH_WIN) && defined(SDL_INIT_SENSOR) 
  751                 SDL_INIT_EVERYTHING & ~(SDL_INIT_SENSOR | SDL_INIT_HAPTIC);
 
  752 #warning        "NOTE: SDL_INIT_SENSOR and SDL_INIT_HAPTIC is not used on Windows because seems to cause problems :(" 
  756         if (!SDL_WasInit(XEMU_SDL_INIT_EVERYTHING)) {
 
  757                 DEBUGPRINT(
"SDL: no SDL subsystem initialization has been done yet, do it!" NL);
 
  759                 DEBUG(
"SDL: before SDL init" NL);
 
  760                 if (SDL_Init(XEMU_SDL_INIT_EVERYTHING)) {
 
  761                         ERROR_WINDOW(
"Cannot initialize SDL: %s", SDL_GetError());
 
  764                 DEBUG(
"SDL: after SDL init" NL);
 
  765                 if (!SDL_WasInit(XEMU_SDL_INIT_EVERYTHING))
 
  766                         FATAL(
"SDL_WasInit()=0 after init??");
 
  768                 DEBUGPRINT(
"SDL: no SDL subsystem initialization has been done already." NL);
 
  772         const char *sdl_video_driver = SDL_GetCurrentVideoDriver();
 
  773         if (!sdl_video_driver)
 
  774                 FATAL(
"SDL_GetCurrentVideoDriver() == NULL");
 
  775         sdl_on_x11 = !strcasecmp(sdl_video_driver, 
"x11");
 
  778                 printf( 
"SDL version: (%s) compiled with %d.%d.%d, used with %d.%d.%d on platform %s" NL 
  779                         "SDL system info: %d bits %s, %d cores, l1_line=%d, RAM=%dMbytes, max_alignment=%d%s, CPU features: " 
  780                         "3DNow=%d AVX=%d AVX2=%d AltiVec=%d MMX=%d RDTSC=%d SSE=%d SSE2=%d SSE3=%d SSE41=%d SSE42=%d" NL 
  781                         "SDL drivers: video = %s, audio = %s" NL,
 
  792                         SDL_Has3DNow(),SDL_HasAVX(),SDL_HasAVX2(),SDL_HasAltiVec(),SDL_HasMMX(),SDL_HasRDTSC(),SDL_HasSSE(),SDL_HasSSE2(),SDL_HasSSE3(),SDL_HasSSE41(),SDL_HasSSE42(),
 
  793                         sdl_video_driver, SDL_GetCurrentAudioDriver()
 
  795 #if defined(XEMU_ARCH_WIN) 
  796 #       define SDL_VER_MISMATCH_WARN_STR "Xemu was not compiled with the linked DLL for SDL.\nPlease upgrade your DLL too, not just Xemu binary." 
  797 #elif defined(XEMU_ARCH_OSX) 
  798 #       define SDL_VER_MISMATCH_WARN_STR "Xemu was not compuled with the linked dylib for SDL.\nPlease upgrade your dylib too, not just Xemu binary." 
  800 #ifdef SDL_VER_MISMATCH_WARN_STR 
  812         static Uint32 last_resize = 0;
 
  814         if (!forced && sdl_viewport_changed && follow_win_size) {
 
  815                 now = SDL_GetTicks();
 
  816                 if (now - last_resize >= 1000) {
 
  817                         sdl_viewport_changed = 0;
 
  824         SDL_GetWindowSize(
sdl_win, &w, &h);
 
  825         float rat = (float)w / (
float)sdl_viewport.w;
 
  826         const float rat2 = (float)h / (
float)sdl_viewport.h;
 
  833         const int w2 = rat * sdl_viewport.w;
 
  834         const int h2 = rat * sdl_viewport.h;
 
  835         if (w != w2 || h != h2) {
 
  837                 SDL_SetWindowSize(
sdl_win, w2, h2);
 
  838                 DEBUGPRINT(
"SDL: auto-resizing window to %d x %d (zoom level approximated: %d)" NL, w2, h2, (
int)rat);
 
  840                 DEBUGPRINT(
"SDL: no auto-resizing was needed (same size)" NL);
 
  846         if (
XEMU_UNLIKELY(x1 == 0 && y1 == 0 && x2 == 0 && y2 == 0)) {
 
  847                 sdl_viewport_ptr = NULL;
 
  850                 sdl_viewport.w = sdl_texture_x_size;
 
  851                 sdl_viewport.h = sdl_texture_y_size;
 
  853                 if (
XEMU_UNLIKELY(x1 > x2 || y1 > y2 || x1 >= sdl_texture_x_size || y1 >= sdl_texture_y_size || x2 >= sdl_texture_x_size || y2 >= sdl_texture_y_size)) {
 
  854                         FATAL(
"Invalid xemu_set_viewport(%d,%d,%d,%d) for texture (%d x %d)", x1, y1, x2, y2, sdl_texture_x_size, sdl_texture_y_size);
 
  856                         sdl_viewport_ptr = &sdl_viewport;
 
  859                         sdl_viewport.w = x2 - x1 + 1;
 
  860                         sdl_viewport.h = y2 - y1 + 1;
 
  863         sdl_viewport_changed = 1;
 
  866                 SDL_RenderSetLogicalSize(
sdl_ren, sdl_viewport.w, sdl_viewport.h);
 
  877 void xemu_get_viewport ( 
unsigned int *x1, 
unsigned int *y1, 
unsigned int *x2, 
unsigned int *y2 )
 
  880                 *x1 = sdl_viewport.x;
 
  882                 *y1 = sdl_viewport.y;
 
  884                 *x2 = sdl_viewport.x + sdl_viewport.w - 1;
 
  886                 *y2 = sdl_viewport.y + sdl_viewport.h - 1;
 
  890 static int xemu_create_main_texture ( 
void )
 
  892         DEBUGPRINT(
"SDL: creating main texture %d x %d" NL, sdl_texture_x_size, sdl_texture_y_size);
 
  893         SDL_Texture *new_tex = SDL_CreateTexture(
sdl_ren, sdl_pixel_format_id, SDL_TEXTUREACCESS_STREAMING, sdl_texture_x_size, sdl_texture_y_size);
 
  895                 DEBUGPRINT(
"SDL: cannot create main texture: %s" NL, SDL_GetError());
 
  909         const char *window_title,               
 
  911         int texture_x_size, 
int texture_y_size, 
 
  912         int logical_x_size, 
int logical_y_size, 
 
  913         int win_x_size, 
int win_y_size,         
 
  918         int render_scale_quality,               
 
  919         int locked_texture_update,              
 
  920         void (*shutdown_callback)(
void)         
 
  922         srand((
unsigned int)time(NULL));
 
  923 #       include "build/xemu-48x48.xpm" 
  924         SDL_RendererInfo ren_info;
 
  929                 printf(
"Logging into file: not enabled." NL);
 
  931                 FATAL(
"xemu_pre_init() hasn't been called yet!");
 
  932         if (xemu_byte_order_test()) {
 
  936 #ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR 
  939         SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, 
"0");
 
  943         shutdown_user_function = shutdown_callback;
 
  948 #ifndef XEMU_ARCH_HTML 
  952 #ifndef XEMU_ARCH_WIN 
  954                 char *p = getenv(
"HOME");
 
  961                                         WARNING_WINDOW(
"Warning: cannot create symlink %s to %s: %s", p, s, strerror(errno));
 
  963                                 INFO_WINDOW(
"Old-style link for pref.directory has been created as %s\npointing to: %s", s, p);
 
  970 #if defined(SDL_HINT_THREAD_STACK_SIZE) && defined(XEMU_THREAD_STACK_SIZE) 
  973         SDL_SetHint(SDL_HINT_THREAD_STACK_SIZE, 
STRINGIFY(XEMU_THREAD_STACK_SIZE));
 
  975 #ifdef SDL_HINT_RENDER_SCALE_QUALITY 
  976         const char render_scale_quality_s[2] = { 
'0' + (render_scale_quality & 3), 
'\0' };
 
  977         SDL_SetHintWithPriority(SDL_HINT_RENDER_SCALE_QUALITY, render_scale_quality_s, SDL_HINT_OVERRIDE);              
 
  979 #ifdef SDL_HINT_VIDEO_X11_NET_WM_PING 
  980         SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_PING, 
"0");                               
 
  982 #ifdef SDL_HINT_RENDER_VSYNC 
  983         SDL_SetHint(SDL_HINT_RENDER_VSYNC, 
"0");                                        
 
  985 #ifdef SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 
  986         SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, 
"1");                          
 
  988 #ifdef SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS 
  989         SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, 
"0");                        
 
  991 #ifdef SDL_HINT_VIDEO_ALLOW_SCREENSAVER 
  992         SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, 
"1");                             
 
  998                 SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
 
  999                 win_x_size, win_y_size,
 
 1000                 SDL_WINDOW_SHOWN | (is_resizable ? SDL_WINDOW_RESIZABLE : 0)
 
 1004         DEBUGPRINT(
"SDL window native pixel format: %s" NL, SDL_GetPixelFormatName(SDL_GetWindowPixelFormat(
sdl_win)));
 
 1006                 ERROR_WINDOW(
"Cannot create SDL window: %s", SDL_GetError());
 
 1009         window_title_buffer = 
xemu_malloc(strlen(window_title) + 128);
 
 1010         strcpy(window_title_buffer, window_title);
 
 1011         window_title_buffer_end = window_title_buffer + strlen(window_title);
 
 1013         a = SDL_GetNumRenderDrivers();
 
 1015                 if (!SDL_GetRenderDriverInfo(a, &ren_info)) {
 
 1016                         DEBUGPRINT(
"SDL renderer driver #%d: \"%s\"" NL, a, ren_info.name);
 
 1018                         DEBUGPRINT(
"SDL renderer driver #%d: FAILURE TO QUERY (%s)" NL, a, SDL_GetError());
 
 1020         sdl_ren = SDL_CreateRenderer(
sdl_win, -1, SDL_RENDERER_ACCELERATED);
 
 1022                 ERROR_WINDOW(
"Cannot create accelerated SDL renderer: %s", SDL_GetError());
 
 1025                         ERROR_WINDOW(
"... and not even non-accelerated driver could be created, giving up: %s", SDL_GetError());
 
 1028                         INFO_WINDOW(
"Created non-accelerated driver. NOTE: it will severly affect the performance!");
 
 1031         SDL_SetRenderDrawColor(
sdl_ren, 0, 0, 0, SDL_ALPHA_OPAQUE);
 
 1032         if (!SDL_GetRendererInfo(
sdl_ren, &ren_info)) {
 
 1033                 DEBUGPRINT(
"SDL renderer used: \"%s\" max_tex=%dx%d tex_formats=%d ", ren_info.name, ren_info.max_texture_width, ren_info.max_texture_height, ren_info.num_texture_formats);
 
 1034                 for (a = 0; a < ren_info.num_texture_formats; a++)
 
 1035                         DEBUGPRINT(
"%c%s", a ? 
' ' : 
'(', SDL_GetPixelFormatName(ren_info.texture_formats[a]));
 
 1038         SDL_RenderSetLogicalSize(
sdl_ren, logical_x_size, logical_y_size);      
 
 1039         sdl_texture_x_size = texture_x_size;
 
 1040         sdl_texture_y_size = texture_y_size;
 
 1041         sdl_pixel_format_id = pixel_format;
 
 1043         if (xemu_create_main_texture()) {
 
 1044                 ERROR_WINDOW(
"Cannot create SDL texture: %s", SDL_GetError());
 
 1051         black_colour = SDL_MapRGBA(
sdl_pix_fmt, 0, 0, 0, 0xFF); 
 
 1055         if (!locked_texture_update)
 
 1068         int width, height, 
colours, chperpix;
 
 1069         if (sscanf(xpm[0], 
"%d %d %d %d", &width, &height, &
colours, &chperpix) != 4) {
 
 1073         if (chperpix != 1) {
 
 1074                 ERROR_WINDOW(
"Icon internal error: not one-char per pixel format");
 
 1078         SDL_Surface *surf = SDL_CreateRGBSurfaceFrom(
data, width, height, 8, width, 0, 0, 0, 0);
 
 1080                 ERROR_WINDOW(
"Icon internal error: cannot allocate surface: %s", SDL_GetError());
 
 1086                 SDL_Color *palentry = &(surf->format->palette->colors[(
Uint8)xpm[i][0]]);
 
 1090                         for (
int a = 0; a < 6; a++) {
 
 1091                                 int hdig = p[a + 1];
 
 1092                                 if (hdig >= 
'0' && hdig <= 
'9')
 
 1093                                         vals[a] = hdig - 
'0';
 
 1094                                 else if (hdig >= 
'A' && hdig <= 
'F')
 
 1095                                         vals[a] = hdig - 
'A' + 10;
 
 1097                                         vals[a] = hdig - 
'a' + 10;
 
 1099                         palentry->r = (vals[0] << 4) + vals[1];
 
 1100                         palentry->g = (vals[2] << 4) + vals[3];
 
 1101                         palentry->b = (vals[4] << 4) + vals[5];
 
 1110                 memcpy(d, xpm[i++], width);
 
 1114         SDL_SetWindowIcon(
sdl_win, surf);
 
 1115         SDL_FreeSurface(surf);
 
 1124         (void)get_elapsed_time(0, &et_old, &unix_time_tv);
 
 1136         for (
int y = 0; 
y < texture_y_size; 
y++) {
 
 1137                 for (
int x = 0; 
x < texture_x_size; 
x++)
 
 1157                 xemu_create_main_texture();
 
 1167                         FATAL(
"Cannot lock texture: %s", SDL_GetError());
 
 1169                         FATAL(
"Not dword aligned texture pitch value got!");
 
 1172                         FATAL(
"Negative pitch value got for the texture size!");
 
 1173                 *texture_tail = (pitch >> 2);
 
 1195 #ifdef XEMU_OSD_SUPPORT 
 1206         static const char *selector_default_yes = 
"!Yes|?No";
 
 1207         static const char *selector_default_no  = 
"Yes|*No";
 
 1208         static const char *selector_generic     = 
"Yes|No";
 
 1209         const char *selector;
 
 1211                 selector = selector_default_yes;
 
 1213                 selector = selector_default_no;
 
 1215                 selector = selector_generic;
 
 1216         return (
QUESTION_WINDOW(selector, (s != NULL && *s != 
'\0') ? s : 
"Are you sure?") == 0);
 
 1222         char items_buf[512], *
items = items_buf;
 
 1224         SDL_MessageBoxButtonData buttons[16];
 
 1225         SDL_MessageBoxData messageboxdata = {
 
 1226                 SDL_MESSAGEBOX_WARNING  
 
 1227 #if SDL_VERSION_ATLEAST(2, 0, 12) 
 1228                 | SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT
 
 1232                 default_window_title,   
 
 1238         if (!SDL_WasInit(0))
 
 1239                 FATAL(
"Calling _sdl_emu_secured_modal_box_() without non-zero SDL_Init() before!");
 
 1240         strcpy(items_buf, items_in);
 
 1242                 char *p = strchr(
items, 
'|');
 
 1245                                 buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
 
 1249                                 buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
 
 1253                                 buttons[messageboxdata.numbuttons].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
 
 1257                                 buttons[messageboxdata.numbuttons].flags = 0;
 
 1260 #ifdef XEMU_ARCH_HTML 
 1261                 if ((buttons[messageboxdata.numbuttons].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT)) {
 
 1262                         DEBUGPRINT(
"Emscripten: faking chooser box answer %d for \"%s\"" NL, messageboxdata.numbuttons, msg);
 
 1263                         return messageboxdata.numbuttons;
 
 1266                 buttons[messageboxdata.numbuttons].text = 
items;
 
 1267                 buttons[messageboxdata.numbuttons].buttonid = messageboxdata.numbuttons;
 
 1268                 messageboxdata.numbuttons++;
 
 1296 #ifdef XEMU_ARCH_WIN 
 1299         CONSOLE_SCREEN_BUFFER_INFO coninfo;
 
 1305         if (!AllocConsole()) {
 
 1311         HWND hwnd = GetConsoleWindow();
 
 1313                 HMENU hmenu = GetSystemMenu(hwnd, FALSE);
 
 1315                         DeleteMenu(hmenu, SC_CLOSE, MF_BYCOMMAND);
 
 1317                         DEBUGPRINT(
"WINDOWS: GetSystemMenu() failed to give the menu for our console window." NL);
 
 1319                 DEBUGPRINT(
"WINDOWS: GetConsoleWindow() failed to give a handle." NL);
 
 1322         SetConsoleOutputCP(65001); 
 
 1323         SetConsoleTitle(
"Xemu Console");
 
 1325         GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
 
 1326         coninfo.dwSize.Y = 1024;
 
 1328         SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
 
 1330         lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
 
 1331         hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
 
 1332         fp = _fdopen( hConHandle, 
"w" );
 
 1334         setvbuf( stdout, NULL, _IONBF, 0 );
 
 1336         lStdHandle = GetStdHandle(STD_INPUT_HANDLE);
 
 1337         hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
 
 1338         fp = _fdopen( hConHandle, 
"r" );
 
 1340         setvbuf( stdin, NULL, _IONBF, 0 );
 
 1342         lStdHandle = GetStdHandle(STD_ERROR_HANDLE);
 
 1343         hConHandle = _open_osfhandle((INT_PTR)lStdHandle, _O_TEXT);
 
 1344         fp = _fdopen( hConHandle, 
"w" );
 
 1346         setvbuf( stderr, NULL, _IONBF, 0 );
 
 1351         SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
 
 1352         SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT);
 
 1353         SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
 
 1355         if (!atexit_callback_for_console_registered) {
 
 1356                 atexit(atexit_callback_for_console);
 
 1357                 atexit_callback_for_console_registered = 1;
 
 1364 #ifdef XEMU_ARCH_WIN 
 1365 static CHAR sysconsole_getch( 
void )
 
 1367         HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
 
 1370         DWORD cc, mode_saved;
 
 1371         GetConsoleMode(h, &mode_saved);
 
 1372         SetConsoleMode(h, mode_saved & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
 
 1374         ReadConsole(h, &c, 1, &cc, NULL);
 
 1375         SetConsoleMode(h, mode_saved);
 
 1381 #ifdef XEMU_ARCH_WIN 
 1382 static int file_handle_redirect ( 
const char *target, 
const char *symname, 
const char *mode, FILE *handle )
 
 1384         if (!freopen(target, mode, handle)) {
 
 1385                 ERROR_WINDOW(
"Failed to redirect [%s] to \"%s\"\n%s", symname, target, strerror(errno));
 
 1397 #ifdef XEMU_ARCH_WIN 
 1401                 printf(
"\n\n*** %s\nPress SPACE to continue.", waitmsg);
 
 1402                 while (sysconsole_getch() != 32)
 
 1405         if (!FreeConsole()) {
 
 1413                 int ret = file_handle_redirect(
NULL_DEVICE, 
"stderr", 
"w", stderr);
 
 1414                 ret |=    file_handle_redirect(
NULL_DEVICE, 
"stdout", 
"w", stdout);
 
 1415                 ret |=    file_handle_redirect(
NULL_DEVICE, 
"stdin",  
"r", stdin );
 
 1416                 DEBUG(
"WINDOWS: console has been closed (file_handle_redirect: %s)" NL, ret ? 
"ERROR" : 
"OK");
 
 1421 #elif defined(XEMU_ARCH_MAC) 
 1422         if (macos_gui_started) {
 
 1423                 DEBUGPRINT(
"MACOS: GUI-startup detected, closing standard in/out/error file descriptors ..." NL);
 
 1424                 for (
int fd = 0; 
fd <= 2; 
fd++) {
 
 1425                         int devnull = open(
"/dev/null", O_WRONLY);      
 
 1426                         if (devnull >= 0 && devnull != 
fd)
 
 1433         for (
int fd = 0; 
fd < 100; 
fd++) {
 
 1437                                 int devnull = open(
"/dev/null", O_WRONLY);      
 
 1438                                 if (devnull >= 0 && devnull != 
fd)
 
 1439                                         dupres = dup2(devnull, 
fd);
 
 1474 #ifdef XEMU_ARCH_WIN 
 1478 #define WIN_WCHAR_TO_UTF8(o,i,size) !WideCharToMultiByte(CP_UTF8, 0, i, -1, o, size, NULL, NULL) 
 1481 #define WIN_UTF8_TO_WCHAR(o,i,size) !MultiByteToWideChar(CP_UTF8, 0, i, -1, o, size) 
 1484 #define WIN_WCHAR_TO_UTF8(o,i,size)     xemu_winos_wchar_to_utf8 
 1485 #define WIN_UTF8_TO_WCHAR(o,i,size)     xemu_winos_utf8_to_wchar 
 1488 int xemu_winos_utf8_to_wchar ( 
wchar_t *restrict o, 
const char *restrict i, 
size_t size )
 
 1493         static_assert(
sizeof(
wchar_t) == 2, 
"wchar_t must be two bytes long");
 
 1495                 Uint8 c = (unsigned)*i++;
 
 1496                 if (ulen == 1 && (c & 0xC0) != 0x80) {
 
 1502                         if (
XEMU_UNLIKELY(upos >= (1U << (
sizeof(
wchar_t) << 3)))) {
 
 1505                                 *o++ = (upos >>  10) + 0xD800;  
 
 1506                                 upos = (upos & 1023) + 0xDC00;  
 
 1512                 if ((c & 0x80) == 0) {
 
 1520                 } 
else if ((c & 0xE0) == 0xC0) {
 
 1525                 } 
else if ((c & 0xF0) == 0xE0) {
 
 1530                 } 
else if ((c & 0xF8) == 0xF0) {
 
 1535                 } 
else if ((c & 0xC0) == 0x80) {
 
 1539                         upos = (upos << 6) + (c & 0x3F);
 
 1549 int xemu_winos_wchar_to_utf8 ( 
char *restrict o, 
const wchar_t *restrict i, 
size_t size )
 
 1551         unsigned int sur = 0;
 
 1553                 unsigned int c = *i++;
 
 1561                         sur = (c - 0xD800) << 10;
 
 1568                         c = sur + (c - 0xDC00);
 
 1580                 } 
else if (c < 0x800) {
 
 1584                         *o++ = 0xC0 + ( c >>  6        );
 
 1585                         *o++ = 0x80 + ( c        & 0x3F);
 
 1586                 } 
else if (c < 0x10000) {
 
 1590                         *o++ = 0xE0 + ( c >> 12        );
 
 1591                         *o++ = 0x80 + ((c >>  6) & 0x3F);
 
 1592                         *o++ = 0x80 + ( c        & 0x3F);
 
 1593                 } 
else if (c < 0x110000) {
 
 1597                         *o++ = 0xF0 + ( c >> 18        );
 
 1598                         *o++ = 0x80 + ((c >> 12) & 0x3F);
 
 1599                         *o++ = 0x80 + ((c >>  6) & 0x3F);
 
 1600                         *o++ = 0x80 + ( c        & 0x3F);
 
 1609         wchar_t wchar_fn[PATH_MAX];
 
 1610         if (WIN_UTF8_TO_WCHAR(wchar_fn, 
fn, PATH_MAX)) {
 
 1619         wchar_t wchar_fn[PATH_MAX];
 
 1620         if (WIN_UTF8_TO_WCHAR(wchar_fn, 
fn, PATH_MAX)) {
 
 1627 FILE *
xemu_os_fopen ( 
const char *restrict 
fn, 
const char *restrict mode )
 
 1629         wchar_t wchar_fn[PATH_MAX];
 
 1630         wchar_t wchar_mode[32]; 
 
 1631         if (WIN_UTF8_TO_WCHAR(wchar_fn, 
fn, PATH_MAX)) {
 
 1635         if (WIN_UTF8_TO_WCHAR(wchar_mode, mode, 
sizeof wchar_mode)) {
 
 1639         return _wfopen(wchar_fn, wchar_mode);
 
 1644         wchar_t wchar_fn[PATH_MAX];
 
 1645         if (WIN_UTF8_TO_WCHAR(wchar_fn, 
fn, PATH_MAX)) {
 
 1649         return _wunlink(wchar_fn);
 
 1656         wchar_t wchar_fn[PATH_MAX];
 
 1657         if (WIN_UTF8_TO_WCHAR(wchar_fn, 
fn, PATH_MAX)) {
 
 1661         return _wmkdir(wchar_fn);
 
 1666         wchar_t wchar_fn[PATH_MAX];
 
 1667         if (WIN_UTF8_TO_WCHAR(wchar_fn, 
fn, PATH_MAX)) {
 
 1671         return _wopendir(wchar_fn);
 
 1676         return _wclosedir(
dirp);
 
 1681         const struct _wdirent *p;
 
 1684                 p = _wreaddir(
dirp);
 
 1687         } 
while (WIN_WCHAR_TO_UTF8(
fn, p->d_name, FILENAME_MAX));       
 
 1695         wchar_t wchar_fn[PATH_MAX];
 
 1696         if (WIN_UTF8_TO_WCHAR(wchar_fn, 
fn, PATH_MAX)) {
 
 1701         if (_wstat64(wchar_fn, &
st))
 
 1707         statbuf->st_gid   = 
st.st_gid;
 
 1708         statbuf->st_atime = 
st.st_atime;
 
 1709         statbuf->st_ctime = 
st.st_ctime;
 
 1710         statbuf->st_dev   = 
st.st_dev;
 
 1711         statbuf->st_ino   = 
st.st_ino;
 
 1712         statbuf->st_mode  = 
st.st_mode;
 
 1713         statbuf->st_mtime = 
st.st_mtime;
 
 1714         statbuf->st_nlink = 
st.st_nlink;
 
 1715         statbuf->st_rdev  = 
st.st_rdev;
 
 1716         statbuf->st_size  = 
st.st_size;
 
 1717         statbuf->st_uid   = 
st.st_uid;
 
 1732 #ifndef XEMU_ARCH_WIN 
 1736         const struct dirent *p = readdir(
dirp);
 
 1739         strcpy(
fn, p->d_name);
 
 1748 static inline Uint32 leftrotate ( 
Uint32 i, 
unsigned int count )
 
 1751         return (i << count) + (i >> (32 - count));
 
 1760         for (
unsigned int i = 0; i < 16; i++) {
 
 1765         for (
unsigned int i = 16; i <= 79; i++)
 
 1766                 w[i] = leftrotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
 
 1774         for (
unsigned int i = 0; i <= 79; i++) {
 
 1777                         f = (b & c) | ((~b) & d);
 
 1779                 } 
else if (i <= 39) {   
 
 1782                 } 
else if (i <= 59) {   
 
 1783                         f = (b & c) | (b & d) | (c & d);
 
 1789                 Uint32 temp = leftrotate(a, 5) + f + e + k + w[i];
 
 1792                 c = leftrotate(b, 30);
 
 1807         hash[0] = 0x67452301U;
 
 1808         hash[1] = 0xEFCDAB89U;
 
 1809         hash[2] = 0x98BADCFEU;
 
 1810         hash[3] = 0x10325476U;
 
 1811         hash[4] = 0xC3D2E1F0U;
 
 1812         Uint64 size_in_bits = (Uint64)
size << 3;
 
 1814         while (
size >= 64) {    
 
 1815                 sha1_chunk(hash, 
data);
 
 1820         Uint8 tail[128], *tail_p;
 
 1821         memset(tail, 0, 
sizeof tail);
 
 1824         tail[
size++] = 0x80;    
 
 1825         if (
size > 64 - 8) {
 
 1827                 sha1_chunk(hash, tail);
 
 1832         for (
unsigned int i = 63; i >= 56; i--) {
 
 1833                 tail_p[i] = size_in_bits & 0xFF;
 
 1836         sha1_chunk(hash, tail_p);
 
 1844         for (
unsigned int i = 0; i < 5; i++) {
 
 1845                 *hash_bytes++ = (hash[i] >> 24) & 0xFF;
 
 1846                 *hash_bytes++ = (hash[i] >> 16) & 0xFF;
 
 1847                 *hash_bytes++ = (hash[i] >>  8) & 0xFF;
 
 1848                 *hash_bytes++ = (hash[i]      ) & 0xFF;
 
 1857         sprintf(hash_str, 
"%08x%08x%08x%08x%08x", hash[0], hash[1], hash[2], hash[3], hash[4]);