38 #ifdef HAVE_XEMU_EXEC_API
42 int xemuexec_run (
char *
const args[] )
46 DEBUGPRINT(
"EXEC: fork() failed: %s" NL, strerror(errno));
51 for(a = 3; a < 1024; a++)
54 execvp(args[0], args);
56 printf(
"EXEC: execution of \"%s\" failed: %s" NL, args[0], strerror(errno));
63 int xemuexec_check_status ( pid_t pid,
int wait )
70 ret = waitpid(pid, &
status, wait ? 0 : WNOHANG);
74 DEBUGPRINT(
"EXEC: WAIT: waitpid(%d) returned error: %s" NL, pid, strerror(errno));
80 return XEMUEXEC_STILL_RUNNING;
83 return WEXITSTATUS(
status);
95 struct ugly_windows_ps_t {
96 PROCESS_INFORMATION pi;
102 void *xemuexec_run (
char *
const args[] )
105 int cmdlinesize =
sizeof cmdline;
106 struct ugly_windows_ps_t *
st = malloc(
sizeof(
struct ugly_windows_ps_t));
108 FATAL(
"exec: cannot allocate memory");
109 ZeroMemory(
st,
sizeof(
struct ugly_windows_ps_t));
110 st->si.cb =
sizeof(STARTUPINFO);
112 if (snprintf(cmdline, cmdlinesize,
"\"%s\"", args[0]) != strlen(args[0]) + 2)
113 FATAL(
"exec: too long commandline");
114 cmdlinesize -= strlen(args[0]) + 2;
116 int arg_padding_len = strchr(*args,
' ') ? 3 : 1;
117 if (cmdlinesize <= 0)
118 FATAL(
"exec: too long commandline");
119 if (snprintf(cmdline + strlen(cmdline), cmdlinesize, arg_padding_len == 1 ?
" %s" :
" \"%s\"", *args) != strlen(*args) + arg_padding_len)
120 FATAL(
"exec: too long commandline");
121 cmdlinesize -= strlen(*args) + arg_padding_len;
123 st->cmdline = _tcsdup(TEXT(cmdline));
126 FATAL(
"exec: cannot allocate memory");
131 st->si.hStdError = (HANDLE)_open_osfhandle(_fileno(stderr), _O_TEXT);
132 st->si.hStdOutput = (HANDLE)_open_osfhandle(_fileno(stdout), _O_TEXT);
136 st->si.hStdInput = (HANDLE)_get_osfhandle(fileno(stdin));
138 SetHandleInformation(
st->si.hStdError, HANDLE_FLAG_INHERIT, 0);
139 SetHandleInformation(
st->si.hStdOutput, HANDLE_FLAG_INHERIT, 0);
140 SetHandleInformation(
st->si.hStdInput, HANDLE_FLAG_INHERIT, 0);
142 if (CreateProcess(NULL,
153 st->creationstatus = 0;
154 DEBUGPRINT(
"EXEC: (%s) seems to be OK :-)" NL, cmdline);
156 st->creationstatus = GetLastError();
157 DEBUGPRINT(
"EXEC: (%s) failed with %d" NL, cmdline, (
int)
st->creationstatus);
158 if (!
st->creationstatus) {
159 st->creationstatus = 1;
169 static void free_exec_struct_win32 (
struct ugly_windows_ps_t *
st )
173 if (
st->creationstatus) {
174 CloseHandle(
st->pi.hProcess);
175 CloseHandle(
st->pi.hThread);
183 #define PID ((struct ugly_windows_ps_t *)pid)
184 int xemuexec_check_status (
void* pid,
int wait )
188 if (PID->creationstatus) {
189 DEBUGPRINT(
"EXEC: WAIT: returning because of deferred creationstatus(%d) != 0 situation" NL, (
int)PID->creationstatus);
190 free_exec_struct_win32(PID);
197 GetExitCodeProcess(PID->pi.hProcess, &result);
198 }
while (wait && result == STILL_ACTIVE);
199 if (result == STILL_ACTIVE)
200 return XEMUEXEC_STILL_RUNNING;
201 free_exec_struct_win32(PID);
212 #ifdef HAVE_XEMU_EXEC_API
213 static xemuexec_process_t fbp = XEMUEXEC_NULL_PROCESS_ID;
214 while (*
dir ==
' ' || *
dir ==
'\t')
216 if (!strncasecmp(
dir,
"file://", 7))
226 if (!strncasecmp(
dir,
"ftp://", 6) || !strncasecmp(
dir,
"http://", 7) || !strncasecmp(
dir,
"https://", 8)) {
236 if (fbp != XEMUEXEC_NULL_PROCESS_ID) {
237 int w = xemuexec_check_status(fbp, 0);
238 DEBUGPRINT(
"EXEC: FILEBROWSER: previous file browser process (" PRINTF_LLD ") status was: %d" NL, (
unsigned long long int)(uintptr_t)fbp, w);
239 if (w == XEMUEXEC_STILL_RUNNING)
240 ERROR_WINDOW(
"A file browser is already has been opened.");
244 fbp = XEMUEXEC_NULL_PROCESS_ID;
247 fbp = xemuexec_run(args);
249 ERROR_WINDOW(
"Sorry, no execution API is supported by this Xemu build\nto allow to launch an OS-native file browser for you on directory:\n%s",
dir);
254 #ifdef HAVE_XEMU_INSTALLER
256 char *xemu_installer_db = NULL;
258 static const char installer_marker_prefix[] =
"[XEMU_DOWNLOADER]=";
260 static char installer_store_to[PATH_MAX];
261 static char installer_fetch_url[256];
262 static const char *downloader_utility_specifications[] = {
264 "powershell",
"-Command",
"Invoke-WebRequest", installer_fetch_url,
"-OutFile", installer_store_to,
"-Verbose", NULL,
265 "powershell.exe",
"-Command",
"Invoke-WebRequest", installer_fetch_url,
"-OutFile", installer_store_to,
"-Verbose", NULL,
267 "curl",
"-o", installer_store_to, installer_fetch_url, NULL,
269 "curl.exe",
"-o", installer_store_to, installer_fetch_url, NULL,
271 "wget",
"-O", installer_store_to, installer_fetch_url, NULL,
273 "wget.exe",
"-O", installer_store_to, installer_fetch_url, NULL,
278 static const char **downloader_utility_spec_start_p = downloader_utility_specifications;
279 static int downloader_utility_selected = 0;
280 static int legal_warning = 1;
284 static int download_file (
int size )
287 char path_final[PATH_MAX];
288 const char **execargs_p = downloader_utility_spec_start_p;
290 strcpy(path_final, installer_store_to);
291 strcat(installer_store_to,
".temp");
292 DEBUGPRINT(
"INSTALLER: goal: %s -> %s -> %s (%d bytes)" NL,
293 installer_fetch_url, installer_store_to, path_final,
size
295 if (unlink(path_final) && errno != ENOENT) {
296 ERROR_WINDOW(
"Installer: cannot delete already existing final file");
300 xemuexec_process_t proc;
301 printf(
"Tryning: %s\n", *execargs_p);
302 if (unlink(installer_store_to) && errno != ENOENT) {
303 ERROR_WINDOW(
"Installer: cannot delete already exisiting temp file");
306 proc = xemuexec_run((
char*
const*)execargs_p);
307 ret = xemuexec_check_status(proc, 1);
308 printf(
"Exit status: %d\n", ret);
309 if (!ret || downloader_utility_selected)
311 while (*(execargs_p++))
313 }
while (*execargs_p);
315 ERROR_WINDOW(
"Installer: cannot download and/or no working download utility can be used");
316 unlink(installer_store_to);
319 if (stat(installer_store_to, &
st)) {
320 ERROR_WINDOW(
"Installer: cannot stat file (not downloaded at all?)");
323 printf(
"File size = %d\n", (
int)
st.st_size);
325 unlink(installer_store_to);
326 ERROR_WINDOW(
"Installer: downloaded file has wrong size (%d, wanted: %d)", (
int)
st.st_size,
size);
329 if (rename(installer_store_to, path_final)) {
333 if (!downloader_utility_selected) {
334 downloader_utility_spec_start_p = execargs_p;
335 downloader_utility_selected = 1;
336 DEBUGPRINT(
"INSTALLER: setting \"%s\" as the default downloader utility for this session." NL, *execargs_p);
343 static int download_file_by_db (
const char *filename,
const char *storepath )
347 if (!xemu_installer_db)
349 strcpy(installer_store_to, storepath);
350 p = xemu_installer_db;
351 i = strlen(filename);
353 while (*p && *p <= 32)
355 if (!strncmp(filename, p, i) && (p[i] ==
'\t' || p[i] ==
' ')) {
357 while (*p ==
' ' || *p ==
'\t')
362 if (strncasecmp(p,
"http://", 7) && strncasecmp(p,
"https://", 8) && strncasecmp(p,
"ftp://", 6)) {
363 ERROR_WINDOW(
"Bad download descriptor file at URL field (bar protocol) for record \"%s\"", filename);
366 q = installer_fetch_url;
369 if (sizereq ==
sizeof(installer_fetch_url) - 2) {
370 ERROR_WINDOW(
"Bad download descriptor file at URL field (too long) for record \"%s\"", filename);
377 sizereq = strtol(p, &p, 0);
380 if (sizereq > 0 && sizereq <= 4194304) {
382 char msgbuffer[
sizeof(installer_fetch_url) + 256];
387 sprintf(msgbuffer,
"Downloading file \"%s\". Do you agree?\nSource: %s", filename, installer_fetch_url);
390 ret = download_file(sizereq);
392 INFO_WINDOW(
"File %s seems to be downloaded nicely with %s", filename, *downloader_utility_spec_start_p);
395 ERROR_WINDOW(
"Bad download descriptor file at size field for record \"%s\" (or this file is not auto-installable)", filename);
400 while (*p && *p !=
'\n' && *p !=
'\r')
403 DEBUGPRINT(
"INSTALLER: file-key %s cannot be found in the download description file" NL, filename);
408 void xemu_set_installer (
const char *filename )
410 if (xemu_installer_db) {
411 free(xemu_installer_db);
412 xemu_installer_db = NULL;
415 int ret =
xemu_load_file(filename, NULL, 32, 65535,
"Specified installer-description file cannot be loaded");
418 DEBUGPRINT(
"INSTALLER: description file loaded, %d bytes. Parsing will be done only on demand." NL, ret);
433 ERROR_WINDOW(
"Sorry, no execution API is supported by this Xemu build\nto allow to launch an OS-native file browser for you on directory:\n%s",
dir);
469 int xemu_open_file (
const char *filename,
int mode,
int *mode2,
char *filepath_back )
471 char paths[16][PATH_MAX];
474 FATAL(
"Calling xemu_open_file() with NULL filename!");
476 FATAL(
"Calling xemu_open_file() with empty filename!");
478 #ifdef XEMU_ARCH_HTML
479 sprintf(paths[max_paths++],
"%s%s", EMSCRIPTEN_SDL_BASE_DIR, (filename[0] ==
'@' || filename[0] ==
'#') ? filename + 1 : filename);
481 if (*filename ==
'@') {
482 sprintf(paths[max_paths++],
"%s%s",
sdl_pref_dir, filename + 1);
483 }
else if (*filename ==
'#') {
484 sprintf(paths[max_paths++],
"%s%s",
sdl_inst_dir, filename + 1);
485 sprintf(paths[max_paths++],
"%s%s",
sdl_pref_dir, filename + 1);
487 sprintf(paths[max_paths++],
"%s%s",
sdl_base_dir, filename + 1);
488 #ifndef XEMU_ARCH_WIN
494 #ifdef HAVE_XEMU_INSTALLER
495 sprintf(paths[max_paths++],
"%s%s%s", installer_marker_prefix,
sdl_inst_dir, filename + 1);
498 strcpy(paths[max_paths++], filename);
504 const char *filepath = paths[a];
505 #ifdef HAVE_XEMU_INSTALLER
506 if (!strncmp(paths[a], installer_marker_prefix, strlen(installer_marker_prefix))) {
507 filepath += strlen(installer_marker_prefix);
508 download_file_by_db(filename + 1, filepath);
516 strcpy(filepath_back, filepath);
520 DEBUGPRINT(
"FILE: file %s opened as %s with base mode-set as fd=%d" NL, filename, paths[a],
fd);
526 DEBUGPRINT(
"FILE: file %s opened as %s with *second* mode-set as fd=%d" NL, filename, paths[a],
fd);
530 }
while (++a < max_paths);
533 strcpy(filepath_back, paths[0]);
534 DEBUGPRINT(
"FILE: %s cannot be open, tried path(s): ", filename);
535 for (a = 0; a < max_paths; a++)
547 ssize_t
r = read(
fd, buffer, length);
549 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
567 ssize_t w = write(
fd, buffer, length);
569 if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
624 static const char temp_end[] =
".TMP";
625 char filename[PATH_MAX];
626 char filename_real[PATH_MAX];
627 strcpy(filename, filename_in);
628 strcat(filename, temp_end);
629 int fd =
xemu_open_file(filename, O_WRONLY | O_TRUNC | O_CREAT, NULL, filename_real);
632 ERROR_WINDOW(
"%s\nCannot create file: %s\n%s", cry, filename, strerror(errno));
637 ERROR_WINDOW(
"%s\nCannot write %d bytes into file: %s\n%s", cry,
size, filename_real, strerror(errno));
639 unlink(filename_real);
644 char filename_real2[PATH_MAX];
645 strcpy(filename_real2, filename_real);
646 filename_real2[strlen(filename_real2) - strlen(temp_end)] = 0;
647 DEBUGPRINT(
"FILE: renaming file: %s -> %s" NL, filename_real, filename_real2);
649 unlink(filename_real2);
651 if (rename(filename_real, filename_real2)) {
653 ERROR_WINDOW(
"%s\nCannot rename file %s to %s\n%s", cry, filename_real, filename_real2, strerror(errno));
654 unlink(filename_real);
674 int xemu_load_file (
const char *filename,
void *store_to,
int min_size,
int max_size,
const char *cry )
680 (*filename ==
'#') ?
"(# prefixed, multiple paths also tried)\n" :
"",
697 if (load_size < min_size) {
706 if (load_size > max_size) {
730 int fd = open(os_path,
O_BINARY | O_RDWR | O_CREAT | O_TRUNC, 0600);
736 if (DeviceIoControl((HANDLE)_get_osfhandle(
fd), FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL) == 0) {
737 ERROR_WINDOW(
"Cannot set file as sparse file!\nWindows error #" PRINTF_LLU "\nIt's not a fatal problem, though the file will take much more space than usual", (
unsigned long long int)GetLastError());
740 DEBUGPRINT(
"WINDOWS: file has been made sparse, lpBytesReturned=" PRINTF_LLU NL, (
unsigned long long int)dwTemp);
747 static const Uint8 zero = 0;
751 if (write(
fd, &zero, 1) != 1)
753 if (lseek(
fd, -1, SEEK_CUR) !=
size)
771 #if defined(XEMU_USE_LODEPNG) && defined(XEMU_FILES_SCREENSHOT_SUPPORT)
772 char xemu_screenshot_full_path[PATH_MAX+1];
779 int xemu_screenshot_png (
const char *path,
const char *
fn,
unsigned int zoom_width,
unsigned int zoom_height,
Uint32 *source_pixels,
unsigned int source_width,
unsigned int source_height,
unsigned int source_texture_width )
781 int target_width = source_width * zoom_width;
782 int target_height = source_height * zoom_height;
783 if (!source_pixels) {
786 if (!source_pixels) {
787 DEBUGPRINT(
"SCREENSHOT: FAILED: No opened frame with source_pixels=NULL" NL);
791 Uint8 *target_pixels = malloc(target_width * target_height * 3);
792 if (!target_pixels) {
793 ERROR_WINDOW(
"Not enough memory for taking a screenshot :(\n(could not allocate %d bytes of memory)", target_width * target_height * 3);
796 for (
int i = 0; i < target_width * target_height; i++) {
800 Uint32 pixel = source_pixels[(
801 (i % target_width) / zoom_width
803 ((i / target_width) / zoom_height) * source_texture_width
814 Uint8 *png_stream = NULL;
818 int ret = lodepng_encode24(&png_stream, &png_size, target_pixels, target_width, target_height);
821 ERROR_WINDOW(
"Screenshot problem: loadPNG encode returned with error %u", (
unsigned)ret);
826 if (!png_stream || !png_size) {
829 ERROR_WINDOW(
"Screenshot problem: lodePNG returned invalid memory/size");
835 sprintf(xemu_screenshot_full_path,
"%s%s",
sdl_pref_dir,
"screenshots");
836 MKDIR(xemu_screenshot_full_path);
837 time_t ut = time(NULL);
838 struct tm *t = localtime(&ut);
840 xemu_screenshot_full_path + strlen(xemu_screenshot_full_path),
841 DIRSEP_STR "screenshot-%04d%02d%02d-%02d%02d%02d.png",
842 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec
846 FATAL(
"Invalid %s mode", __func__);
848 sprintf(xemu_screenshot_full_path,
"%s%c%s", path,
DIRSEP_CHR,
fn);
850 strcpy(xemu_screenshot_full_path,
fn);
852 ret =
xemu_save_file(xemu_screenshot_full_path, png_stream, png_size,
"Cannot save screenshot PNG");
856 "SCREENSHOT: (%dx%d -> %dx%d) successfully saved as %s" NL,
857 source_width, source_height, target_width, target_height, xemu_screenshot_full_path