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]);