From 197c4db204e4d632655583ca332af68d16189d38 Mon Sep 17 00:00:00 2001 From: Themaister Date: Wed, 1 May 2013 00:56:13 +0200 Subject: [PATCH] Add RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME. Allows libretro core to not require a ROM to be loaded. Kill stdin ROM loading support (pointless these days). Replace "no ROM on CLI" behavior to be attempting to load a core with no ROM. --- docs/retroarch.1 | 7 +- dynamic.c | 17 ++++- file.c | 115 ++++++------------------------- general.h | 3 + libretro-test-gl/libretro-test.c | 3 + libretro-test/libretro-test.c | 3 + libretro.h | 6 ++ retroarch.c | 53 +++----------- 8 files changed, 61 insertions(+), 146 deletions(-) diff --git a/docs/retroarch.1 b/docs/retroarch.1 index 8ad6302b48..761f7adb48 100644 --- a/docs/retroarch.1 +++ b/docs/retroarch.1 @@ -20,7 +20,7 @@ libretro provides emulation of a game system, and can be implemented by any fron .TP \fB[rom file]\fR -If no rom file path is defined on the command line, \fBretroarch\fR will try to load a rom from \fBstdin\fR. +If no rom file path is defined on the command line, \fBretroarch\fR will try to load a core with no rom. This will only work with some libretro cores. \fBretroarch\fR use uncompressed ROMs, but can uncompress roms in the .zip/deflate format if support for it is compiled in. ROM types supported depend on the libretro implementation used. @@ -53,17 +53,13 @@ If two or more different implementations claim to support a certain ROM extensio \fB--save PATH, -s PATH\fR Overrides the path used for save ram (*.srm). Without this flag, the save ram path will be inferred from the rom path name, and put in the same directory as the rom file with the extention replaced with '.srm'. -When rom is loaded from \fBstdin\fR, this flag is mandatory to define as no path can be inferred. If PATH is a directory, RetroArch will treat this as the save file directory, where the save file name will be inferred from the rom name. -When loading a rom from stdin, the path must be a full path, however. .TP \fB--savestate PATH, -S PATH\fR Overrides the path used for save states. Without this flag, the save state path will be inferred from the rom path name, and put in the same directory as the rom file with the extention replace with '.state'. -When rom is loaded from \fBstdin\fR, this flag is mandatory to define as no path can be inferred. If PATH is a directory, RetroArch will treat this as the save state directory, where the state file name will be inferred from the rom name. -When loading a rom from stdin, the path must be a full path, however. Do note that save states are bound to the libretro implementation being used. Using a different libretro could invalidate the save state file. .TP @@ -76,7 +72,6 @@ Sets the configuration file path. \fBretroarch\fR will use this path to load the Should this not be defined, \fBretroarch\fR will look in platform specific paths to attempt finding the config file. /etc/retroarch.cfg (when installed), or retroarch.cfg in the source tarball serves as a skeleton configuration file. If PATH is a directory, RetroArch will treat this as the config file directory, where the state file name will be inferred from the rom name (*.cfg). -When loading a rom from stdin, the path must be a full path, however. If a config cannot be found when using directory path, the default config path will be used instead. .IP diff --git a/dynamic.c b/dynamic.c index 26645ac05a..55ca6077ad 100644 --- a/dynamic.c +++ b/dynamic.c @@ -130,9 +130,10 @@ bool libretro_get_system_info(const char *path, struct retro_system_info *info) return false; memcpy(info, &dummy_info, sizeof(*info)); - info->library_name = strdup(dummy_info.library_name); - info->library_version = strdup(dummy_info.library_version); - info->valid_extensions = strdup(dummy_info.valid_extensions); + info->library_name = strdup(dummy_info.library_name); + info->library_version = strdup(dummy_info.library_version); + if (dummy_info.valid_extensions) + info->valid_extensions = strdup(dummy_info.valid_extensions); dylib_close(lib); return true; } @@ -371,6 +372,8 @@ void uninit_libretro_sym(void) memset(&g_extern.system.av_info, 0, sizeof(g_extern.system.av_info)); memset(&g_extern.frame_cache, 0, sizeof(g_extern.frame_cache)); g_extern.system.pix_fmt = RETRO_PIXEL_FORMAT_0RGB1555; + g_extern.system.no_game = false; + g_extern.system.shutdown = false; } #ifdef NEED_DYNAMIC @@ -637,6 +640,14 @@ static bool environment_cb(unsigned cmd, void *data) break; } + case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: + { + bool state = *(const bool*)data; + RARCH_LOG("Environ SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no"); + g_extern.system.no_game = state; + break; + } + default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); return false; diff --git a/file.c b/file.c index 4ff631292f..afb1b22f88 100644 --- a/file.c +++ b/file.c @@ -209,83 +209,21 @@ static void patch_rom(uint8_t **buf, ssize_t *size) *size = target_size; } - if (patch_data) - free(patch_data); - + free(patch_data); return; error: *buf = ret_buf; *size = ret_size; - if (patch_data) - free(patch_data); + free(patch_data); } -static ssize_t read_rom_file(FILE *file, void **buf) +static ssize_t read_rom_file(const char *path, void **buf) { - ssize_t ret = 0; uint8_t *ret_buf = NULL; - - if (file == NULL) // stdin - { -#if defined(_WIN32) && !defined(_XBOX) - _setmode(0, O_BINARY); -#endif - - RARCH_LOG("Reading ROM from stdin ...\n"); - size_t buf_size = 0xfffff; // Some initial guesstimate. - size_t buf_ptr = 0; - uint8_t *rom_buf = (uint8_t*)malloc(buf_size); - if (rom_buf == NULL) - { - RARCH_ERR("Couldn't allocate memory.\n"); - return -1; - } - - for (;;) - { - size_t ret = fread(rom_buf + buf_ptr, 1, buf_size - buf_ptr, stdin); - buf_ptr += ret; - - // We've reached the end - if (buf_ptr < buf_size) - break; - - rom_buf = (uint8_t*)realloc(rom_buf, buf_size * 2); - if (rom_buf == NULL) - { - RARCH_ERR("Couldn't allocate memory.\n"); - return -1; - } - - buf_size *= 2; - } - - ret_buf = rom_buf; - ret = buf_ptr; - } - else - { - fseek(file, 0, SEEK_END); - ret = ftell(file); - rewind(file); - - void *rom_buf = malloc(ret); - if (rom_buf == NULL) - { - RARCH_ERR("Couldn't allocate memory.\n"); - return -1; - } - - if (fread(rom_buf, 1, ret, file) < (size_t)ret) - { - RARCH_ERR("Didn't read whole file.\n"); - free(rom_buf); - return -1; - } - - ret_buf = (uint8_t*)rom_buf; - } + ssize_t ret = read_file(path, (void**)&ret_buf); + if (ret <= 0) + return ret; if (!g_extern.block_patch) { @@ -539,22 +477,10 @@ static bool load_roms(unsigned rom_type, const char **rom_paths, size_t roms) struct retro_game_info info[MAX_ROMS] = {{NULL}}; char *xml_buf = load_xml_map(g_extern.xml_name); - FILE *rom_file = NULL; - if (rom_paths[0]) - { - RARCH_LOG("Loading ROM file: %s.\n", rom_paths[0]); - rom_file = fopen(rom_paths[0], "rb"); - if (!rom_file) - { - RARCH_ERR("Failed to load ROM file: %s.\n", rom_paths[0]); - ret = false; - goto end; - } - } - if (!g_extern.system.info.need_fullpath) { - if ((rom_len[0] = read_rom_file(rom_file, &rom_buf[0])) == -1) + RARCH_LOG("Loading ROM file: %s.\n", rom_paths[0]); + if ((rom_len[0] = read_rom_file(rom_paths[0], &rom_buf[0])) == -1) { RARCH_ERR("Could not read ROM file.\n"); ret = false; @@ -564,16 +490,7 @@ static bool load_roms(unsigned rom_type, const char **rom_paths, size_t roms) RARCH_LOG("ROM size: %u bytes.\n", (unsigned)rom_len[0]); } else - { - if (!rom_file) - { - RARCH_ERR("Implementation requires a full path to be set, cannot load ROM from stdin. Aborting ...\n"); - ret = false; - goto end; - } - RARCH_LOG("ROM loading skipped. Implementation will load it on its own.\n"); - } info[0].path = rom_paths[0]; info[0].data = rom_buf[0]; @@ -608,16 +525,24 @@ end: for (unsigned i = 0; i < MAX_ROMS; i++) free(rom_buf[i]); free(xml_buf); - if (rom_file) - fclose(rom_file); return ret; } static bool load_normal_rom(void) { - const char *path = *g_extern.fullpath ? g_extern.fullpath : NULL; - return load_roms(0, &path, 1); + if (g_extern.libretro_no_rom && g_extern.system.no_game) + return pretro_load_game(NULL); + else if (g_extern.libretro_no_rom && !g_extern.system.no_game) + { + RARCH_ERR("No ROM is used, but libretro core does not support this.\n"); + return false; + } + else + { + const char *path = g_extern.fullpath; + return load_roms(0, &path, 1); + } } static bool load_sgb_rom(void) diff --git a/general.h b/general.h index d940aaa4d7..c75025063e 100644 --- a/general.h +++ b/general.h @@ -369,6 +369,7 @@ struct global bool block_extract; bool force_nonblock; + bool no_game; const char *input_desc_btn[MAX_PLAYERS][RARCH_FIRST_CUSTOM_BIND]; char valid_extensions[PATH_MAX]; @@ -379,6 +380,7 @@ struct global struct retro_hw_render_callback hw_render_callback; core_option_manager_t *core_options; + } system; struct @@ -597,6 +599,7 @@ struct global jmp_buf error_sjlj_context; unsigned menu_toggle_behavior; + bool libretro_no_rom; bool libretro_dummy; }; diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c index b6c4c50ce6..bc3eaa6201 100644 --- a/libretro-test-gl/libretro-test.c +++ b/libretro-test-gl/libretro-test.c @@ -190,6 +190,9 @@ static retro_input_state_t input_state_cb; void retro_set_environment(retro_environment_t cb) { environ_cb = cb; + + bool no_rom = true; + cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_rom); } void retro_set_audio_sample(retro_audio_sample_t cb) diff --git a/libretro-test/libretro-test.c b/libretro-test/libretro-test.c index 8819cee086..abf5c6c2c5 100644 --- a/libretro-test/libretro-test.c +++ b/libretro-test/libretro-test.c @@ -73,6 +73,9 @@ void retro_set_environment(retro_environment_t cb) }; cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars); + + bool no_rom = true; + cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_rom); } void retro_set_audio_sample(retro_audio_sample_t cb) diff --git a/libretro.h b/libretro.h index 3e0ea73287..f1857c9591 100755 --- a/libretro.h +++ b/libretro.h @@ -452,6 +452,12 @@ enum retro_mod // Result is set to true if some variables are updated by // frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE. // Variables should be queried with GET_VARIABLE. + // +#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18 + // const bool * -- + // If true, the libretro implementation supports calls to retro_load_game() with NULL as argument. + // Used by cores which can run without particular game data. + // Pass this to retro_video_refresh_t if rendering to hardware. // Passing NULL to retro_video_refresh_t is still a frame dupe as normal. diff --git a/retroarch.c b/retroarch.c index bc10f628d1..c3fc8e43f1 100644 --- a/retroarch.c +++ b/retroarch.c @@ -646,7 +646,7 @@ static void print_help(void) puts("\t--menu: Do not require ROM or libretro core to be loaded, starts directly in menu."); puts("\t\tIf no arguments are passed to RetroArch, it is equivalent to using --menu as only argument."); puts("\t--features: Prints available features compiled into RetroArch."); - puts("\t-s/--save: Path for save file (*.srm). Required when rom is input from stdin."); + puts("\t-s/--save: Path for save file (*.srm)."); puts("\t-f/--fullscreen: Start RetroArch in fullscreen regardless of config settings."); puts("\t-S/--savestate: Path to use for save states. If not selected, *.state will be assumed."); puts("\t-c/--config: Path for config file." RARCH_DEFAULT_CONF_PATH_STR); @@ -753,45 +753,9 @@ static void set_paths(const char *path) } } -static void verify_stdin_paths(void) -{ - if (!*g_extern.savefile_name_srm) - { - RARCH_ERR("Need savefile path argument (--save) when reading rom from stdin.\n"); - print_help(); - rarch_fail(1, "verify_stdin_paths()"); - } - else if (!*g_extern.savestate_name) - { - RARCH_ERR("Need savestate path argument (--savestate) when reading rom from stdin.\n"); - print_help(); - rarch_fail(1, "verify_stdin_paths()"); - } - - if (path_is_directory(g_extern.savefile_name_srm)) - { - RARCH_ERR("Cannot specify directory for path argument (--save) when reading from stdin.\n"); - print_help(); - rarch_fail(1, "verify_stdin_paths()"); - } - else if (path_is_directory(g_extern.savestate_name)) - { - RARCH_ERR("Cannot specify directory for path argument (--savestate) when reading from stdin.\n"); - print_help(); - rarch_fail(1, "verify_stdin_paths()"); - } - else if (path_is_directory(g_extern.config_path)) - { - RARCH_ERR("Cannot specify directory for config file (--config) when reading from stdin.\n"); - print_help(); - rarch_fail(1, "verify_stdin_paths()"); - } - - driver.stdin_claimed = true; -} - static void parse_input(int argc, char *argv[]) { + g_extern.libretro_no_rom = false; g_extern.libretro_dummy = false; g_extern.has_set_save_path = false; g_extern.has_set_state_path = false; @@ -1177,7 +1141,7 @@ static void parse_input(int argc, char *argv[]) else if (optind < argc) set_paths(argv[optind]); else - verify_stdin_paths(); + g_extern.libretro_no_rom = true; // Copy SRM/state dirs used, so they can be reused on reentrancy. if (g_extern.has_set_save_path && path_is_directory(g_extern.savefile_name_srm)) @@ -2907,10 +2871,15 @@ int rarch_main_init(int argc, char *argv[]) verify_api_version(); pretro_init(); - g_extern.use_sram = !g_extern.libretro_dummy; + g_extern.use_sram = !g_extern.libretro_dummy && !g_extern.libretro_no_rom; bool allow_cheats = true; - if (!g_extern.libretro_dummy) + if (g_extern.libretro_no_rom && !g_extern.libretro_dummy) + { + if (!init_rom_file(g_extern.game_type)) + goto error; + } + else if (!g_extern.libretro_dummy) { fill_pathnames(); @@ -3123,7 +3092,7 @@ void rarch_main_deinit(void) deinit_movie(); #endif - if (!g_extern.libretro_dummy) + if (!g_extern.libretro_dummy && !g_extern.libretro_no_rom) save_auto_state(); pretro_unload_game();