diff --git a/CHANGES.md b/CHANGES.md index afb55b0acb..85e5e4267c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,16 +1,39 @@ -# 1.6.4 (future) +# 1.6.5 (future) +- AUDIO: MOD/S3M/XM sound should now be properly mixed in with the core's sound. +- LOCALIZATION: Update Italian translation +- INPUT: Overlay controller response - when we press buttons on the gamepad or keyboard, the corresponding buttons on the overlay will be highlighted as well. +- NETBSD: Silence some compilation warnings. + +# 1.6.4 - ANDROID: Fire Stick & Fire TV remote overrides gamepad port 0 on button press and viceversa like SHIELD devices +- ANDROID: Provide default save / system / state / screenshot locations - AUDIO: Audio mixer supports MOD/S3M/XM file types now! - INPUT: input swap override flag (for remotes) is cleared correctly -- COMMON: Add 'Delete Core'option to Core Information menu. +- INPUT: allow specifying libretro device in remap files +- INPUT: allow specifying analog dpad mode in remap files +- INPUT: allow saving libretro device to remap files +- INPUT: allow saving analog dpad mode to remap files +- INPUT: allow removing core and game remap files from the menu +- COMMON: Cores can now request to set a 'shared context'. You no longer need to explicitly enable 'Shared Hardware Context' for Citra/OpenLara/Dolphin. +- COMMON: Add 'Delete Core' option to Core Information menu. - COMMON: Allow Max Timing Skew to be set to 0. +- COMMON: Change the "content dir" behavior so it works on either a flag or an empty directory setting, now platform drivers can provide defaults for save / system / state / screenshot dirs and still allow the content dir functionality, these settings are under settings / saving and flagged as advanced +- GUI: You can turn on/off 'Horizontal Animation' now for the XMB menu. Turning animations off can result in a performance boost. +- GUI: Fix sublabel word-wrapping in XMB where multi-byte languages were cut off too soon +- LOCALIZATION: Update Dutch translation +- LOCALIZATION: Update Traditional Chinese translation +- LOCALIZATION: Update Italian translation - LOCALIZATION: Update Russian translation +- WINDOWS: Provide default save / system / state / screenshot locations +- LOBBIES: Show what country the host is in +- MENU: Enable OSD text rendering for gdi and libcaca drivers - WINDOWS 98/ME/2K: Set default directory for MSVC 2005 RetroArch version. +- WII: Better V-Sync handling, backported from SuperrSonic. - WIIU: Exception handler rewritten. # 1.6.3 -- IOS: Fix GL regression - 32bit color format cores were no longer rendering +- IOS: Fix GL regression - 32bit color format cores were no longer rendering - CHEEVOS: Add support for N64 cheevos and other small fixes. - CHEEVOS: Add 'Achievements -> Achievements Verbose Mode'. Ability to display cheevos related messages in OSD, useful for RetroAchievements users. - AUDIO: Audio mixer's volume can now be independently increased/decreased, and muted. diff --git a/Makefile.common b/Makefile.common index f7f4459735..698187ecd2 100644 --- a/Makefile.common +++ b/Makefile.common @@ -91,7 +91,7 @@ ifeq ($(HAVE_SHADERPIPELINE), 1) CFLAGS += -DHAVE_SHADERPIPELINE endif -CFLAGS += -I$(LIBRETRO_COMM_DIR)/include +CFLAGS += -I$(LIBRETRO_COMM_DIR)/include -I$(DEPS_DIR) # Switches diff --git a/Makefile.ctr.salamander b/Makefile.ctr.salamander index 91d13691dc..98ce0ea170 100644 --- a/Makefile.ctr.salamander +++ b/Makefile.ctr.salamander @@ -25,6 +25,7 @@ OBJ := ctr/ctr_system.o \ frontend/frontend_driver.o \ frontend/drivers/platform_ctr.o \ frontend/drivers/platform_null.o \ + libretro-common/encodings/encoding_utf.o \ libretro-common/compat/compat_strcasestr.o \ libretro-common/file/file_path.o \ libretro-common/string/stdstring.o \ diff --git a/Makefile.ps3 b/Makefile.ps3 index b473249cb6..944839aed5 100644 --- a/Makefile.ps3 +++ b/Makefile.ps3 @@ -1,4 +1,4 @@ -RARCH_VERSION = "0.9.9.3" +RARCH_VERSION = "1.6.4.0" #which compiler to build with - GCC or SNC #set to GCC for debug builds for use with debugger diff --git a/Makefile.ps3.salamander b/Makefile.ps3.salamander index b6e17aed55..ab51d0db4d 100644 --- a/Makefile.ps3.salamander +++ b/Makefile.ps3.salamander @@ -16,9 +16,20 @@ else ifneq ($(findstring MINGW,$(shell uname -a)),) system_platform = win endif +ifeq ($(DEBUG), 1) + PPU_OPTIMIZE_LV := -O0 -g +else + PPU_OPTIMIZE_LV := -O2 -DNDEBUG +endif + STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe -PPU_CFLAGS += -I. -Ilibretro-common/include -Ideps/libz -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC +INCFLAGS = -I. -Idefines -Ilibretro-common/include -Ideps/libz +DEFINES = -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC + +PPU_CFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES) +PPU_CXXFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES) + PPU_SRCS = frontend/frontend_salamander.c \ frontend/frontend_driver.c \ frontend/drivers/platform_ps3.c \ @@ -29,6 +40,7 @@ PPU_SRCS = frontend/frontend_salamander.c \ libretro-common/file/retro_dirent.c \ libretro-common/hash/rhash.c \ libretro-common/string/stdstring.c \ + libretro-common/encodings/encoding_utf.c \ libretro-common/compat/compat_strl.c \ libretro-common/compat/compat_strcasestr.c \ libretro-common/streams/file_stream.c \ @@ -60,8 +72,6 @@ endif PPU_LDLIBS += -lm -lnet_stub -lnetctl_stub -lio_stub -lsysmodule_stub -lsysutil_stub -lsysutil_game_stub -lfs_stub -lsysutil_np_stub -PPU_OPTIMIZE_LV := -O2 - MAKE_FSELF = $(CELL_SDK)/host-win32/bin/make_fself.exe include $(CELL_MK_DIR)/sdk.target.mk diff --git a/Makefile.psl1ght b/Makefile.psl1ght index 341fa5dbbf..0569e41311 100644 --- a/Makefile.psl1ght +++ b/Makefile.psl1ght @@ -1,4 +1,4 @@ -RARCH_VERSION = "0.9.9.3" +RARCH_VERSION = "1.6.4.0" DEBUG = 0 HAVE_LOGGER = 0 diff --git a/Makefile.psp1.salamander b/Makefile.psp1.salamander index 70093392c5..68e0732582 100644 --- a/Makefile.psp1.salamander +++ b/Makefile.psp1.salamander @@ -40,6 +40,7 @@ OBJS = frontend/frontend_salamander.o \ libretro-common/lists/string_list.o \ libretro-common/lists/dir_list.o \ libretro-common/file/retro_dirent.o \ + libretro-common/encodings/encoding_utf.o \ libretro-common/compat/compat_strl.o \ libretro-common/compat/compat_strcasestr.o \ libretro-common/file/config_file.o \ diff --git a/Makefile.vita.salamander b/Makefile.vita.salamander index d49970dd53..3af34fb28e 100644 --- a/Makefile.vita.salamander +++ b/Makefile.vita.salamander @@ -41,6 +41,7 @@ OBJS = frontend/frontend_salamander.o \ libretro-common/lists/string_list.o \ libretro-common/lists/dir_list.o \ libretro-common/file/retro_dirent.o \ + libretro-common/encodings/encoding_utf.o \ libretro-common/compat/compat_strl.o \ libretro-common/compat/compat_strcasestr.o \ libretro-common/file/config_file.o \ diff --git a/Makefile.wii.salamander b/Makefile.wii.salamander index ddc65ab10c..896a020c4b 100644 --- a/Makefile.wii.salamander +++ b/Makefile.wii.salamander @@ -51,6 +51,7 @@ OBJ = frontend/frontend_salamander.o \ libretro-common/lists/dir_list.o \ libretro-common/streams/file_stream.o \ libretro-common/file/retro_dirent.o \ + libretro-common/encodings/encoding_utf.o \ libretro-common/compat/compat_strl.o \ libretro-common/compat/compat_strcasestr.o \ libretro-common/file/config_file.o \ diff --git a/Makefile.wiiu.salamander b/Makefile.wiiu.salamander index 6e3c43b61a..221d8193d1 100644 --- a/Makefile.wiiu.salamander +++ b/Makefile.wiiu.salamander @@ -16,6 +16,7 @@ OBJ += frontend/frontend_salamander.o OBJ += frontend/frontend_driver.o OBJ += frontend/drivers/platform_wiiu.o OBJ += frontend/drivers/platform_null.o +OBJ += libretro-common/encodings/encoding_utf.o OBJ += libretro-common/compat/compat_strcasestr.o OBJ += libretro-common/file/file_path.o OBJ += libretro-common/string/stdstring.o diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c index 2f0acb88b1..9514236f4a 100644 --- a/audio/drivers/dsound.c +++ b/audio/drivers/dsound.c @@ -322,7 +322,11 @@ static void *dsound_init(const char *device, unsigned rate, unsigned latency, RARCH_LOG("DirectSound devices:\n"); #ifndef _XBOX - DirectSoundEnumerate(enumerate_cb, &dev); +#ifdef UNICODE + DirectSoundEnumerate((LPDSENUMCALLBACKW)enumerate_cb, &dev); +#else + DirectSoundEnumerate((LPDSENUMCALLBACKA)enumerate_cb, &dev); +#endif #endif if (DirectSoundCreate(dev.guid, &ds->ds, NULL) != DS_OK) diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 0d3b7ba0f9..d3d82891fb 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -921,7 +921,7 @@ static unsigned cheevos_prefix_to_comp_size(char prefix) { /* Careful not to use ABCDEF here, this denotes part of an actual variable! */ - switch( toupper( prefix ) ) + switch( toupper( (unsigned char)prefix ) ) { case 'M': return CHEEVOS_VAR_SIZE_BIT_0; @@ -1141,13 +1141,13 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr) const char *str = *memaddr; unsigned base = 16; - if (toupper(*str) == 'D' && str[1] == '0' && toupper(str[2]) == 'X') + if (toupper((unsigned char)*str) == 'D' && str[1] == '0' && toupper((unsigned char)str[2]) == 'X') { /* d0x + 4 hex digits */ str += 3; var->type = CHEEVOS_VAR_TYPE_DELTA_MEM; } - else if (*str == '0' && toupper(str[1]) == 'X') + else if (*str == '0' && toupper((unsigned char)str[1]) == 'X') { /* 0x + 4 hex digits */ str += 2; @@ -1157,11 +1157,11 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr) { var->type = CHEEVOS_VAR_TYPE_VALUE_COMP; - if (toupper(*str) == 'H') + if (toupper((unsigned char)*str) == 'H') str++; else { - if (toupper(*str) == 'V') + if (toupper((unsigned char)*str) == 'V') str++; base = 10; @@ -1372,9 +1372,7 @@ static void cheevos_free_condition(cheevos_condition_t* condition) if (condition->condsets) { for (i = 0; i < condition->count; i++) - { free((void*)condition->condsets[i].conds); - } free((void*)condition->condsets); } @@ -2074,7 +2072,7 @@ static void cheevos_url_encode(const char *str, char *encoded, size_t len) { while (*str) { - if ( isalnum(*str) || *str == '-' + if ( isalnum((unsigned char)*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~') { @@ -2652,44 +2650,45 @@ bool cheevos_toggle_hardcore_mode(void) static void cheevos_patch_addresses(cheevoset_t* set) { + unsigned i, j, k; cheevo_t* cheevo = set->cheevos; - for (unsigned i = set->count; i != 0; i--, cheevo++) + for (i = set->count; i != 0; i--, cheevo++) { cheevos_condset_t* condset = cheevo->condition.condsets; - for (unsigned j = cheevo->condition.count; j != 0; j--, condset++) + for (j = cheevo->condition.count; j != 0; j--, condset++) { cheevos_cond_t* cond = condset->conds; - for (unsigned k = condset->count; k != 0; k--, cond++) + for (k = condset->count; k != 0; k--, cond++) { switch (cond->source.type) { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_parse_guest_addr(&cond->source, cond->source.value); - #ifdef CHEEVOS_DUMP_ADDRS - RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->source.bank_id + 1, cond->source.value); - #endif - break; + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_parse_guest_addr(&cond->source, cond->source.value); +#ifdef CHEEVOS_DUMP_ADDRS + RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->source.bank_id + 1, cond->source.value); +#endif + break; - default: - break; + default: + break; } switch (cond->target.type) { - case CHEEVOS_VAR_TYPE_ADDRESS: - case CHEEVOS_VAR_TYPE_DELTA_MEM: - cheevos_parse_guest_addr(&cond->target, cond->target.value); - #ifdef CHEEVOS_DUMP_ADDRS - RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->target.bank_id + 1, cond->target.value); - #endif - break; + case CHEEVOS_VAR_TYPE_ADDRESS: + case CHEEVOS_VAR_TYPE_DELTA_MEM: + cheevos_parse_guest_addr(&cond->target, cond->target.value); +#ifdef CHEEVOS_DUMP_ADDRS + RARCH_LOG("CHEEVOS var %03d:%08X\n", cond->target.bank_id + 1, cond->target.value); +#endif + break; - default: - break; + default: + break; } } } diff --git a/command.c b/command.c index ca21d18931..878a24f211 100644 --- a/command.c +++ b/command.c @@ -1,5 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2015-2017 - Andrés Suárez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -1053,6 +1054,7 @@ static void command_event_deinit_core(bool reinit) command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL); command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL); + command_event(CMD_EVENT_RESTORE_REMAPS, NULL); } static void command_event_init_cheats(void) @@ -1226,7 +1228,7 @@ static bool command_event_init_core(enum rarch_core_type *data) rarch_ctl(RARCH_CTL_UNSET_OVERRIDES_ACTIVE, NULL); } - /* Auto-remap: apply shader preset files */ + /* Auto-shaders: apply shader preset files */ if(settings->bools.auto_shaders_enable) config_load_shader_preset(); @@ -1287,6 +1289,12 @@ static void command_event_restore_default_shader_preset(void) path_clear(RARCH_PATH_DEFAULT_SHADER_PRESET); } +static void command_event_restore_remaps(void) +{ + if (rarch_ctl(RARCH_CTL_IS_REMAPS_GAME_ACTIVE, NULL)) + input_remapping_set_defaults(); +} + static bool command_event_save_auto_state(void) { char savestate_name_auto[PATH_MAX_LENGTH] = {0}; @@ -1797,6 +1805,7 @@ bool command_event(enum event_command cmd, void *data) command_event(CMD_EVENT_AUTOSAVE_STATE, NULL); command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL); command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL); + command_event(CMD_EVENT_RESTORE_REMAPS, NULL); if (is_inited) if (!task_push_start_dummy_core(&content_info)) @@ -2589,6 +2598,9 @@ bool command_event(enum event_command cmd, void *data) case CMD_EVENT_DISABLE_OVERRIDES: command_event_disable_overrides(); break; + case CMD_EVENT_RESTORE_REMAPS: + command_event_restore_remaps(); + break; case CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET: command_event_restore_default_shader_preset(); break; diff --git a/command.h b/command.h index 8cd7ec2132..ccac457ef8 100644 --- a/command.h +++ b/command.h @@ -218,6 +218,7 @@ enum event_command CMD_EVENT_MIXER_VOLUME_UP, CMD_EVENT_MIXER_VOLUME_DOWN, CMD_EVENT_DISABLE_OVERRIDES, + CMD_EVENT_RESTORE_REMAPS, CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, CMD_EVENT_LIBUI_TEST }; diff --git a/config.def.h b/config.def.h index 86d2475636..f426c5b61b 100644 --- a/config.def.h +++ b/config.def.h @@ -295,6 +295,11 @@ static bool default_auto_shaders_enable = true; static bool default_sort_savefiles_enable = false; static bool default_sort_savestates_enable = false; +static bool default_savestates_in_content_dir = false; +static bool default_savefiles_in_content_dir = false; +static bool default_systemfiles_in_content_dir = false; +static bool default_screenshots_in_content_dir = false; + #if defined(__CELLOS_LV2__) || defined(_XBOX1) || defined(_XBOX360) static unsigned menu_toggle_gamepad_combo = INPUT_TOGGLE_L3_R3; #elif defined(VITA) diff --git a/configuration.c b/configuration.c index 1704386fbb..62bb385401 100644 --- a/configuration.c +++ b/configuration.c @@ -2,6 +2,7 @@ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2015-2017 - Andrés Suárez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -52,7 +53,7 @@ /* All config related settings go here. */ struct config_bool_setting -{ +{ const char *ident; bool *ptr; bool def_enable; @@ -61,7 +62,7 @@ struct config_bool_setting }; struct config_int_setting -{ +{ const char *ident; int *ptr; bool def_enable; @@ -70,7 +71,7 @@ struct config_int_setting }; struct config_uint_setting -{ +{ const char *ident; unsigned *ptr; bool def_enable; @@ -79,7 +80,7 @@ struct config_uint_setting }; struct config_float_setting -{ +{ const char *ident; float *ptr; bool def_enable; @@ -88,7 +89,7 @@ struct config_float_setting }; struct config_array_setting -{ +{ const char *ident; char *ptr; bool def_enable; @@ -97,7 +98,7 @@ struct config_array_setting }; struct config_path_setting -{ +{ const char *ident; char *ptr; bool def_enable; @@ -485,7 +486,7 @@ static enum menu_driver_enum MENU_DEFAULT_DRIVER = MENU_NULL; tmp[count].def = default_setting; \ tmp[count].handle = handle_setting; \ count++; \ -} +} #define SETTING_BOOL(key, configval, default_enable, default_setting, handle_setting) \ GENERAL_SETTING(key, configval, default_enable, default_setting, struct config_bool_setting, handle_setting) @@ -1014,7 +1015,7 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, SETTING_PATH("cheat_database_path", settings->paths.path_cheat_database, false, NULL, true); #ifdef HAVE_MENU - SETTING_PATH("menu_wallpaper", + SETTING_PATH("menu_wallpaper", settings->paths.path_menu_wallpaper, false, NULL, true); #endif SETTING_PATH("content_history_path", @@ -1033,7 +1034,7 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, settings->paths.path_font, false, NULL, true); SETTING_PATH("cursor_directory", settings->paths.directory_cursor, false, NULL, true); - SETTING_PATH("content_history_dir", + SETTING_PATH("content_history_dir", settings->paths.directory_content_history, false, NULL, true); SETTING_PATH("screenshot_directory", settings->paths.directory_screenshot, true, NULL, true); @@ -1063,7 +1064,7 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, settings->paths.directory_autoconfig, false, NULL, true); SETTING_PATH("audio_filter_dir", settings->paths.directory_audio_filter, true, NULL, true); - SETTING_PATH("savefile_directory", + SETTING_PATH("savefile_directory", dir_get_ptr(RARCH_DIR_SAVEFILE), true, NULL, false); SETTING_PATH("savestate_directory", dir_get_ptr(RARCH_DIR_SAVESTATE), true, NULL, false); @@ -1078,11 +1079,11 @@ static struct config_path_setting *populate_settings_path(settings_t *settings, settings->paths.directory_overlay, true, NULL, true); #endif #ifndef HAVE_DYNAMIC - SETTING_PATH("libretro_path", + SETTING_PATH("libretro_path", path_get_ptr(RARCH_PATH_CORE), false, NULL, false); #endif SETTING_PATH( - "screenshot_directory", + "screenshot_directory", settings->paths.directory_screenshot, true, NULL, false); if (global) @@ -1180,6 +1181,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, #endif SETTING_BOOL("menu_throttle_framerate", &settings->bools.menu_throttle_framerate, true, true, false); SETTING_BOOL("menu_linear_filter", &settings->bools.menu_linear_filter, true, true, false); + SETTING_BOOL("menu_horizontal_animation", &settings->bools.menu_horizontal_animation, true, true, false); SETTING_BOOL("dpi_override_enable", &settings->bools.menu_dpi_override_enable, true, menu_dpi_override_enable, false); SETTING_BOOL("menu_pause_libretro", &settings->bools.menu_pause_libretro, true, true, false); SETTING_BOOL("menu_mouse_enable", &settings->bools.menu_mouse_enable, true, def_mouse_enable, false); @@ -1204,14 +1206,14 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("xmb_show_netplay", &settings->bools.menu_xmb_show_netplay, true, xmb_show_netplay, false); #endif SETTING_BOOL("xmb_show_history", &settings->bools.menu_xmb_show_history, true, xmb_show_history, false); -#ifdef HAVE_LIBRETRODB +#ifdef HAVE_LIBRETRODB SETTING_BOOL("xmb_show_add", &settings->bools.menu_xmb_show_add, true, xmb_show_add, false); #endif #endif SETTING_BOOL("filter_by_current_core", &settings->bools.filter_by_current_core, false, false /* TODO */, false); SETTING_BOOL("rgui_show_start_screen", &settings->bools.menu_show_start_screen, false, false /* TODO */, false); SETTING_BOOL("menu_navigation_wraparound_enable", &settings->bools.menu_navigation_wraparound_enable, true, true, false); - SETTING_BOOL("menu_navigation_browser_filter_supported_extensions_enable", + SETTING_BOOL("menu_navigation_browser_filter_supported_extensions_enable", &settings->bools.menu_navigation_browser_filter_supported_extensions_enable, true, true, false); SETTING_BOOL("menu_show_advanced_settings", &settings->bools.menu_show_advanced_settings, true, show_advanced_settings, false); #endif @@ -1224,6 +1226,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, #ifdef HAVE_OVERLAY SETTING_BOOL("input_overlay_enable", &settings->bools.input_overlay_enable, true, config_overlay_enable_default(), false); SETTING_BOOL("input_overlay_enable_autopreferred", &settings->bools.input_overlay_enable_autopreferred, true, true, false); + SETTING_BOOL("input_overlay_show_physical_inputs", &settings->bools.input_overlay_show_physical_inputs, true, false, false); SETTING_BOOL("input_overlay_hide_in_menu", &settings->bools.input_overlay_hide_in_menu, true, overlay_hide_in_menu, false); #endif #ifdef HAVE_COMMAND @@ -1258,6 +1261,11 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("audio_wasapi_float_format", &settings->bools.audio_wasapi_float_format, true, wasapi_float_format, false); #endif + SETTING_BOOL("savestates_in_content_dir", &settings->bools.savestates_in_content_dir, true, default_savestates_in_content_dir, false); + SETTING_BOOL("savefiles_in_content_dir", &settings->bools.savefiles_in_content_dir, true, default_savefiles_in_content_dir, false); + SETTING_BOOL("systemfiles_in_content_dir", &settings->bools.systemfiles_in_content_dir, true, default_systemfiles_in_content_dir, false); + SETTING_BOOL("screenshots_in_content_dir", &settings->bools.screenshots_in_content_dir, true, default_screenshots_in_content_dir, false); + if (global) { SETTING_BOOL("custom_bgm_enable", &global->console.sound.system_bgm_enable, true, false, false); @@ -1366,6 +1374,7 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings, #endif SETTING_UINT("bundle_assets_extract_version_current", &settings->uints.bundle_assets_extract_version_current, true, 0, false); SETTING_UINT("bundle_assets_extract_last_version", &settings->uints.bundle_assets_extract_last_version, true, 0, false); + SETTING_UINT("input_overlay_show_physical_inputs_port", &settings->uints.input_overlay_show_physical_inputs_port, true, 0, false); *size = count; @@ -1923,7 +1932,7 @@ static config_file_t *open_default_config_file(void) RARCH_WARN("Created new config file in: \"%s\".\n", conf_path); } #elif !defined(RARCH_CONSOLE) - bool has_application_data = + bool has_application_data = fill_pathname_application_data(application_data, sizeof(application_data)); @@ -2099,7 +2108,7 @@ static bool check_shader_compatibility(enum file_path_enum enum_idx) return true; } - if (string_is_equal_fast(settings->arrays.video_driver, "gl", 2) || + if (string_is_equal_fast(settings->arrays.video_driver, "gl", 2) || string_is_equal_fast(settings->arrays.video_driver, "d3d", 3) ) { @@ -2170,7 +2179,7 @@ static void config_get_hex_base(config_file_t *conf, * Loads a config file and reads all the values into memory. * */ -static bool config_load_file(const char *path, bool set_defaults, +static bool config_load_file(const char *path, bool set_defaults, settings_t *settings) { unsigned i; @@ -2706,10 +2715,10 @@ end: * This function only has an effect if a game-specific or core-specific * configuration file exists at respective locations. * - * core-specific: $CONFIG_DIR/$CORE_NAME/$CORE_NAME.cfg + * core-specific: $CONFIG_DIR/$CORE_NAME/$CORE_NAME.cfg * fallback: $CURRENT_CFG_LOCATION/$CORE_NAME/$CORE_NAME.cfg * - * game-specific: $CONFIG_DIR/$CORE_NAME/$ROM_NAME.cfg + * game-specific: $CONFIG_DIR/$CORE_NAME/$ROM_NAME.cfg * fallback: $CURRENT_CFG_LOCATION/$CORE_NAME/$GAME_NAME.cfg * * Returns: false if there was an error or no action was performed. @@ -2805,7 +2814,7 @@ bool config_load_override(void) /* Re-load the configuration with any overrides that might have been found */ buf[0] = '\0'; - /* Store the libretro_path we're using since it will be + /* Store the libretro_path we're using since it will be * overwritten by the override when reloading. */ strlcpy(buf, path_get(RARCH_PATH_CORE), sizeof(buf)); @@ -2925,6 +2934,7 @@ bool config_load_remap(void) if (input_remapping_load_file(new_conf, game_path)) { runloop_msg_queue_push("Game remap file loaded.", 1, 100, true); + rarch_ctl(RARCH_CTL_SET_REMAPS_GAME_ACTIVE, NULL); return true; } } @@ -2944,6 +2954,7 @@ bool config_load_remap(void) if (input_remapping_load_file(new_conf, core_path)) { runloop_msg_queue_push("Core remap file loaded.", 1, 100, true); + rarch_ctl(RARCH_CTL_SET_REMAPS_CORE_ACTIVE, NULL); return true; } } @@ -3252,7 +3263,7 @@ static void save_keybinds_user(config_file_t *conf, unsigned user) */ void config_load(void) { - /* Flush out some states that could have been + /* Flush out some states that could have been * set by core environment variables */ core_unset_input_descriptors(); @@ -3442,7 +3453,7 @@ bool config_save_file(const char *path) #ifdef HAVE_MENU config_set_path(conf, "xmb_font", - !string_is_empty(settings->paths.path_menu_xmb_font) + !string_is_empty(settings->paths.path_menu_xmb_font) ? settings->paths.path_menu_xmb_font : ""); #endif @@ -3633,7 +3644,7 @@ bool config_save_overrides(int override_type) fill_pathname_application_special(config_directory, sizeof(config_directory), APPLICATION_SPECIAL_DIRECTORY_CONFIG); - fill_pathname_join(override_directory, config_directory, core_name, + fill_pathname_join(override_directory, config_directory, core_name, sizeof(override_directory)); if(!path_file_exists(override_directory)) @@ -3690,9 +3701,9 @@ bool config_save_overrides(int override_type) { if ((*bool_settings[i].ptr) != (*bool_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%d\n", + RARCH_LOG(" original: %s=%d\n", bool_settings[i].ident, (*bool_settings[i].ptr)); - RARCH_LOG(" override: %s=%d\n", + RARCH_LOG(" override: %s=%d\n", bool_overrides[i].ident, (*bool_overrides[i].ptr)); config_set_bool(conf, bool_overrides[i].ident, (*bool_overrides[i].ptr)); @@ -3702,9 +3713,9 @@ bool config_save_overrides(int override_type) { if ((*int_settings[i].ptr) != (*int_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%d\n", + RARCH_LOG(" original: %s=%d\n", int_settings[i].ident, (*int_settings[i].ptr)); - RARCH_LOG(" override: %s=%d\n", + RARCH_LOG(" override: %s=%d\n", int_overrides[i].ident, (*int_overrides[i].ptr)); config_set_int(conf, int_overrides[i].ident, (*int_overrides[i].ptr)); @@ -3714,9 +3725,9 @@ bool config_save_overrides(int override_type) { if ((*uint_settings[i].ptr) != (*uint_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%d\n", + RARCH_LOG(" original: %s=%d\n", uint_settings[i].ident, (*uint_settings[i].ptr)); - RARCH_LOG(" override: %s=%d\n", + RARCH_LOG(" override: %s=%d\n", uint_overrides[i].ident, (*uint_overrides[i].ptr)); config_set_int(conf, uint_overrides[i].ident, (*uint_overrides[i].ptr)); @@ -3726,9 +3737,9 @@ bool config_save_overrides(int override_type) { if ((*float_settings[i].ptr) != (*float_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%f\n", + RARCH_LOG(" original: %s=%f\n", float_settings[i].ident, *float_settings[i].ptr); - RARCH_LOG(" override: %s=%f\n", + RARCH_LOG(" override: %s=%f\n", float_overrides[i].ident, *float_overrides[i].ptr); config_set_float(conf, float_overrides[i].ident, *float_overrides[i].ptr); @@ -3739,9 +3750,9 @@ bool config_save_overrides(int override_type) { if (!string_is_equal(array_settings[i].ptr, array_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%s\n", + RARCH_LOG(" original: %s=%s\n", array_settings[i].ident, array_settings[i].ptr); - RARCH_LOG(" override: %s=%s\n", + RARCH_LOG(" override: %s=%s\n", array_overrides[i].ident, array_overrides[i].ptr); config_set_string(conf, array_overrides[i].ident, array_overrides[i].ptr); @@ -3752,9 +3763,9 @@ bool config_save_overrides(int override_type) { if (!string_is_equal(path_settings[i].ptr, path_overrides[i].ptr)) { - RARCH_LOG(" original: %s=%s\n", + RARCH_LOG(" original: %s=%s\n", path_settings[i].ident, path_settings[i].ptr); - RARCH_LOG(" override: %s=%s\n", + RARCH_LOG(" override: %s=%s\n", path_overrides[i].ident, path_overrides[i].ptr); config_set_path(conf, path_overrides[i].ident, path_overrides[i].ptr); @@ -3776,7 +3787,8 @@ bool config_save_overrides(int override_type) snprintf(cfg, sizeof(cfg), "input_player%u_joypad_index", i + 1); config_set_int(conf, cfg, overrides->uints.input_joypad_map[i]); } - if (input_config_get_device(i) != overrides->uints.input_libretro_device[i]) + + if (settings->uints.input_libretro_device[i] != overrides->uints.input_libretro_device[i]) { snprintf(cfg, sizeof(cfg), "input_libretro_device_p%u", i + 1); config_set_int(conf, cfg, overrides->uints.input_libretro_device[i]); diff --git a/configuration.h b/configuration.h index 8d20c8daaf..9018d965dd 100644 --- a/configuration.h +++ b/configuration.h @@ -88,6 +88,7 @@ typedef struct settings bool input_overlay_enable; bool input_overlay_enable_autopreferred; bool input_overlay_hide_in_menu; + bool input_overlay_show_physical_inputs; bool input_descriptor_label_show; bool input_descriptor_hide_unbound; bool input_all_users_control_menu; @@ -119,6 +120,7 @@ typedef struct settings bool menu_show_advanced_settings; bool menu_throttle_framerate; bool menu_linear_filter; + bool menu_horizontal_animation; bool menu_show_online_updater; bool menu_show_core_updater; bool menu_xmb_shadows_enable; @@ -209,6 +211,11 @@ typedef struct settings bool sort_savestates_enable; bool config_save_on_exit; bool show_hidden_files; + + bool savefiles_in_content_dir; + bool savestates_in_content_dir; + bool screenshots_in_content_dir; + bool systemfiles_in_content_dir; #ifdef HAVE_LAKKA bool ssh_enable; bool samba_enable; @@ -322,6 +329,8 @@ typedef struct settings unsigned camera_width; unsigned camera_height; + + unsigned input_overlay_show_physical_inputs_port; } uints; struct diff --git a/dist-scripts/dist-cores.sh b/dist-scripts/dist-cores.sh index 360eb879b6..e2eb5d7096 100755 --- a/dist-scripts/dist-cores.sh +++ b/dist-scripts/dist-cores.sh @@ -1,6 +1,6 @@ #!/bin/sh -RARCH_VERSION=1.3.6 +RARCH_VERSION=1.6.4 PLATFORM=$1 SALAMANDER=no MAKEFILE_GRIFFIN=no @@ -90,6 +90,8 @@ SCETOOL_PATH=${PS3TOOLS_PATH}/scetool/scetool.exe SCETOOL_FLAGS_CORE="--sce-type=SELF --compress-data=TRUE --skip-sections=TRUE --key-revision=04 --self-auth-id=1010000001000003 --self-vendor-id=01000002 --self-type=APP --self-app-version=0001000000000000 --self-fw-version=0003004100000000 --encrypt" SCETOOL_FLAGS_EBOOT="--sce-type=SELF --compress-data=TRUE --skip-sections=TRUE --key-revision=04 --self-auth-id=1010000001000003 --self-vendor-id=01000002 --self-type=NPDRM --self-fw-version=0003004100000000 --np-license-type=FREE --np-content-id=UP0001-SSNE10000_00-0000000000000001 --np-app-type=EXEC --self-app-version=0001000000000000 --np-real-fname=EBOOT.BIN --encrypt" +cp -rfv ${PS3TOOLS_PATH}/scetool/data . + # ODE PS3 elif [ $PLATFORM = "ode-ps3" ]; then #For this script to work correctly, you must place scetool.exe and the "data" folder containing your ps3 keys for scetool to use in the dist-scripts folder. @@ -418,6 +420,8 @@ if [ $PLATFORM = "dex-ps3" ] ; then elif [ $PLATFORM = "cex-ps3" ] ; then $SCETOOL_PATH $SCETOOL_FLAGS_EBOOT ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN rm -rf ../retroarch-salamander_${platform}.elf + (cd ../tools/ps3/ps3py && python2 setup.py build) + find ../tools/ps3/ps3py/build -name '*.dll' -exec cp {} ../tools/ps3/ps3py \; ../tools/ps3/ps3py/pkg.py --contentid UP0001-SSNE10000_00-0000000000000001 ../pkg/${platform}/SSNE10000/ ../pkg/${platform}/RetroArch.PS3.CEX.PS3.pkg elif [ $PLATFORM = "ode-ps3" ] ; then $SCETOOL_PATH $SCETOOL_FLAGS_ODE ../retroarch-salamander_${platform}.elf ../pkg/${platform}_iso/PS3_GAME/USRDIR/EBOOT.BIN diff --git a/dynamic.c b/dynamic.c index 6e07579230..873ca7316b 100644 --- a/dynamic.c +++ b/dynamic.c @@ -92,8 +92,9 @@ static dylib_t lib_handle; #define SYMBOL_VIDEOPROCESSOR(x) current_core->x = libretro_videoprocessor_##x #endif -static bool ignore_environment_cb = false; -static bool *load_no_content_hook = NULL; +static bool ignore_environment_cb = false; +static bool core_set_shared_context = false; +static bool *load_no_content_hook = NULL; const struct retro_subsystem_info *libretro_find_subsystem_info( const struct retro_subsystem_info *info, unsigned num_info, @@ -632,6 +633,11 @@ bool init_libretro_sym(enum rarch_core_type type, struct retro_core_t *current_c return true; } +bool libretro_get_shared_context(void) +{ + return core_set_shared_context; +} + /** * uninit_libretro_sym: * @@ -651,6 +657,8 @@ void uninit_libretro_sym(struct retro_core_t *current_core) memset(current_core, 0, sizeof(struct retro_core_t)); + core_set_shared_context = false; + rarch_ctl(RARCH_CTL_CORE_OPTIONS_DEINIT, NULL); rarch_ctl(RARCH_CTL_SYSTEM_INFO_FREE, NULL); rarch_ctl(RARCH_CTL_FRAME_TIME_FREE, NULL); @@ -1016,7 +1024,7 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: - if (string_is_empty(settings->paths.directory_system)) + if (string_is_empty(settings->paths.directory_system) || settings->bools.systemfiles_in_content_dir) { const char *fullpath = path_get(RARCH_PATH_CONTENT); if (!string_is_empty(fullpath)) @@ -1025,8 +1033,9 @@ bool rarch_environment_cb(unsigned cmd, void *data) temp_path[0] = '\0'; - RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", - fullpath); + if (string_is_empty(settings->paths.directory_system)) + RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", + fullpath); fill_pathname_basedir(temp_path, fullpath, sizeof(temp_path)); dir_set(RARCH_DIR_SYSTEM, temp_path); } @@ -1633,6 +1642,12 @@ bool rarch_environment_cb(unsigned cmd, void *data) break; } + case RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT: + { + core_set_shared_context = true; + break; + } + /* Default */ default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); diff --git a/dynamic.h b/dynamic.h index 6999486be8..d2b529520b 100644 --- a/dynamic.h +++ b/dynamic.h @@ -117,6 +117,8 @@ struct retro_core_t uint64_t serialization_quirks_v; }; +bool libretro_get_shared_context(void); + /** * init_libretro_sym: * @type : Type of core to be loaded. diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index b53cf33e35..eddd9a99eb 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -1557,18 +1557,6 @@ static void frontend_unix_get_env(int *argc, fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS], app_dir, "assets/wallpapers", sizeof(g_defaults.dirs[DEFAULT_DIR_WALLPAPERS])); - if(!string_is_empty(downloads_dir) && test_permissions(downloads_dir)) - { - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], - downloads_dir, "", - sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); - } - else - { - fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], - app_dir, "downloads", - sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); - } __android_log_print(ANDROID_LOG_INFO, "RetroArch", "[ENV]: default download folder: [%s]", @@ -1576,8 +1564,7 @@ static void frontend_unix_get_env(int *argc, switch (perms) { - /* Set defaults for this since we can't guarantee - * saving on content dir will work in this case */ + /* only sdcard/Android/data/com.retroarch is writable */ case INTERNAL_STORAGE_APPDIR_WRITABLE: fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], internal_storage_app_path, "saves", @@ -1605,11 +1592,11 @@ static void frontend_unix_get_env(int *argc, internal_storage_app_path, "cheats", sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS])); - if( !string_is_empty(screenshot_dir) - && test_permissions(screenshot_dir)) + if(!string_is_empty(screenshot_dir) + && test_permissions(screenshot_dir)) { fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], - screenshot_dir, "", + screenshot_dir, "RetroArch", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } else @@ -1619,10 +1606,24 @@ static void frontend_unix_get_env(int *argc, sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } + if(!string_is_empty(downloads_dir) + && test_permissions(downloads_dir)) + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + downloads_dir, "RetroArch", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + else + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + internal_storage_app_path, "downloads", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + break; + + /* only the internal app dir is writable, this should never happen*/ case INTERNAL_STORAGE_NOT_WRITABLE: - /* Set defaults for this since we can't guarantee - * saving on content dir will work in this case. */ fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], app_dir, "saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); @@ -1653,7 +1654,7 @@ static void frontend_unix_get_env(int *argc, && test_permissions(screenshot_dir)) { fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], - screenshot_dir, "", + screenshot_dir, "RetroArch", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } else @@ -1663,10 +1664,40 @@ static void frontend_unix_get_env(int *argc, sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); } + if(!string_is_empty(downloads_dir) + && test_permissions(downloads_dir)) + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + downloads_dir, "RetroArch", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + else + { + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + app_dir, "downloads", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + } + break; + /* sdcard is writable, this should be the case most of the time*/ case INTERNAL_STORAGE_WRITABLE: - /* Don't set defaults for saves, states, system or screenshots - in this case to be able to honour saving on content dir */ + + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], + internal_storage_path, "RetroArch/saves", + sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], + internal_storage_path, "RetroArch/states", + sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + internal_storage_path, "RetroArch/system", + sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], + internal_storage_path, "RetroArch/screenshots", + sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + internal_storage_path, "RetroArch/downloads", + sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], internal_storage_path, "RetroArch/config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); diff --git a/frontend/drivers/platform_win32.c b/frontend/drivers/platform_win32.c index 5133f0c27e..2aa65eb10b 100644 --- a/frontend/drivers/platform_win32.c +++ b/frontend/drivers/platform_win32.c @@ -46,6 +46,9 @@ */ static dylib_t dwmlib; +static dylib_t shell32lib; + +VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); static bool dwm_composition_disabled; @@ -55,7 +58,10 @@ static void gfx_dwm_shutdown(void) { if (dwmlib) dylib_close(dwmlib); - dwmlib = NULL; + if (shell32lib) + dylib_close(shell32lib); + dwmlib = NULL; + shell32lib = NULL; } static bool gfx_init_dwm(void) @@ -65,13 +71,23 @@ static bool gfx_init_dwm(void) if (inited) return true; + atexit(gfx_dwm_shutdown); + + shell32lib = dylib_load("shell32.dll"); + if (!shell32lib) + { + RARCH_WARN("Did not find shell32.dll.\n"); + } + dwmlib = dylib_load("dwmapi.dll"); if (!dwmlib) { - RARCH_LOG("Did not find dwmapi.dll.\n"); + RARCH_WARN("Did not find dwmapi.dll.\n"); return false; } - atexit(gfx_dwm_shutdown); + + DragAcceptFiles_func = + (VOID (WINAPI*)(HWND, BOOL))dylib_proc(shell32lib, "DragAcceptFiles"); HRESULT (WINAPI *mmcss)(BOOL) = (HRESULT (WINAPI*)(BOOL))dylib_proc(dwmlib, "DwmEnableMMCSS"); @@ -278,9 +294,9 @@ static void frontend_win32_environment_get(int *argc, char *argv[], fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], ":\\playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG], - ":\\records_config", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG])); + ":\\config\\record", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_CONFIG])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT], - ":\\records", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT])); + ":\\recordings", sizeof(g_defaults.dirs[DEFAULT_DIR_RECORD_OUTPUT])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], ":\\config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_REMAP], @@ -303,6 +319,12 @@ static void frontend_win32_environment_get(int *argc, char *argv[], ":\\downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], ":\\screenshots", sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SRAM], + ":\\saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], + ":\\states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); + fill_pathname_expand_special(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + ":\\system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); #ifdef HAVE_MENU #if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.c similarity index 83% rename from gfx/common/win32_common.cpp rename to gfx/common/win32_common.c index 3801f92700..cfeb717de2 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.c @@ -50,20 +50,12 @@ #include "../../menu/menu_driver.h" #endif -#ifndef _MSC_VER -extern "C" { -#endif - #include -LRESULT win32_menu_loop(HWND owner, WPARAM wparam); - -#ifndef _MSC_VER -} -#endif +extern LRESULT win32_menu_loop(HWND owner, WPARAM wparam); #ifdef HAVE_D3D9 -extern "C" bool dinput_handle_message(void *dinput, UINT message, +extern bool dinput_handle_message(void *dinput, UINT message, WPARAM wParam, LPARAM lParam); extern void *dinput_gdi; extern void *dinput_wgl; @@ -128,18 +120,15 @@ static HMONITOR win32_monitor_last; static HMONITOR win32_monitor_all[MAX_MONITORS]; static unsigned win32_monitor_count = 0; -extern "C" +bool doubleclick_on_titlebar_pressed(void) { - bool doubleclick_on_titlebar_pressed(void) - { - return doubleclick_on_titlebar; - } + return doubleclick_on_titlebar; +} - void unset_doubleclick_on_titlebar(void) - { - doubleclick_on_titlebar = false; - } -}; +void unset_doubleclick_on_titlebar(void) +{ + doubleclick_on_titlebar = false; +} INT_PTR CALLBACK PickCoreProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) @@ -184,10 +173,12 @@ INT_PTR CALLBACK PickCoreProc(HWND hDlg, UINT message, { case LBN_SELCHANGE: { - int lbItem; const core_info_t *info = NULL; - HWND hwndList = GetDlgItem(hDlg, ID_CORELISTBOX); - lbItem = (int)SendMessage(hwndList, LB_GETCURSEL, 0, 0); + HWND hwndList = GetDlgItem( + hDlg, ID_CORELISTBOX); + int lbItem = (int) + SendMessage(hwndList, LB_GETCURSEL, 0, 0); + core_info_get_list(&core_info_list); core_info_list_get_supported_cores(core_info_list, path_get(RARCH_PATH_CONTENT), &core_info, &list_size); @@ -214,7 +205,8 @@ static BOOL CALLBACK win32_monitor_enum_proc(HMONITOR hMonitor, void win32_monitor_from_window(void) { #ifndef _XBOX - win32_monitor_last = MonitorFromWindow(main_window.hwnd, MONITOR_DEFAULTTONEAREST); + win32_monitor_last = + MonitorFromWindow(main_window.hwnd, MONITOR_DEFAULTTONEAREST); const ui_window_t *window = ui_companion_driver_get_window_ptr(); if (window) @@ -229,23 +221,23 @@ void win32_monitor_get_info(void) memset(¤t_mon, 0, sizeof(current_mon)); current_mon.cbSize = sizeof(MONITORINFOEX); - GetMonitorInfo(win32_monitor_last, (MONITORINFOEX*)¤t_mon); + GetMonitorInfo(win32_monitor_last, (LPMONITORINFO)¤t_mon); ChangeDisplaySettingsEx(current_mon.szDevice, NULL, NULL, 0, NULL); } void win32_monitor_info(void *data, void *hm_data, unsigned *mon_id) { unsigned i; - settings_t *settings = config_get_ptr(); - MONITORINFOEX *mon = (MONITORINFOEX*)data; - HMONITOR *hm_to_use = (HMONITOR*)hm_data; - unsigned fs_monitor = settings->uints.video_monitor_index; + settings_t *settings = config_get_ptr(); + MONITORINFOEX *mon = (MONITORINFOEX*)data; + HMONITOR *hm_to_use = (HMONITOR*)hm_data; + unsigned fs_monitor = settings->uints.video_monitor_index; if (!win32_monitor_last) win32_monitor_last = MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST); - *hm_to_use = win32_monitor_last; + *hm_to_use = win32_monitor_last; if (fs_monitor && fs_monitor <= win32_monitor_count && win32_monitor_all[fs_monitor - 1]) @@ -267,7 +259,7 @@ void win32_monitor_info(void *data, void *hm_data, unsigned *mon_id) memset(mon, 0, sizeof(*mon)); mon->cbSize = sizeof(MONITORINFOEX); - GetMonitorInfo(*hm_to_use, (MONITORINFOEX*)mon); + GetMonitorInfo(*hm_to_use, (LPMONITORINFO)mon); } /* Get the count of the files dropped */ @@ -480,14 +472,14 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, { g_resize_width = LOWORD(lparam); g_resize_height = HIWORD(lparam); - g_resized = true; + g_resized = true; } *quit = true; break; case WM_COMMAND: { settings_t *settings = config_get_ptr(); - if (settings->bools.ui_menubar_enable) + if (settings && settings->bools.ui_menubar_enable) win32_menu_loop(main_window.hwnd, wparam); } break; @@ -495,7 +487,13 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, return 0; } -extern void ui_window_win32_set_droppable(void *data, bool droppable); +extern VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); + +static void win32_set_droppable(ui_window_win32_t *window, bool droppable) +{ + if (DragAcceptFiles_func != NULL) + DragAcceptFiles_func(window->hwnd, droppable); +} #ifdef HAVE_D3D9 LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message, @@ -533,12 +531,13 @@ LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message, win32_window.hwnd = hwnd; - ui_window_win32_set_droppable(&win32_window, true); + win32_set_droppable(&win32_window, true); } return 0; } - if (dinput && dinput_handle_message(dinput, message, wparam, lparam)) + if (dinput && dinput_handle_message(dinput, + message, wparam, lparam)) return 0; return DefWindowProc(hwnd, message, wparam, lparam); } @@ -568,7 +567,8 @@ LRESULT CALLBACK WndProcGL(HWND hwnd, UINT message, case WM_QUIT: case WM_SIZE: case WM_COMMAND: - ret = WndProcCommon(&quit, hwnd, message, wparam, lparam); + ret = WndProcCommon(&quit, + hwnd, message, wparam, lparam); if (quit) return ret; break; @@ -579,13 +579,14 @@ LRESULT CALLBACK WndProcGL(HWND hwnd, UINT message, create_graphics_context(hwnd, &g_quit); - ui_window_win32_set_droppable(&win32_window, true); + win32_set_droppable(&win32_window, true); } return 0; } #ifdef HAVE_D3D9 - if (dinput_wgl && dinput_handle_message(dinput_wgl, message, wparam, lparam)) + if (dinput_wgl && dinput_handle_message(dinput_wgl, + message, wparam, lparam)) return 0; #endif return DefWindowProc(hwnd, message, wparam, lparam); @@ -664,13 +665,14 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, create_gdi_context(hwnd, &g_quit); - ui_window_win32_set_droppable(&win32_window, true); + win32_set_droppable(&win32_window, true); } return 0; } #ifdef HAVE_D3D9 - if (dinput_gdi && dinput_handle_message(dinput_gdi, message, wparam, lparam)) + if (dinput_gdi && dinput_handle_message(dinput_gdi, + message, wparam, lparam)) return 0; #endif return DefWindowProc(hwnd, message, wparam, lparam); @@ -681,7 +683,8 @@ bool win32_window_create(void *data, unsigned style, unsigned height, bool fullscreen) { #ifndef _XBOX - main_window.hwnd = CreateWindowEx(0, "RetroArch", "RetroArch", + main_window.hwnd = CreateWindowEx(0, + "RetroArch", "RetroArch", style, fullscreen ? mon_rect->left : g_pos_x, fullscreen ? mon_rect->top : g_pos_y, @@ -738,13 +741,15 @@ void win32_monitor_init(void) { #ifndef _XBOX win32_monitor_count = 0; - EnumDisplayMonitors(NULL, NULL, win32_monitor_enum_proc, 0); + EnumDisplayMonitors(NULL, NULL, + win32_monitor_enum_proc, 0); #endif g_quit = false; } -static bool win32_monitor_set_fullscreen(unsigned width, unsigned height, +static bool win32_monitor_set_fullscreen( + unsigned width, unsigned height, unsigned refresh, char *dev_name) { #ifndef _XBOX @@ -755,7 +760,8 @@ static bool win32_monitor_set_fullscreen(unsigned width, unsigned height, devmode.dmPelsWidth = width; devmode.dmPelsHeight = height; devmode.dmDisplayFrequency = refresh; - devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + devmode.dmFields = DM_PELSWIDTH + | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; RARCH_LOG("Setting fullscreen to %ux%u @ %uHz on device %s.\n", width, height, refresh, dev_name); @@ -797,10 +803,7 @@ void win32_check_window(bool *quit, bool *resize, bool win32_suppress_screensaver(void *data, bool enable) { -#ifdef _XBOX - return false; -#else - +#ifndef _XBOX if(enable) { int major, minor; @@ -849,9 +852,9 @@ bool win32_suppress_screensaver(void *data, bool enable) return true; } } +#endif return false; -#endif } /* FIXME: It should not be necessary to add the W after MONITORINFOEX, but linking fails without it. */ @@ -887,7 +890,7 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, {} /* Display settings might have changed, get new coordinates. */ - GetMonitorInfo(*hm_to_use, (MONITORINFOEX*)current_mon); + GetMonitorInfo(*hm_to_use, (LPMONITORINFO)current_mon); *mon_rect = current_mon->rcMonitor; } } @@ -949,10 +952,10 @@ bool win32_set_video_mode(void *data, DWORD style; MSG msg; RECT mon_rect; - unsigned mon_id; - MONITORINFOEX current_mon; - bool windowed_full; RECT rect; + MONITORINFOEX current_mon; + unsigned mon_id = 0; + bool windowed_full = false; HMONITOR hm_to_use = NULL; settings_t *settings = config_get_ptr(); int res = 0; @@ -964,23 +967,26 @@ bool win32_set_video_mode(void *data, win32_monitor_info(¤t_mon, &hm_to_use, &mon_id); - mon_rect = current_mon.rcMonitor; - g_resize_width = width; - g_resize_height = height; + mon_rect = current_mon.rcMonitor; + g_resize_width = width; + g_resize_height = height; - windowed_full = settings->bools.video_windowed_fullscreen; + windowed_full = settings->bools.video_windowed_fullscreen; win32_set_style(¤t_mon, &hm_to_use, &width, &height, fullscreen, windowed_full, &rect, &mon_rect, &style); - if (!win32_window_create(data, style, &mon_rect, width, height, fullscreen)) + if (!win32_window_create(data, style, + &mon_rect, width, height, fullscreen)) return false; - win32_set_window(&width, &height, fullscreen, windowed_full, &rect); + win32_set_window(&width, &height, + fullscreen, windowed_full, &rect); /* Wait until context is created (or failed to do so ...). * Please don't remove the (res = ) as GetMessage can return -1. */ - while (!g_inited && !g_quit && (res = GetMessage(&msg, main_window.hwnd, 0, 0)) != 0) + while (!g_inited && !g_quit + && (res = GetMessage(&msg, main_window.hwnd, 0, 0)) != 0) { if (res == -1) { @@ -1020,19 +1026,20 @@ BOOL IsIconic(HWND hwnd) bool win32_has_focus(void) { -#ifndef _XBOX - const ui_window_t *window = ui_companion_driver_get_window_ptr(); -#endif - if (!g_inited) - return false; - + if (g_inited) + { #ifdef _XBOX - return GetForegroundWindow() == main_window.hwnd; + if (GetForegroundWindow() == main_window.hwnd) + return true; #else - if (window) - return window->focused(&main_window); - return false; + const ui_window_t *window = + ui_companion_driver_get_window_ptr(); + if (window) + return window->focused(&main_window); #endif + } + + return false; } HWND win32_get_window(void) @@ -1053,3 +1060,90 @@ void win32_destroy_window(void) #endif main_window.hwnd = NULL; } + +void win32_get_video_output_prev( + unsigned *width, unsigned *height) +{ + DEVMODE dm; + int iModeNum; + bool found = false; + unsigned prev_width = 0; + unsigned prev_height = 0; + unsigned curr_width = 0; + unsigned curr_height = 0; + + memset(&dm, 0, sizeof(dm)); + + dm.dmSize = sizeof(dm); + + win32_get_video_output_size(&curr_width, &curr_height); + + for (iModeNum = 0; + EnumDisplaySettings(NULL, iModeNum, &dm) != 0; + iModeNum++) + { + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) + { + if ( prev_width != curr_width + && prev_height != curr_height) + { + found = true; + break; + } + } + + prev_width = dm.dmPelsWidth; + prev_height = dm.dmPelsHeight; + } + + if (found) + { + *width = prev_width; + *height = prev_height; + } +} + +void win32_get_video_output_next( + unsigned *width, unsigned *height) +{ + DEVMODE dm; + int iModeNum; + bool found = false; + unsigned curr_width = 0; + unsigned curr_height = 0; + + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + + win32_get_video_output_size(&curr_width, &curr_height); + + for (iModeNum = 0; + EnumDisplaySettings(NULL, iModeNum, &dm) != 0; + iModeNum++) + { + if (found) + { + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + break; + } + + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) + found = true; + } +} + +void win32_get_video_output_size(unsigned *width, unsigned *height) +{ + DEVMODE dm; + memset(&dm, 0, sizeof(dm)); + dm.dmSize = sizeof(dm); + + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) + { + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + } +} diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index a5c8b1f722..975eb5caf8 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -31,12 +31,16 @@ #ifdef _XBOX #include "../../defines/xdk_defines.h" +#else +#include "../../ui/drivers/ui_win32_resource.h" +#include "../../ui/drivers/ui_win32.h" +#endif + +#ifdef __cplusplus +extern "C" { #endif #ifndef _XBOX -#include "../../ui/drivers/ui_win32_resource.h" -#include "../../ui/drivers/ui_win32.h" - extern unsigned g_resize_width; extern unsigned g_resize_height; extern bool g_inited; @@ -51,13 +55,7 @@ void create_graphics_context(HWND hwnd, bool *quit); void create_gdi_context(HWND hwnd, bool *quit); -#ifdef __cplusplus -extern "C" { -#endif bool gdi_has_menu_frame(void); -#ifdef __cplusplus -} -#endif bool win32_shader_dlg_init(void); void shader_dlg_show(HWND parent_hwnd); @@ -91,13 +89,7 @@ bool win32_get_metrics(void *data, void win32_show_cursor(bool state); -#ifdef __cplusplus -extern "C" { -#endif HWND win32_get_window(void); -#ifdef __cplusplus -} -#endif bool win32_has_focus(void); @@ -113,6 +105,15 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, RECT *rect, RECT *mon_rect, DWORD *style); #endif +void win32_get_video_output_size( + unsigned *width, unsigned *height); + +void win32_get_video_output_prev( + unsigned *width, unsigned *height); + +void win32_get_video_output_next( + unsigned *width, unsigned *height); + void win32_window_reset(void); void win32_destroy_window(void); @@ -134,4 +135,8 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, BOOL IsIconic(HWND hwnd); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/gfx/drivers/caca_gfx.c b/gfx/drivers/caca_gfx.c index fd5e86ad8e..c558602666 100644 --- a/gfx/drivers/caca_gfx.c +++ b/gfx/drivers/caca_gfx.c @@ -94,7 +94,7 @@ static void *caca_gfx_init(const video_info_t *video, } if (video->font_enable) - font_driver_init_osd(NULL, false, video->is_threaded, + font_driver_init_osd(caca, false, video->is_threaded, FONT_DRIVER_RENDER_CACA); return caca; diff --git a/gfx/drivers/gdi_gfx.c b/gfx/drivers/gdi_gfx.c index c65b9f752c..99f3118580 100644 --- a/gfx/drivers/gdi_gfx.c +++ b/gfx/drivers/gdi_gfx.c @@ -140,7 +140,7 @@ static void *gdi_gfx_init(const video_info_t *video, video_context_driver_input_driver(&inp); if (settings->bools.video_font_enable) - font_driver_init_osd(NULL, false, + font_driver_init_osd(gdi, false, video->is_threaded, FONT_DRIVER_RENDER_GDI); diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index ed694fd727..391836a9bc 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -43,6 +43,7 @@ #include "../drivers_renderchain/gl_legacy_renderchain.h" #include "../../configuration.h" +#include "../../dynamic.h" #include "../../record/record_driver.h" #include "../../retroarch.h" @@ -1658,6 +1659,9 @@ static const gfx_ctx_driver_t *gl_get_context(gl_t *gl) gl_shared_context_use = settings->bools.video_shared_context && hwr->context_type != RETRO_HW_CONTEXT_NONE; + if (libretro_get_shared_context() && (hwr->context_type != RETRO_HW_CONTEXT_NONE)) + gl_shared_context_use = true; + return video_context_driver_init_first(gl, settings->arrays.video_context_driver, api, major, minor, gl_shared_context_use); } diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index f7f6cfeef8..3f36723efd 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -42,6 +42,37 @@ #include "../../configuration.h" #include "../../driver.h" +#ifndef _CPU_ISR_Disable +#define _CPU_ISR_Disable( _isr_cookie ) \ + { register u32 _disable_mask = 0; \ + _isr_cookie = 0; \ + __asm__ __volatile__ ( \ + "mfmsr %0\n" \ + "rlwinm %1,%0,0,17,15\n" \ + "mtmsr %1\n" \ + "extrwi %0,%0,1,16" \ + : "=&r" ((_isr_cookie)), "=&r" ((_disable_mask)) \ + : "0" ((_isr_cookie)), "1" ((_disable_mask)) \ + ); \ + } +#endif + +#ifndef _CPU_ISR_Restore +#define _CPU_ISR_Restore( _isr_cookie ) \ + { register u32 _enable_mask = 0; \ + __asm__ __volatile__ ( \ + " cmpwi %0,0\n" \ + " beq 1f\n" \ + " mfmsr %1\n" \ + " ori %1,%1,0x8000\n" \ + " mtmsr %1\n" \ + "1:" \ + : "=r"((_isr_cookie)),"=&r" ((_enable_mask)) \ + : "0"((_isr_cookie)),"1" ((_enable_mask)) \ + ); \ + } +#endif + extern syssram* __SYS_LockSram(void); extern u32 __SYS_UnlockSram(u32 write); @@ -92,6 +123,9 @@ static volatile bool g_draw_done = false; static bool g_vsync = false; static uint32_t g_orientation = 0; +static uint32_t retraceCount; +static uint32_t referenceRetraceCount; + static uint8_t gx_fifo[256 * 1024] ATTRIBUTE_ALIGN(32); static uint8_t display_list[1024] ATTRIBUTE_ALIGN(32); static size_t display_list_size; @@ -213,9 +247,15 @@ unsigned menu_gx_resolutions[][2] = { static void retrace_callback(u32 retrace_count) { + u32 level = 0; + (void)retrace_count; + g_draw_done = true; OSSignalCond(g_video_cond); + _CPU_ISR_Disable(level); + retraceCount = retrace_count; + _CPU_ISR_Restore(level); } static bool gx_isValidXOrigin(int origin) @@ -249,7 +289,7 @@ static void gx_set_video_mode(void *data, unsigned fbWidth, unsigned lines, VIDEO_SetPostRetraceCallback(NULL); g_draw_done = false; /* wait for next even field */ - /* this prevents screen artefacts when switching + /* this prevents screen artifacts when switching * between interlaced & non-interlaced modes */ do VIDEO_WaitVSync(); while (!VIDEO_GetNextField()); @@ -293,13 +333,13 @@ static void gx_set_video_mode(void *data, unsigned fbWidth, unsigned lines, max_height = VI_MAX_HEIGHT_MPAL; break; case VI_EURGB60: - max_width = VI_MAX_WIDTH_NTSC; - max_height = VI_MAX_HEIGHT_NTSC; + max_width = VI_MAX_WIDTH_EURGB60; + max_height = VI_MAX_HEIGHT_EURGB60; break; default: tvmode = VI_NTSC; - max_width = VI_MAX_WIDTH_EURGB60; - max_height = VI_MAX_HEIGHT_EURGB60; + max_width = VI_MAX_WIDTH_NTSC; + max_height = VI_MAX_HEIGHT_NTSC; break; } @@ -575,6 +615,10 @@ static void init_vtx(void *data, const video_info_t *video) { Mtx44 m; gx_video_t *gx = (gx_video_t*)data; + u32 level = 0; + _CPU_ISR_Disable(level); + referenceRetraceCount = retraceCount; + _CPU_ISR_Restore(level); GX_SetCullMode(GX_CULL_NONE); GX_SetClipMode(GX_CLIP_DISABLE); @@ -1440,6 +1484,7 @@ static bool gx_frame(void *data, const void *frame, char fps_text_buf[128]; gx_video_t *gx = (gx_video_t*)data; u8 clear_efb = GX_FALSE; + u32 level = 0; fps_text_buf[0] = '\0'; @@ -1524,6 +1569,12 @@ static bool gx_frame(void *data, const void *frame, gx_render_overlay(gx); #endif + _CPU_ISR_Disable(level); + if (referenceRetraceCount > retraceCount) + VIDEO_WaitVSync(); + referenceRetraceCount = retraceCount; + _CPU_ISR_Restore(level); + GX_DrawDone(); if (video_info->fps_show) @@ -1564,6 +1615,10 @@ static bool gx_frame(void *data, const void *frame, VIDEO_SetNextFramebuffer(gx->framebuf[g_current_framebuf]); VIDEO_Flush(); + _CPU_ISR_Disable(level); + ++referenceRetraceCount; + _CPU_ISR_Restore(level); + return true; } diff --git a/gfx/drivers_context/gdi_ctx.cpp b/gfx/drivers_context/gdi_ctx.c similarity index 98% rename from gfx/drivers_context/gdi_ctx.cpp rename to gfx/drivers_context/gdi_ctx.c index f4f1a9c265..3773a6d1c8 100644 --- a/gfx/drivers_context/gdi_ctx.cpp +++ b/gfx/drivers_context/gdi_ctx.c @@ -126,7 +126,8 @@ static void gfx_ctx_gdi_get_video_size(void *data, } } -static void *gfx_ctx_gdi_init(video_frame_info_t *video_info, void *video_driver) +static void *gfx_ctx_gdi_init( + video_frame_info_t *video_info, void *video_driver) { WNDCLASSEX wndclass = {0}; diff --git a/gfx/drivers_context/wgl_ctx.cpp b/gfx/drivers_context/wgl_ctx.c similarity index 96% rename from gfx/drivers_context/wgl_ctx.cpp rename to gfx/drivers_context/wgl_ctx.c index 9e6ebef484..5e19fbfa67 100644 --- a/gfx/drivers_context/wgl_ctx.cpp +++ b/gfx/drivers_context/wgl_ctx.c @@ -23,7 +23,10 @@ #define _WIN32_WINNT 0x0500 //_WIN32_WINNT_WIN2K #endif +#if !defined(_MSC_VER) || _MSC_VER > 1400 #define UNICODE +#endif + #include #include @@ -270,14 +273,21 @@ void create_graphics_context(HWND hwnd, bool *quit) { #ifdef HAVE_VULKAN RECT rect; - unsigned width = rect.right - rect.left; - unsigned height = rect.bottom - rect.top; + HINSTANCE instance; + unsigned width = 0; + unsigned height = 0; + GetClientRect(hwnd, &rect); - HINSTANCE instance = GetModuleHandle(NULL); + + instance = GetModuleHandle(NULL); + width = rect.right - rect.left; + height = rect.bottom - rect.top; + if (!vulkan_surface_create(&win32_vk, VULKAN_WSI_WIN32, &instance, &hwnd, width, height, win32_interval)) *quit = true; + g_inited = true; #endif } @@ -702,6 +712,20 @@ static void gfx_ctx_wgl_set_flags(void *data, uint32_t flags) win32_core_hw_context_enable = true; } +static void gfx_ctx_wgl_get_video_output_size(void *data, + unsigned *width, unsigned *height) +{ + win32_get_video_output_size(width, height); +} + +static void gfx_ctx_wgl_get_video_output_prev(void *data) +{ +} + +static void gfx_ctx_wgl_get_video_output_next(void *data) +{ +} + const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_wgl_init, gfx_ctx_wgl_destroy, @@ -709,9 +733,9 @@ const gfx_ctx_driver_t gfx_ctx_wgl = { gfx_ctx_wgl_swap_interval, gfx_ctx_wgl_set_video_mode, gfx_ctx_wgl_get_video_size, - NULL, /* get_video_output_size */ - NULL, /* get_video_output_prev */ - NULL, /* get_video_output_next */ + gfx_ctx_wgl_get_video_output_size, + gfx_ctx_wgl_get_video_output_prev, + gfx_ctx_wgl_get_video_output_next, gfx_ctx_wgl_get_metrics, NULL, gfx_ctx_wgl_update_title, diff --git a/gfx/drivers_font/caca_font.c b/gfx/drivers_font/caca_font.c index dfe0f9c91f..af2e17cf29 100644 --- a/gfx/drivers_font/caca_font.c +++ b/gfx/drivers_font/caca_font.c @@ -45,8 +45,6 @@ static void *caca_init_font(void *data, font->caca = (caca_t*)data; - font_size = 1; - if (!font_renderer_create_default((const void**)&font->caca_font_driver, &font->caca_font_data, font_path, font_size)) { diff --git a/gfx/drivers_font/d3d_w32_font.cpp b/gfx/drivers_font/d3d_w32_font.cpp index 1eff6798c0..6347bb5bf2 100644 --- a/gfx/drivers_font/d3d_w32_font.cpp +++ b/gfx/drivers_font/d3d_w32_font.cpp @@ -27,6 +27,8 @@ #include "../include/d3d9/d3dx9core.h" #endif +#include + typedef struct { d3d_video_t *d3d; @@ -47,11 +49,7 @@ static void *d3dfonts_w32_init_font(void *video_data, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_PITCH, -#if defined(_MSC_VER) /* MSVC needs w_char* */ - L"Verdana" /* Hardcode FTL */ -#else - "Verdana" -#endif + _T("Verdana") /* Hardcode FTL */ }; d3dfonts = (d3dfonts_t*)calloc(1, sizeof(*d3dfonts)); diff --git a/gfx/drivers_font/gdi_font.c b/gfx/drivers_font/gdi_font.c index 9e43be5072..578b7705c2 100644 --- a/gfx/drivers_font/gdi_font.c +++ b/gfx/drivers_font/gdi_font.c @@ -51,8 +51,6 @@ static void *gdi_init_font(void *data, font->gdi = (gdi_t*)data; - font_size = 1; - if (!font_renderer_create_default((const void**)&font->gdi_font_driver, &font->gdi_font_data, font_path, font_size)) { diff --git a/gfx/drivers_shader/shader_glsl.c b/gfx/drivers_shader/shader_glsl.c index 48b082823f..40f5ed78ce 100644 --- a/gfx/drivers_shader/shader_glsl.c +++ b/gfx/drivers_shader/shader_glsl.c @@ -162,7 +162,7 @@ static GLint gl_glsl_get_uniform(glsl_shader_data_t *glsl, { unsigned i; GLint loc; - char buf[64]; + char buf[80]; buf[0] = '\0'; @@ -187,7 +187,7 @@ static GLint gl_glsl_get_attrib(glsl_shader_data_t *glsl, { unsigned i; GLint loc; - char buf[64]; + char buf[80]; buf[0] = '\0'; diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 277a1b2c22..1d3ed375e4 100644 --- a/gfx/font_driver.c +++ b/gfx/font_driver.c @@ -34,7 +34,7 @@ static const font_renderer_driver_t *font_backends[] = { &coretext_font_renderer, #endif #ifdef HAVE_STB_FONT -#if defined(VITA) || defined(WIIU) || defined(ANDROID) || defined(_WIN32) && !defined(_XBOX) +#if defined(VITA) || defined(WIIU) || defined(ANDROID) || defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) || defined(_WIN32) && !defined(_XBOX) && defined(_MSC_VER) && _MSC_VER > 1400 &stb_unicode_font_renderer, #else &stb_font_renderer, diff --git a/gfx/video_driver.c b/gfx/video_driver.c index d420786bb7..02125f91e1 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -35,6 +35,8 @@ #include "../config.h" #endif +#include "../dynamic.h" + #ifdef HAVE_THREADS #include #endif @@ -1429,6 +1431,7 @@ void video_driver_menu_settings(void **list_data, void *list_info_data, void *group_data, void *subgroup_data, const char *parent_group) { #ifdef HAVE_MENU + bool has_video_output = false; rarch_setting_t **list = (rarch_setting_t**)list_data; rarch_setting_info_t *list_info = (rarch_setting_info_t*)list_info_data; rarch_setting_group_info_t *group_info = (rarch_setting_group_info_t*)group_data; @@ -1441,15 +1444,26 @@ void video_driver_menu_settings(void **list_data, void *list_info_data, (void)subgroup_info; (void)global; -#if defined(GEKKO) || defined(__CELLOS_LV2__) - CONFIG_ACTION( - list, list_info, - MENU_ENUM_LABEL_SCREEN_RESOLUTION, - MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - group_info, - subgroup_info, - parent_group); -#endif + has_video_output = video_driver_poke->get_video_output_next || + current_video_context.get_video_output_next; + if (has_video_output) + has_video_output = video_driver_poke->get_video_output_prev || + current_video_context.get_video_output_prev; + if (has_video_output) + has_video_output = video_driver_poke->get_video_output_size || + current_video_context.get_video_output_size; + + if (has_video_output) + { + CONFIG_ACTION( + list, list_info, + MENU_ENUM_LABEL_SCREEN_RESOLUTION, + MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, + group_info, + subgroup_info, + parent_group); + } + #if defined(__CELLOS_LV2__) CONFIG_BOOL( list, list_info, @@ -2463,6 +2477,8 @@ void video_driver_build_info(video_frame_info_t *video_info) bool is_slowmotion = false; settings_t *settings = NULL; video_viewport_t *custom_vp = NULL; + struct retro_hw_render_callback *hwr = + video_driver_get_hw_context(); #ifdef HAVE_THREADS bool is_threaded = video_driver_is_threaded(); video_driver_threaded_lock(is_threaded); @@ -2483,6 +2499,10 @@ void video_driver_build_info(video_frame_info_t *video_info) video_info->fullscreen = settings->bools.video_fullscreen; video_info->monitor_index = settings->uints.video_monitor_index; video_info->shared_context = settings->bools.video_shared_context; + + if (libretro_get_shared_context() && hwr && hwr->context_type != RETRO_HW_CONTEXT_NONE) + video_info->shared_context = true; + video_info->font_enable = settings->bools.video_font_enable; video_info->font_msg_pos_x = settings->floats.video_msg_pos_x; video_info->font_msg_pos_y = settings->floats.video_msg_pos_y; diff --git a/griffin/griffin.c b/griffin/griffin.c index 77570f40f9..df49afc43a 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -153,11 +153,36 @@ CHEATS #include "../managers/cheat_manager.c" #include "../libretro-common/hash/rhash.c" +/*============================================================ +UI COMMON CONTEXT +============================================================ */ +#if defined(_WIN32) && !defined(_XBOX) +#include "../gfx/common/win32_common.c" +#endif + /*============================================================ VIDEO CONTEXT ============================================================ */ #include "../gfx/drivers_context/gfx_null_ctx.c" +#if defined(_WIN32) && !defined(_XBOX) + +#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) +#include "../gfx/drivers_context/wgl_ctx.c" +#endif + +#if defined(_WIN32) && !defined(_XBOX) +#include "../gfx/drivers_context/gdi_ctx.c" +#endif + +#if defined(HAVE_FFMPEG) +#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES3) +#include "../cores/libretro-ffmpeg/ffmpeg_fft.c" +#endif +#endif + +#endif + #if defined(__CELLOS_LV2__) #include "../gfx/drivers_context/ps3_ctx.c" #elif defined(ANDROID) diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 2a5a6c8733..53a538109e 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -97,29 +97,6 @@ AUDIO #include "../audio/drivers/xaudio.cpp" #endif -/*============================================================ -UI COMMON CONTEXT -============================================================ */ -#if defined(_WIN32) && !defined(_XBOX) -#include "../gfx/common/win32_common.cpp" - -#if defined(HAVE_OPENGL) || defined(HAVE_VULKAN) -#include "../gfx/drivers_context/wgl_ctx.cpp" -#endif - -#if defined(_WIN32) && !defined(_XBOX) -#include "../gfx/drivers_context/gdi_ctx.cpp" -#endif - -#if defined(HAVE_FFMPEG) -#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES3) -#include "../cores/libretro-ffmpeg/fft/fft.cpp" -#endif -#endif - -#endif - - /*============================================================ MENU ============================================================ */ diff --git a/input/drivers/dinput.c b/input/drivers/dinput.c index 4f78febd2f..4314ce04f5 100644 --- a/input/drivers/dinput.c +++ b/input/drivers/dinput.c @@ -51,7 +51,6 @@ #include "../../gfx/video_driver.h" #include "../../verbosity.h" -#include "../../tasks/tasks_internal.h" /* Keep track of which pad indexes are 360 controllers. * Not static, will be read in xinput_joypad.c @@ -102,7 +101,6 @@ void dinput_destroy_context(void) bool dinput_init_context(void) { - bool context_initialized = false; if (g_dinput_ctx) return true; @@ -110,16 +108,16 @@ bool dinput_init_context(void) /* Who said we shouldn't have same call signature in a COM API? <_< */ #ifdef __cplusplus - context_initialized = (SUCCEEDED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, - (void**)&g_dinput_ctx, NULL))); + if (!(SUCCEEDED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, + IID_IDirectInput8, + (void**)&g_dinput_ctx, NULL)))) #else - context_initialized = (SUCCEEDED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8, - (void**)&g_dinput_ctx, NULL))); + if (!(SUCCEEDED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, + &IID_IDirectInput8, + (void**)&g_dinput_ctx, NULL)))) #endif - - if (!context_initialized) goto error; return true; @@ -149,29 +147,32 @@ static void *dinput_init(const char *joypad_driver) di->joypad_driver_name = strdup(joypad_driver); #ifdef __cplusplus - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, GUID_SysKeyboard, &di->keyboard, NULL))) + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + GUID_SysKeyboard, + &di->keyboard, NULL))) +#else + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + &GUID_SysKeyboard, + &di->keyboard, NULL))) +#endif { RARCH_ERR("[DINPUT]: Failed to create keyboard device.\n"); di->keyboard = NULL; } - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, GUID_SysMouse, &di->mouse, NULL))) - { - RARCH_ERR("[DINPUT]: Failed to create mouse device.\n"); - di->mouse = NULL; - } +#ifdef __cplusplus + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + GUID_SysMouse, + &di->mouse, NULL))) #else - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, &GUID_SysKeyboard, &di->keyboard, NULL))) - { - RARCH_ERR("[DINPUT]: Failed to create keyboard device.\n"); - di->keyboard = NULL; - } - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, &GUID_SysMouse, &di->mouse, NULL))) + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, + &GUID_SysMouse, + &di->mouse, NULL))) +#endif { RARCH_ERR("[DINPUT]: Failed to create mouse device.\n"); di->mouse = NULL; } -#endif if (di->keyboard) { @@ -195,17 +196,9 @@ static void *dinput_init(const char *joypad_driver) return di; } -#if __cplusplus -extern "C" { -#endif - bool doubleclick_on_titlebar_pressed(void); void unset_doubleclick_on_titlebar(void); -#if __cplusplus -} -#endif - static void dinput_poll(void *data) { struct dinput_input *di = (struct dinput_input*)data; @@ -601,9 +594,6 @@ static void dinput_clear_pointers(struct dinput_input *di) } } -#ifdef __cplusplus -extern "C" -#endif bool dinput_handle_message(void *dinput, UINT message, WPARAM wParam, LPARAM lParam) { struct dinput_input *di = (struct dinput_input *)dinput; diff --git a/input/drivers/wiiu_input.c b/input/drivers/wiiu_input.c index dcf19bbc2e..af1a8b7f76 100644 --- a/input/drivers/wiiu_input.c +++ b/input/drivers/wiiu_input.c @@ -100,7 +100,7 @@ static void wiiu_input_poll(void *data) { wiiu_input_t *wiiu = (wiiu_input_t*)data; - if (wiiu->joypad) + if (wiiu && wiiu->joypad) wiiu->joypad->poll(); } diff --git a/input/drivers_joypad/dinput_joypad.c b/input/drivers_joypad/dinput_joypad.c index fb02db9a8a..7541cf0dbb 100644 --- a/input/drivers_joypad/dinput_joypad.c +++ b/input/drivers_joypad/dinput_joypad.c @@ -225,8 +225,8 @@ static BOOL CALLBACK enum_joypad_cb(const DIDEVICEINSTANCE *inst, void *p) #endif return DIENUM_CONTINUE; - g_pads[g_joypad_cnt].joy_name = strdup(inst->tszProductName); - g_pads[g_joypad_cnt].joy_friendly_name = strdup(inst->tszInstanceName); + g_pads[g_joypad_cnt].joy_name = strdup((const char*)inst->tszProductName); + g_pads[g_joypad_cnt].joy_friendly_name = strdup((const char*)inst->tszInstanceName); /* there may be more useful info in the GUID so leave this here for a while */ #if 0 @@ -294,8 +294,8 @@ static bool dinput_joypad_init(void *data) for (i = 0; i < MAX_USERS; ++i) { - g_xinput_pad_indexes[i] = -1; - g_pads[i].joy_name = NULL; + g_xinput_pad_indexes[i] = -1; + g_pads[i].joy_name = NULL; g_pads[i].joy_friendly_name = NULL; } diff --git a/input/drivers_joypad/gx_joypad.c b/input/drivers_joypad/gx_joypad.c index 46347e6f54..348884e833 100644 --- a/input/drivers_joypad/gx_joypad.c +++ b/input/drivers_joypad/gx_joypad.c @@ -324,6 +324,7 @@ static void gx_joypad_poll(void) if (g_quit) { rarch_ctl(RARCH_CTL_SET_SHUTDOWN, NULL); + g_quit = false; return; } diff --git a/input/input_overlay.c b/input/input_overlay.c index 5cb48e6c50..131db8feb6 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -24,6 +24,7 @@ #ifdef HAVE_CONFIG_H #include "../config.h" #endif +#include "../configuration.h" #ifdef HAVE_MENU #include "../menu/menu_driver.h" @@ -31,8 +32,6 @@ #include "../verbosity.h" #include "../gfx/video_driver.h" - -#include "input_driver.h" #include "input_overlay.h" #define OVERLAY_GET_KEY(state, key) (((state)->keys[(key) / 32] >> ((key) % 32)) & 1) @@ -69,6 +68,8 @@ struct input_overlay input_overlay_t *overlay_ptr = NULL; +static bool input_overlay_add_inputs(input_overlay_t *ol, + unsigned port, unsigned analog_dpad_mode); /** * input_overlay_scale: * @ol : Overlay handle. @@ -573,8 +574,10 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad rarch_joypad_info_t joypad_info; input_overlay_state_t old_key_state; unsigned i, j, device; + settings_t *settings = config_get_ptr(); uint16_t key_mod = 0; bool polled = false; + bool button_pressed = false; input_overlay_state_t *ol_state = &ol->overlay_state; if (!ol_state) @@ -703,7 +706,11 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad break; } - if (polled) + if(settings->bools.input_overlay_show_physical_inputs) + { + button_pressed = input_overlay_add_inputs(ol, settings->uints.input_overlay_show_physical_inputs_port, analog_dpad_mode); + } + if (button_pressed || polled) input_overlay_post_poll(ol, opacity); else input_overlay_poll_clear(ol, opacity); @@ -745,4 +752,98 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret, break; } } +/** + * input_overlay_add_inputs: + * @ol : pointer to overlay + * @port : the user to show the inputs of + * + * Adds inputs from current_input to the overlay, so it's displayed + * returns true if an input that is pressed will change the overlay + */ +static bool input_overlay_add_inputs(input_overlay_t *ol, + unsigned port, unsigned analog_dpad_mode) +{ + unsigned i; + uint64_t mask; + int id; + bool button_pressed = false; + bool current_button_pressed = false; + input_overlay_state_t *ol_state = &ol->overlay_state; + if(!ol_state) + return false; + + for(i = 0; i < ol->active->size; i++) + { + overlay_desc_t *desc = &(ol->active->descs[i]); + switch(desc->type) + { + case OVERLAY_TYPE_BUTTONS: + mask = desc->key_mask; + id = RETRO_DEVICE_ID_JOYPAD_B; + /* Need to check all bits in the mask, + * multiple ones can be pressed */ + current_button_pressed = false; + while(mask) + { + /* Get the next button ID */ + while(mask && (mask & 1) == 0) + { + id+=1; + mask = mask >> 1; + } + /* Light up the button if pressed */ + if(input_state(port, RETRO_DEVICE_JOYPAD, 0, id)) + { + current_button_pressed = true; + desc->updated = true; + + id+=1; + mask = mask >> 1; + } + else + { + /* One of the buttons not pressed */ + current_button_pressed = false; + desc->updated = false; + break; + } + } + button_pressed = button_pressed || current_button_pressed; + break; + case OVERLAY_TYPE_ANALOG_LEFT: + case OVERLAY_TYPE_ANALOG_RIGHT: + { + float analog_x, analog_y; + float dx, dy; + unsigned int index = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ? + RETRO_DEVICE_INDEX_ANALOG_RIGHT : RETRO_DEVICE_INDEX_ANALOG_LEFT; + + analog_x = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_X); + analog_y = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_Y); + dx = (analog_x/0x8000)*(desc->range_x/2); + dy = (analog_y/0x8000)*(desc->range_y/2); + + desc->delta_x = dx; + desc->delta_y = dy; + /*Maybe use some option here instead of 0, only display + changes greater than some magnitude. + */ + if((dx*dx) > 0 || (dy*dy) > 0) + button_pressed = true; + } + break; + case OVERLAY_TYPE_KEYBOARD: + if(input_state(port, RETRO_DEVICE_KEYBOARD, 0, desc->key_mask)) + { + desc->updated = true; + button_pressed = true; + } + break; + default: + break; + } + } + + return button_pressed; +} diff --git a/input/input_overlay.h b/input/input_overlay.h index 93f3c83e91..af4305702a 100644 --- a/input/input_overlay.h +++ b/input/input_overlay.h @@ -24,6 +24,8 @@ #include #include +#include "input_driver.h" + RETRO_BEGIN_DECLS #define BOX_RADIAL 0x18df06d2U diff --git a/input/input_remapping.c b/input/input_remapping.c index 17aae07ab3..6ca86e7270 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -1,5 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2015-2017 - Andrés Suárez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -23,6 +24,9 @@ #include "../configuration.h" #include "../retroarch.h" +static unsigned old_analog_dpad_mode[MAX_USERS]; +static unsigned old_libretro_device[MAX_USERS]; + /** * input_remapping_load_file: * @data : Path to config file. @@ -54,6 +58,9 @@ bool input_remapping_load_file(void *data, const char *path) "a", "x", "l", "r", "l2", "r2", "l3", "r3", "l_x", "l_y", "r_x", "r_y" }; + old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i]; + old_libretro_device[i] = settings->uints.input_libretro_device[i]; + snprintf(buf, sizeof(buf), "input_player%u", i + 1); for (j = 0; j < RARCH_FIRST_CUSTOM_BIND + 4; j++) @@ -82,6 +89,12 @@ bool input_remapping_load_file(void *data, const char *path) settings->uints.input_remap_ids[i][RARCH_FIRST_CUSTOM_BIND + j] = key_remap; } + + snprintf(buf, sizeof(buf), "input_player%u_analog_dpad_mode", i + 1); + CONFIG_GET_INT_BASE(conf, settings, uints.input_analog_dpad_mode[i], buf); + + snprintf(buf, sizeof(buf), "input_libretro_device_p%u", i + 1); + CONFIG_GET_INT_BASE(conf, settings, uints.input_libretro_device[i], buf); } config_file_free(conf); @@ -158,6 +171,10 @@ bool input_remapping_save_file(const char *path) config_unset(conf,key_ident[j]); } } + snprintf(buf, sizeof(buf), "input_libretro_device_p%u", i + 1); + config_set_int(conf, buf, input_config_get_device(i)); + snprintf(buf, sizeof(buf), "input_player%u_analog_dpad_mode", i + 1); + config_set_int(conf, buf, settings->uints.input_analog_dpad_mode[i]); } ret = config_file_write(conf, remap_file); @@ -166,6 +183,22 @@ bool input_remapping_save_file(const char *path) return ret; } +bool input_remapping_remove_file(const char *path) +{ + char buf[PATH_MAX_LENGTH]; + char remap_file[PATH_MAX_LENGTH]; + settings_t *settings = config_get_ptr(); + + buf[0] = remap_file[0] = '\0'; + + fill_pathname_join(buf, settings->paths.directory_input_remapping, + path, sizeof(buf)); + + fill_pathname_noext(remap_file, buf, ".rmp", sizeof(remap_file)); + + return remove(remap_file) == 0 ? true : false; +} + void input_remapping_set_defaults(void) { unsigned i, j; @@ -175,10 +208,16 @@ void input_remapping_set_defaults(void) { for (j = 0; j < RARCH_FIRST_CUSTOM_BIND; j++) { - const struct retro_keybind *keybind = &input_config_binds[i][j]; - settings->uints.input_remap_ids[i][j] = keybind->id; + const struct retro_keybind *keybind = &input_config_binds[i][j]; + if (keybind) + settings->uints.input_remap_ids[i][j] = keybind->id; } for (j = 0; j < 4; j++) settings->uints.input_remap_ids[i][RARCH_FIRST_CUSTOM_BIND + j] = j; + + if (old_analog_dpad_mode[i]) + settings->uints.input_analog_dpad_mode[i] = old_analog_dpad_mode[i]; + if (old_libretro_device[i]) + settings->uints.input_libretro_device[i] = old_libretro_device[i]; } } diff --git a/input/input_remapping.h b/input/input_remapping.h index 3c988ad2c5..d2bdec05ac 100644 --- a/input/input_remapping.h +++ b/input/input_remapping.h @@ -44,6 +44,8 @@ bool input_remapping_load_file(void *data, const char *path); **/ bool input_remapping_save_file(const char *path); +bool input_remapping_remove_file(const char *path); + void input_remapping_set_defaults(void); RETRO_END_DECLS diff --git a/intl/msg_hash_cht.c b/intl/msg_hash_cht.c index d04cfc834d..a08736ee89 100644 --- a/intl/msg_hash_cht.c +++ b/intl/msg_hash_cht.c @@ -127,7 +127,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case RARCH_OVERLAY_NEXT: snprintf(s, len, - "切換到下一個屏幕覆層。將會循環選擇。"); + "切換到下一個營幕覆層。將會循環選擇。"); break; case RARCH_DISK_EJECT_TOGGLE: snprintf(s, len, @@ -210,21 +210,21 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) switch (msg) { case MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS: - snprintf(s, len, "你的登陸信息 \n" - "Retro Achievements 賬號. \n" + snprintf(s, len, "你的登入訊息 \n" + "Retro Achievements 帳號. \n" " \n" "訪問 retroachievements.org 並註冊 \n" - "以獲取一個免費賬號. \n" + "以獲取一個免費帳號. \n" " \n" "在你註冊以後, 你需要 \n" "在RetroArch輸入你的 \n" - "賬號以及密碼."); + "帳號以及密碼."); break; case MENU_ENUM_LABEL_CHEEVOS_USERNAME: - snprintf(s, len, "你的Retro Achievements賬號的用戶名。"); + snprintf(s, len, "你的Retro Achievements帳號的用戶名。"); break; case MENU_ENUM_LABEL_CHEEVOS_PASSWORD: - snprintf(s, len, "你的Retro Achievements賬號的密碼。"); + snprintf(s, len, "你的Retro Achievements帳號的密碼。"); break; case MENU_ENUM_LABEL_USER_LANGUAGE: snprintf(s, len, "依據選擇的語言來本地化菜單和其他屏顯消息。 \n" @@ -242,7 +242,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "自動加載遊戲內容指定的核心選項."); break; case MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE: - snprintf(s, len, "自動加載覆蓋配置。"); + snprintf(s, len, "自動加載覆蓋設定。"); break; case MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE: snprintf(s, len, "自動加載輸入重映射文件."); @@ -280,26 +280,26 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) "截圖目錄之中."); break; case MENU_ENUM_LABEL_RUN: - snprintf(s, len, "啟動內容."); + snprintf(s, len, "啟動遊戲."); break; case MENU_ENUM_LABEL_INFORMATION: - snprintf(s, len, "顯示本內容的額外 \n" - "元數據信息."); + snprintf(s, len, "顯示本遊戲的額外 \n" + "元數據訊息."); break; case MENU_ENUM_LABEL_FILE_BROWSER_CONFIG: - snprintf(s, len, "配置文件."); + snprintf(s, len, "設定文件."); break; case MENU_ENUM_LABEL_FILE_BROWSER_COMPRESSED_ARCHIVE: snprintf(s, len, "壓縮歸檔文件."); break; case MENU_ENUM_LABEL_FILE_BROWSER_RECORD_CONFIG: - snprintf(s, len, "記錄配置文件."); + snprintf(s, len, "錄製設定文件."); break; case MENU_ENUM_LABEL_FILE_BROWSER_CURSOR: snprintf(s, len, "數據庫指針文件。"); break; case MENU_ENUM_LABEL_FILE_CONFIG: - snprintf(s, len, "配置文件."); + snprintf(s, len, "設定文件."); break; case MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY: snprintf(s, len, @@ -319,15 +319,15 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY: snprintf(s, len, - "縮略圖目錄. \n" + "縮圖目錄. \n" " \n" "用以存放縮略圖."); break; case MENU_ENUM_LABEL_LIBRETRO_INFO_PATH: snprintf(s, len, - "核心Core信息目錄. \n" + "核心Core訊息目錄. \n" " \n" - "用於搜索libretro核心信息 \n" + "用於搜索libretro核心訊息 \n" "的目錄。"); break; case MENU_ENUM_LABEL_PLAYLIST_DIRECTORY: @@ -400,9 +400,9 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_FILE_BROWSER_MOVIE_OPEN: snprintf(s, len, - "視頻 \n" + "視訊 \n" " \n" - "選擇文件並使用視頻播放器打開。"); + "選擇文件並使用視訊播放器打開。"); break; case MENU_ENUM_LABEL_FILE_BROWSER_MUSIC_OPEN: snprintf(s, len, @@ -476,8 +476,8 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE: snprintf(s, len, - "顯示器的視頻刷新率。 \n" - "可被用來計算一個合適的音頻輸入率。"); + "顯示器的視訊刷新率。 \n" + "可被用來計算一個合適的聲音輸入率。"); break; case MENU_ENUM_LABEL_VIDEO_FORCE_SRGB_DISABLE: snprintf(s, len, @@ -488,11 +488,11 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_AUDIO_ENABLE: snprintf(s, len, - "啟用音頻輸出。"); + "啟用聲音輸出。"); break; case MENU_ENUM_LABEL_AUDIO_SYNC: snprintf(s, len, - "同步音頻(推薦)。"); + "同步聲音(推薦)。"); break; case MENU_ENUM_LABEL_AUDIO_LATENCY: snprintf(s, len, @@ -514,8 +514,8 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_CONTENT_HISTORY_SIZE: snprintf(s, len, - "Number of entries that will be kept in \n" - "content history playlist."); + "可存放在歷史遊戲清單的數量 \n" + "."); break; case MENU_ENUM_LABEL_VIDEO_WINDOWED_FULLSCREEN: snprintf(s, len, @@ -524,7 +524,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_FONT_SIZE: snprintf(s, len, - "屏顯信息的字體大小."); + "屏顯訊息的字體大小."); break; case MENU_ENUM_LABEL_SAVESTATE_AUTO_INDEX: snprintf(s, len, @@ -540,7 +540,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_FONT_ENABLE: snprintf(s, len, - "顯示/隱藏屏顯信息."); + "顯示/隱藏屏顯訊息."); break; case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_X: case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_Y: @@ -550,7 +550,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_INPUT_OVERLAY_ENABLE: snprintf(s, len, - "Enable or disable the current overlay."); + "啟用或取消目前的 overlay."); break; case MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU: snprintf(s, len, @@ -577,7 +577,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_AUDIO_OUTPUT_RATE: snprintf(s, len, - "音頻輸出採樣率."); + "聲音輸出採樣率."); break; case MENU_ENUM_LABEL_VIDEO_SHARED_CONTEXT: snprintf(s, len, @@ -752,12 +752,12 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_DRIVER: snprintf(s, len, - "當前視頻驅動."); + "當前視訊驅動."); if (string_is_equal_fast(settings->arrays.video_driver, "gl", 2)) { snprintf(s, len, - "OpenGL視頻驅動. \n" + "OpenGL視訊驅動. \n" " \n" "This driver allows libretro GL cores to \n" "be used in addition to software-rendered \n" @@ -771,7 +771,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "sdl2", 4)) { snprintf(s, len, - "SDL 2 視頻驅動.\n" + "SDL 2 視訊驅動.\n" " \n" "This is an SDL 2 software-rendered video \n" "driver.\n" @@ -783,7 +783,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "sdl1", 4)) { snprintf(s, len, - "SDL 視頻驅動.\n" + "SDL 視訊驅動.\n" " \n" "This is an SDL 1.2 software-rendered video \n" "driver.\n" @@ -794,7 +794,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "d3d", 3)) { snprintf(s, len, - "Direct3D 視頻驅動. \n" + "Direct3D 視訊驅動. \n" " \n" "Performance for software-rendered cores \n" "is dependent on your graphic card's \n" @@ -803,7 +803,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "exynos", 6)) { snprintf(s, len, - "Exynos-G2D 視頻驅動. \n" + "Exynos-G2D 視訊驅動. \n" " \n" "This is a low-level Exynos video driver. \n" "Uses the G2D block in Samsung Exynos SoC \n" @@ -815,7 +815,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "drm", 3)) { snprintf(s, len, - "Plain DRM 視頻驅動. \n" + "Plain DRM 視訊驅動. \n" " \n" "This is a low-level video driver using. \n" "libdrm for hardware scaling using \n" @@ -824,7 +824,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) else if (string_is_equal_fast(settings->arrays.video_driver, "sunxi", 5)) { snprintf(s, len, - "Sunxi-G2D 視頻驅動. \n" + "Sunxi-G2D 視訊驅動. \n" " \n" "This is a low-level Sunxi video driver. \n" "Uses the G2D block in Allwinner SoCs."); @@ -832,7 +832,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN: snprintf(s, len, - "音頻DSP插件.\n" + "聲音DSP插件.\n" " Processes audio before it's sent to \n" "the driver." ); @@ -1311,7 +1311,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_VSYNC: snprintf(s, len, - "視頻垂直同步.\n"); + "視訊垂直同步.\n"); break; case MENU_ENUM_LABEL_VIDEO_HARD_SYNC: snprintf(s, len, @@ -1332,7 +1332,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_SCREENSHOT: snprintf(s, len, - "Take screenshot."); + "營幕快照."); break; case MENU_ENUM_LABEL_VIDEO_FRAME_DELAY: snprintf(s, len, @@ -1379,7 +1379,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) "'Save Configuration on Exit' is enabled.\n"); break; case MENU_ENUM_LABEL_VIDEO_FULLSCREEN: - snprintf(s, len, "Toggles fullscreen."); + snprintf(s, len, "啟用全營幕."); break; case MENU_ENUM_LABEL_BLOCK_SRAM_OVERWRITE: snprintf(s, len, @@ -1483,7 +1483,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) ); break; case MENU_ENUM_LABEL_INPUT_TOUCH_ENABLE: - snprintf(s, len, "Enable touch support."); + snprintf(s, len, "啟用觸控支援."); break; case MENU_ENUM_LABEL_INPUT_PREFER_FRONT_TOUCH: snprintf(s, len, "Use front instead of back touch."); @@ -1563,27 +1563,27 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_TIMEDATE_ENABLE: snprintf(s, len, - "Shows current date and/or time inside menu."); + "在選單內顯示當前日期或時間."); break; case MENU_ENUM_LABEL_CORE_ENABLE: snprintf(s, len, - "Shows current core inside menu."); + "在選單內顯示當前使用遊戲核心."); break; case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: snprintf(s, len, - "Enables Netplay in host (server) mode."); + "啟用連線遊戲模式 (主機端) ."); break; case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: snprintf(s, len, - "Enables Netplay in client mode."); + "啟用連線遊戲模式 (連線端) ."); break; case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: snprintf(s, len, - "Disconnects an active Netplay connection."); + "中斷使用中的連線遊戲模式."); break; case MENU_ENUM_LABEL_NETPLAY_SETTINGS: snprintf(s, len, - "Setting related to Netplay."); + "連線遊戲模式相關設定."); break; case MENU_ENUM_LABEL_NETPLAY_LAN_SCAN_SETTINGS: snprintf(s, len, @@ -1713,11 +1713,11 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_OSK_ENABLE: snprintf(s, len, - "Enable/disable on-screen keyboard."); + "開啟或取消營幕的虛擬鍵盤."); break; case MENU_ENUM_LABEL_AUDIO_MUTE: snprintf(s, len, - "Mute/unmute audio."); + "開啟或關閉靜音."); break; case MENU_ENUM_LABEL_REWIND: snprintf(s, len, @@ -1739,15 +1739,15 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_LOAD_STATE: snprintf(s, len, - "Loads state."); + "載入即時存檔."); break; case MENU_ENUM_LABEL_SAVE_STATE: snprintf(s, len, - "Saves state."); + "儲存即時存檔."); break; case MENU_ENUM_LABEL_NETPLAY_FLIP_PLAYERS: snprintf(s, len, - "Netplay flip users."); + "踢掉連線遊戲的使用者."); break; case MENU_ENUM_LABEL_CHEAT_INDEX_PLUS: snprintf(s, len, @@ -1767,7 +1767,7 @@ int menu_hash_get_help_cht_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_RESET: snprintf(s, len, - "Reset the content.\n"); + "重設遊戲.\n"); break; case MENU_ENUM_LABEL_PAUSE_TOGGLE: snprintf(s, len, diff --git a/intl/msg_hash_cht.h b/intl/msg_hash_cht.h index f5afd1e642..80d6073a5c 100644 --- a/intl/msg_hash_cht.h +++ b/intl/msg_hash_cht.h @@ -8,15 +8,15 @@ MSG_HASH( ) MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT, - "設備已從端口上斷開" + "設備已從連接口上移開" ) MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "接收到未知的聯機遊戲指令" + "接收到未知的連線遊戲指令" ) MSG_HASH( MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, - "文件已存在。保存到備份緩衝區" + "文件已存在。儲存到備份至緩衝區" ) MSG_HASH( MSG_GOT_CONNECTION_FROM, @@ -32,15 +32,15 @@ MSG_HASH( ) MSG_HASH( MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "未提供參數也沒有內建菜單,顯示幫助..." + "未提供參數也沒有內建選單,顯示幫助..." ) MSG_HASH( MSG_NETPLAY_USERS_HAS_FLIPPED, - "聯機遊戲用戶已被踢出" + "連線遊戲用戶已被踢出" ) MSG_HASH( MSG_SETTING_DISK_IN_TRAY, - "Setting disk in tray" + "設定光碟機裡光碟" ) MSG_HASH( MSG_WAITING_FOR_CLIENT, @@ -56,7 +56,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_IMPLEMENTATIONS_DIFFER, - "實現有差異。確保正在使用的RetroArch和核心是同版本的。" + "執行時錯誤發生。請確保雙方的所使用的RetroArch跟核心是同版本的。" ) MSG_HASH( MSG_NETPLAY_ENDIAN_DEPENDENT, @@ -64,11 +64,11 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_PLATFORM_DEPENDENT, - "This core does not support inter-architecture netplay" + "此模擬器且不支援此兩種架構下的連線遊戲模式" ) MSG_HASH( MSG_NETPLAY_ENTER_PASSWORD, - "輸入聯機遊戲服務器的密碼:" + "輸入連線遊戲服務器的密碼:" ) MSG_HASH( MSG_NETPLAY_INCORRECT_PASSWORD, @@ -76,15 +76,15 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_SERVER_NAMED_HANGUP, - "\"%s\" 已斷開連接" + "\"%s\" 已斷開連線" ) MSG_HASH( MSG_NETPLAY_SERVER_HANGUP, - "一個聯機遊戲客戶端已斷開" + "連線遊戲客戶端已離開" ) MSG_HASH( MSG_NETPLAY_CLIENT_HANGUP, - "聯機遊戲已斷開" + "已離開連線遊戲模式" ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, @@ -92,7 +92,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, - "已無空閒插槽" /*FIXME:"There are no free player slots"*/ + "連線遊戲人數已滿" /*FIXME:"There are no free player slots"*/ ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY, @@ -100,7 +100,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_PEER_PAUSED, - "聯機遊戲對方 \"%s\" 暫停" + "連線遊戲對方 \"%s\" 已暫停" ) MSG_HASH( MSG_NETPLAY_CHANGED_NICK, @@ -108,11 +108,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Give hardware-rendered cores their own private context. Avoids having to assume hardware state changes inbetween frames." + "使用模擬器硬體渲染私人內容時可避免硬體在各frames時的狀態改變." ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "調整菜單屏幕相關的設置。" + "調整選單顯示的相關設定。" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, @@ -120,20 +120,20 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "以延遲和視頻撕裂為代價換取高性能,當且僅當能\n" + "以延遲和視訊撕裂為代價換取高性能,當且僅當能\n" "達到全速模擬時使用。" ) MSG_HASH( MSG_AUDIO_VOLUME, - "音頻音量" + "聲音音量" ) MSG_HASH( MSG_AUTODETECT, - "自動檢測" + "自動偵測" ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FROM, - "自動加載存檔從" + "自動載入存檔從" ) MSG_HASH( MSG_CAPABILITIES, @@ -141,11 +141,11 @@ MSG_HASH( ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "連接到聯機遊戲主機" + "連線到連線遊戲主機" ) MSG_HASH( MSG_CONNECTING_TO_PORT, - "連接到端口" + "連接到連接口" ) MSG_HASH( MSG_CONNECTION_SLOT, @@ -153,18 +153,18 @@ MSG_HASH( ) MSG_HASH( MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "對不起,未實現:核心未請求內容,無法加入聯機遊戲。" + "對不起,錯誤發生:模擬器核心未請求內容,無法加入連線遊戲。" ) MSG_HASH( MSG_FAILED_TO_SET_DISK, - "設置磁盤失敗") + "設定磁盤失敗") MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, "密碼" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Cheevos賬戶" /*FIXME:"Accounts Cheevos"*/ + "Cheevos帳戶" /*FIXME:"Accounts Cheevos"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, @@ -172,11 +172,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, - "賬戶" + "帳戶" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, - "賬戶列表終端" + "帳戶列表終端" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, @@ -189,7 +189,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "成就列表(硬核)" /*FIXME:"Achievement List (Hardcore)"*/ + "成就列表(專家模式)" /*FIXME:"Achievement List (Hardcore)"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, @@ -197,7 +197,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "配置" + "設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_TAB, @@ -205,7 +205,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "聯機遊戲房間" + "連線遊戲房間" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, @@ -221,23 +221,23 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, - "音頻設備" + "聲音設備" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, - "音頻驅動" + "聲音驅動程式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, - "音頻DSP插件" + "聲音DSP插件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, - "啟用音頻" + "啟用聲音" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, - "音頻過濾器目錄" + "聲音過濾器目錄" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, @@ -245,55 +245,55 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - "音頻時延(ms)" + "聲音時延(ms)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, - "音頻最大採樣間隔" + "聲音最大採樣間隔" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "音頻靜音" + "聲音靜音" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, - "音頻輸出碼率(Hz)" + "聲音輸出碼率(Hz)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, - "音頻碼率控制間隔" + "動態聲音碼率控制間隔" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, - "音頻重採樣驅動" + "聲音重採樣驅動程式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, - "音頻" + "聲音" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, - "啟用音頻同步" + "啟用聲音同步" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "音頻音量級別(dB)" + "聲音音量級別(dB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "SaveRAM自動保存間隔" + "SaveRAM自動儲存間隔" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, - "自動加載覆寫文件" + "自動載入覆寫文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, - "自動加載重映射文件" + "自動戴入重映射文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, - "自動加載Shader預設" + "自動戴入Shader預設" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, @@ -305,7 +305,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "信息" + "訊息" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, @@ -329,11 +329,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "切換菜單" + "切換選單" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "基本菜單控制" + "基本選單控制" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, @@ -341,7 +341,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, - "信息" + "訊息" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, @@ -361,11 +361,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "切換菜單" + "切換選單" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "加載保存狀態時不覆蓋SaveRAM" + "載入儲存狀態時不覆蓋SaveRAM" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, @@ -377,7 +377,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, - "緩存目錄" + "緩沖目錄" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, @@ -385,7 +385,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, - "相機驅動" + "相機驅動程式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT, @@ -393,7 +393,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, - "應用金手指修改" + "執行金手指修改" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, @@ -405,11 +405,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "加載金手指文件" + "載入金手指文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "另存為金手指文件" + "另存金手指文件" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, @@ -422,7 +422,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, /* FIXME? Translate 'Achievements Hardcore Mode' */ - "專家模式" + "成就-專家模式" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, @@ -439,7 +439,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, /* FIXME? Translate 'Test Unofficial Achievements' */ - "非官方測試" + "非官方測試成就" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, @@ -455,19 +455,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG, - "配置" + "設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "加載配置" + "載入設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, - "配置" + "設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, - "退出時保存配置" + "退出時儲存設定" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIRM_ON_EXIT, @@ -491,7 +491,7 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, "允許移除記錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "快捷菜單") + "快捷選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, "下載目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, @@ -503,7 +503,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, "顯示核心名稱") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, - "核心信息") + "核心訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, "作者") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, @@ -513,7 +513,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, "核心名稱") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, - "固件") + "韌體") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, "許可證") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, @@ -527,7 +527,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "控制") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_LIST, - "加載核心") + "戴入核心") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, @@ -573,11 +573,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, "Disk Cycle Tray Status") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, - "追加光盤鏡像") + "追加光碟鏡像") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_INDEX, - "光盤索引") + "光碟索引") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, - "光盤控制") + "光碟控制") MSG_HASH(MENU_ENUM_LABEL_VALUE_DONT_CARE, "不關心") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, @@ -594,22 +594,22 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, "驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, /* FIXME? Translate 'Load Dummy on Core Shutdown' */ - "核心關閉時加載虛擬程序") + "核心關閉時戴入虛擬程序") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, - "加載前檢查丟失的固件") /*FIXME: "Check for Missing Firmware Before Loading"*/ + "載入前檢查韌體/BIOS是否存在") /*FIXME: "Check for Missing Firmware Before Loading"*/ MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "動態壁紙") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, "動態壁紙目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, /* FIXME? Translate 'Enable Achievements' */ - "啟用") + "啟用成就系統") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, - "菜單項懸停顏色") + "選單項懸停顏色") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, - "菜單項正常顏色") + "選單項正常顏色") MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, - "假") + "取消") MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, "最大運行速度") MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, @@ -621,7 +621,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, "前端計數器") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "自動加載遊戲內容特定的核心選項") + "自動戴入遊戲內容特定的核心選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, "創建遊戲選項文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, @@ -629,15 +629,15 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, "幫助") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "音頻/視頻故障排除") + "聲音/視訊故障排除") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, "變更虛擬遊戲控制器覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, - "基本菜單控制") + "基本選單控制") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST, "幫助") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LOADING_CONTENT, - "加載遊戲內容") + "戴入遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, "掃瞄遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, @@ -647,17 +647,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_TAB, "歷史") MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, - "水平化菜單") + "水平化選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, "圖像") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION, - "信息") + "訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, - "信息") + "訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, "手柄輸入轉數字選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "所有用戶都能控制菜單") + "所有用戶都能控制選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, "左搖桿X") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, @@ -683,11 +683,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, "右搖桿Y+ (下)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, - "啟用自動配置") + "啟用自動設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, "輸入軸閾值") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "菜單切換 確定/取消 按鈕") /*FIXME:"Menu Swap OK & Cancel Buttons"*/ + "選單切換 確定/取消 按鈕") /*FIXME:"Menu Swap OK & Cancel Buttons"*/ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, "綁定全部") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, @@ -749,7 +749,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, "最大用戶數") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "遊戲控制器菜單切出組合鍵") + "遊戲控制器選單切出組合鍵") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, "金手指索引 -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, @@ -759,9 +759,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, "光驅出倉切換") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, - "下一張光盤") + "下一張光碟") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, - "上一張光盤") + "上一張光碟") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, "啟用熱鍵") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, @@ -771,25 +771,25 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, "幀提前量") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, - "切換全屏幕") + "切換全營幕") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, "鼠標捕獲開關") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, - "Game focus toggle") + "切換遊戲焦距") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "加載狀態") + "戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, - "切換菜單") + "切換選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, - "視頻錄製開關") + "視訊錄製開關") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, "靜音開關") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, - "聯機遊戲踢出用戶") + "連線遊戲踢出用戶") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "聯機遊戲切換 遊戲/圍觀 模式") + "連線遊戲切換 遊戲/圍觀 模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, - "切換屏幕鍵盤") + "切換營幕鍵盤") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, "下一個覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, @@ -801,9 +801,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, "回溯") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "保存狀態") + "儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, - "屏幕截圖") + "營幕截圖") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, "下一個Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, @@ -823,7 +823,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OSK_OVERLAY_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, "顯示覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, - "在菜單中隱藏覆層") + "在選單中隱藏覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, "輪詢類型行為") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, @@ -839,7 +839,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, "啟用綁定重映射") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, - "保存自動設置") + "儲存自動設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, "輸入") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, @@ -855,7 +855,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, MSG_HASH(MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, "內部存儲狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "輸入設備自動配置目錄") + "輸入設備自動設定目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, "手柄驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, @@ -897,19 +897,19 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, "核心目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "核心信息目錄") + "核心訊息目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, "核心日誌級別") MSG_HASH(MENU_ENUM_LABEL_VALUE_LINEAR, "線性") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, - "使用核心加載壓縮包") + "使用核心戴入壓縮包") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, - "加載最近的遊戲內容") + "戴入最近的遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, "載入遊戲內容") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_STATE, - "加載狀態") + "戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, "允許使用位置") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, @@ -919,11 +919,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, "完整日誌記錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_MAIN_MENU, - "主菜單") + "主選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_MANAGEMENT, - "數據庫設置") + "數據庫設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, - "菜單顏色主題") + "選單顏色主題") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, "藍色") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, @@ -943,17 +943,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, "頂部不透明度") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DRIVER, - "菜單驅動") + "選單驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, - "限制菜單幀率") + "限制選單幀率") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, /* TODO/FIXME - update */ - "菜單文件瀏覽器") + "選單文件瀏覽器") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, - "菜單線性過濾") + "選單線性過濾") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "菜單") + "選單") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, - "菜單壁紙") + "選單壁紙") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, "壁紙不透明度") MSG_HASH(MENU_ENUM_LABEL_VALUE_MISSING, @@ -973,57 +973,57 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, MSG_HASH(MENU_ENUM_LABEL_VALUE_NEAREST, "最近") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY, - "在線遊戲") + "連線遊戲") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, - "在線遊戲檢查幀數") + "連線遊戲檢查幀數") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CLIENT_SWAP_INPUT, - "在線玩家P2使用C1") + "連線玩家P2使用C1") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "在線遊戲延遲幀數") + "連線遊戲延遲幀數") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, "斷開連接") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, - "啟用在線遊戲") + "啟用連線遊戲") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, "連接到遊戲主機") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, "作為遊戲主機") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, - "Stop netplay host") + "停止連線主機") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, "服務器地址") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, - "掃瞄本地網絡") + "掃瞄本地網路") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "啟用在線遊戲客戶端") + "啟用連線遊戲客戶端") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "用戶名") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, "服務器密碼") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "在線遊戲設置") + "連線遊戲設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "聯機無狀態模式") + "連線遊戲無狀態模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, "服務器圍觀的密碼") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "啟用在線遊戲旁觀者") + "啟用連線遊戲旁觀者") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "在線遊戲TCP/UDP端口") + "連線遊戲TCP/UDP端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "聯機NAT遍歷") + "連線遊戲使用NAT穿透技術") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, - "網絡命令") + "網路命令") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, - "網絡命令端口") + "網路命令端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, - "網絡信息") + "網路訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, - "網絡遊戲控制器") + "網路遊戲控制器") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, - "網絡遠端基本端口") + "網路遠端基本端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, - "網絡") + "網路") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO, "否") MSG_HASH(MENU_ENUM_LABEL_VALUE_NONE, @@ -1037,7 +1037,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE, "沒有可用的核心。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, - "沒有可用的核心信息。") + "沒有可用的核心訊息。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, "沒有可用的核心選項。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, @@ -1045,13 +1045,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, "沒有可用的歷史記錄。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, - "沒有可用的信息。") + "沒有可用的訊息。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS, "沒有條目。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, - "未發現聯機遊戲主機。") + "未發現連線遊戲主機。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, - "未發現網絡。") + "未發現網路。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, "沒有性能計數器。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, @@ -1059,7 +1059,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, "沒有可用的遊戲列表項目。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, - "沒有找到設置。") + "沒有找到設定。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, "沒有Shader參數.") MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, @@ -1067,15 +1067,15 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, MSG_HASH(MENU_ENUM_LABEL_VALUE_ON, "開") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, - "在線更新器") + "連線更新器") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, - "屏幕顯示") + "營幕顯示") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, - "屏幕覆層") + "營幕覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, "以文件夾形式打開壓縮包") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, - "屏幕通知") + "營幕通知") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPTIONAL, "任意") MSG_HASH(MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_DIRECTORY, @@ -1083,7 +1083,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY, "覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, - "自動加載最佳的覆層") + "自動戴入最佳的覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, "覆層目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, @@ -1093,13 +1093,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, "覆層縮放比例") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, - "屏幕覆層") + "營幕覆層") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, "使用PAL60模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, "上一級目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, - "當菜單激活時暫停") + "當選單激活時暫停") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, "禁止後台運行") MSG_HASH(MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, @@ -1111,7 +1111,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, "遊戲列表") MSG_HASH(MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, - "觸摸支持") + "觸控支援") MSG_HASH(MENU_ENUM_LABEL_VALUE_PORT, "端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_PRESENT, @@ -1179,17 +1179,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, "重啟") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, - "錄像配置目錄") + "錄影設定目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, - "錄像輸出目錄") + "錄影輸出目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, - "錄像") + "錄影") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "錄像配置") + "錄影設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, - "錄像驅動") + "錄影驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, - "啟用錄像") + "啟用錄影") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, "輸出文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, @@ -1197,11 +1197,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE, "重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, - "加載重映射文件") + "戴入重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, - "保存核心重映射文件") + "儲存核心重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, - "保存遊戲重映射文件") + "儲存遊戲重映射文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, "必須") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -1215,7 +1215,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, "Retro鍵盤") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD, - "Retro觸摸板") + "Retro觸控板") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, "RetroPad w/ Analog") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, @@ -1229,9 +1229,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, "文件瀏覽器目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, - "配置目錄") + "設定目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, - "顯示開始屏幕") + "顯示開始營幕") MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, "右側搖桿") MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, @@ -1241,25 +1241,25 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, "存檔文件目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, - "自動索引保存狀態") + "自動索引儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "自動加載狀態") + "自動戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "自動保存狀態") + "自動儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, "狀態存儲目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Savestate Thumbnails") + "既時存檔縮圖") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, - "保存當前配置") + "儲存當前設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, - "保存核心覆寫") + "儲存核心覆寫") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "保存遊戲覆寫") + "儲存遊戲覆寫") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, - "保存新配置") + "儲存新設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, - "保存狀態") + "儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, "存檔") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, @@ -1269,17 +1269,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, "<掃瞄當前目錄>") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, - "屏幕截圖目錄") + "營幕截圖目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - "屏幕分辨率") + "營幕分辨率") MSG_HASH(MENU_ENUM_LABEL_VALUE_SEARCH, "搜索:") MSG_HASH(MENU_ENUM_LABEL_VALUE_SECONDS, "秒") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS, - "設置") + "設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - "設置") + "設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER, "Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, @@ -1295,7 +1295,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, "Snow") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, - "顯示高級設置") + "顯示高級設定") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, "顯示隱藏的文件和文件夾") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHUTDOWN, @@ -1313,7 +1313,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, MSG_HASH(MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, "啟動遠程的RetroPad") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, - "啟動視頻處理") + "啟動視訊處理") MSG_HASH(MENU_ENUM_LABEL_VALUE_STATE_SLOT, "狀態存儲槽") MSG_HASH(MENU_ENUM_LABEL_VALUE_STATUS, @@ -1329,7 +1329,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, "系統/BIOS目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "系統信息") + "系統訊息") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, "7zip 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, @@ -1359,7 +1359,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, "動態鏈接庫支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, - "運行時動態加載libretro庫") + "運行時動態戴入libretro庫") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, "EGL 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, @@ -1393,9 +1393,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, "Netplay (點對點) 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, - "網絡控制台支持") + "網路控制台支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, - "網絡控制器支持") + "網路控制器支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, "OpenAL 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, @@ -1453,7 +1453,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, - "視頻上下文驅動") + "視訊上下文驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, "Vulkan 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, @@ -1467,7 +1467,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, "Zlib 支持") MSG_HASH(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, - "截取屏幕") + "截取營幕") MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, /* TODO/FIXME - update */ "啟用多線程數據執行循環") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS, @@ -1485,7 +1485,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, MSG_HASH(MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, "顯示時間日期") MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, - "菜單標題顏色") + "選單標題顏色") MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, "真") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, @@ -1497,9 +1497,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, "無法讀取壓縮的文件。") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, - "撤銷加載狀態") + "撤銷戴入狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, - "撤銷保存狀態") + "撤銷儲存狀態") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNKNOWN, "未知") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, @@ -1507,13 +1507,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, "更新資源") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "更新自動配置檔案") + "更新自動設定檔案") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, "更新CG Shader效果文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, "更新金手指") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "更新核心信息文件") + "更新核心訊息文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, "更新數據庫") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, @@ -1541,9 +1541,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, "允許旋轉") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, - "自動選擇視口比例") + "自動選擇畫面比例") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, - "視口比例選項") + "畫面比例選項") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, "黑色幀補間") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, @@ -1551,11 +1551,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, "禁用桌面元素") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, - "視頻驅動") + "視訊驅動") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, - "視頻濾鏡") + "視訊濾鏡") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, - "視頻濾鏡目錄") + "視訊濾鏡目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, "閃爍過濾器") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, @@ -1565,7 +1565,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, "屏顯消息(OSD)大小") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, - "強制視口比例") + "強制畫面比例") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, "強制禁止sRGB幀緩衝") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, @@ -1573,9 +1573,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, "使用全屏模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, - "視頻Gamma") + "視訊Gamma") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, - "啟用GPU錄像") + "啟用GPU錄影") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, "啟用GPU截屏") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, @@ -1591,7 +1591,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, "顯示器索引") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, - "啟用錄像後期濾鏡") + "啟用錄影後期濾鏡") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, "刷新率") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, @@ -1603,23 +1603,23 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, "整數化縮放量") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, - "視頻") + "視訊") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, - "視頻Shader目錄") + "視訊Shader目錄") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, "Shader渲染遍數") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, "預覽Shader參數") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, - "加載Shader預設") + "戴入Shader預設") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_PARAMETERS, - "菜單Shader參數") + "選單Shader參數") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, - "保存Shader預設為") + "儲存Shader預設為") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, - "保存核心預設") + "儲存核心預設") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, - "保存遊戲預設") + "儲存遊戲預設") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, "啟用硬件共享上下文") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, @@ -1629,21 +1629,21 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, "垂直同步交換間隔") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_TAB, - "視頻") + "視訊") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, "多線程渲染") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, "降低閃爍") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "自定義視口高度") + "自定義畫面高度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "自定義視口寬度") + "自定義畫面寬度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, - "自定義視口X") + "自定義畫面X") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, - "自定義視口Y") + "自定義畫面Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "設置 VI 屏幕寬度") + "設定 VI 營幕寬度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, "垂直同步") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, @@ -1657,9 +1657,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, "Wi-Fi") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, - "菜單透明度因子") + "選單透明度因子") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_FONT, - "菜單字體") + "選單字體") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, "自定義") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, @@ -1677,7 +1677,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, "Dot-Art") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, - "菜單顏色主題") + "選單顏色主題") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, "蘋果綠") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, @@ -1699,9 +1699,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, "火山紅") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, - "菜單Shader管線") + "選單Shader管線") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, - "菜單縮放因子") + "選單縮放因子") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, "啟用圖標陰影") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_HISTORY, @@ -1713,11 +1713,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_IMAGES, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_MUSIC, "顯示音樂頁") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_SETTINGS, - "顯示設置頁") + "顯示設定頁") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_VIDEO, - "顯示視頻頁") + "顯示視訊頁") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_THEME, - "菜單圖標主題") + "選單圖標主題") MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, "是") MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, @@ -1729,69 +1729,69 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, "為所有遊戲打開或關閉存檔、金手指、回退、快進、暫停和慢動作。") MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "修改驅動設置。") + "修改驅動設定。") MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "修改成就設置。") + "修改成就設定。") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "修改核心設置。") + "修改核心設定。") MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "修改錄製的設置。") + "修改錄製的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "修改顯示覆蓋、鍵盤覆蓋和屏幕通知的設置。") + "修改顯示覆蓋、鍵盤覆蓋和營幕通知的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "修改回滾、快進和慢動作的設置。") + "修改回滾、快進和慢動作的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "修改存檔設置。") + "修改存檔設定。") MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "修改日誌設置。") + "修改日誌設定。") MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "修改用戶界面設置。") + "修改用戶界面設定。") MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, "修改帳號、用戶名和語言。") MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "修改你的隱私設置。") + "修改你的隱私設定。") MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, "修改此系統的默認目錄。") MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "修改遊戲列表設置。") + "修改遊戲列表設定。") MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, - "修改網絡設置。") + "修改網路設定。") MSG_HASH(MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, "下載且/或者掃瞄遊戲內容,並將其加入你的收藏中。") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "調整音頻輸出的選項。") + "調整聲音輸出的選項。") MSG_HASH(MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, "啟用或者禁止藍牙。") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "程序將在退出時保存修改到配置文件。") + "程序將在退出時儲存修改到設定文件。") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, - "修改配置文件的默認設置。") + "修改設定文件的默認設定。") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, - "管理和創建配置文件。") + "管理和創建設定文件。") MSG_HASH(MENU_ENUM_SUBLABEL_CPU_CORES, "CPU擁有的核心總數。") MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, - "在屏幕上顯示當前每秒的幀率。") + "在營幕上顯示當前每秒的幀率。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "配置熱鍵選項。") + "設定熱鍵選項。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "控制器用來切出菜單的組合鍵。") + "控制器用來切出選單的組合鍵。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "調整遊戲控制器、鍵盤和鼠標的設置。") + "調整遊戲控制器、鍵盤和鼠標的設定。") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, - "配置該用戶的控制選項。") + "設定該用戶的控制選項。") MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, "啟用或禁止向控制台打印日誌。") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, - "加入或者開啟一個在線多人遊戲的會話。") + "加入或者開啟一個連線多人遊戲的會話。") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, "在局域網內搜索並連接聯網遊戲的主機。") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "顯示核心、網絡和系統的信息。顯示數據庫和光標的管理器。") + "顯示核心、網路和系統的訊息。顯示數據庫和光標的管理器。") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "下載並更新RetroArch的附加插件和組件。") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, - "啟用或者禁止網絡文件夾共享(SAMBA)。") + "啟用或者禁止網路文件夾共享(SAMBA)。") MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, "管理操作系統層級的服務。") MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, @@ -1799,9 +1799,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, "啟用或者禁止遠程終端訪問(SSH)。") MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "阻止系統激活屏幕保護程序。") + "阻止系統激活營幕保護程序。") MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "設置用戶界面的語言。") + "設定用戶界面的語言。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, "在幀與幀之間插入黑色的中間幀,通常用於消除在\n" "120Hz刷新率的顯示器上運行60Hz的遊戲內容帶來\n" @@ -1810,7 +1810,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, "以增加畫面卡頓的風險換取低延時,在垂直同步後增加\n" "時延(毫秒)。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "設置當開啟「強制GPU同步」時CPU可以預先GPU多少幀。") + "設定當開啟「強制GPU同步」時CPU可以預先GPU多少幀。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "強制顯示驅動程序使用特定的緩衝模式。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, @@ -1818,9 +1818,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, "估算的顯示器刷新率(Hz)。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "調整視頻輸出的選項。") + "調整視訊輸出的選項。") MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, - "掃瞄無線網絡並且建立連接。") + "掃瞄無線網路並且建立連接。") MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, "學習更多關於其是如何工作的。") MSG_HASH(MSG_APPENDED_DISK, @@ -1828,27 +1828,27 @@ MSG_HASH(MSG_APPENDED_DISK, MSG_HASH(MSG_APPLICATION_DIR, "應用程序目錄") MSG_HASH(MSG_APPLYING_SHADER, - "Applying shader") + "載入 shader") MSG_HASH(MSG_AUDIO_MUTED, "靜音。") MSG_HASH(MSG_AUDIO_UNMUTED, "取消靜音。") MSG_HASH(MSG_AUTOCONFIG_FILE_ERROR_SAVING, - "保存 autoconf 文件錯誤。") + "儲存 autoconf 文件錯誤。") MSG_HASH(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, - "自動配置文件保存成功。") + "自動設定文件儲存成功。") MSG_HASH(MSG_AUTOSAVE_FAILED, - "無法初始化自動保存。") + "無法初始化自動儲存。") MSG_HASH(MSG_AUTO_SAVE_STATE_TO, - "自動保存狀態至") + "自動儲存狀態至") MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, "阻止 SRAM 覆蓋") MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, - "Bringing up command interface on port") + "啟用通訊埠上的指令介面") MSG_HASH(MSG_BYTES, "字節") MSG_HASH(MSG_CANNOT_INFER_NEW_CONFIG_PATH, - "無法推斷新的配置路徑,使用當前時間。") + "無法推斷新的設定路徑,使用當前時間。") MSG_HASH(MSG_CHEEVOS_HARDCORE_MODE_ENABLE, "硬核模式開啟:及時存檔和回放被禁用.") MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, @@ -1856,21 +1856,21 @@ MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, MSG_HASH(MSG_COMPILED_AGAINST_API, "Compiled against API") MSG_HASH(MSG_CONFIG_DIRECTORY_NOT_SET, - "未設置配置目錄,無法保存新的配置。") + "未設定設定目錄,無法儲存新的設定。") MSG_HASH(MSG_CONNECTED_TO, "連接至") MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, "內容的CRC32s不同。無法使用不同的遊戲。") MSG_HASH(MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, - "跳過內容加載。實現將自行加載。") + "跳過內容戴入。實現將自行戴入。") MSG_HASH(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "核心不支持保存狀態。") + "核心不支持儲存狀態。") MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, - "Core options file created successfully.") + "模擬器核心設定檔建立成功.") MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, - "Could not find any next driver") + "無法找到磁碟") MSG_HASH(MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, - "Could not find compatible system.") + "無法找到相容系統.") MSG_HASH(MSG_COULD_NOT_FIND_VALID_DATA_TRACK, "無法找到有效的數據軌") MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, @@ -1878,9 +1878,9 @@ MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, MSG_HASH(MSG_COULD_NOT_READ_CONTENT_FILE, "無法讀取內容文件") MSG_HASH(MSG_COULD_NOT_READ_MOVIE_HEADER, - "無法讀取視頻頭部信息.") + "無法讀取視訊頭部訊息.") MSG_HASH(MSG_COULD_NOT_READ_STATE_FROM_MOVIE, - "無法讀取視頻狀態.") + "無法讀取視訊狀態.") MSG_HASH(MSG_CRC32_CHECKSUM_MISMATCH, "CRC32 checksum mismatch between content file and saved content checksum in replay file header; replay highly likely to desync on playback.") MSG_HASH(MSG_CUSTOM_TIMING_GIVEN, @@ -1892,9 +1892,9 @@ MSG_HASH(MSG_DECOMPRESSION_FAILED, MSG_HASH(MSG_DETECTED_VIEWPORT_OF, "Detected viewport of") MSG_HASH(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, - "Did not find a valid content patch.") + "無法找到任何有效的內容位置.") MSG_HASH(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, - "Disconnect device from a valid port.") + "從連接埠離開.") MSG_HASH(MSG_DISK_CLOSED, "已關閉") MSG_HASH(MSG_DISK_EJECTED, @@ -1924,17 +1924,17 @@ MSG_HASH(MSG_EXTRACTING, MSG_HASH(MSG_EXTRACTING_FILE, "解壓文件") MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, - "無法保存配置到") + "無法儲存設定到") MSG_HASH(MSG_FAILED_TO, "Failed to") MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, - "Failed to accept incoming spectator.") + "無法讓觀眾加入.") MSG_HASH(MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, - "Failed to allocate memory for patched content...") + "無法配置記憶體給已俢改的遊戲") MSG_HASH(MSG_FAILED_TO_APPLY_SHADER, - "Failed to apply shader.") + "無法載入 shader.") MSG_HASH(MSG_FAILED_TO_BIND_SOCKET, - "Failed to bind socket.") + "無法連接通訊埠.") MSG_HASH(MSG_FAILED_TO_CREATE_THE_DIRECTORY, "創建目錄失敗。") MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, @@ -1942,37 +1942,37 @@ MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, MSG_HASH(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, "從客戶端獲取暱稱失敗.") MSG_HASH(MSG_FAILED_TO_LOAD, - "無法加載") + "無法戴入") MSG_HASH(MSG_FAILED_TO_LOAD_CONTENT, "載入內容失敗") MSG_HASH(MSG_FAILED_TO_LOAD_MOVIE_FILE, - "載入視頻文件失敗") + "載入視訊文件失敗") MSG_HASH(MSG_FAILED_TO_LOAD_OVERLAY, - "Failed to load overlay.") + "無法戴入 overlay.") MSG_HASH(MSG_FAILED_TO_LOAD_STATE, - "Failed to load state from") + "無法戴入 state ") MSG_HASH(MSG_FAILED_TO_OPEN_LIBRETRO_CORE, "打開libretro核心失敗") MSG_HASH(MSG_FAILED_TO_PATCH, "補丁應用失敗") MSG_HASH(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, - "Failed to receive header from client.") + "無法接收連線端的資訊") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME, - "Failed to receive nickname.") + "無法接收暱稱.") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, - "Failed to receive nickname from host.") + "無法接收主控端的暱稱.") MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, - "Failed to receive nickname size from host.") + "無法接收主控端的暱稱大小.") MSG_HASH(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, - "Failed to receive SRAM data from host.") + "無法接收主控端 SRAM 資料.") MSG_HASH(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, - "Failed to remove disk from tray.") + "移除光碟失敗.") MSG_HASH(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, "移除臨時文件失敗") MSG_HASH(MSG_FAILED_TO_SAVE_SRAM, - "Failed to save SRAM") + "SRAM 存檔失敗") MSG_HASH(MSG_FAILED_TO_SAVE_STATE_TO, - "Failed to save state to") + "即時存檔儲存失敗") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME, "發送暱稱失敗.") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, @@ -1980,17 +1980,17 @@ MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, "發送暱稱至客戶端失敗.") MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, - "發送暱稱至宿主端失敗.") + "發送暱稱至主控端失敗.") MSG_HASH(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, "發送SRAM數據至客戶端失敗.") MSG_HASH(MSG_FAILED_TO_START_AUDIO_DRIVER, - "音頻驅動啟動失敗,將在無音頻模式下繼續啟動。") + "聲音驅動啟動失敗,將在無聲音模式下繼續啟動。") MSG_HASH(MSG_FAILED_TO_START_MOVIE_RECORD, - "啟動視頻錄製失敗.") + "啟動視訊錄製失敗.") MSG_HASH(MSG_FAILED_TO_START_RECORDING, - "Failed to start recording.") + "建用錄製視訊失敗.") MSG_HASH(MSG_FAILED_TO_TAKE_SCREENSHOT, - "Failed to take screenshot.") + "營幕快照失敗.") MSG_HASH(MSG_FAILED_TO_UNDO_LOAD_STATE, "Failed to undo load state.") MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, @@ -2030,17 +2030,17 @@ MSG_HASH(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, MSG_HASH(MSG_INPUT_CHEAT, "輸入金手指") MSG_HASH(MSG_INPUT_CHEAT_FILENAME, - "Cheat Filename") + "金手指檔案") MSG_HASH(MSG_INPUT_PRESET_FILENAME, - "Preset Filename") + "目前檔案") MSG_HASH(MSG_INTERFACE, "接口") MSG_HASH(MSG_INTERNAL_STORAGE, "內部存儲") MSG_HASH(MSG_REMOVABLE_STORAGE, - "Removable Storage") + "可移除的儲存空間") MSG_HASH(MSG_INVALID_NICKNAME_SIZE, - "Invalid nickname size.") + "不合法暱稱大小.") MSG_HASH(MSG_IN_BYTES, "(字節)") MSG_HASH(MSG_IN_GIGABYTES, @@ -2052,15 +2052,15 @@ MSG_HASH(MSG_LIBRETRO_ABI_BREAK, MSG_HASH(MSG_LIBRETRO_FRONTEND, "為libretro而設計的前端") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, - "加載狀態從槽 #%d.") + "戴入狀態從槽 #%d.") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, - "加載狀態從槽 #-1 (auto).") + "戴入狀態從槽 #-1 (auto).") MSG_HASH(MSG_LOADING, - "正在加載") + "正在戴入") MSG_HASH(MSG_FIRMWARE, "一個或多個固件文件丟失") MSG_HASH(MSG_LOADING_CONTENT_FILE, - "正在加載內容文件") + "正在戴入內容文件") MSG_HASH(MSG_LOADING_HISTORY_FILE, "正在讀取歷史文件") MSG_HASH(MSG_LOADING_STATE, @@ -2068,25 +2068,25 @@ MSG_HASH(MSG_LOADING_STATE, MSG_HASH(MSG_MEMORY, "內存") MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, - "視頻不是有效的BSV1文件。") + "視訊不是有效的BSV1文件。") MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, - "視頻格式看起來使用了不同的序列化版本。很有可能失敗。") + "視訊格式看起來使用了不同的序列化版本。很有可能失敗。") MSG_HASH(MSG_MOVIE_PLAYBACK_ENDED, - "視頻回放結束.") + "視訊回放結束.") MSG_HASH(MSG_MOVIE_RECORD_STOPPED, - "停止視頻錄製。") + "停止視訊錄製。") MSG_HASH(MSG_NETPLAY_FAILED, - "初始化聯機遊戲失敗。") + "初始化連線遊戲失敗。") MSG_HASH(MSG_NO_CONTENT_STARTING_DUMMY_CORE, "沒有內容,啟動虛擬核心。") MSG_HASH(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, "未覆蓋任何存檔。") MSG_HASH(MSG_NO_STATE_HAS_BEEN_LOADED_YET, - "沒有加載任何存檔。") + "沒有戴入任何存檔。") MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, - "保存覆蓋錯誤。") + "儲存覆蓋錯誤。") MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, - "覆蓋保存成功。") + "覆蓋儲存成功。") MSG_HASH(MSG_PAUSED, "暫停。") MSG_HASH(MSG_PROGRAM, @@ -2134,15 +2134,15 @@ MSG_HASH(MSG_REWIND_INIT_FAILED_THREADED_AUDIO, MSG_HASH(MSG_REWIND_REACHED_END, "到達回放緩存末端.") MSG_HASH(MSG_SAVED_NEW_CONFIG_TO, - "已保存新配置到") + "已儲存新設定到") MSG_HASH(MSG_SAVED_STATE_TO_SLOT, - "保存狀態至槽 #%d.") + "儲存狀態至槽 #%d.") MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, - "保存狀態至槽 #-1 (auto).") + "儲存狀態至槽 #-1 (auto).") MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, - "成功保存至") + "成功儲存至") MSG_HASH(MSG_SAVING_RAM_TYPE, - "保存 RAM 類型") + "儲存 RAM 類型") MSG_HASH(MSG_SAVING_STATE, "存檔中") MSG_HASH(MSG_SCANNING, @@ -2158,19 +2158,19 @@ MSG_HASH(MSG_SHADER, MSG_HASH(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, "Shader preset saved successfully.") MSG_HASH(MSG_SKIPPING_SRAM_LOAD, - "跳過 SRAM 加載。") + "跳過 SRAM 戴入。") MSG_HASH(MSG_SLOW_MOTION, "慢動作。") MSG_HASH(MSG_SLOW_MOTION_REWIND, "慢動作回溯。") MSG_HASH(MSG_SRAM_WILL_NOT_BE_SAVED, - "SRAM will not be saved.") + "SRAM 將不會被儲存.") MSG_HASH(MSG_STARTING_MOVIE_PLAYBACK, - "視頻回放.") + "視訊回放.") MSG_HASH(MSG_STARTING_MOVIE_RECORD_TO, "Starting movie record to") MSG_HASH(MSG_STATE_SIZE, - "State size") + "即時存檔大小") MSG_HASH(MSG_STATE_SLOT, "狀態存檔槽") MSG_HASH(MSG_TAKING_SCREENSHOT, @@ -2178,7 +2178,7 @@ MSG_HASH(MSG_TAKING_SCREENSHOT, MSG_HASH(MSG_TO, "到") MSG_HASH(MSG_UNDID_LOAD_STATE, - "已撤銷加載狀態。") + "已撤銷戴入狀態。") MSG_HASH(MSG_UNDOING_SAVE_STATE, "撤銷即時存檔") MSG_HASH(MSG_UNKNOWN, @@ -2223,7 +2223,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, - "Maximum amount of users supported by RetroArch." + "RetroArch 最大遊戲支援人數" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, @@ -2231,15 +2231,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Allows any user to control the menu. If disabled, only User 1 can control the menu." + "允許任何使用者去控制選單,如果取消,將只會有1個人可以控制選單." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Audio volume (in dB). 0 dB is normal volume, no gain applied." + "音量大小 (in dB). 0 dB 是標準大小." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "同步音頻。推薦。" + "同步聲音。推薦。" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, @@ -2259,7 +2259,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "同步顯卡的視頻輸出到屏幕刷新率。推薦。" + "同步顯卡的視訊輸出到營幕刷新率。推薦。" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, @@ -2271,7 +2271,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, - "Check if all the required firmware is present before attempting to load content." + "載入遊戲前檢查必要的韌體/BIOS是否存在." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, @@ -2279,7 +2279,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_ENABLE, - "啟用音頻輸出。" + "啟用聲音輸出。" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, @@ -2295,11 +2295,11 @@ MSG_HASH( ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, - "未配置" + "未設定" ) MSG_HASH( MSG_DEVICE_NOT_CONFIGURED_FALLBACK, - "not configured, using fallback" + "未設定,將使用內定值" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, @@ -2351,29 +2351,29 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, "數據庫 - 過濾器 : Edge Magazine Rating") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, - "數據庫信息") + "數據庫訊息") MSG_HASH(MSG_WIFI_SCAN_COMPLETE, "Wi-Fi 掃瞄完成。") MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS, - "掃瞄無線網絡...") + "掃瞄無線網路...") MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, - "聯機遊戲主機掃瞄完成。") + "連線遊戲主機掃瞄完成。") MSG_HASH(MSG_NETPLAY_LAN_SCANNING, - "掃瞄聯機遊戲主機...") + "掃瞄連線遊戲主機...") MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, "當窗口失去焦點時暫停遊戲。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, "Enable or disable composition (Windows only).") MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, - "為遊戲、圖片、音樂和視頻啟用/禁用歷史記錄。") + "為遊戲、圖片、音樂和視訊啟用/禁用歷史記錄。") MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, - "遊戲、圖片、音樂和視頻歷史記錄的數量限制。") + "遊戲、圖片、音樂和視訊歷史記錄的數量限制。") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, - "統一菜單控制") + "統一選單控制") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, "Use the same controls for both the menu and the game. Applies to the keyboard.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "顯示屏幕消息。") + "顯示營幕消息。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, "用戶 %d 遠程允許") MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, @@ -2387,9 +2387,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, "刻度") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "聯機遊戲將在內容加載後開始。") + "連線遊戲將在內容戴入後開始。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, - "無法找到合適的核心或內容文件,手動加載。") + "無法找到合適的核心或內容文件,手動戴入。") MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, "瀏覽URL" @@ -2405,13 +2405,13 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, "Bokeh") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Refresh Room List") + "更新 Room 列表") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, - "Nickname: %s") + "暱稱: %s") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, - "Nickname (lan): %s") + "暱稱 (lan): %s") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, - "Compatible content found") + "找到相容遊戲") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, "Cuts off a few pixels around the edges of the image customarily left blank by developers which sometimes also contain garbage pixels.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, @@ -2419,9 +2419,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, "Apply a CPU-powered video filter. NOTE: Might come at a high performance cost. Some video filters might only work for cores that use 32bit or 16bit color.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, - "Input the username of your Retro Achievements account.") + "輸入Retro Achievements 的帳號.") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, - "Input the password of your Retro Achievements account.") + "輸入Retro Achievements 的密碼.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, "Input your user name here. This will be used for netplay sessions, among other things.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, @@ -2435,7 +2435,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, "Show information specific to the device.") MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, - "Quit the program.") + "離開程式.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, "Set the custom width size for the display window. Leaving it at 0 will attempt to scale the window as large as possible.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, diff --git a/intl/msg_hash_eo.h b/intl/msg_hash_eo.h index 89c6b8208c..58d85f3d4e 100644 --- a/intl/msg_hash_eo.h +++ b/intl/msg_hash_eo.h @@ -860,6 +860,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "Menu File Browser") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Menu Linear Filter") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Horizontal Animation") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, "Menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 0f363da56f..8417b5701c 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -159,7 +159,7 @@ MSG_HASH( "Password" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Obiettivi dell'account") + "Accounts Cheevos") MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, "Nome utente") MSG_HASH( @@ -181,7 +181,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, "Carica Configurazione") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TAB, - "Aggiungi scheda") + "Scansione/Aggiungi directory") MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, "Stanze Netplay " @@ -211,7 +211,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, "Variazione massima di sincronia dell'audio") MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "Silenzia audio") + "Disattiva audio") MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, "Frequenza audio di output (Hz)") MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, @@ -462,7 +462,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DONT_CARE, MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, "Scarica sulle directories") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, - "Download Core...") + "Scarica Core...") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, "Scarica contenuto") MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, @@ -523,13 +523,13 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, "Abilita cronologia") MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_TAB, - "Cronologia scheda") + "Cronologia") MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, "Menú orizzontale") MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, - "Image") + "Immagini") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION, - "Information") + "Informazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, "Informazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, @@ -621,7 +621,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, "Pulsante Y (sinistra)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, - "(Key: %s)") + "(Tasto: %s)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, "Tipologia di mappatura gamepad tastiera") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, @@ -863,7 +863,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, "Connetti alla rete ospite") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Comincia ad ospitare") + "Avvia host netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST, "Stop netplay host") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, @@ -1119,9 +1119,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, "Cataloga automaticamente gli stati di salvataggio") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "Carica automaticamente gli stati di salvataggio") + "Carica automaticamente i salvataggi") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "Salva stato automaticamente") + "Salva stato automatico") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, "Directory degli stati di salvataggio") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, @@ -1139,11 +1139,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, "Salvataggi") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, - "Scansiona directory") + "Scansione delle directory") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, "Scansione dei file") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, - "") + "") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, "Directory delle screenshot") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, @@ -1155,7 +1155,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SECONDS, MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS, "Settaggi") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, - "Settaggi scheda") + "Impostazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER, "Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, @@ -1663,9 +1663,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, "Cerca e connetti all' host netplay sulla rete locale.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Visualizzare le informazioni dei core, di rete e di sistema.") + "Visualizza le informazioni dei core, di rete e di sistema.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Scarica i componenti aggiuntivi, i componenti e il contenuto di RetroArch.") + "Scarica i componenti aggiuntivi e il contenuto di RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, "Attiva o disattiva la condivisione di rete delle cartelle.") MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, @@ -1685,11 +1685,11 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, "Riduce la latenza a costo di un più alto rischio di stuttering video. Aggiunge un ritardo dopo V-Sync (in ms).") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "Sets how many frames the CPU can run ahead of the GPU when using 'Hard GPU Sync'.") + "Imposta quanti frame la CPU può eseguire dinanzi alla GPU quando utilizza 'Hard GPU Sync'.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, "Indica al driver video di utilizzare esplicitamente una modalità di buffering specifica.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, - "Seleziona quale schermo da utilizzare.") + "Seleziona lo schermo da utilizzare.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, "La stima precisa di aggiornamento dello schermo in Hz.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, @@ -1719,7 +1719,7 @@ MSG_HASH(MSG_AUTOSAVE_FAILED, MSG_HASH(MSG_AUTO_SAVE_STATE_TO, "Auto save state to") MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, - "Bloccare SRAM Overwrite") + "Bloccare la sovrascrittura della SRAM") MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, "Bringing up command interface on port") MSG_HASH(MSG_BYTES, @@ -1741,7 +1741,7 @@ MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, MSG_HASH(MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, "Content loading skipped. Implementation will load it on its own.") MSG_HASH(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, - "Core does not support save states.") + "Il Core non supporta gli salva stati.") MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, "Il file delle opzioni dei core è stato creato correttamente.") MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, @@ -1771,7 +1771,7 @@ MSG_HASH(MSG_DETECTED_VIEWPORT_OF, MSG_HASH(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, "Did not find a valid content patch.") MSG_HASH(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, - "Disconnect device from a valid port.") + "Scollegare il dispositivo da una porta valida.") MSG_HASH(MSG_DISK_CLOSED, "Chiuso") MSG_HASH(MSG_DISK_EJECTED, @@ -1861,13 +1861,13 @@ MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, MSG_HASH(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, "Failed to send SRAM data to client.") MSG_HASH(MSG_FAILED_TO_START_AUDIO_DRIVER, - "Failed to start audio driver. Will continue without audio.") + "Impossibile avviare il driver audio. Continuerà senza audio.") MSG_HASH(MSG_FAILED_TO_START_MOVIE_RECORD, - "Failed to start movie record.") + "Impossibile avviare una registrazione di un filmato.") MSG_HASH(MSG_FAILED_TO_START_RECORDING, - "Failed to start recording.") + "Impossibile avviare la registrazione.") MSG_HASH(MSG_FAILED_TO_TAKE_SCREENSHOT, - "Failed to take screenshot.") + "Impossibile eseguire lo screenshot.") MSG_HASH(MSG_FAILED_TO_UNDO_LOAD_STATE, "Failed to undo load state.") MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, @@ -1875,7 +1875,7 @@ MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, MSG_HASH(MSG_FAILED_TO_UNMUTE_AUDIO, "Failed to unmute audio.") MSG_HASH(MSG_FATAL_ERROR_RECEIVED_IN, - "Fatal error received in") + "Errore irreversibile ricevuto su") MSG_HASH(MSG_FILE_NOT_FOUND, "File non trovato") MSG_HASH(MSG_FOUND_AUTO_SAVESTATE_IN, @@ -1915,7 +1915,7 @@ MSG_HASH(MSG_INTERFACE, MSG_HASH(MSG_INTERNAL_STORAGE, "Memoria interna") MSG_HASH(MSG_REMOVABLE_STORAGE, - "Removable Storage") + "Dispositivi di memoria rimovibili") MSG_HASH(MSG_INVALID_NICKNAME_SIZE, "Dimensione del nickname non valido.") MSG_HASH(MSG_IN_BYTES, @@ -1935,7 +1935,7 @@ MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, MSG_HASH(MSG_LOADING, "Caricamento") MSG_HASH(MSG_FIRMWARE, - "One or more firmware files are missing") + "Uno o più file del firmware sono mancanti") MSG_HASH(MSG_LOADING_CONTENT_FILE, "Loading content file") MSG_HASH(MSG_LOADING_HISTORY_FILE, @@ -2017,7 +2017,7 @@ MSG_HASH(MSG_SAVED_STATE_TO_SLOT, MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, "Saved state to slot #-1 (auto).") MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, - "Saved successfully to") + "Salvato con successo su") MSG_HASH(MSG_SAVING_RAM_TYPE, "Saving RAM type") MSG_HASH(MSG_SAVING_STATE, @@ -2051,7 +2051,7 @@ MSG_HASH(MSG_STATE_SIZE, MSG_HASH(MSG_STATE_SLOT, "State slot") MSG_HASH(MSG_TAKING_SCREENSHOT, - "Taking screenshot.") + "Cattura screenshot.") MSG_HASH(MSG_TO, "to") MSG_HASH(MSG_UNDID_LOAD_STATE, @@ -2065,7 +2065,7 @@ MSG_HASH(MSG_UNPAUSED, MSG_HASH(MSG_UNRECOGNIZED_COMMAND, "Unrecognized command") MSG_HASH(MSG_USING_CORE_NAME_FOR_NEW_CONFIG, - "Using core name for new config.") + "Utilizzo del core di base per la nuova configurazione.") MSG_HASH(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, "Using libretro dummy core. Skipping recording.") MSG_HASH(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, @@ -2083,9 +2083,9 @@ MSG_HASH(MSG_VIEWPORT_SIZE_CALCULATION_FAILED, MSG_HASH(MSG_VIRTUAL_DISK_TRAY, "virtual disk tray.") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_LATENCY, - "Desired audio latency in milliseconds. Might not be honored if the audio driver can't provide given latency.") + "Latenza audio desiderata in millisecondi. Non può essere onorato se il driver audio non è in grado di fornire una data latenza.") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Audio Muto/non Muto .") + "Disattiva/Attiva Audio.") MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, "Helps smooth out imperfections in timing when synchronizing audio and video at the same time. Be aware that if disabled, proper synchronization is nearly impossible to obtain." @@ -2104,7 +2104,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, - "Influence how input polling is done inside RetroArch. Setting it to 'Early' or 'Late' can result in less latency, depending on your configuration." + "Influisce come il polling degli input che viene fatto all'interno di RetroArch. L'impostazione 'Early' o 'Late' può causare una minore latenza, a seconda della configurazione." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, @@ -2112,7 +2112,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Audio volume (in dB). 0 dB è un volume normale , nessun guadagno applicato." + "Volume audio (in dB). 0 dB è un volume normale , nessun guadagno applicato." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, @@ -2120,7 +2120,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, - "How far an axis must be tilted to result in a button press." + "Quanto deve essere inclinato un asse durante la pressione di un pulsante." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, @@ -2136,7 +2136,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "Synchronizes the output video of the graphics card to the refresh rate of the screen. Recommended." + "Sincronizza il video di uscita della scheda grafica alla frequenza di aggiornamento dello schermo. Consigliato." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, @@ -2150,10 +2150,8 @@ MSG_HASH( MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, "Check if all the required firmware is present before attempting to load content." ) -MSG_HASH( - MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, - "Vertical refresh rate of your screen. Used to calculate a suitable audio input rate. NOTE: This will be ignored if 'Threaded Video' is enabled." - ) +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, + "Frequenza di aggiornamento verticale dello schermo. Utilizzato per calcolare un'adeguata frequenza di ingresso audio. NOTA: questa verrà ignorata se è abilitato 'Threaded Video'.") MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_ENABLE, "Abilita audio output." @@ -2184,11 +2182,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, - "Database - Filter : Developer" + "Database - Filtro : Developer" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, - "Database - Filter : Publisher" + "Database - Filtro : Publisher" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_DISABLED, "Disattivato") @@ -2246,7 +2244,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, "Unified Menu Controls") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, - "Use the same controls for both the menu and the game. Applies to the keyboard.") + "Utilizzare gli stessi controlli sia per il menu che per il gioco. Si applica alla tastiera.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, "Show onscreen messages.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, @@ -2275,7 +2273,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_START, - "Start" + "Avvia" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, "Bokeh") @@ -2287,27 +2285,117 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME_LAN, "Nickname (lan): %s") MSG_HASH( MSG_AUDIO_MIXER_VOLUME, - "Global audio mixer volume" + "Volume globale del mixer audio" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, - "Global audio mixer volume (in dB). 0 dB is normal volume, and no gain is applied." + "Volume globale del mixer audio(in dB). 0 dB è il volume normale e non viene applicato alcun guadagno." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, - "Audio Mixer Volume Level (dB)" + "Livello del Volume del mixer audio (dB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Audio Mixer Mute" + "Disattiva Mixer Audio" ) MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Mute/unmute mixer audio.") + "Attiva/disattiva Mixer audio.") MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, - "Show Online Updater") + "Visualizza Online Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, - "Show/hide the 'Online Updater' option.") + "Visualizza/Nascondi l'opzione 'Online Updater'.") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, - "Show Core Updater") + "Visualizza Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, - "Show/hide the ability to update cores (and core info files).") + "Visualizza/Nascondi l'abilità di aggiornare i core (e i file di informazione dei core).") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_LIST, + "Seleziona quale core utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, + "Seleziona quale contenuto avviare.") +MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, + "Permette di uscire dal programma.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_DRIVER, + "Driver di input da utilizzare. A seconda del driver video, potrebbe forzare un diverso driver di input.") +MSG_HASH(MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "I driver del Joypad da utilizzare") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DRIVER, + "I driver video da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_DRIVER, + "I driver audio da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, + "I driver di riprogrammazione audio da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_CAMERA_DRIVER, + "I driver della fotocamera da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_LOCATION_DRIVER, + "Posizione dei driver da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_DRIVER, + "I driver del menu da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_RECORD_DRIVER, + "I driver per la registrazione da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_DRIVER, + "I driver WiFi da utilizzare.") +MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, + "Effettua la scansione di una directory per i file compatibili e li aggiunge alla raccolta.") +MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_FILE, + "Esegue la scansione di un file compatibile e li aggiunge alla raccolta.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, + "Mostra le interfacce di rete e gli indirizzi IP associati.") +MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, + "Mostra le informazioni specifiche del dispositivo.") +MSG_HASH(MENU_ENUM_SUBLABEL_DATABASE_MANAGER, + "Visualizza i database.") +MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_MANAGER, + "Visualizza le ricerche precedenti") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, + "Avvia a schermo intero. Può essere modificato in fase di runtime.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, + "Se è a schermo intero e si preferisce utilizzare una modalità a schermo intero a finestre.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Offset di visualizzazione personalizzata utilizzata per definire la posizione dell'asse X di visualizzazione. Queste vengono ignorate se è abilitata l'opzione 'Integer Scale' e sarà centrata automaticamente.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Offset di visualizzazione personalizzata utilizzata per definire la posizione dell'asse Y di visualizzazione. Queste vengono ignorate se è abilitata l'opzione 'Integer Scale' e sarà centrata automaticamente.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Altezza di visualizzazione personalizzata utilizzata se l'Aspect Ratio è impostato su 'Custom'.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Larghezza di visualizzazione personalizzata utilizzata se l'Aspect Ratio è impostato su 'Custom'.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Permette di scalare solo il video in intero. La dimensione base dipende dalla geometria e dall' Aspect Ratio riportati dal sistema. Se non è impostata l'opzione Force Aspect, X / Y sarà scalato indipendentemente.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, + "Abilita il Netplay in modalità host (server).") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, + "Abilita il netplay in modalità client.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, + "Effettua la scansione di nuove stanze di gioco.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, + "Utilizza un intervallo di swap personalizzato per Vsync. Impostare questo per dimezzare efficacemente la frequenza di aggiornamento del monitor.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, + "Taglia alcuni pixel intorno ai bordi dell'immagine generalmente lasciati vuoti dagli sviluppatori che a volte contengono anche i pixel che non vengono utilizzati.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, + "Aggiunge una leggera sfocatura dell'immagine per togliere il bordo del pixel. Questa opzione ha un piccolo impatto sulle prestazioni.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, + "Applica un filtro video aumentando la potenza della CPU. NOTA: Potrebbe avere un costo sul rendimento. Alcuni filtri video potrebbero funzionare solo per i core che utilizzano un colore a 32 bit o 16 bit.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_DEVICE, + "Sovrascrive il dispositivo audio predefinito utilizzato dal driver audio. Questo è dipendente dal driver.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, + "Audio plugin DSP che elabora l'audio prima di essere inviato al driver.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, + "Scambia i pulsanti OK / Annulla. Disabilitato è l'orientamento del pulsanti per gli utenti giapponesi, abilitato è l'orientamento occidentale.") +MSG_HASH(MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, + "Blocca il Salvataggio della RAM alla sovrascrittura durante il caricamento degli salva stato. Potenzialmente può portare a buggare giochi.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, + "Salva automaticamente la memoria RAM non volatile ad un intervallo regolare. Questa impostazione è disabilitata per impostazione predefinita, L'intervallo è misurato in secondi. Un valore 0 disabilita l'auto-salvataggio.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, + "Quando si effettua un salvataggio, viene salvato automaticamente l'indice di stato di un salvataggio prima di essere salvato. Quando carichi il contenuto, l'indice sarà impostato sull'indice più alto esistente.") + MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Esegue automaticamente un salvataggio alla fine del runtime di RetroArch. RetroArch caricherà automaticamente questo salvataggio se è abilitato 'Carica automaticamente i Salvataggi'.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, + "Carica automaticamente i salvataggi all'avvio.") +MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, + "Qui vengono visualizzati i contenuti scansionati.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Regola le impostazioni del filebrowser.") +MSG_HASH(MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Filtra i file visualizzati nel filebrowser con estensioni supportate.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, + "Filtra per core corrente") diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 254a5a89f3..e56ffe5f8a 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -479,6 +479,10 @@ MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_ENABLE, "input_overlay_enable") MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU, "overlay_hide_in_menu") +MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "overlay_show_physical_inputs") +MSG_HASH(MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "overlay_show_physical_inputs_port") MSG_HASH(MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE, "input_player%u_analog_dpad_mode") MSG_HASH(MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR, @@ -581,6 +585,8 @@ MSG_HASH(MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, "menu_file_browser_settings") MSG_HASH(MENU_ENUM_LABEL_MENU_LINEAR_FILTER, "menu_linear_filter") +MSG_HASH(MENU_ENUM_LABEL_MENU_HORIZONTAL_ANIMATION, + "menu_horizontal_animation") MSG_HASH(MENU_ENUM_LABEL_MENU_SETTINGS, "menu_settings") MSG_HASH(MENU_ENUM_LABEL_MENU_WALLPAPER, @@ -821,6 +827,10 @@ MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE, "remap_file_save_core") MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME, "remap_file_save_game") +MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE, + "remap_file_remove_core") +MSG_HASH(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME, + "remap_file_remove_game") MSG_HASH(MENU_ENUM_LABEL_RESTART_CONTENT, "restart_content") MSG_HASH(MENU_ENUM_LABEL_RESTART_RETROARCH, @@ -911,6 +921,14 @@ MSG_HASH(MENU_ENUM_LABEL_SORT_SAVEFILES_ENABLE, "sort_savefiles_enable") MSG_HASH(MENU_ENUM_LABEL_SORT_SAVESTATES_ENABLE, "sort_savestates_enable") +MSG_HASH(MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "savefiles_in_content_dir_enable") +MSG_HASH(MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "savestates_in_content_dir_enable") +MSG_HASH(MENU_ENUM_LABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "systemfiles_in_content_dir_enable") +MSG_HASH(MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "screenshots_in_content_dir_enable") MSG_HASH(MENU_ENUM_LABEL_SSH_ENABLE, "ssh_enable") MSG_HASH(MENU_ENUM_LABEL_START_CORE, diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index d33f317605..c6de568cab 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -4,15 +4,15 @@ MSG_HASH( ) MSG_HASH( MSG_UNKNOWN_COMPILER, - "Unknown compiler" + "Onbekende compiler" ) MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT, - "Device disconnected from port" + "Apparaat ontkoppeld van poprt" ) MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "Unknown netplay command received" + "Onbekend netplay commando ontvangen" ) MSG_HASH( MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, @@ -56,15 +56,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "Improves performance at the cost of latency and more video stuttering. Use only if you cannot obtain full speed otherwise." + "Verbetert prestaties ten kosten van latentie en meer video stotteringen. Gebruik dit enkel als het niet mogelijk is om full speed te bereiken zonder dit te activeren." ) MSG_HASH( MSG_AUDIO_VOLUME, - "Audio volume" + "Geluidsvolume" ) MSG_HASH( MSG_AUTODETECT, - "Autodetect" + "Autodetecteren" ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FROM, @@ -76,11 +76,11 @@ MSG_HASH( ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "Connecting to netplay host" + "Verbinden met netplay host" ) MSG_HASH( MSG_CONNECTING_TO_PORT, - "Connecting to port" + "Verbinding maken met port" ) MSG_HASH( MSG_CONNECTION_SLOT, @@ -116,12 +116,12 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Achievement List" + "Achievements Lijst" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Achievement List (Hardcore)" + "Achievements Lijst (Hardcore)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, @@ -261,11 +261,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "Basic menu controls" + "Basis menu besturing" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, - "Confirm/OK" + "Bevestigen/OK" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, @@ -273,11 +273,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, - "Quit" + "Afsluiten" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Scroll Up" + "Omhoog scrollen" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, @@ -297,7 +297,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Bluetooth Enable" + "Bluetooth Activeren" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, @@ -329,11 +329,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE, - "Cheat File" + "Cheat Bestand" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Load Cheat File" + "Laad Cheat Bestand" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, @@ -365,7 +365,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - "Test Unofficial Achievements" + "Test Onofficiele Achievements" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, @@ -519,7 +519,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, "Dynamische Wallpapers") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Achievements Aciveren") + "Achievements Activeren") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, "Menu entry hover kleur") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, @@ -627,37 +627,37 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, "Keyboard Gamepad Mapping Enable") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, - "A button (right)") + "A knop (right)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, - "B button (down)") + "B knop (down)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, "Down D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, - "L2 button (trigger)") + "L2 knop (trigger)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, - "L3 button (thumb)") + "L3 knop (thumb)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, - "L button (shoulder)") + "L knop (shoulder)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, "Left D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, - "R2 button (trigger)") + "R2 knop (trigger)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, - "R3 button (thumb)") + "R3 knop (thumb)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, - "R button (shoulder)") + "R knop (shoulder)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, "Right D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, - "Select button") + "Select knop") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, - "Start button") + "Start knop") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, "Up D-pad") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, - "X button (top)") + "X knop (top)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, - "Y button (left)") + "Y knop (left)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, "(Key: %s)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, @@ -1667,7 +1667,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, "Configure hotkey settings.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Gamepad button combination to toggle menu.") + "Gamepad knoppencombination to toggle menu.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, "Adjusts settings for joypads, keyboard and mouse.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, @@ -1693,7 +1693,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, "Sets the window size relative to the core viewport size. Alternatively you can set a window width and height below for a fixed window size") MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "Sets the language of the interface.") + "Stel de taal in van de gebruikersinterface.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, "Inserts a black frame inbetween frames. Useful for users of 120 Hz screens who want to play 60 Hz material with eliminated ghosting.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, @@ -1793,7 +1793,7 @@ MSG_HASH(MSG_DISK_EJECTED, MSG_HASH(MSG_DOWNLOADING, "Downloading") MSG_HASH(MSG_DOWNLOAD_FAILED, - "Download failed") + "Download mislukt") MSG_HASH(MSG_ERROR, "Error") MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, @@ -1805,17 +1805,17 @@ MSG_HASH(MSG_ERROR_PARSING_ARGUMENTS, MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, "Error saving core options file.") MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, - "Error saving remap file.") + "Fout is opgetreden tijdens het opslaan van remap bestand.") MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, - "Error saving shader preset.") + "Fout is opgetreden tijdens het opslaan van shader preset.") MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, - "External Application Dir") + "Externe Applicatie Dir") MSG_HASH(MSG_EXTRACTING, - "Extracting") + "Uitpakken") MSG_HASH(MSG_EXTRACTING_FILE, - "Extracting file") + "Uitpakken van bestand") MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, - "Failed saving config to") + "Fout is opgetrijdens tijdens het opslaan van configuratie naar ") MSG_HASH(MSG_FAILED_TO, "Failed to") MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, @@ -1937,11 +1937,11 @@ MSG_HASH(MSG_IN_MEGABYTES, MSG_HASH(MSG_LIBRETRO_ABI_BREAK, "is compiled against a different version of libretro than this libretro implementation.") MSG_HASH(MSG_LIBRETRO_FRONTEND, - "Frontend for libretro") + "Frontend voor libretro") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, - "Loaded state from slot #%d.") + "State geladen van slot #%d.") MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, - "Loaded state from slot #-1 (auto).") + "State geladen van slot #-1 (auto).") MSG_HASH(MSG_LOADING, "Laden") MSG_HASH(MSG_FIRMWARE, @@ -1953,7 +1953,7 @@ MSG_HASH(MSG_LOADING_HISTORY_FILE, MSG_HASH(MSG_LOADING_STATE, "Loading state") MSG_HASH(MSG_MEMORY, - "Memory") + "Geheugen") MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, "Movie file is not a valid BSV1 file.") MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, @@ -1975,13 +1975,13 @@ MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, "Overrides saved successfully.") MSG_HASH(MSG_PAUSED, - "Paused.") + "Gepauzeerd.") MSG_HASH(MSG_PROGRAM, "RetroArch") MSG_HASH(MSG_READING_FIRST_DATA_TRACK, "Reading first data track...") MSG_HASH(MSG_RECEIVED, - "received") + "ontvangen") MSG_HASH(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, "Recording terminated due to resize.") MSG_HASH(MSG_RECORDING_TO, @@ -2753,10 +2753,10 @@ MSG_HASH( "If set to a directory, content which is temporarily extracted (e.g. from archives) will be extracted to this directory." ) MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, - "Saved queries are stored to this directory.") + "Bewaarde queries worden in deze directory opgeslagen.") MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, - "Databases are stored to this directory." + "Databases worden in deze directory opgeslagen." ) MSG_HASH( MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, @@ -2837,22 +2837,22 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, "Custom viewport offset used for defining the Y-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_USE_MITM_SERVER, - "Use Relay Server") + "Gebruik Relay Server") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER, "Forward netplay connections through a man-in-the-middle server. Useful if the host is behind a firewall or has NAT/UPnP problems.") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER, - "Add to mixer") + "Aan audio mixer toevoegen") MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION, - "Add to mixer") + "Aan audio mixer toevoegen") MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER_BY_CURRENT_CORE, "Filter by current core") MSG_HASH( MSG_AUDIO_MIXER_VOLUME, - "Global audio mixer volume" + "Globale volume voor audio mixer" ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME, - "Global audio mixer volume (in dB). 0 dB is normal volume, and no gain is applied." + "Globale volume voor audio mixer (in dB uitgedrukt). 0 dB is het normale geluidsniveau." ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, @@ -2865,7 +2865,7 @@ MSG_HASH( MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, "Mute/unmute mixer audio.") MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, - "Show Online Updater") + "Online Updater Weergeven") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, "Show/hide the 'Online Updater' option.") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index b31278748b..5dded686d6 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -575,6 +575,16 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) { "Hide the current overlay from appearing \n" "inside the menu."); break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS: + snprintf(s, len, + "Show keyboard/controller button presses on \n" + "the onscreen overlay."); + break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT: + snprintf(s, len, + "Select the port to listen for controller input \n" + "to display on the onscreen overlay."); + break; case MENU_ENUM_LABEL_OVERLAY_PRESET: snprintf(s, len, "Path to input overlay."); diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 92be732417..c5118e44a2 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -827,6 +827,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, "Display Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, "Hide Overlay In Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Show Inputs On Overlay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Show Inputs Listen Port") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, "Poll Type Behavior") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, @@ -953,6 +957,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "Settings") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, "Menu Linear Filter") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + "Horizontal Animation") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, "Menu") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, @@ -1217,6 +1223,10 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, "Save Core Remap File") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, "Save Game Remap File") +MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE, + "Delete Core Remap File") +MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME, + "Delete Game Remap File") MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, "Required") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -1325,6 +1335,14 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, "Sort Saves In Folders") MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, "Sort Savestates In Folders") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE, + "Write Savestates to Content Dir") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE, + "Write Saves to Content Dir") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + "System Files are in Content Dir") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + "Write Screenshots to Content Dir") MSG_HASH(MENU_ENUM_LABEL_VALUE_SSH_ENABLE, "SSH Enable") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, @@ -1947,6 +1965,8 @@ MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, "Error saving core options file.") MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, "Error saving remap file.") +MSG_HASH(MSG_ERROR_REMOVING_REMAP_FILE, + "Error removing remap file.") MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, "Error saving shader preset.") MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, @@ -2139,6 +2159,8 @@ MSG_HASH(MSG_REDIRECTING_SAVESTATE_TO, "Redirecting savestate to") MSG_HASH(MSG_REMAP_FILE_SAVED_SUCCESSFULLY, "Remap file saved successfully.") +MSG_HASH(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, + "Remap file removed successfully.") MSG_HASH(MSG_REMOVED_DISK_FROM_TRAY, "Removed disk from tray.") MSG_HASH(MSG_REMOVING_TEMPORARY_CONTENT_FILE, @@ -2496,6 +2518,10 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, "Specify the font size in points.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, "Hide the overlay while inside the menu, and show it again when exiting the menu.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + "Show keyboard/controller inputs on the onscreen overlay.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + "Select the port for the overlay to listen to if Show Inputs On Overlay is enabled.") MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, "Scanned content will appear here." diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index 489ae7a000..f9a1a226bc 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -462,7 +462,6 @@ error: #endif #ifdef HAVE_IBXM -#ifdef HAVE_STB_VORBIS static bool audio_mixer_play_mod( audio_mixer_sound_t* sound, audio_mixer_voice_t* voice, @@ -477,9 +476,10 @@ static bool audio_mixer_play_mod( struct module* module = NULL; struct replay* replay = NULL; - data.buffer = (char*)sound->types.ogg.data; - data.length = sound->types.ogg.size; - module = module_load(&data, message); + data.buffer = (char*)sound->types.mod.data; + data.length = sound->types.mod.size; + module = module_load(&data, message); + if (!module) { printf("audio_mixer_play_mod module_load() failed with error: %s\n", message); @@ -511,7 +511,7 @@ static bool audio_mixer_play_mod( goto error; } - voice->types.mod.buffer = mod_buffer; + voice->types.mod.buffer = (int*)mod_buffer; voice->types.mod.buf_samples = buf_samples; voice->types.mod.stream = replay; voice->types.mod.position = 0; @@ -522,12 +522,12 @@ static bool audio_mixer_play_mod( error: if (mod_buffer) memalign_free(mod_buffer); - dispose_module(module); + if (module) + dispose_module(module); return false; } #endif -#endif audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, float volume, audio_mixer_stop_cb_t stop_cb) @@ -560,9 +560,7 @@ audio_mixer_voice_t* audio_mixer_play(audio_mixer_sound_t* sound, bool repeat, break; case AUDIO_MIXER_TYPE_MOD: #ifdef HAVE_IBXM -#ifdef HAVE_STB_VORBIS res = audio_mixer_play_mod(sound, voice, repeat, volume, stop_cb); -#endif #endif break; case AUDIO_MIXER_TYPE_NONE: @@ -737,6 +735,8 @@ static void audio_mixer_mix_mod(float* buffer, size_t num_frames, float volume) { int i; + float samplef = 0.0f; + int samplei = 0; unsigned temp_samples = 0; unsigned buf_free = num_frames * 2; int* pcm = NULL; @@ -744,7 +744,9 @@ static void audio_mixer_mix_mod(float* buffer, size_t num_frames, if (voice->types.mod.position == voice->types.mod.samples) { again: - temp_samples = replay_get_audio( voice->types.mod.stream, voice->types.mod.buffer ); + temp_samples = replay_get_audio( + voice->types.mod.stream, voice->types.mod.buffer ); + temp_samples *= 2; /* stereo */ if (temp_samples == 0) @@ -772,16 +774,14 @@ again: } pcm = voice->types.mod.buffer + voice->types.mod.position; - float samplef = 0.0f; - int samplei = 0; if (voice->types.mod.samples < buf_free) { for (i = voice->types.mod.samples; i != 0; i--) { - samplei = *pcm++ * volume; - samplef = (float)((int)samplei + 32768) / 65535.0f; - samplef = samplef * 2.0f - 1.0f; - *buffer++ = samplef; + samplei = *pcm++ * volume; + samplef = (float)((int)samplei + 32768) / 65535.0f; + samplef = samplef * 2.0f - 1.0f; + *buffer++ += samplef; } buf_free -= voice->types.mod.samples; @@ -792,10 +792,10 @@ again: int i; for (i = buf_free; i != 0; --i ) { - samplei = *pcm++ * volume; - samplef = (float)((int)samplei + 32768) / 65535.0f; - samplef = samplef * 2.0f - 1.0f; - *buffer++ = samplef; + samplei = *pcm++ * volume; + samplef = (float)((int)samplei + 32768) / 65535.0f; + samplef = samplef * 2.0f - 1.0f; + *buffer++ += samplef; } voice->types.mod.position += buf_free; @@ -828,6 +828,7 @@ void audio_mixer_mix(float* buffer, size_t num_frames, float volume_override, bo #ifdef HAVE_STB_VORBIS audio_mixer_mix_ogg(buffer, num_frames, voice, volume); #endif + break; case AUDIO_MIXER_TYPE_MOD: #ifdef HAVE_IBXM audio_mixer_mix_mod(buffer, num_frames, voice, volume); diff --git a/libretro-common/audio/dsp_filters/Crystalizer.dsp b/libretro-common/audio/dsp_filters/Crystalizer.dsp new file mode 100644 index 0000000000..f8fceb5f96 --- /dev/null +++ b/libretro-common/audio/dsp_filters/Crystalizer.dsp @@ -0,0 +1,4 @@ +filters = 1 +filter0 = crystalizer +# Controls dry/wet-ness of effect. 0.0 = none, 10.0 = max. +crystalizer_intensity = 5.0 diff --git a/libretro-common/audio/dsp_filters/crystalizer.c b/libretro-common/audio/dsp_filters/crystalizer.c new file mode 100644 index 0000000000..c0e253c7e3 --- /dev/null +++ b/libretro-common/audio/dsp_filters/crystalizer.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2010-2017 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (echo.c). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#include +#include +#include + +#include +#include + +struct delta_data +{ + float intensity; + float old[2]; +}; + +static void delta_free(void *data) +{ + free(data); +} + +static void delta_process(void *data, struct dspfilter_output *output, + const struct dspfilter_input *input) +{ + unsigned i, c; + struct delta_data *d = (struct delta_data*)data; + float *out = output->samples; + output->samples = input->samples; + output->frames = input->frames; + + for (i = 0; i < input->frames; i++) + { + for (c = 0; c < 2; c++) + { + float current = *out; + *out++ = current + (current - d->old[c]) * d->intensity; + d->old[c] = current; + } + } +} + +static void *delta_init(const struct dspfilter_info *info, + const struct dspfilter_config *config, void *userdata) +{ + struct delta_data *d = (struct delta_data*)calloc(1, sizeof(*d)); + if (!d) + return NULL; + config->get_float(userdata, "intensity", &d->intensity, 5.0f); + return d; +} + +static const struct dspfilter_implementation delta_plug = { + delta_init, + delta_process, + delta_free, + DSPFILTER_API_VERSION, + "Delta Sharpening", + "crystalizer", +}; + +#ifdef HAVE_FILTERS_BUILTIN +#define dspfilter_get_implementation delta_dspfilter_get_implementation +#endif + +const struct dspfilter_implementation *dspfilter_get_implementation(dspfilter_simd_mask_t mask) +{ + (void)mask; + return &delta_plug; +} + + +#undef dspfilter_get_implementation + diff --git a/libretro-common/file/retro_dirent.c b/libretro-common/file/retro_dirent.c index c21b2d669c..26f3e8a897 100644 --- a/libretro-common/file/retro_dirent.c +++ b/libretro-common/file/retro_dirent.c @@ -20,8 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include #include +#include +#include #include @@ -156,45 +157,6 @@ const char *retro_dirent_get_name(struct RDIR *rdir) #endif } -static bool path_is_directory_internal(const char *path) -{ -#if defined(VITA) || defined(PSP) - SceIoStat buf; - char *tmp = strdup(path); - size_t len = strlen(tmp); - if (tmp[len-1] == '/') - tmp[len-1]='\0'; - - if (sceIoGetstat(tmp, &buf) < 0) - { - free(tmp); - return false; - } - free(tmp); - - return FIO_S_ISDIR(buf.st_mode); -#elif defined(__CELLOS_LV2__) - CellFsStat buf; - if (cellFsStat(path, &buf) < 0) - return false; - return ((buf.st_mode & S_IFMT) == S_IFDIR); -#elif defined(_WIN32) - struct _stat buf; - DWORD file_info = GetFileAttributes(path); - - _stat(path, &buf); - - if (file_info == INVALID_FILE_ATTRIBUTES) - return false; - return (file_info & FILE_ATTRIBUTE_DIRECTORY); -#else - struct stat buf; - if (stat(path, &buf) < 0) - return false; - return S_ISDIR(buf.st_mode); -#endif -} - /** * * retro_dirent_is_dir: @@ -221,17 +183,20 @@ bool retro_dirent_is_dir(struct RDIR *rdir, const char *path) #elif defined(__CELLOS_LV2__) CellFsDirent *entry = (CellFsDirent*)&rdir->entry; return (entry->d_type == CELL_FS_TYPE_DIRECTORY); -#elif defined(DT_DIR) +#else + struct stat buf; +#if defined(DT_DIR) const struct dirent *entry = (const struct dirent*)rdir->entry; if (entry->d_type == DT_DIR) return true; /* This can happen on certain file systems. */ - if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) - return path_is_directory_internal(path); - return false; -#else + if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK)) + return false; +#endif /* dirent struct doesn't have d_type, do it the slow way ... */ - return path_is_directory_internal(path); + if (stat(path, &buf) < 0) + return false; + return S_ISDIR(buf.st_mode); #endif } diff --git a/libretro-common/formats/json/jsonsax.c b/libretro-common/formats/json/jsonsax.c index 1a7ac93555..fec8a7df8a 100644 --- a/libretro-common/formats/json/jsonsax.c +++ b/libretro-common/formats/json/jsonsax.c @@ -54,13 +54,13 @@ state_t; static INLINE void skip_spaces( state_t* state ) { - while ( isspace( *state->json ) ) + while ( isspace( (unsigned char)*state->json ) ) state->json++; } static INLINE void skip_digits( state_t* state ) { - while ( isdigit( *state->json ) ) + while ( isdigit( (unsigned char)*state->json ) ) state->json++; } @@ -218,7 +218,7 @@ static void jsonx_parse_number(state_t* state) if ( *state->json == '-' ) state->json++; - if ( !isdigit( *state->json ) ) + if ( !isdigit( (unsigned char)*state->json ) ) longjmp( state->env, JSONSAX_INVALID_VALUE ); skip_digits( state ); @@ -227,7 +227,7 @@ static void jsonx_parse_number(state_t* state) { state->json++; - if ( !isdigit( *state->json ) ) + if ( !isdigit( (unsigned char)*state->json ) ) longjmp( state->env, JSONSAX_INVALID_VALUE ); skip_digits( state ); @@ -240,7 +240,7 @@ static void jsonx_parse_number(state_t* state) if ( *state->json == '-' || *state->json == '+' ) state->json++; - if ( !isdigit( *state->json ) ) + if ( !isdigit( (unsigned char)*state->json ) ) longjmp( state->env, JSONSAX_INVALID_VALUE ); skip_digits( state ); diff --git a/libretro-common/formats/libchdr/bitstream.c b/libretro-common/formats/libchdr/bitstream.c new file mode 100644 index 0000000000..735b97f4b1 --- /dev/null +++ b/libretro-common/formats/libchdr/bitstream.c @@ -0,0 +1,118 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + bitstream.c + + Helper classes for reading/writing at the bit level. + +***************************************************************************/ + +#include "bitstream.h" +#include + +//************************************************************************** +// INLINE FUNCTIONS +//************************************************************************** + +int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); } + +//------------------------------------------------- +// create_bitstream - constructor +//------------------------------------------------- + +struct bitstream* create_bitstream(const void *src, uint32_t srclength) +{ + struct bitstream* bitstream = (struct bitstream*)malloc(sizeof(struct bitstream)); + bitstream->buffer = 0; + bitstream->bits = 0; + bitstream->read = (const uint8_t*)src; + bitstream->doffset = 0; + bitstream->dlength = srclength; + return bitstream; +} + + +//----------------------------------------------------- +// bitstream_peek - fetch the requested number of bits +// but don't advance the input pointer +//----------------------------------------------------- + +uint32_t bitstream_peek(struct bitstream* bitstream, int numbits) +{ + if (numbits == 0) + return 0; + + // fetch data if we need more + if (numbits > bitstream->bits) + { + while (bitstream->bits <= 24) + { + if (bitstream->doffset < bitstream->dlength) + bitstream->buffer |= bitstream->read[bitstream->doffset] << (24 - bitstream->bits); + bitstream->doffset++; + bitstream->bits += 8; + } + } + + // return the data + return bitstream->buffer >> (32 - numbits); +} + + +//----------------------------------------------------- +// bitstream_remove - advance the input pointer by the +// specified number of bits +//----------------------------------------------------- + +void bitstream_remove(struct bitstream* bitstream, int numbits) +{ + bitstream->buffer <<= numbits; + bitstream->bits -= numbits; +} + + +//----------------------------------------------------- +// bitstream_read - fetch the requested number of bits +//----------------------------------------------------- + +uint32_t bitstream_read(struct bitstream* bitstream, int numbits) +{ + uint32_t result = bitstream_peek(bitstream, numbits); + bitstream_remove(bitstream, numbits); + return result; +} + + +//------------------------------------------------- +// read_offset - return the current read offset +//------------------------------------------------- + +uint32_t bitstream_read_offset(struct bitstream* bitstream) +{ + uint32_t result = bitstream->doffset; + int bits = bitstream->bits; + while (bits >= 8) + { + result--; + bits -= 8; + } + return result; +} + + +//------------------------------------------------- +// flush - flush to the nearest byte +//------------------------------------------------- + +uint32_t bitstream_flush(struct bitstream* bitstream) +{ + while (bitstream->bits >= 8) + { + bitstream->doffset--; + bitstream->bits -= 8; + } + bitstream->bits = bitstream->buffer = 0; + return bitstream->doffset; +} + diff --git a/libretro-common/formats/libchdr/bitstream.h b/libretro-common/formats/libchdr/bitstream.h new file mode 100644 index 0000000000..9250d3369e --- /dev/null +++ b/libretro-common/formats/libchdr/bitstream.h @@ -0,0 +1,42 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + bitstream.h + + Helper classes for reading/writing at the bit level. + +***************************************************************************/ + +#pragma once + +#ifndef __BITSTREAM_H__ +#define __BITSTREAM_H__ + +#include + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// helper class for reading from a bit buffer +struct bitstream +{ + uint32_t buffer; // current bit accumulator + int bits; // number of bits in the accumulator + const uint8_t * read; // read pointer + uint32_t doffset; // byte offset within the data + uint32_t dlength; // length of the data +}; + +struct bitstream* create_bitstream(const void *src, uint32_t srclength); +int bitstream_overflow(struct bitstream* bitstream); +uint32_t bitstream_read_offset(struct bitstream* bitstream); + +uint32_t bitstream_read(struct bitstream* bitstream, int numbits); +uint32_t bitstream_peek(struct bitstream* bitstream, int numbits); +void bitstream_remove(struct bitstream* bitstream, int numbits); +uint32_t bitstream_flush(struct bitstream* bitstream); + + +#endif diff --git a/libretro-common/formats/libchdr/cdrom.c b/libretro-common/formats/libchdr/cdrom.c new file mode 100644 index 0000000000..6c120cbc2a --- /dev/null +++ b/libretro-common/formats/libchdr/cdrom.c @@ -0,0 +1,417 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + cdrom.c + + Generic MAME CD-ROM utilties - build IDE and SCSI CD-ROMs on top of this + +**************************************************************************** + + IMPORTANT: + "physical" block addresses are the actual addresses on the emulated CD. + "chd" block addresses are the block addresses in the CHD file. + Because we pad each track to a 4-frame boundary, these addressing + schemes will differ after track 1! + +***************************************************************************/ + +#include +#include + +#include "cdrom.h" + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +/** @brief The verbose. */ +#define VERBOSE (0) +#if VERBOSE + +/** + * @def LOG(x) do + * + * @brief A macro that defines log. + * + * @param x The void to process. + */ + +#define LOG(x) do { if (VERBOSE) logerror x; } while (0) + +/** + * @fn void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); + * + * @brief Logerrors the given text. + * + * @param text The text. + * + * @return A CLIB_DECL. + */ + +void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2); +#else + +/** + * @def LOG(x); + * + * @brief A macro that defines log. + * + * @param x The void to process. + */ + +#define LOG(x) +#endif + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/** @brief offset within sector. */ +#define SYNC_OFFSET 0x000 +/** @brief 12 bytes. */ +#define SYNC_NUM_BYTES 12 + +/** @brief offset within sector. */ +#define MODE_OFFSET 0x00f + +/** @brief offset within sector. */ +#define ECC_P_OFFSET 0x81c +/** @brief 2 lots of 86. */ +#define ECC_P_NUM_BYTES 86 +/** @brief 24 bytes each. */ +#define ECC_P_COMP 24 + +/** @brief The ECC q offset. */ +#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES) +/** @brief 2 lots of 52. */ +#define ECC_Q_NUM_BYTES 52 +/** @brief 43 bytes each. */ +#define ECC_Q_COMP 43 + + + +/** + * @brief ------------------------------------------------- + * ECC lookup tables pre-calculated tables for ECC data calcs + * -------------------------------------------------. + */ + +static const uint8_t ecclow[256] = +{ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, + 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, + 0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03, + 0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23, + 0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43, + 0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63, + 0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83, + 0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3, + 0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3, + 0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3 +}; + +/** @brief The ecchigh[ 256]. */ +static const uint8_t ecchigh[256] = +{ + 0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05, + 0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe, + 0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee, + 0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15, + 0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce, + 0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35, + 0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25, + 0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde, + 0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e, + 0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75, + 0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65, + 0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e, + 0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45, + 0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe, + 0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae, + 0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55 +}; + +/** + * @brief ------------------------------------------------- + * poffsets - each row represents the addresses used to calculate a byte of the ECC P + * data 86 (*2) ECC P bytes, 24 values represented by each + * -------------------------------------------------. + */ + +static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] = +{ + { 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba }, + { 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb }, + { 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc }, + { 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd }, + { 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be }, + { 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf }, + { 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 }, + { 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 }, + { 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 }, + { 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 }, + { 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 }, + { 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 }, + { 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 }, + { 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 }, + { 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 }, + { 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 }, + { 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca }, + { 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb }, + { 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc }, + { 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd }, + { 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce }, + { 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf }, + { 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 }, + { 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 }, + { 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 }, + { 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 }, + { 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 }, + { 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 }, + { 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 }, + { 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 }, + { 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 }, + { 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 }, + { 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da }, + { 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db }, + { 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc }, + { 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd }, + { 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de }, + { 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df }, + { 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 }, + { 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 }, + { 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 }, + { 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 }, + { 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 }, + { 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 }, + { 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 }, + { 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 }, + { 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 }, + { 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 }, + { 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea }, + { 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb }, + { 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec }, + { 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed }, + { 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee }, + { 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef }, + { 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 }, + { 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 }, + { 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 }, + { 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 }, + { 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 }, + { 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 }, + { 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 }, + { 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 }, + { 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 }, + { 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 }, + { 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa }, + { 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb }, + { 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc }, + { 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd }, + { 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe }, + { 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff }, + { 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 }, + { 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 }, + { 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 }, + { 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 }, + { 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 }, + { 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 }, + { 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 }, + { 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 }, + { 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 }, + { 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 }, + { 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a }, + { 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b }, + { 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c }, + { 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d }, + { 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e }, + { 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f } +}; + +/** + * @brief ------------------------------------------------- + * qoffsets - each row represents the addresses used to calculate a byte of the ECC Q + * data 52 (*2) ECC Q bytes, 43 values represented by each + * -------------------------------------------------. + */ + +static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] = +{ + { 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 }, + { 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 }, + { 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a }, + { 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b }, + { 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 }, + { 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 }, + { 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 }, + { 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 }, + { 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c }, + { 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d }, + { 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 }, + { 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 }, + { 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 }, + { 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 }, + { 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e }, + { 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f }, + { 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 }, + { 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 }, + { 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba }, + { 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb }, + { 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 }, + { 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 }, + { 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa }, + { 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab }, + { 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 }, + { 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 }, + { 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 }, + { 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 }, + { 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac }, + { 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad }, + { 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 }, + { 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 }, + { 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 }, + { 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 }, + { 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae }, + { 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af }, + { 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 }, + { 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 }, + { 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a }, + { 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b }, + { 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 }, + { 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 }, + { 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 }, + { 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 }, + { 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c }, + { 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d }, + { 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 }, + { 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 }, + { 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 }, + { 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 }, + { 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e }, + { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f } +}; + + +//------------------------------------------------- +// ecc_source_byte - return data from the sector +// at the given offset, masking anything +// particular to a mode +//------------------------------------------------- + +static uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset) +{ + // in mode 2 always treat these as 0 bytes + return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset]; +} + +/** + * @fn void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2) + * + * @brief ------------------------------------------------- + * ecc_compute_bytes - calculate an ECC value (P or Q) + * -------------------------------------------------. + * + * @param sector The sector. + * @param row The row. + * @param rowlen The rowlen. + * @param [in,out] val1 The first value. + * @param [in,out] val2 The second value. + */ + +void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2) +{ + int component; + *val1 = *val2 = 0; + for (component = 0; component < rowlen; component++) + { + *val1 ^= ecc_source_byte(sector, row[component]); + *val2 ^= ecc_source_byte(sector, row[component]); + *val1 = ecclow[*val1]; + } + *val1 = ecchigh[ecclow[*val1] ^ *val2]; + *val2 ^= *val1; +} + +/** + * @fn int ecc_verify(const uint8_t *sector) + * + * @brief ------------------------------------------------- + * ecc_verify - verify the P and Q ECC codes in a sector + * -------------------------------------------------. + * + * @param sector The sector. + * + * @return true if it succeeds, false if it fails. + */ + +int ecc_verify(const uint8_t *sector) +{ + int byte; + + // first verify P bytes + for (byte = 0; byte < ECC_P_NUM_BYTES; byte++) + { + uint8_t val1, val2; + ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2); + if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2) + return 0; + } + + // then verify Q bytes + for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++) + { + uint8_t val1, val2; + ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2); + if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2) + return 0; + } + return 1; +} + +/** + * @fn void ecc_generate(uint8_t *sector) + * + * @brief ------------------------------------------------- + * ecc_generate - generate the P and Q ECC codes for a sector, overwriting any + * existing codes + * -------------------------------------------------. + * + * @param [in,out] sector If non-null, the sector. + */ + +void ecc_generate(uint8_t *sector) +{ + int byte; + // first verify P bytes + for (byte = 0; byte < ECC_P_NUM_BYTES; byte++) + ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, §or[ECC_P_OFFSET + byte], §or[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]); + + // then verify Q bytes + for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++) + ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, §or[ECC_Q_OFFSET + byte], §or[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]); +} + +/** + * @fn void ecc_clear(uint8_t *sector) + * + * @brief ------------------------------------------------- + * ecc_clear - erase the ECC P and Q cods to 0 within a sector + * -------------------------------------------------. + * + * @param [in,out] sector If non-null, the sector. + */ + +void ecc_clear(uint8_t *sector) +{ + memset(§or[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES); + memset(§or[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES); +} diff --git a/libretro-common/formats/libchdr/cdrom.h b/libretro-common/formats/libchdr/cdrom.h new file mode 100644 index 0000000000..8fc52bfa92 --- /dev/null +++ b/libretro-common/formats/libchdr/cdrom.h @@ -0,0 +1,108 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + cdrom.h + + Generic MAME cd-rom implementation + +***************************************************************************/ + +#pragma once + +#ifndef __CDROM_H__ +#define __CDROM_H__ + +#include + +#include + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +// tracks are padded to a multiple of this many frames +extern const uint32_t CD_TRACK_PADDING; + +#define CD_MAX_TRACKS (99) /* AFAIK the theoretical limit */ +#define CD_MAX_SECTOR_DATA (2352) +#define CD_MAX_SUBCODE_DATA (96) + +#define CD_FRAME_SIZE (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA) +#define CD_FRAMES_PER_HUNK (8) + +#define CD_METADATA_WORDS (1+(CD_MAX_TRACKS * 6)) + +enum +{ + CD_TRACK_MODE1 = 0, /* mode 1 2048 bytes/sector */ + CD_TRACK_MODE1_RAW, /* mode 1 2352 bytes/sector */ + CD_TRACK_MODE2, /* mode 2 2336 bytes/sector */ + CD_TRACK_MODE2_FORM1, /* mode 2 2048 bytes/sector */ + CD_TRACK_MODE2_FORM2, /* mode 2 2324 bytes/sector */ + CD_TRACK_MODE2_FORM_MIX, /* mode 2 2336 bytes/sector */ + CD_TRACK_MODE2_RAW, /* mode 2 2352 bytes / sector */ + CD_TRACK_AUDIO, /* redbook audio track 2352 bytes/sector (588 samples) */ + + CD_TRACK_RAW_DONTCARE /* special flag for cdrom_read_data: just return me whatever is there */ +}; + +enum +{ + CD_SUB_NORMAL = 0, /* "cooked" 96 bytes per sector */ + CD_SUB_RAW, /* raw uninterleaved 96 bytes per sector */ + CD_SUB_NONE /* no subcode data stored */ +}; + +#define CD_FLAG_GDROM 0x00000001 // disc is a GD-ROM, all tracks should be stored with GD-ROM metadata +#define CD_FLAG_GDROMLE 0x00000002 // legacy GD-ROM, with little-endian CDDA data + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +// ECC utilities +int ecc_verify(const uint8_t *sector); +void ecc_generate(uint8_t *sector); +void ecc_clear(uint8_t *sector); + + + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +static INLINE uint32_t msf_to_lba(uint32_t msf) +{ + return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0); +} + +static INLINE uint32_t lba_to_msf(uint32_t lba) +{ + uint8_t m, s, f; + + m = lba / (60 * 75); + lba -= m * (60 * 75); + s = lba / 75; + f = lba % 75; + + return ((m / 10) << 20) | ((m % 10) << 16) | + ((s / 10) << 12) | ((s % 10) << 8) | + ((f / 10) << 4) | ((f % 10) << 0); +} + +// segacd needs it like this.. investigate +// Angelo also says PCE tracks often start playing at the +// wrong address.. related? +static INLINE uint32_t lba_to_msf_alt(int lba) +{ + uint32_t ret = 0; + + ret |= ((lba / (60 * 75))&0xff)<<16; + ret |= (((lba / 75) % 60)&0xff)<<8; + ret |= ((lba % 75)&0xff)<<0; + + return ret; +} + +#endif // __CDROM_H__ diff --git a/libretro-common/formats/libchdr/chd.c b/libretro-common/formats/libchdr/chd.c new file mode 100644 index 0000000000..9adecc6627 --- /dev/null +++ b/libretro-common/formats/libchdr/chd.c @@ -0,0 +1,2453 @@ +/*************************************************************************** + + chd.c + + MAME Compressed Hunks of Data file format + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ +#define DONT_SET_BYTE +typedef unsigned char Byte; + +#include "chd.h" +#include "cdrom.h" +#include "huffman.h" +#include "flac.h" + +#include "md5.h" +#include "sha1.h" +#include "LzmaEnc.h" +#include "LzmaDec.h" + +#include +#include + +#include +#include +#include +#include + +#include + +#define TRUE 1 +#define FALSE 0 + +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +#define SHA1_DIGEST_SIZE 20 + +#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +/*************************************************************************** + DEBUGGING +***************************************************************************/ + +#define PRINTF_MAX_HUNK (0) + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define MAP_STACK_ENTRIES 512 /* max number of entries to use on the stack */ +#define MAP_ENTRY_SIZE 16 /* V3 and later */ +#define OLD_MAP_ENTRY_SIZE 8 /* V1-V2 */ +#define METADATA_HEADER_SIZE 16 /* metadata header size */ +#define CRCMAP_HASH_SIZE 4095 /* number of CRC hashtable entries */ + +#define MAP_ENTRY_FLAG_TYPE_MASK 0x0f /* what type of hunk */ +#define MAP_ENTRY_FLAG_NO_CRC 0x10 /* no CRC is present */ + +#define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */ + +#define COOKIE_VALUE 0xbaadf00d +#define MAX_ZLIB_ALLOCS 64 + +#define END_OF_LIST_COOKIE "EndOfListCookie" + +#define NO_MATCH (~0) + +static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 }; + +// V3-V4 entry types +enum +{ + V34_MAP_ENTRY_TYPE_INVALID = 0, // invalid type + V34_MAP_ENTRY_TYPE_COMPRESSED = 1, // standard compression + V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2, // uncompressed data + V34_MAP_ENTRY_TYPE_MINI = 3, // mini: use offset as raw data + V34_MAP_ENTRY_TYPE_SELF_HUNK = 4, // same as another hunk in this file + V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5, // same as a hunk in the parent file + V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6 // compressed with secondary algorithm (usually FLAC CDDA) +}; + +// V5 compression types +enum +{ + ///< codec #0 + // these types are live when running + COMPRESSION_TYPE_0 = 0, + ///< codec #1 + COMPRESSION_TYPE_1 = 1, + ///< codec #2 + COMPRESSION_TYPE_2 = 2, + ///< codec #3 + COMPRESSION_TYPE_3 = 3, + ///< no compression; implicit length = hunkbytes + COMPRESSION_NONE = 4, + ///< same as another block in this chd + COMPRESSION_SELF = 5, + ///< same as a hunk's worth of units in the parent chd + COMPRESSION_PARENT = 6, + + ///< start of small RLE run (4-bit length) + // these additional pseudo-types are used for compressed encodings: + COMPRESSION_RLE_SMALL, + ///< start of large RLE run (8-bit length) + COMPRESSION_RLE_LARGE, + ///< same as the last COMPRESSION_SELF block + COMPRESSION_SELF_0, + ///< same as the last COMPRESSION_SELF block + 1 + COMPRESSION_SELF_1, + ///< same block in the parent + COMPRESSION_PARENT_SELF, + ///< same as the last COMPRESSION_PARENT block + COMPRESSION_PARENT_0, + ///< same as the last COMPRESSION_PARENT block + 1 + COMPRESSION_PARENT_1 +}; + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0) + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* interface to a codec */ +typedef struct _codec_interface codec_interface; +struct _codec_interface +{ + UINT32 compression; /* type of compression */ + const char *compname; /* name of the algorithm */ + UINT8 lossy; /* is this a lossy algorithm? */ + chd_error (*init)(void *codec, UINT32 hunkbytes); /* codec initialize */ + void (*free)(void *codec); /* codec free */ + chd_error (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */ + chd_error (*config)(void *codec, int param, void *config); /* configure */ +}; + + +/* a single map entry */ +typedef struct _map_entry map_entry; +struct _map_entry +{ + UINT64 offset; /* offset within the file of the data */ + UINT32 crc; /* 32-bit CRC of the data */ + UINT32 length; /* length of the data */ + UINT8 flags; /* misc flags */ +}; + + +/* simple linked-list of hunks used for our CRC map */ +typedef struct _crcmap_entry crcmap_entry; +struct _crcmap_entry +{ + UINT32 hunknum; /* hunk number */ + crcmap_entry * next; /* next entry in list */ +}; + + +/* a single metadata entry */ +typedef struct _metadata_entry metadata_entry; +struct _metadata_entry +{ + UINT64 offset; /* offset within the file of the header */ + UINT64 next; /* offset within the file of the next header */ + UINT64 prev; /* offset within the file of the previous header */ + UINT32 length; /* length of the metadata */ + UINT32 metatag; /* metadata tag */ + UINT8 flags; /* flag bits */ +}; + +/* codec-private data for the ZLIB codec */ + +typedef struct _zlib_allocator zlib_allocator; +struct _zlib_allocator +{ + UINT32 * allocptr[MAX_ZLIB_ALLOCS]; +}; + +typedef struct _zlib_codec_data zlib_codec_data; +struct _zlib_codec_data +{ + z_stream inflater; + zlib_allocator allocator; +}; + +/* codec-private data for the LZMA codec */ +#define MAX_LZMA_ALLOCS 64 + +typedef struct _lzma_allocator lzma_allocator; +struct _lzma_allocator +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ + void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */ + uint32_t* allocptr[MAX_LZMA_ALLOCS]; +}; + +typedef struct _lzma_codec_data lzma_codec_data; +struct _lzma_codec_data +{ + CLzmaDec decoder; + lzma_allocator allocator; +}; + +/* codec-private data for the CDZL codec */ +typedef struct _cdzl_codec_data cdzl_codec_data; +struct _cdzl_codec_data { + // internal state + zlib_codec_data base_decompressor; + zlib_codec_data subcode_decompressor; + uint8_t* buffer; +}; + +/* codec-private data for the CDLZ codec */ +typedef struct _cdlz_codec_data cdlz_codec_data; +struct _cdlz_codec_data { + // internal state + lzma_codec_data base_decompressor; + zlib_codec_data subcode_decompressor; + uint8_t* buffer; +}; + +/* codec-private data for the CDFL codec */ +typedef struct _cdfl_codec_data cdfl_codec_data; +struct _cdfl_codec_data { + // internal state + int swap_endian; + flac_decoder decoder; + z_stream inflater; + zlib_allocator allocator; + uint8_t* buffer; +}; + +/* internal representation of an open CHD file */ +struct _chd_file +{ + UINT32 cookie; /* cookie, should equal COOKIE_VALUE */ + + core_file * file; /* handle to the open core file */ + UINT8 owns_file; /* flag indicating if this file should be closed on chd_close() */ + chd_header header; /* header, extracted from file */ + + chd_file * parent; /* pointer to parent file, or NULL */ + + map_entry * map; /* array of map entries */ + + UINT8 * cache; /* hunk cache pointer */ + UINT32 cachehunk; /* index of currently cached hunk */ + + UINT8 * compare; /* hunk compare pointer */ + UINT32 comparehunk; /* index of current compare data */ + + UINT8 * compressed; /* pointer to buffer for compressed data */ + const codec_interface * codecintf[4]; /* interface to the codec */ + + zlib_codec_data zlib_codec_data; /* zlib codec data */ + cdzl_codec_data cdzl_codec_data; /* cdzl codec data */ + cdlz_codec_data cdlz_codec_data; /* cdlz codec data */ + cdfl_codec_data cdfl_codec_data; /* cdfl codec data */ + + crcmap_entry * crcmap; /* CRC map entries */ + crcmap_entry * crcfree; /* free list CRC entries */ + crcmap_entry ** crctable; /* table of CRC entries */ + + UINT32 maxhunk; /* maximum hunk accessed */ + + UINT8 compressing; /* are we compressing? */ + MD5_CTX compmd5; /* running MD5 during compression */ + SHA1_CTX compsha1; /* running SHA1 during compression */ + UINT32 comphunk; /* next hunk we will compress */ + + UINT8 verifying; /* are we verifying? */ + MD5_CTX vermd5; /* running MD5 during verification */ + SHA1_CTX versha1; /* running SHA1 during verification */ + UINT32 verhunk; /* next hunk we will verify */ + + UINT32 async_hunknum; /* hunk index for asynchronous operations */ + void * async_buffer; /* buffer pointer for asynchronous operations */ +}; + + +/* a single metadata hash entry */ +typedef struct _metadata_hash metadata_hash; +struct _metadata_hash +{ + UINT8 tag[4]; /* tag of the metadata in big-endian */ + UINT8 sha1[CHD_SHA1_BYTES]; /* hash */ +}; + + + +/*************************************************************************** + GLOBAL VARIABLES +***************************************************************************/ + +static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 }; +static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 }; + + + +/*************************************************************************** + PROTOTYPES +***************************************************************************/ + +/* internal header operations */ +static chd_error header_validate(const chd_header *header); +static chd_error header_read(core_file *file, chd_header *header); + + +/* internal hunk read/write */ +static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum); +static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest); + +/* internal map access */ +static chd_error map_read(chd_file *chd); + +/* metadata management */ +static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry); + + +/* zlib compression codec */ +static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes); +static void zlib_codec_free(void *codec); +static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); +static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size); +static void zlib_fast_free(voidpf opaque, voidpf address); + +/* lzma compression codec */ +static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes); +static void lzma_codec_free(void *codec); +static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* cdzl compression codec */ +static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes); +static void cdzl_codec_free(void* codec); +static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* cdlz compression codec */ +static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes); +static void cdlz_codec_free(void* codec); +static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +/* cdfl compression codec */ +static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes); +static void cdfl_codec_free(void* codec); +static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); + +//************************************************************************** +// LZMA ALLOCATOR HELPER +//************************************************************************** + +void *lzma_fast_alloc(void *p, size_t size); +void lzma_fast_free(void *p, void *address); + +//------------------------------------------------- +// lzma_allocator_init +//------------------------------------------------- + +void lzma_allocator_init(void* p) +{ + lzma_allocator *codec = (lzma_allocator *)(p); + + // reset pointer list + memset(codec->allocptr, 0, sizeof(codec->allocptr)); + codec->Alloc = lzma_fast_alloc; + codec->Free = lzma_fast_free; +} + +//------------------------------------------------- +// lzma_allocator_free +//------------------------------------------------- + +void lzma_allocator_free(void* p ) +{ + int i; + lzma_allocator *codec = (lzma_allocator *)(p); + + // free our memory + for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++) + { + if (codec->allocptr[i] != NULL) + free(codec->allocptr[i]); + } +} + +//------------------------------------------------- +// lzma_fast_alloc - fast malloc for lzma, which +// allocates and frees memory frequently +//------------------------------------------------- + +void *lzma_fast_alloc(void *p, size_t size) +{ + int scan; + uint32_t *addr = NULL; + lzma_allocator *codec = (lzma_allocator *)(p); + + // compute the size, rounding to the nearest 1k + size = (size + 0x3ff) & ~0x3ff; + + // reuse a hunk if we can + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + uint32_t *ptr = codec->allocptr[scan]; + if (ptr != NULL && size == *ptr) + { + // set the low bit of the size so we don't match next time + *ptr |= 1; + return ptr + 1; + } + } + + // alloc a new one and put it into the list + addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t))); + if (addr==NULL) + return NULL; + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + if (codec->allocptr[scan] == NULL) + { + codec->allocptr[scan] = addr; + break; + } + } + + // set the low bit of the size so we don't match next time + *addr = size | 1; + return addr + 1; +} + + +//------------------------------------------------- +// lzma_fast_free - fast free for lzma, which +// allocates and frees memory frequently +//------------------------------------------------- + +void lzma_fast_free(void *p, void *address) +{ + int scan; + uint32_t *ptr; + lzma_allocator *codec; + if (address == NULL) + return; + + codec = (lzma_allocator *)(p); + + // find the hunk + ptr = (uint32_t *)(address) - 1; + for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++) + { + if (ptr == codec->allocptr[scan]) + { + // clear the low bit of the size to allow matches + *ptr &= ~1; + return; + } + } +} + +//************************************************************************** +// LZMA DECOMPRESSOR +//************************************************************************** + + +//------------------------------------------------- +// lzma_codec_init - constructor +//------------------------------------------------- + +chd_error lzma_codec_init(void* codec, uint32_t hunkbytes) +{ + CLzmaEncHandle enc; + CLzmaEncProps encoder_props; + Byte decoder_props[LZMA_PROPS_SIZE]; + SizeT props_size; + lzma_allocator* alloc; + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + + // construct the decoder + LzmaDec_Construct(&lzma_codec->decoder); + + // FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK + // This code assumes that the current version of the encoder imposes the same requirements on the + // decoder as the encoder used to produce the file. This is not necessarily true. The format + // needs to be changed so the encoder properties are written to the file. + + // configure the properties like the compressor did + LzmaEncProps_Init(&encoder_props); + encoder_props.level = 9; + encoder_props.reduceSize = hunkbytes; + LzmaEncProps_Normalize(&encoder_props); + + // convert to decoder properties + alloc = &lzma_codec->allocator; + lzma_allocator_init(alloc); + enc = LzmaEnc_Create((ISzAlloc*)alloc); + if (!enc) + return CHDERR_DECOMPRESSION_ERROR; + if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK) + { + LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc); + return CHDERR_DECOMPRESSION_ERROR; + } + props_size = sizeof(decoder_props); + if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK) + { + LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); + return CHDERR_DECOMPRESSION_ERROR; + } + LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc); + + // do memory allocations + if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK) + return CHDERR_DECOMPRESSION_ERROR; + + // Okay + return CHDERR_NONE; +} + + +//------------------------------------------------- +// lzma_codec_free +//------------------------------------------------- + +void lzma_codec_free(void* codec) +{ + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + + // free memory + LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator); +} + + +//------------------------------------------------- +// decompress - decompress data using the LZMA +// codec +//------------------------------------------------- + +chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + ELzmaStatus status; + SRes res; + SizeT consumedlen, decodedlen; + // initialize + lzma_codec_data* lzma_codec = (lzma_codec_data*) codec; + LzmaDec_Init(&lzma_codec->decoder); + + // decode + consumedlen = complen; + decodedlen = destlen; + res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status); + if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen) + return CHDERR_DECOMPRESSION_ERROR; + return CHDERR_NONE; +} + +// cdlz +chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes) +{ + cdlz_codec_data* cdlz = (cdlz_codec_data*) codec; + + // allocate buffer + cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + + // make sure the CHD's hunk size is an even multiple of the frame size + lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); + + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + return CHDERR_NONE; +} + +void cdlz_codec_free(void* codec) +{ + // TODO +} + +chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + uint32_t framenum; + cdlz_codec_data* cdlz = (cdlz_codec_data*)codec; + + // determine header bytes + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + // extract compressed length of base + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + // reset and decode + lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA); + zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + + // reassemble the data + for (framenum = 0; framenum < frames; framenum++) + { + uint8_t *sector; + + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + + // reconstitute the ECC data and sync header + sector = &dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } + } + return CHDERR_NONE; +} + + +// cdzl + +chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes) +{ + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + + // make sure the CHD's hunk size is an even multiple of the frame size + zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA); + zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA); + + cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + return CHDERR_NONE; +} + +void cdzl_codec_free(void *codec) +{ + // TODO +} + +chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + uint32_t framenum; + cdzl_codec_data* cdzl = (cdzl_codec_data*)codec; + + // determine header bytes + uint32_t frames = destlen / CD_FRAME_SIZE; + uint32_t complen_bytes = (destlen < 65536) ? 2 : 3; + uint32_t ecc_bytes = (frames + 7) / 8; + uint32_t header_bytes = ecc_bytes + complen_bytes; + + // extract compressed length of base + uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1]; + if (complen_bytes > 2) + complen_base = (complen_base << 8) | src[ecc_bytes + 2]; + + // reset and decode + zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA); + zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA); + + // reassemble the data + for (framenum = 0; framenum < frames; framenum++) + { + uint8_t *sector; + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + + // reconstitute the ECC data and sync header + sector = &dest[framenum * CD_FRAME_SIZE]; + if ((src[framenum / 8] & (1 << (framenum % 8))) != 0) + { + memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header)); + ecc_generate(sector); + } + } + return CHDERR_NONE; +} + +//************************************************************************** +// CD FLAC DECOMPRESSOR +//************************************************************************** + + + +//------------------------------------------------------ +// cdfl_codec_blocksize - return the optimal block size +//------------------------------------------------------ + +static uint32_t cdfl_codec_blocksize(uint32_t bytes) +{ + // determine FLAC block size, which must be 16-65535 + // clamp to 2k since that's supposed to be the sweet spot + uint32_t hunkbytes = bytes / 4; + while (hunkbytes > 2048) + hunkbytes /= 2; + return hunkbytes; +} + +chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes) +{ + int zerr; + uint16_t native_endian = 0; + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + + cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes); + + // make sure the CHD's hunk size is an even multiple of the frame size + if (hunkbytes % CD_FRAME_SIZE != 0) + return CHDERR_CODEC_ERROR; + + // determine whether we want native or swapped samples + *(uint8_t *)(&native_endian) = 1; + cdfl->swap_endian = (native_endian & 1); + + // init the inflater + cdfl->inflater.next_in = (Bytef *)cdfl; // bogus, but that's ok + cdfl->inflater.avail_in = 0; + //cdfl->allocator.install(cdfl->inflater); + cdfl->inflater.zalloc = zlib_fast_alloc; + cdfl->inflater.zfree = zlib_fast_free; + cdfl->inflater.opaque = &cdfl->allocator; + zerr = inflateInit2(&cdfl->inflater, -MAX_WBITS); + + // convert errors + if (zerr == Z_MEM_ERROR) + return CHDERR_OUT_OF_MEMORY; + else if (zerr != Z_OK) + return CHDERR_CODEC_ERROR; + + // init flac decoder + flac_decoder_init(&cdfl->decoder); + + return CHDERR_NONE; +} + +void cdfl_codec_free(void *codec) +{ + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + inflateEnd(&cdfl->inflater); +} + +chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + int zerr; + uint8_t *buffer; + uint32_t framenum, offset; + cdfl_codec_data *cdfl = (cdfl_codec_data*)codec; + + // reset and decode + uint32_t frames = destlen / CD_FRAME_SIZE; + if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen)) + return CHDERR_DECOMPRESSION_ERROR; + buffer = &cdfl->buffer[0]; + if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian)) + return CHDERR_DECOMPRESSION_ERROR; + + // inflate the subcode data + offset = flac_decoder_finish(&cdfl->decoder); + cdfl->inflater.next_in = (Bytef *)(src + offset); + cdfl->inflater.avail_in = complen - offset; + cdfl->inflater.total_in = 0; + cdfl->inflater.next_out = &cdfl->buffer[frames * CD_MAX_SECTOR_DATA]; + cdfl->inflater.avail_out = frames * CD_MAX_SUBCODE_DATA; + cdfl->inflater.total_out = 0; + zerr = inflateReset(&cdfl->inflater); + if (zerr != Z_OK) + return CHDERR_DECOMPRESSION_ERROR; + + // do it + zerr = inflate(&cdfl->inflater, Z_FINISH); + if (zerr != Z_STREAM_END) + return CHDERR_DECOMPRESSION_ERROR; + if (cdfl->inflater.total_out != frames * CD_MAX_SUBCODE_DATA) + return CHDERR_DECOMPRESSION_ERROR; + + // reassemble the data + for (framenum = 0; framenum < frames; framenum++) + { + memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA); + memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA); + } + + return CHDERR_NONE; +} +/*************************************************************************** + CODEC INTERFACES +***************************************************************************/ + +#define CHD_MAKE_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) + +// general codecs with CD frontend +#define CHD_CODEC_CD_ZLIB CHD_MAKE_TAG('c','d','z','l') +#define CHD_CODEC_CD_LZMA CHD_MAKE_TAG('c','d','l','z') +#define CHD_CODEC_CD_FLAC CHD_MAKE_TAG('c','d','f','l') + +static const codec_interface codec_interfaces[] = +{ + /* "none" or no compression */ + { + CHDCOMPRESSION_NONE, + "none", + FALSE, + NULL, + NULL, + NULL, + NULL + }, + + /* standard zlib compression */ + { + CHDCOMPRESSION_ZLIB, + "zlib", + FALSE, + zlib_codec_init, + zlib_codec_free, + zlib_codec_decompress, + NULL + }, + + /* zlib+ compression */ + { + CHDCOMPRESSION_ZLIB_PLUS, + "zlib+", + FALSE, + zlib_codec_init, + zlib_codec_free, + zlib_codec_decompress, + NULL + }, + + /* V5 CD zlib compression */ + { + CHD_CODEC_CD_ZLIB, + "cdzl (CD Deflate)", + FALSE, + cdzl_codec_init, + cdzl_codec_free, + cdzl_codec_decompress, + NULL + }, + + /* V5 CD lzma compression */ + { + CHD_CODEC_CD_LZMA, + "cdlz (CD LZMA)", + FALSE, + cdlz_codec_init, + cdlz_codec_free, + cdlz_codec_decompress, + NULL + }, + + /* V5 CD flac compression */ + { + CHD_CODEC_CD_FLAC, + "cdfl (CD FLAC)", + FALSE, + cdfl_codec_init, + cdfl_codec_free, + cdfl_codec_decompress, + NULL + }, +}; + +/*************************************************************************** + INLINE FUNCTIONS +***************************************************************************/ + +/*------------------------------------------------- + get_bigendian_uint64 - fetch a UINT64 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT64 get_bigendian_uint64(const UINT8 *base) +{ + return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) | + ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7]; +} + + +/*------------------------------------------------- + put_bigendian_uint64 - write a UINT64 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value) +{ + base[0] = value >> 56; + base[1] = value >> 48; + base[2] = value >> 40; + base[3] = value >> 32; + base[4] = value >> 24; + base[5] = value >> 16; + base[6] = value >> 8; + base[7] = value; +} + +/*------------------------------------------------- + get_bigendian_uint48 - fetch a UINT48 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT64 get_bigendian_uint48(const UINT8 *base) +{ + return ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) | + ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5]; +} + +/*------------------------------------------------- + put_bigendian_uint48 - write a UINT48 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint48(UINT8 *base, UINT64 value) +{ + value &= 0xffffffffffff; + base[0] = value >> 40; + base[1] = value >> 32; + base[2] = value >> 24; + base[3] = value >> 16; + base[4] = value >> 8; + base[5] = value; +} +/*------------------------------------------------- + get_bigendian_uint32 - fetch a UINT32 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT32 get_bigendian_uint32(const UINT8 *base) +{ + return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3]; +} + + +/*------------------------------------------------- + put_bigendian_uint32 - write a UINT32 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint24(UINT8 *base, UINT32 value) +{ + value &= 0xffffff; + base[0] = value >> 16; + base[1] = value >> 8; + base[2] = value; +} + + +/*------------------------------------------------- + put_bigendian_uint24 - write a UINT24 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value) +{ + value &= 0xffffff; + base[0] = value >> 16; + base[1] = value >> 8; + base[2] = value; +} + +/*------------------------------------------------- + get_bigendian_uint24 - fetch a UINT24 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT32 get_bigendian_uint24(const UINT8 *base) +{ + return (base[0] << 16) | (base[1] << 8) | base[2]; +} + +/*------------------------------------------------- + get_bigendian_uint16 - fetch a UINT16 from + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE UINT16 get_bigendian_uint16(const UINT8 *base) +{ + return (base[0] << 8) | base[1]; +} + + +/*------------------------------------------------- + put_bigendian_uint16 - write a UINT16 to + the data stream in bigendian order +-------------------------------------------------*/ + +static INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value) +{ + base[0] = value >> 8; + base[1] = value; +} + + +/*------------------------------------------------- + map_extract - extract a single map + entry from the datastream +-------------------------------------------------*/ + +static INLINE void map_extract(const UINT8 *base, map_entry *entry) +{ + entry->offset = get_bigendian_uint64(&base[0]); + entry->crc = get_bigendian_uint32(&base[8]); + entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16); + entry->flags = base[15]; +} + + +/*------------------------------------------------- + map_assemble - write a single map + entry to the datastream +-------------------------------------------------*/ + +static INLINE void map_assemble(UINT8 *base, map_entry *entry) +{ + put_bigendian_uint64(&base[0], entry->offset); + put_bigendian_uint32(&base[8], entry->crc); + put_bigendian_uint16(&base[12], entry->length); + base[14] = entry->length >> 16; + base[15] = entry->flags; +} + +/*------------------------------------------------- + map_size_v5 - calculate CHDv5 map size +-------------------------------------------------*/ +static INLINE int map_size_v5(chd_header* header) +{ + return header->hunkcount * header->mapentrybytes; +} + + +/*------------------------------------------------- + crc16 - calculate CRC16 (from hashing.cpp) +-------------------------------------------------*/ +uint16_t crc16(const void *data, uint32_t length) +{ + uint16_t crc = 0xffff; + + static const uint16_t s_table[256] = + { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 + }; + + const uint8_t *src = (uint8_t*)data; + + // fetch the current value into a local and rip through the source data + while (length-- != 0) + crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++]; + return crc; +} + +/*------------------------------------------------- + decompress_v5_map - decompress the v5 map +-------------------------------------------------*/ + +static chd_error decompress_v5_map(chd_file* chd, chd_header* header) +{ + int hunknum; + uint8_t lastcomp = 0; + int repcount = 0; + uint32_t last_self = 0; + uint64_t last_parent = 0; + struct bitstream* bitbuf; + uint32_t mapbytes; + uint64_t firstoffs; + uint16_t mapcrc; + uint8_t lengthbits; + uint8_t selfbits; + uint8_t parentbits; + uint8_t *compressed; + uint8_t rawbuf[16]; + struct huffman_decoder* decoder; + enum huffman_error err; + uint64_t curoffset; + + if (header->mapoffset == 0) + { + //memset(header->rawmap, 0xff,map_size_v5(header)); + return CHDERR_READ_ERROR; + } + + // read the reader + core_fseek(chd->file, header->mapoffset, SEEK_SET); + core_fread(chd->file, rawbuf, sizeof(rawbuf)); + mapbytes = get_bigendian_uint32(&rawbuf[0]); + firstoffs = get_bigendian_uint48(&rawbuf[4]); + mapcrc = get_bigendian_uint16(&rawbuf[10]); + lengthbits = rawbuf[12]; + selfbits = rawbuf[13]; + parentbits = rawbuf[14]; + + // now read the map + compressed = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes); + core_fseek(chd->file, header->mapoffset + 16, SEEK_SET); + core_fread(chd->file, compressed, mapbytes); + bitbuf = create_bitstream(compressed, sizeof(uint8_t) * mapbytes); + header->rawmap = (uint8_t*)malloc(sizeof(uint8_t) * map_size_v5(header)); + + // first decode the compression types + decoder = create_huffman_decoder(16, 8); + err = huffman_import_tree_rle(decoder, bitbuf); + if (err != HUFFERR_NONE) + return CHDERR_DECOMPRESSION_ERROR; + for (hunknum = 0; hunknum < header->hunkcount; hunknum++) + { + uint8_t *rawmap = header->rawmap + (hunknum * 12); + if (repcount > 0) + rawmap[0] = lastcomp, repcount--; + else + { + uint8_t val = huffman_decode_one(decoder, bitbuf); + if (val == COMPRESSION_RLE_SMALL) + rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf); + else if (val == COMPRESSION_RLE_LARGE) + rawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4), repcount += huffman_decode_one(decoder, bitbuf); + else + rawmap[0] = lastcomp = val; + } + } + + // then iterate through the hunks and extract the needed data + curoffset = firstoffs; + for (hunknum = 0; hunknum < header->hunkcount; hunknum++) + { + uint8_t *rawmap = header->rawmap + (hunknum * 12); + uint64_t offset = curoffset; + uint32_t length = 0; + uint16_t crc = 0; + switch (rawmap[0]) + { + // base types + case COMPRESSION_TYPE_0: + case COMPRESSION_TYPE_1: + case COMPRESSION_TYPE_2: + case COMPRESSION_TYPE_3: + curoffset += length = bitstream_read(bitbuf, lengthbits); + crc = bitstream_read(bitbuf, 16); + break; + + case COMPRESSION_NONE: + curoffset += length = header->hunkbytes; + crc = bitstream_read(bitbuf, 16); + break; + + case COMPRESSION_SELF: + last_self = offset = bitstream_read(bitbuf, selfbits); + break; + + case COMPRESSION_PARENT: + offset = bitstream_read(bitbuf, parentbits); + last_parent = offset; + break; + + // pseudo-types; convert into base types + case COMPRESSION_SELF_1: + last_self++; + case COMPRESSION_SELF_0: + rawmap[0] = COMPRESSION_SELF; + offset = last_self; + break; + + case COMPRESSION_PARENT_SELF: + rawmap[0] = COMPRESSION_PARENT; + last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes; + break; + + case COMPRESSION_PARENT_1: + last_parent += header->hunkbytes / header->unitbytes; + case COMPRESSION_PARENT_0: + rawmap[0] = COMPRESSION_PARENT; + offset = last_parent; + break; + } + // UINT24 length + put_bigendian_uint24(&rawmap[1], length); + + // UINT48 offset + put_bigendian_uint48(&rawmap[4], offset); + + // crc16 + put_bigendian_uint16(&rawmap[10], crc); + } + + // verify the final CRC + if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc) + return CHDERR_DECOMPRESSION_ERROR; + + return CHDERR_NONE; +} + +/*------------------------------------------------- + map_extract_old - extract a single map + entry in old format from the datastream +-------------------------------------------------*/ + +static INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes) +{ + entry->offset = get_bigendian_uint64(&base[0]); + entry->crc = 0; + entry->length = entry->offset >> 44; + entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED); +#ifdef __MWERKS__ + entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL; +#else + entry->offset = (entry->offset << 20) >> 20; +#endif +} + + +/*************************************************************************** + CHD FILE MANAGEMENT +***************************************************************************/ + + +/*------------------------------------------------- + chd_open_file - open a CHD file for access +-------------------------------------------------*/ + +chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd) +{ + chd_file *newchd = NULL; + chd_error err; + int intfnum; + + /* verify parameters */ + if (file == NULL) + EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); + + /* punt if invalid parent */ + if (parent != NULL && parent->cookie != COOKIE_VALUE) + EARLY_EXIT(err = CHDERR_INVALID_PARAMETER); + + /* allocate memory for the final result */ + newchd = (chd_file *)malloc(sizeof(chd_file)); + if (newchd == NULL) + EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); + memset(newchd, 0, sizeof(chd_file)); + newchd->cookie = COOKIE_VALUE; + newchd->parent = parent; + newchd->file = file; + + /* now attempt to read the header */ + err = header_read(newchd->file, &newchd->header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + + /* validate the header */ + err = header_validate(&newchd->header); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + + /* make sure we don't open a read-only file writeable */ + if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE)) + EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE); + + /* also, never open an older version writeable */ + if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION) + EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION); + + /* if we need a parent, make sure we have one */ + if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT)) + EARLY_EXIT(err = CHDERR_REQUIRES_PARENT); + + /* make sure we have a valid parent */ + if (parent != NULL) + { + /* check MD5 if it isn't empty */ + if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 && + memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 && + memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0) + EARLY_EXIT(err = CHDERR_INVALID_PARENT); + + /* check SHA1 if it isn't empty */ + if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 && + memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 && + memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0) + EARLY_EXIT(err = CHDERR_INVALID_PARENT); + } + + /* now read the hunk map */ + if (newchd->header.version < 5) + { + err = map_read(newchd); + if (err != CHDERR_NONE) + EARLY_EXIT(err); + } + else + { + err = decompress_v5_map(newchd, &(newchd->header)); + } + + /* allocate and init the hunk cache */ + newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes); + newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes); + if (newchd->cache == NULL || newchd->compare == NULL) + EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); + newchd->cachehunk = ~0; + newchd->comparehunk = ~0; + + /* allocate the temporary compressed buffer */ + newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes); + if (newchd->compressed == NULL) + EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY); + + /* find the codec interface */ + if (newchd->header.version < 5) + { + for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++) + if (codec_interfaces[intfnum].compression == newchd->header.compression[0]) + { + newchd->codecintf[0] = &codec_interfaces[intfnum]; + break; + } + if (intfnum == ARRAY_LENGTH(codec_interfaces)) + EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT); + + /* initialize the codec */ + if (newchd->codecintf[0]->init != NULL) + err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes); + } + else + { + int decompnum; + + // verify the compression types and initialize the codecs + for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++) + { + int i; + for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++) + { + if (codec_interfaces[i].compression == newchd->header.compression[decompnum]) + { + newchd->codecintf[decompnum] = &codec_interfaces[i]; + if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0) + err = CHDERR_UNSUPPORTED_FORMAT; + + /* initialize the codec */ + if (newchd->codecintf[decompnum]->init != NULL) + { + void* codec = NULL; + switch (newchd->header.compression[decompnum]) + { + case CHD_CODEC_CD_ZLIB: + codec = &newchd->cdzl_codec_data; + break; + + case CHD_CODEC_CD_LZMA: + codec = &newchd->cdlz_codec_data; + break; + + case CHD_CODEC_CD_FLAC: + codec = &newchd->cdfl_codec_data; + break; + } + if (codec != NULL) + { + err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes); + } + } + } + } + } + } + + // HACK + //if (err != CHDERR_NONE) + // EARLY_EXIT(err); + + /* all done */ + *chd = newchd; + return CHDERR_NONE; + +cleanup: + if (newchd != NULL) + chd_close(newchd); + return err; +} + +/*------------------------------------------------- + chd_open - open a CHD file by + filename +-------------------------------------------------*/ + +chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd) +{ + chd_error err; + core_file *file = NULL; + UINT32 openflags; + + /* choose the proper mode */ + switch(mode) + { + case CHD_OPEN_READ: + break; + + default: + err = CHDERR_INVALID_PARAMETER; + goto cleanup; + } + + /* open the file */ + file = core_fopen(filename); + if (file == 0) + { + err = CHDERR_FILE_NOT_FOUND; + goto cleanup; + } + + /* now open the CHD */ + err = chd_open_file(file, mode, parent, chd); + if (err != CHDERR_NONE) + goto cleanup; + + /* we now own this file */ + (*chd)->owns_file = TRUE; + +cleanup: + if ((err != CHDERR_NONE) && (file != NULL)) + core_fclose(file); + return err; +} + + +/*------------------------------------------------- + chd_close - close a CHD file for access +-------------------------------------------------*/ + +void chd_close(chd_file *chd) +{ + /* punt if NULL or invalid */ + if (chd == NULL || chd->cookie != COOKIE_VALUE) + return; + + /* deinit the codec */ + if (chd->header.version < 5) + { + if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL) + (*chd->codecintf[0]->free)(&chd->zlib_codec_data); + } + else + { + int i; + // Free the codecs + for (i = 0 ; i < 4 ; i++) + { + void* codec = NULL; + switch (chd->codecintf[i]->compression) + { + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + + case CHD_CODEC_CD_ZLIB: + codec = &chd->cdzl_codec_data; + break; + + case CHD_CODEC_CD_FLAC: + codec = &chd->cdfl_codec_data; + break; + } + if (codec) + { + (*chd->codecintf[i]->free)(codec); + } + } + + // Free the raw map + if (chd->header.rawmap != NULL) + free(chd->header.rawmap); + } + + /* free the compressed data buffer */ + if (chd->compressed != NULL) + free(chd->compressed); + + /* free the hunk cache and compare data */ + if (chd->compare != NULL) + free(chd->compare); + if (chd->cache != NULL) + free(chd->cache); + + /* free the hunk map */ + if (chd->map != NULL) + free(chd->map); + + /* free the CRC table */ + if (chd->crctable != NULL) + free(chd->crctable); + + /* free the CRC map */ + if (chd->crcmap != NULL) + free(chd->crcmap); + + /* close the file */ + if (chd->owns_file && chd->file != NULL) + core_fclose(chd->file); + + if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks); + + /* free our memory */ + free(chd); +} + + +/*------------------------------------------------- + chd_core_file - return the associated + core_file +-------------------------------------------------*/ + +core_file *chd_core_file(chd_file *chd) +{ + return chd->file; +} + + +/*------------------------------------------------- + chd_error_string - return an error string for + the given CHD error +-------------------------------------------------*/ + +const char *chd_error_string(chd_error err) +{ + switch (err) + { + case CHDERR_NONE: return "no error"; + case CHDERR_NO_INTERFACE: return "no drive interface"; + case CHDERR_OUT_OF_MEMORY: return "out of memory"; + case CHDERR_INVALID_FILE: return "invalid file"; + case CHDERR_INVALID_PARAMETER: return "invalid parameter"; + case CHDERR_INVALID_DATA: return "invalid data"; + case CHDERR_FILE_NOT_FOUND: return "file not found"; + case CHDERR_REQUIRES_PARENT: return "requires parent"; + case CHDERR_FILE_NOT_WRITEABLE: return "file not writeable"; + case CHDERR_READ_ERROR: return "read error"; + case CHDERR_WRITE_ERROR: return "write error"; + case CHDERR_CODEC_ERROR: return "codec error"; + case CHDERR_INVALID_PARENT: return "invalid parent"; + case CHDERR_HUNK_OUT_OF_RANGE: return "hunk out of range"; + case CHDERR_DECOMPRESSION_ERROR: return "decompression error"; + case CHDERR_COMPRESSION_ERROR: return "compression error"; + case CHDERR_CANT_CREATE_FILE: return "can't create file"; + case CHDERR_CANT_VERIFY: return "can't verify file"; + case CHDERR_NOT_SUPPORTED: return "operation not supported"; + case CHDERR_METADATA_NOT_FOUND: return "can't find metadata"; + case CHDERR_INVALID_METADATA_SIZE: return "invalid metadata size"; + case CHDERR_UNSUPPORTED_VERSION: return "unsupported CHD version"; + case CHDERR_VERIFY_INCOMPLETE: return "incomplete verify"; + case CHDERR_INVALID_METADATA: return "invalid metadata"; + case CHDERR_INVALID_STATE: return "invalid state"; + case CHDERR_OPERATION_PENDING: return "operation pending"; + case CHDERR_NO_ASYNC_OPERATION: return "no async operation in progress"; + case CHDERR_UNSUPPORTED_FORMAT: return "unsupported format"; + default: return "undocumented error"; + } +} + + + +/*************************************************************************** + CHD HEADER MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + chd_get_header - return a pointer to the + extracted header data +-------------------------------------------------*/ + +const chd_header *chd_get_header(chd_file *chd) +{ + /* punt if NULL or invalid */ + if (chd == NULL || chd->cookie != COOKIE_VALUE) + return NULL; + + return &chd->header; +} + + + +/*************************************************************************** + CORE DATA READ/WRITE +***************************************************************************/ + +/*------------------------------------------------- + chd_read - read a single hunk from the CHD + file +-------------------------------------------------*/ + +chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer) +{ + /* punt if NULL or invalid */ + if (chd == NULL || chd->cookie != COOKIE_VALUE) + return CHDERR_INVALID_PARAMETER; + + /* if we're past the end, fail */ + if (hunknum >= chd->header.totalhunks) + return CHDERR_HUNK_OUT_OF_RANGE; + + /* perform the read */ + return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer); +} + + + + + +/*************************************************************************** + METADATA MANAGEMENT +***************************************************************************/ + +/*------------------------------------------------- + chd_get_metadata - get the indexed metadata + of the given type +-------------------------------------------------*/ + +chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags) +{ + metadata_entry metaentry; + chd_error err; + UINT32 count; + + /* if we didn't find it, just return */ + err = metadata_find_entry(chd, searchtag, searchindex, &metaentry); + if (err != CHDERR_NONE) + { + /* unless we're an old version and they are requesting hard disk metadata */ + if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0) + { + char faux_metadata[256]; + UINT32 faux_length; + + /* fill in the faux metadata */ + sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize); + faux_length = (UINT32)strlen(faux_metadata) + 1; + + /* copy the metadata itself */ + memcpy(output, faux_metadata, MIN(outputlen, faux_length)); + + /* return the length of the data and the tag */ + if (resultlen != NULL) + *resultlen = faux_length; + if (resulttag != NULL) + *resulttag = HARD_DISK_METADATA_TAG; + return CHDERR_NONE; + } + return err; + } + + /* read the metadata */ + outputlen = MIN(outputlen, metaentry.length); + core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET); + count = core_fread(chd->file, output, outputlen); + if (count != outputlen) + return CHDERR_READ_ERROR; + + /* return the length of the data and the tag */ + if (resultlen != NULL) + *resultlen = metaentry.length; + if (resulttag != NULL) + *resulttag = metaentry.metatag; + if (resultflags != NULL) + *resultflags = metaentry.flags; + return CHDERR_NONE; +} + + + +/*************************************************************************** + CODEC INTERFACES +***************************************************************************/ + +/*------------------------------------------------- + chd_codec_config - set internal codec + parameters +-------------------------------------------------*/ + +chd_error chd_codec_config(chd_file *chd, int param, void *config) +{ + + return CHDERR_INVALID_PARAMETER; +} + + +/*------------------------------------------------- + chd_get_codec_name - get the name of a + particular codec +-------------------------------------------------*/ + +const char *chd_get_codec_name(UINT32 codec) +{ + return "Unknown"; +} + + +/*************************************************************************** + INTERNAL HEADER OPERATIONS +***************************************************************************/ + +/*------------------------------------------------- + header_validate - check the validity of a + CHD header +-------------------------------------------------*/ + +static chd_error header_validate(const chd_header *header) +{ + int intfnum; + + /* require a valid version */ + if (header->version == 0 || header->version > CHD_HEADER_VERSION) + return CHDERR_UNSUPPORTED_VERSION; + + /* require a valid length */ + if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) || + (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) || + (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) || + (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) || + (header->version == 5 && header->length != CHD_V5_HEADER_SIZE)) + return CHDERR_INVALID_PARAMETER; + + /* Do not validate v5 header */ + if (header->version <= 4) + { + /* require valid flags */ + if (header->flags & CHDFLAGS_UNDEFINED) + return CHDERR_INVALID_PARAMETER; + + /* require a supported compression mechanism */ + for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++) + if (codec_interfaces[intfnum].compression == header->compression[0]) + break; + + if (intfnum == ARRAY_LENGTH(codec_interfaces)) + return CHDERR_INVALID_PARAMETER; + + /* require a valid hunksize */ + if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256) + return CHDERR_INVALID_PARAMETER; + + /* require a valid hunk count */ + if (header->totalhunks == 0) + return CHDERR_INVALID_PARAMETER; + + /* require a valid MD5 and/or SHA1 if we're using a parent */ + if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0) + return CHDERR_INVALID_PARAMETER; + + /* if we're V3 or later, the obsolete fields must be 0 */ + if (header->version >= 3 && + (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 || + header->obsolete_heads != 0 || header->obsolete_hunksize != 0)) + return CHDERR_INVALID_PARAMETER; + + /* if we're pre-V3, the obsolete fields must NOT be 0 */ + if (header->version < 3 && + (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 || + header->obsolete_heads == 0 || header->obsolete_hunksize == 0)) + return CHDERR_INVALID_PARAMETER; + } + + return CHDERR_NONE; +} + + +/*------------------------------------------------- + header_read - read a CHD header into the + internal data structure +-------------------------------------------------*/ + +static chd_error header_read(core_file *file, chd_header *header) +{ + UINT8 rawheader[CHD_MAX_HEADER_SIZE]; + UINT32 count; + + /* punt if NULL */ + if (header == NULL) + return CHDERR_INVALID_PARAMETER; + + /* punt if invalid file */ + if (file == NULL) + return CHDERR_INVALID_FILE; + + /* seek and read */ + core_fseek(file, 0, SEEK_SET); + count = core_fread(file, rawheader, sizeof(rawheader)); + if (count != sizeof(rawheader)) + return CHDERR_READ_ERROR; + + /* verify the tag */ + if (strncmp((char *)rawheader, "MComprHD", 8) != 0) + return CHDERR_INVALID_DATA; + + /* extract the direct data */ + memset(header, 0, sizeof(*header)); + header->length = get_bigendian_uint32(&rawheader[8]); + header->version = get_bigendian_uint32(&rawheader[12]); + + /* make sure it's a version we understand */ + if (header->version == 0 || header->version > CHD_HEADER_VERSION) + return CHDERR_UNSUPPORTED_VERSION; + + /* make sure the length is expected */ + if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) || + (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) || + (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) || + (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) || + (header->version == 5 && header->length != CHD_V5_HEADER_SIZE)) + + return CHDERR_INVALID_DATA; + + /* extract the common data */ + header->flags = get_bigendian_uint32(&rawheader[16]); + header->compression[0] = get_bigendian_uint32(&rawheader[20]); + + /* extract the V1/V2-specific data */ + if (header->version < 3) + { + int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]); + header->obsolete_hunksize = get_bigendian_uint32(&rawheader[24]); + header->totalhunks = get_bigendian_uint32(&rawheader[28]); + header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]); + header->obsolete_heads = get_bigendian_uint32(&rawheader[36]); + header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]); + memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES); + memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); + header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen; + header->hunkbytes = seclen * header->obsolete_hunksize; + header->metaoffset = 0; + } + + /* extract the V3-specific data */ + else if (header->version == 3) + { + header->totalhunks = get_bigendian_uint32(&rawheader[24]); + header->logicalbytes = get_bigendian_uint64(&rawheader[28]); + header->metaoffset = get_bigendian_uint64(&rawheader[36]); + memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES); + memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES); + header->hunkbytes = get_bigendian_uint32(&rawheader[76]); + memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES); + memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES); + } + + /* extract the V4-specific data */ + else if (header->version == 4) + { + header->totalhunks = get_bigendian_uint32(&rawheader[24]); + header->logicalbytes = get_bigendian_uint64(&rawheader[28]); + header->metaoffset = get_bigendian_uint64(&rawheader[36]); + header->hunkbytes = get_bigendian_uint32(&rawheader[44]); + memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES); + memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES); + memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES); + } + + /* extract the V5-specific data */ + else if (header->version == 5) + { + /* TODO */ + header->compression[0] = get_bigendian_uint32(&rawheader[16]); + header->compression[1] = get_bigendian_uint32(&rawheader[20]); + header->compression[2] = get_bigendian_uint32(&rawheader[24]); + header->compression[3] = get_bigendian_uint32(&rawheader[28]); + header->logicalbytes = get_bigendian_uint64(&rawheader[32]); + header->mapoffset = get_bigendian_uint64(&rawheader[40]); + header->metaoffset = get_bigendian_uint64(&rawheader[48]); + header->hunkbytes = get_bigendian_uint32(&rawheader[56]); + header->hunkcount = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes; + header->unitbytes = get_bigendian_uint32(&rawheader[60]); + header->unitcount = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes; + memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES); + memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES); + memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES); + + // determine properties of map entries + header->mapentrybytes = 12; //TODO compressed() ? 12 : 4; + + // hack + header->totalhunks = header->hunkcount; + } + + /* Unknown version */ + else + { + /* TODO */ + } + + /* guess it worked */ + return CHDERR_NONE; +} + + +/*************************************************************************** + INTERNAL HUNK READ/WRITE +***************************************************************************/ + +/*------------------------------------------------- + hunk_read_into_cache - read a hunk into + the CHD's hunk cache +-------------------------------------------------*/ + +static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum) +{ + chd_error err; + + /* track the max */ + if (hunknum > chd->maxhunk) + chd->maxhunk = hunknum; + + /* if we're already in the cache, we're done */ + if (chd->cachehunk == hunknum) + return CHDERR_NONE; + chd->cachehunk = ~0; + + /* otherwise, read the data */ + err = hunk_read_into_memory(chd, hunknum, chd->cache); + if (err != CHDERR_NONE) + return err; + + /* mark the hunk successfully cached in */ + chd->cachehunk = hunknum; + return CHDERR_NONE; +} + + +/*------------------------------------------------- + hunk_read_into_memory - read a hunk into + memory at the given location +-------------------------------------------------*/ + +static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest) +{ + chd_error err; + + // punt if no file + if (chd->file == NULL) + return CHDERR_INVALID_FILE; + + /* return an error if out of range */ + if (hunknum >= chd->header.totalhunks) + return CHDERR_HUNK_OUT_OF_RANGE; + + if (chd->header.version < 5) + { + map_entry *entry = &chd->map[hunknum]; + UINT32 bytes; + + /* switch off the entry type */ + switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK) + { + /* compressed data */ + case V34_MAP_ENTRY_TYPE_COMPRESSED: + { + void* codec; + /* read it into the decompression buffer */ + core_fseek(chd->file, entry->offset, SEEK_SET); + bytes = core_fread(chd->file, chd->compressed, entry->length); + if (bytes != entry->length) + return CHDERR_READ_ERROR; + + /* now decompress using the codec */ + err = CHDERR_NONE; + codec = &chd->zlib_codec_data; + if (chd->codecintf[0]->decompress != NULL) + err = (*chd->codecintf[0]->decompress)(codec, chd->compressed, entry->length, dest, chd->header.hunkbytes); + if (err != CHDERR_NONE) + return err; + } + break; + + /* uncompressed data */ + case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: + core_fseek(chd->file, entry->offset, SEEK_SET); + bytes = core_fread(chd->file, dest, chd->header.hunkbytes); + if (bytes != chd->header.hunkbytes) + return CHDERR_READ_ERROR; + break; + + /* mini-compressed data */ + case V34_MAP_ENTRY_TYPE_MINI: + put_bigendian_uint64(&dest[0], entry->offset); + for (bytes = 8; bytes < chd->header.hunkbytes; bytes++) + dest[bytes] = dest[bytes - 8]; + break; + + /* self-referenced data */ + case V34_MAP_ENTRY_TYPE_SELF_HUNK: + if (chd->cachehunk == entry->offset && dest == chd->cache) + break; + return hunk_read_into_memory(chd, entry->offset, dest); + + /* parent-referenced data */ + case V34_MAP_ENTRY_TYPE_PARENT_HUNK: + err = hunk_read_into_memory(chd->parent, entry->offset, dest); + if (err != CHDERR_NONE) + return err; + break; + } + return CHDERR_NONE; + } + else + { + + // get a pointer to the map entry + uint64_t blockoffs; + uint32_t blocklen; + uint16_t blockcrc; + void* codec = NULL; + uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum]; + + // uncompressed case + /* TODO + if (!compressed()) + { + blockoffs = uint64_t(be_read(rawmap, 4)) * uint64_t(m_hunkbytes); + if (blockoffs != 0) + file_read(blockoffs, dest, m_hunkbytes); + else if (m_parent_missing) + throw CHDERR_REQUIRES_PARENT; + else if (m_parent != nullptr) + m_parent->read_hunk(hunknum, dest); + else + memset(dest, 0, m_hunkbytes); + return CHDERR_NONE; + }*/ + + // compressed case + blocklen = get_bigendian_uint24(&rawmap[1]); + blockoffs = get_bigendian_uint48(&rawmap[4]); + blockcrc = get_bigendian_uint16(&rawmap[10]); + switch (rawmap[0]) + { + case COMPRESSION_TYPE_0: + case COMPRESSION_TYPE_1: + case COMPRESSION_TYPE_2: + case COMPRESSION_TYPE_3: + core_fseek(chd->file, blockoffs, SEEK_SET); + core_fread(chd->file, chd->compressed, blocklen); + switch (chd->codecintf[rawmap[0]]->compression) + { + case CHD_CODEC_CD_LZMA: + codec = &chd->cdlz_codec_data; + break; + + case CHD_CODEC_CD_ZLIB: + codec = &chd->cdzl_codec_data; + break; + + case CHD_CODEC_CD_FLAC: + codec = &chd->cdfl_codec_data; + break; + } + if (codec==NULL) + return CHDERR_DECOMPRESSION_ERROR; + chd->codecintf[rawmap[0]]->decompress(codec, chd->compressed, blocklen, dest, chd->header.hunkbytes); + if (dest != NULL && crc16(dest, chd->header.hunkbytes) != blockcrc) + return CHDERR_DECOMPRESSION_ERROR; + return CHDERR_NONE; + + case COMPRESSION_NONE: + core_fseek(chd->file, blockoffs, SEEK_SET); + core_fread(chd->file, dest, chd->header.hunkbytes); + if (crc16(dest, chd->header.hunkbytes) != blockcrc) + return CHDERR_DECOMPRESSION_ERROR; + return CHDERR_NONE; + + case COMPRESSION_SELF: + return hunk_read_into_memory(chd, blockoffs, dest); + + case COMPRESSION_PARENT: + // TODO + //if (m_parent_missing) + // return CHDERR_REQUIRES_PARENT; + //return m_parent->read_bytes(uint64_t(blockoffs) * uint64_t(m_parent->unit_bytes()), dest, m_hunkbytes); + return CHDERR_DECOMPRESSION_ERROR; + } + return CHDERR_NONE; + } + + // We should not reach this code + return CHDERR_DECOMPRESSION_ERROR; +} + + +/*************************************************************************** + INTERNAL MAP ACCESS +***************************************************************************/ + +/*------------------------------------------------- + map_read - read the initial sector map +-------------------------------------------------*/ + +static chd_error map_read(chd_file *chd) +{ + UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE; + UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE]; + UINT64 fileoffset, maxoffset = 0; + UINT8 cookie[MAP_ENTRY_SIZE]; + UINT32 count; + chd_error err; + int i; + + /* first allocate memory */ + chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks); + if (!chd->map) + return CHDERR_OUT_OF_MEMORY; + + /* read the map entries in in chunks and extract to the map list */ + fileoffset = chd->header.length; + for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES) + { + /* compute how many entries this time */ + int entries = chd->header.totalhunks - i, j; + if (entries > MAP_STACK_ENTRIES) + entries = MAP_STACK_ENTRIES; + + /* read that many */ + core_fseek(chd->file, fileoffset, SEEK_SET); + count = core_fread(chd->file, raw_map_entries, entries * entrysize); + if (count != entries * entrysize) + { + err = CHDERR_READ_ERROR; + goto cleanup; + } + fileoffset += entries * entrysize; + + /* process that many */ + if (entrysize == MAP_ENTRY_SIZE) + { + for (j = 0; j < entries; j++) + map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]); + } + else + { + for (j = 0; j < entries; j++) + map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes); + } + + /* track the maximum offset */ + for (j = 0; j < entries; j++) + if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED || + (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED) + maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length); + } + + /* verify the cookie */ + core_fseek(chd->file, fileoffset, SEEK_SET); + count = core_fread(chd->file, &cookie, entrysize); + if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize)) + { + err = CHDERR_INVALID_FILE; + goto cleanup; + } + + /* verify the length */ + if (maxoffset > core_fsize(chd->file)) + { + err = CHDERR_INVALID_FILE; + goto cleanup; + } + return CHDERR_NONE; + +cleanup: + if (chd->map) + free(chd->map); + chd->map = NULL; + return err; +} + + + + +/*************************************************************************** + INTERNAL METADATA ACCESS +***************************************************************************/ + +/*------------------------------------------------- + metadata_find_entry - find a metadata entry +-------------------------------------------------*/ + +static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry) +{ + /* start at the beginning */ + metaentry->offset = chd->header.metaoffset; + metaentry->prev = 0; + + /* loop until we run out of options */ + while (metaentry->offset != 0) + { + UINT8 raw_meta_header[METADATA_HEADER_SIZE]; + UINT32 count; + + /* read the raw header */ + core_fseek(chd->file, metaentry->offset, SEEK_SET); + count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header)); + if (count != sizeof(raw_meta_header)) + break; + + /* extract the data */ + metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]); + metaentry->length = get_bigendian_uint32(&raw_meta_header[4]); + metaentry->next = get_bigendian_uint64(&raw_meta_header[8]); + + /* flags are encoded in the high byte of length */ + metaentry->flags = metaentry->length >> 24; + metaentry->length &= 0x00ffffff; + + /* if we got a match, proceed */ + if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag) + if (metaindex-- == 0) + return CHDERR_NONE; + + /* no match, fetch the next link */ + metaentry->prev = metaentry->offset; + metaentry->offset = metaentry->next; + } + + /* if we get here, we didn't find it */ + return CHDERR_METADATA_NOT_FOUND; +} + + + +/*************************************************************************** + ZLIB COMPRESSION CODEC +***************************************************************************/ + +/*------------------------------------------------- + zlib_codec_init - initialize the ZLIB codec +-------------------------------------------------*/ + +static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes) +{ + zlib_codec_data *data = (zlib_codec_data*)codec; + chd_error err; + int zerr; + + /* clear the buffers */ + memset(data, 0, sizeof(zlib_codec_data)); + + /* init the inflater first */ + data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */ + data->inflater.avail_in = 0; + data->inflater.zalloc = zlib_fast_alloc; + data->inflater.zfree = zlib_fast_free; + data->inflater.opaque = &data->allocator; + zerr = inflateInit2(&data->inflater, -MAX_WBITS); + + /* convert errors */ + if (zerr == Z_MEM_ERROR) + err = CHDERR_OUT_OF_MEMORY; + else if (zerr != Z_OK) + err = CHDERR_CODEC_ERROR; + else + err = CHDERR_NONE; + + /* handle an error */ + if (err != CHDERR_NONE) + free(data); + + return err; +} + + +/*------------------------------------------------- + zlib_codec_free - free data for the ZLIB + codec +-------------------------------------------------*/ + +static void zlib_codec_free(void *codec) +{ + zlib_codec_data *data = (zlib_codec_data *)codec; + + /* deinit the streams */ + if (data != NULL) + { + int i; + zlib_allocator alloc; + + inflateEnd(&data->inflater); + + /* free our fast memory */ + alloc = data->allocator; + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (alloc.allocptr[i]) + free(alloc.allocptr[i]); + } +} + + +/*------------------------------------------------- + zlib_codec_decompress - decomrpess data using + the ZLIB codec +-------------------------------------------------*/ + +static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen) +{ + zlib_codec_data *data = (zlib_codec_data *)codec; + int zerr; + + /* reset the decompressor */ + data->inflater.next_in = (Bytef *)src; + data->inflater.avail_in = complen; + data->inflater.total_in = 0; + data->inflater.next_out = (Bytef *)dest; + data->inflater.avail_out = destlen; + data->inflater.total_out = 0; + zerr = inflateReset(&data->inflater); + if (zerr != Z_OK) + return CHDERR_DECOMPRESSION_ERROR; + + /* do it */ + zerr = inflate(&data->inflater, Z_FINISH); + if (data->inflater.total_out != destlen) + return CHDERR_DECOMPRESSION_ERROR; + + return CHDERR_NONE; +} + + +/*------------------------------------------------- + zlib_fast_alloc - fast malloc for ZLIB, which + allocates and frees memory frequently +-------------------------------------------------*/ + +static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size) +{ + zlib_allocator *alloc = (zlib_allocator *)opaque; + UINT32 *ptr; + int i; + + /* compute the size, rounding to the nearest 1k */ + size = (size * items + 0x3ff) & ~0x3ff; + + /* reuse a hunk if we can */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + { + ptr = alloc->allocptr[i]; + if (ptr && size == *ptr) + { + /* set the low bit of the size so we don't match next time */ + *ptr |= 1; + return ptr + 1; + } + } + + /* alloc a new one */ + ptr = (UINT32 *)malloc(size + sizeof(UINT32)); + if (!ptr) + return NULL; + + /* put it into the list */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (!alloc->allocptr[i]) + { + alloc->allocptr[i] = ptr; + break; + } + + /* set the low bit of the size so we don't match next time */ + *ptr = size | 1; + return ptr + 1; +} + + +/*------------------------------------------------- + zlib_fast_free - fast free for ZLIB, which + allocates and frees memory frequently +-------------------------------------------------*/ + +static void zlib_fast_free(voidpf opaque, voidpf address) +{ + zlib_allocator *alloc = (zlib_allocator *)opaque; + UINT32 *ptr = (UINT32 *)address - 1; + int i; + + /* find the hunk */ + for (i = 0; i < MAX_ZLIB_ALLOCS; i++) + if (ptr == alloc->allocptr[i]) + { + /* clear the low bit of the size to allow matches */ + *ptr &= ~1; + return; + } +} diff --git a/libretro-common/formats/libchdr/chd.h b/libretro-common/formats/libchdr/chd.h new file mode 100644 index 0000000000..a3a44b840a --- /dev/null +++ b/libretro-common/formats/libchdr/chd.h @@ -0,0 +1,399 @@ +/*************************************************************************** + + chd.h + + MAME Compressed Hunks of Data file format + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +***************************************************************************/ + +#pragma once + +#ifndef __CHD_H__ +#define __CHD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "coretypes.h" + + +/*************************************************************************** + + Compressed Hunks of Data header format. All numbers are stored in + Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2) + bytes long. + + V1 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 hunksize; // 512-byte sectors per hunk + [ 28] UINT32 totalhunks; // total # of hunks represented + [ 32] UINT32 cylinders; // number of cylinders on hard disk + [ 36] UINT32 heads; // number of heads on hard disk + [ 40] UINT32 sectors; // number of sectors on hard disk + [ 44] UINT8 md5[16]; // MD5 checksum of raw data + [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file + [ 76] (V1 header length) + + V2 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 hunksize; // seclen-byte sectors per hunk + [ 28] UINT32 totalhunks; // total # of hunks represented + [ 32] UINT32 cylinders; // number of cylinders on hard disk + [ 36] UINT32 heads; // number of heads on hard disk + [ 40] UINT32 sectors; // number of sectors on hard disk + [ 44] UINT8 md5[16]; // MD5 checksum of raw data + [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file + [ 76] UINT32 seclen; // number of bytes per sector + [ 80] (V2 header length) + + V3 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 totalhunks; // total # of hunks represented + [ 28] UINT64 logicalbytes; // logical size of the data (in bytes) + [ 36] UINT64 metaoffset; // offset to the first blob of metadata + [ 44] UINT8 md5[16]; // MD5 checksum of raw data + [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file + [ 76] UINT32 hunkbytes; // number of bytes per hunk + [ 80] UINT8 sha1[20]; // SHA1 checksum of raw data + [100] UINT8 parentsha1[20];// SHA1 checksum of parent file + [120] (V3 header length) + + V4 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] UINT32 length; // length of header (including tag and length fields) + [ 12] UINT32 version; // drive format version + [ 16] UINT32 flags; // flags (see below) + [ 20] UINT32 compression; // compression type + [ 24] UINT32 totalhunks; // total # of hunks represented + [ 28] UINT64 logicalbytes; // logical size of the data (in bytes) + [ 36] UINT64 metaoffset; // offset to the first blob of metadata + [ 44] UINT32 hunkbytes; // number of bytes per hunk + [ 48] UINT8 sha1[20]; // combined raw+meta SHA1 + [ 68] UINT8 parentsha1[20];// combined raw+meta SHA1 of parent + [ 88] UINT8 rawsha1[20]; // raw data SHA1 + [108] (V4 header length) + + Flags: + 0x00000001 - set if this drive has a parent + 0x00000002 - set if this drive allows writes + + ========================================================================= + + V5 header: + + [ 0] char tag[8]; // 'MComprHD' + [ 8] uint32_t length; // length of header (including tag and length fields) + [ 12] uint32_t version; // drive format version + [ 16] uint32_t compressors[4];// which custom compressors are used? + [ 32] uint64_t logicalbytes; // logical size of the data (in bytes) + [ 40] uint64_t mapoffset; // offset to the map + [ 48] uint64_t metaoffset; // offset to the first blob of metadata + [ 56] uint32_t hunkbytes; // number of bytes per hunk (512k maximum) + [ 60] uint32_t unitbytes; // number of bytes per unit within each hunk + [ 64] uint8_t rawsha1[20]; // raw data SHA1 + [ 84] uint8_t sha1[20]; // combined raw+meta SHA1 + [104] uint8_t parentsha1[20];// combined raw+meta SHA1 of parent + [124] (V5 header length) + + If parentsha1 != 0, we have a parent (no need for flags) + If compressors[0] == 0, we are uncompressed (including maps) + + V5 uncompressed map format: + + [ 0] uint32_t offset; // starting offset / hunk size + + V5 compressed map format header: + + [ 0] uint32_t length; // length of compressed map + [ 4] UINT48 datastart; // offset of first block + [ 10] uint16_t crc; // crc-16 of the map + [ 12] uint8_t lengthbits; // bits used to encode complength + [ 13] uint8_t hunkbits; // bits used to encode self-refs + [ 14] uint8_t parentunitbits; // bits used to encode parent unit refs + [ 15] uint8_t reserved; // future use + [ 16] (compressed header length) + + Each compressed map entry, once expanded, looks like: + + [ 0] uint8_t compression; // compression type + [ 1] UINT24 complength; // compressed length + [ 4] UINT48 offset; // offset + [ 10] uint16_t crc; // crc-16 of the data + +***************************************************************************/ + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +/* header information */ +#define CHD_HEADER_VERSION 5 +#define CHD_V1_HEADER_SIZE 76 +#define CHD_V2_HEADER_SIZE 80 +#define CHD_V3_HEADER_SIZE 120 +#define CHD_V4_HEADER_SIZE 108 +#define CHD_V5_HEADER_SIZE 124 + +#define CHD_MAX_HEADER_SIZE CHD_V5_HEADER_SIZE + +/* checksumming information */ +#define CHD_MD5_BYTES 16 +#define CHD_SHA1_BYTES 20 + +/* CHD global flags */ +#define CHDFLAGS_HAS_PARENT 0x00000001 +#define CHDFLAGS_IS_WRITEABLE 0x00000002 +#define CHDFLAGS_UNDEFINED 0xfffffffc + +/* compression types */ +#define CHDCOMPRESSION_NONE 0 +#define CHDCOMPRESSION_ZLIB 1 +#define CHDCOMPRESSION_ZLIB_PLUS 2 +#define CHDCOMPRESSION_AV 3 + +/* A/V codec configuration parameters */ +#define AV_CODEC_COMPRESS_CONFIG 1 +#define AV_CODEC_DECOMPRESS_CONFIG 2 + +/* metadata parameters */ +#define CHDMETATAG_WILDCARD 0 +#define CHD_METAINDEX_APPEND ((UINT32)-1) + +/* metadata flags */ +#define CHD_MDFLAGS_CHECKSUM 0x01 /* indicates data is checksummed */ + +/* standard hard disk metadata */ +#define HARD_DISK_METADATA_TAG 0x47444444 /* 'GDDD' */ +#define HARD_DISK_METADATA_FORMAT "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d" + +/* hard disk identify information */ +#define HARD_DISK_IDENT_METADATA_TAG 0x49444e54 /* 'IDNT' */ + +/* hard disk key information */ +#define HARD_DISK_KEY_METADATA_TAG 0x4b455920 /* 'KEY ' */ + +/* pcmcia CIS information */ +#define PCMCIA_CIS_METADATA_TAG 0x43495320 /* 'CIS ' */ + +/* standard CD-ROM metadata */ +#define CDROM_OLD_METADATA_TAG 0x43484344 /* 'CHCD' */ +#define CDROM_TRACK_METADATA_TAG 0x43485452 /* 'CHTR' */ +#define CDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d" +#define CDROM_TRACK_METADATA2_TAG 0x43485432 /* 'CHT2' */ +#define CDROM_TRACK_METADATA2_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" +#define GDROM_TRACK_METADATA_TAG 0x43484744 /* 'CHTD' */ +#define GDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d" + +/* standard A/V metadata */ +#define AV_METADATA_TAG 0x41564156 /* 'AVAV' */ +#define AV_METADATA_FORMAT "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d" + +/* A/V laserdisc frame metadata */ +#define AV_LD_METADATA_TAG 0x41564C44 /* 'AVLD' */ + +/* CHD open values */ +#define CHD_OPEN_READ 1 +#define CHD_OPEN_READWRITE 2 + +/* error types */ +enum _chd_error +{ + CHDERR_NONE, + CHDERR_NO_INTERFACE, + CHDERR_OUT_OF_MEMORY, + CHDERR_INVALID_FILE, + CHDERR_INVALID_PARAMETER, + CHDERR_INVALID_DATA, + CHDERR_FILE_NOT_FOUND, + CHDERR_REQUIRES_PARENT, + CHDERR_FILE_NOT_WRITEABLE, + CHDERR_READ_ERROR, + CHDERR_WRITE_ERROR, + CHDERR_CODEC_ERROR, + CHDERR_INVALID_PARENT, + CHDERR_HUNK_OUT_OF_RANGE, + CHDERR_DECOMPRESSION_ERROR, + CHDERR_COMPRESSION_ERROR, + CHDERR_CANT_CREATE_FILE, + CHDERR_CANT_VERIFY, + CHDERR_NOT_SUPPORTED, + CHDERR_METADATA_NOT_FOUND, + CHDERR_INVALID_METADATA_SIZE, + CHDERR_UNSUPPORTED_VERSION, + CHDERR_VERIFY_INCOMPLETE, + CHDERR_INVALID_METADATA, + CHDERR_INVALID_STATE, + CHDERR_OPERATION_PENDING, + CHDERR_NO_ASYNC_OPERATION, + CHDERR_UNSUPPORTED_FORMAT +}; +typedef enum _chd_error chd_error; + + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +/* opaque types */ +typedef struct _chd_file chd_file; + + +/* extract header structure (NOT the on-disk header structure) */ +typedef struct _chd_header chd_header; +struct _chd_header +{ + UINT32 length; /* length of header data */ + UINT32 version; /* drive format version */ + UINT32 flags; /* flags field */ + UINT32 compression[4]; /* compression type */ + UINT32 hunkbytes; /* number of bytes per hunk */ + UINT32 totalhunks; /* total # of hunks represented */ + UINT64 logicalbytes; /* logical size of the data */ + UINT64 metaoffset; /* offset in file of first metadata */ + UINT64 mapoffset; /* TOOD V5 */ + UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ + UINT8 parentmd5[CHD_MD5_BYTES]; /* overall MD5 checksum of parent */ + UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ + UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ + UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */ + UINT32 unitbytes; /* TODO V5 */ + UINT64 unitcount; /* TODO V5 */ + UINT32 hunkcount; /* TODO V5 */ + + // map information + UINT32 mapentrybytes; // length of each entry in a map (V5) + UINT8* rawmap; // raw map data + + UINT32 obsolete_cylinders; /* obsolete field -- do not use! */ + UINT32 obsolete_sectors; /* obsolete field -- do not use! */ + UINT32 obsolete_heads; /* obsolete field -- do not use! */ + UINT32 obsolete_hunksize; /* obsolete field -- do not use! */ +}; + + +/* structure for returning information about a verification pass */ +typedef struct _chd_verify_result chd_verify_result; +struct _chd_verify_result +{ + UINT8 md5[CHD_MD5_BYTES]; /* overall MD5 checksum */ + UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */ + UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */ + UINT8 metasha1[CHD_SHA1_BYTES]; /* SHA1 checksum of metadata */ +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + + +/* ----- CHD file management ----- */ + +/* create a new CHD file fitting the given description */ +// chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); + +/* same as chd_create(), but accepts an already-opened core_file object */ +// chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); + +/* open an existing CHD file */ +chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd); + + +/* close a CHD file */ +void chd_close(chd_file *chd); + +/* return the associated core_file */ +core_file *chd_core_file(chd_file *chd); + +/* return an error string for the given CHD error */ +const char *chd_error_string(chd_error err); + + + +/* ----- CHD header management ----- */ + +/* return a pointer to the extracted CHD header data */ +const chd_header *chd_get_header(chd_file *chd); + + + + +/* ----- core data read/write ----- */ + +/* read one hunk from the CHD file */ +chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer); + + + +/* ----- metadata management ----- */ + +/* get indexed metadata of a particular sort */ +chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags); + + + + +/* ----- codec interfaces ----- */ + +/* set internal codec parameters */ +chd_error chd_codec_config(chd_file *chd, int param, void *config); + +/* return a string description of a codec */ +const char *chd_get_codec_name(UINT32 codec); + +#ifdef __cplusplus +} +#endif + +#endif /* __CHD_H__ */ diff --git a/libretro-common/formats/libchdr/coretypes.h b/libretro-common/formats/libchdr/coretypes.h new file mode 100644 index 0000000000..80f161f2b6 --- /dev/null +++ b/libretro-common/formats/libchdr/coretypes.h @@ -0,0 +1,36 @@ +#ifndef __CORETYPES_H__ +#define __CORETYPES_H__ + +#include +#include + +#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0])) + +typedef uint64_t UINT64; +typedef uint32_t UINT32; +typedef uint16_t UINT16; +typedef uint8_t UINT8; + +typedef int64_t INT64; +typedef int32_t INT32; +typedef int16_t INT16; +typedef int8_t INT8; + +#define core_file FILE +#define core_fopen(file) fopen(file, "rb") +#define core_fseek fseek +#define core_fread(fc, buff, len) fread(buff, 1, len, fc) +#define core_fclose fclose +#define core_ftell ftell + +static size_t core_fsize(core_file* f) +{ + size_t rv; + size_t p = ftell(f); + fseek(f, 0, SEEK_END); + rv = ftell(f); + fseek(f, p, SEEK_SET); + return rv; +} + +#endif diff --git a/libretro-common/formats/libchdr/flac.c b/libretro-common/formats/libchdr/flac.c new file mode 100644 index 0000000000..29844b6513 --- /dev/null +++ b/libretro-common/formats/libchdr/flac.c @@ -0,0 +1,331 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + flac.c + + FLAC compression wrappers + +***************************************************************************/ + +#include +#include +#include "flac.h" + +//************************************************************************** +// FLAC DECODER +//************************************************************************** + +static FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes); +static void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); +static FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void* client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); +static void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +// getters (valid after reset) +static uint32_t sample_rate(flac_decoder *decoder) { return decoder->sample_rate; } +static uint8_t channels(flac_decoder *decoder) { return decoder->channels; } +static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; } +static uint32_t total_samples(flac_decoder *decoder) { return FLAC__stream_decoder_get_total_samples(decoder->decoder); } +static FLAC__StreamDecoderState state(flac_decoder *decoder) { return FLAC__stream_decoder_get_state(decoder->decoder); } +static const char *state_string(flac_decoder *decoder) { return FLAC__stream_decoder_get_resolved_state_string(decoder->decoder); } + +//------------------------------------------------- +// flac_decoder - constructor +//------------------------------------------------- + +void flac_decoder_init(flac_decoder *decoder) +{ + decoder->decoder = FLAC__stream_decoder_new(); + decoder->sample_rate = 0; + decoder->channels = 0; + decoder->bits_per_sample = 0; + decoder->compressed_offset = 0; + decoder->compressed_start = NULL; + decoder->compressed_length = 0; + decoder->compressed2_start = NULL; + decoder->compressed2_length = 0; + decoder->uncompressed_offset = 0; + decoder->uncompressed_length = 0; + decoder->uncompressed_swap = 0; +} + +//------------------------------------------------- +// flac_decoder - destructor +//------------------------------------------------- + +void flac_decoder_free(flac_decoder* decoder) +{ + if ((decoder != NULL) && (decoder->decoder != NULL)) + FLAC__stream_decoder_delete(decoder->decoder); +} + + +//------------------------------------------------- +// reset - reset state with the original +// parameters +//------------------------------------------------- + +static int flac_decoder_internal_reset(flac_decoder* decoder) +{ + decoder->compressed_offset = 0; + if (FLAC__stream_decoder_init_stream(decoder->decoder, + &flac_decoder_read_callback_static, + NULL, + &flac_decoder_tell_callback_static, + NULL, + NULL, + &flac_decoder_write_callback_static, + &flac_decoder_metadata_callback_static, + &flac_decoder_error_callback_static, decoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return 0; + return FLAC__stream_decoder_process_until_end_of_metadata(decoder->decoder); +} + + + +//------------------------------------------------- +// reset - reset state with new memory parameters +// and a custom-generated header +//------------------------------------------------- + +int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length) +{ + // modify the template header with our parameters + static const uint8_t s_header_template[0x2a] = + { + 0x66, 0x4C, 0x61, 0x43, // +00: 'fLaC' stream header + 0x80, // +04: metadata block type 0 (STREAMINFO), + // flagged as last block + 0x00, 0x00, 0x22, // +05: metadata block length = 0x22 + 0x00, 0x00, // +08: minimum block size + 0x00, 0x00, // +0A: maximum block size + 0x00, 0x00, 0x00, // +0C: minimum frame size (0 == unknown) + 0x00, 0x00, 0x00, // +0F: maximum frame size (0 == unknown) + 0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, // +12: sample rate (0x0ac44 == 44100), + // numchannels (2), sample bits (16), + // samples in stream (0 == unknown) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // +1A: MD5 signature (0 == none) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // + // +2A: start of stream data + }; + memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template)); + decoder->custom_header[0x08] = decoder->custom_header[0x0a] = block_size >> 8; + decoder->custom_header[0x09] = decoder->custom_header[0x0b] = block_size & 0xff; + decoder->custom_header[0x12] = sample_rate >> 12; + decoder->custom_header[0x13] = sample_rate >> 4; + decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1); + + // configure the header ahead of the provided buffer + decoder->compressed_start = (const FLAC__byte *)(decoder->custom_header); + decoder->compressed_length = sizeof(decoder->custom_header); + decoder->compressed2_start = (const FLAC__byte *)(buffer); + decoder->compressed2_length = length; + return flac_decoder_internal_reset(decoder); +} + + +//------------------------------------------------- +// decode_interleaved - decode to an interleaved +// sound stream +//------------------------------------------------- + +int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian) +{ + // configure the uncompressed buffer + memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start)); + decoder->uncompressed_start[0] = samples; + decoder->uncompressed_offset = 0; + decoder->uncompressed_length = num_samples; + decoder->uncompressed_swap = swap_endian; + + // loop until we get everything we want + while (decoder->uncompressed_offset < decoder->uncompressed_length) + if (!FLAC__stream_decoder_process_single(decoder->decoder)) + return 0; + return 1; +} + + +/* +//------------------------------------------------- +// decode - decode to an multiple independent +// data streams +//------------------------------------------------- + +bool flac_decoder::decode(int16_t **samples, uint32_t num_samples, bool swap_endian) +{ + // make sure we don't have too many channels + int chans = channels(); + if (chans > ARRAY_LENGTH(m_uncompressed_start)) + return false; + + // configure the uncompressed buffer + memset(m_uncompressed_start, 0, sizeof(m_uncompressed_start)); + for (int curchan = 0; curchan < chans; curchan++) + m_uncompressed_start[curchan] = samples[curchan]; + m_uncompressed_offset = 0; + m_uncompressed_length = num_samples; + m_uncompressed_swap = swap_endian; + + // loop until we get everything we want + while (m_uncompressed_offset < m_uncompressed_length) + if (!FLAC__stream_decoder_process_single(m_decoder)) + return false; + return true; +} +*/ + +//------------------------------------------------- +// finish - finish up the decode +//------------------------------------------------- + +uint32_t flac_decoder_finish(flac_decoder* decoder) +{ + // get the final decoding position and move forward + FLAC__uint64 position = 0; + FLAC__stream_decoder_get_decode_position(decoder->decoder, &position); + FLAC__stream_decoder_finish(decoder->decoder); + + // adjust position if we provided the header + if (position == 0) + return 0; + if (decoder->compressed_start == (const FLAC__byte *)(decoder->custom_header)) + position -= decoder->compressed_length; + return position; +} + + +//------------------------------------------------- +// read_callback - handle reads from the input +// stream +//------------------------------------------------- + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +FLAC__StreamDecoderReadStatus flac_decoder_read_callback_static(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + return flac_decoder_read_callback(client_data, buffer, bytes); +} + +FLAC__StreamDecoderReadStatus flac_decoder_read_callback(void* client_data, FLAC__byte buffer[], size_t *bytes) +{ + flac_decoder* decoder = (flac_decoder*)client_data; + + uint32_t expected = *bytes; + + // copy from primary buffer first + uint32_t outputpos = 0; + if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length) + { + uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed_length - decoder->compressed_offset); + memcpy(&buffer[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy); + outputpos += bytes_to_copy; + decoder->compressed_offset += bytes_to_copy; + } + + // once we're out of that, copy from the secondary buffer + if (outputpos < *bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length) + { + uint32_t bytes_to_copy = MIN(*bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length)); + memcpy(&buffer[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy); + outputpos += bytes_to_copy; + decoder->compressed_offset += bytes_to_copy; + } + *bytes = outputpos; + + // return based on whether we ran out of data + return (*bytes < expected) ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; +} + + +//------------------------------------------------- +// metadata_callback - handle STREAMINFO metadata +//------------------------------------------------- + +void flac_decoder_metadata_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + flac_decoder *fldecoder; + // ignore all but STREAMINFO metadata + if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) + return; + + // parse out the data we care about + fldecoder = (flac_decoder *)(client_data); + fldecoder->sample_rate = metadata->data.stream_info.sample_rate; + fldecoder->bits_per_sample = metadata->data.stream_info.bits_per_sample; + fldecoder->channels = metadata->data.stream_info.channels; +} + + +//------------------------------------------------- +// tell_callback - handle requests to find out +// where in the input stream we are +//------------------------------------------------- + +FLAC__StreamDecoderTellStatus flac_decoder_tell_callback_static(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + *absolute_byte_offset = ((flac_decoder *)client_data)->compressed_offset; + return FLAC__STREAM_DECODER_TELL_STATUS_OK; +} + + +//------------------------------------------------- +// write_callback - handle writes to the output +// stream +//------------------------------------------------- + +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback_static(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + return flac_decoder_write_callback(client_data, frame, buffer); +} + +FLAC__StreamDecoderWriteStatus flac_decoder_write_callback(void *client_data, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) +{ + int shift, blocksize; + flac_decoder * decoder = (flac_decoder *)client_data; + + assert(frame->header.channels == channels(decoder)); + + // interleaved case + shift = decoder->uncompressed_swap ? 8 : 0; + blocksize = frame->header.blocksize; + + if (decoder->uncompressed_start[1] == NULL) + { + int sampnum, chan; + int16_t *dest = decoder->uncompressed_start[0] + decoder->uncompressed_offset * frame->header.channels; + for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) + for (chan = 0; chan < frame->header.channels; chan++) + *dest++ = (int16_t)((((uint16_t)buffer[chan][sampnum]) << shift) | (((uint16_t)buffer[chan][sampnum]) >> shift)); + } + + // non-interleaved case + else + { + int sampnum, chan; + for (sampnum = 0; sampnum < blocksize && decoder->uncompressed_offset < decoder->uncompressed_length; sampnum++, decoder->uncompressed_offset++) + for (chan = 0; chan < frame->header.channels; chan++) + if (decoder->uncompressed_start[chan] != NULL) + decoder->uncompressed_start[chan][decoder->uncompressed_offset] = (int16_t) ( (((uint16_t)(buffer[chan][sampnum])) << shift) | ( ((uint16_t)(buffer[chan][sampnum])) >> shift) ); + } + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +/** + * @fn void flac_decoder::error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) + * + * @brief ------------------------------------------------- + * error_callback - handle errors (ignore them) + * -------------------------------------------------. + * + * @param decoder The decoder. + * @param status The status. + * @param [in,out] client_data If non-null, information describing the client. + */ + +void flac_decoder_error_callback_static(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ +} diff --git a/libretro-common/formats/libchdr/flac.h b/libretro-common/formats/libchdr/flac.h new file mode 100644 index 0000000000..23e91a9ae3 --- /dev/null +++ b/libretro-common/formats/libchdr/flac.h @@ -0,0 +1,50 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + flac.h + + FLAC compression wrappers + +***************************************************************************/ + +#pragma once + +#ifndef __FLAC_H__ +#define __FLAC_H__ + +#include +#include "FLAC/all.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef struct _flac_decoder flac_decoder; +struct _flac_decoder { + // output state + FLAC__StreamDecoder* decoder; // actual encoder + uint32_t sample_rate; // decoded sample rate + uint8_t channels; // decoded number of channels + uint8_t bits_per_sample; // decoded bits per sample + uint32_t compressed_offset; // current offset in compressed data + const FLAC__byte * compressed_start; // start of compressed data + uint32_t compressed_length; // length of compressed data + const FLAC__byte * compressed2_start; // start of compressed data + uint32_t compressed2_length; // length of compressed data + int16_t * uncompressed_start[8]; // pointer to start of uncompressed data (up to 8 streams) + uint32_t uncompressed_offset; // current position in uncompressed data + uint32_t uncompressed_length; // length of uncompressed data + int uncompressed_swap; // swap uncompressed sample data + uint8_t custom_header[0x2a]; // custom header +}; + +// ======================> flac_decoder + +void flac_decoder_init(flac_decoder* decoder); +void flac_decoder_free(flac_decoder* decoder); +int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length); +int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian); +uint32_t flac_decoder_finish(flac_decoder* decoder); + +#endif // __FLAC_H__ diff --git a/libretro-common/formats/libchdr/huffman.c b/libretro-common/formats/libchdr/huffman.c new file mode 100644 index 0000000000..d67ec19c96 --- /dev/null +++ b/libretro-common/formats/libchdr/huffman.c @@ -0,0 +1,528 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + huffman.c + + Static Huffman compression and decompression helpers. + +**************************************************************************** + + Maximum codelength is officially (alphabetsize - 1). This would be 255 bits + (since we use 1 byte values). However, it is also dependent upon the number + of samples used, as follows: + + 2 bits -> 3..4 samples + 3 bits -> 5..7 samples + 4 bits -> 8..12 samples + 5 bits -> 13..20 samples + 6 bits -> 21..33 samples + 7 bits -> 34..54 samples + 8 bits -> 55..88 samples + 9 bits -> 89..143 samples + 10 bits -> 144..232 samples + 11 bits -> 233..376 samples + 12 bits -> 377..609 samples + 13 bits -> 610..986 samples + 14 bits -> 987..1596 samples + 15 bits -> 1597..2583 samples + 16 bits -> 2584..4180 samples -> note that a 4k data size guarantees codelength <= 16 bits + 17 bits -> 4181..6764 samples + 18 bits -> 6765..10945 samples + 19 bits -> 10946..17710 samples + 20 bits -> 17711..28656 samples + 21 bits -> 28657..46367 samples + 22 bits -> 46368..75024 samples + 23 bits -> 75025..121392 samples + 24 bits -> 121393..196417 samples + 25 bits -> 196418..317810 samples + 26 bits -> 317811..514228 samples + 27 bits -> 514229..832039 samples + 28 bits -> 832040..1346268 samples + 29 bits -> 1346269..2178308 samples + 30 bits -> 2178309..3524577 samples + 31 bits -> 3524578..5702886 samples + 32 bits -> 5702887..9227464 samples + + Looking at it differently, here is where powers of 2 fall into these buckets: + + 256 samples -> 11 bits max + 512 samples -> 12 bits max + 1k samples -> 14 bits max + 2k samples -> 15 bits max + 4k samples -> 16 bits max + 8k samples -> 18 bits max + 16k samples -> 19 bits max + 32k samples -> 21 bits max + 64k samples -> 22 bits max + 128k samples -> 24 bits max + 256k samples -> 25 bits max + 512k samples -> 27 bits max + 1M samples -> 28 bits max + 2M samples -> 29 bits max + 4M samples -> 31 bits max + 8M samples -> 32 bits max + +**************************************************************************** + + Delta-RLE encoding works as follows: + + Starting value is assumed to be 0. All data is encoded as a delta + from the previous value, such that final[i] = final[i - 1] + delta. + Long runs of 0s are RLE-encoded as follows: + + 0x100 = repeat count of 8 + 0x101 = repeat count of 9 + 0x102 = repeat count of 10 + 0x103 = repeat count of 11 + 0x104 = repeat count of 12 + 0x105 = repeat count of 13 + 0x106 = repeat count of 14 + 0x107 = repeat count of 15 + 0x108 = repeat count of 16 + 0x109 = repeat count of 32 + 0x10a = repeat count of 64 + 0x10b = repeat count of 128 + 0x10c = repeat count of 256 + 0x10d = repeat count of 512 + 0x10e = repeat count of 1024 + 0x10f = repeat count of 2048 + + Note that repeat counts are reset at the end of a row, so if a 0 run + extends to the end of a row, a large repeat count may be used. + + The reason for starting the run counts at 8 is that 0 is expected to + be the most common symbol, and is typically encoded in 1 or 2 bits. + +***************************************************************************/ + +#include +#include +#include +#include + +#include "huffman.h" + +#define MAX(x,y) ((x) > (y) ? (x) : (y)) + +//************************************************************************** +// MACROS +//************************************************************************** + +#define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f)) + + +//************************************************************************** +// IMPLEMENTATION +//************************************************************************** + +//------------------------------------------------- +// huffman_context_base - create an encoding/ +// decoding context +//------------------------------------------------- + +struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits) +{ + struct huffman_decoder* decoder; + + /* limit to 24 bits */ + if (maxbits > 24) + return NULL; + + decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder)); + decoder->numcodes = numcodes; + decoder->maxbits = maxbits; + decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits)); + decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes); + decoder->datahisto = NULL; + decoder->prevdata = 0; + decoder->rleremaining = 0; + return decoder; +} + +//------------------------------------------------- +// decode_one - decode a single code from the +// huffman stream +//------------------------------------------------- + +uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf) +{ + /* peek ahead to get maxbits worth of data */ + uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits); + + /* look it up, then remove the actual number of bits for this code */ + lookup_value lookup = decoder->lookup[bits]; + bitstream_remove(bitbuf, lookup & 0x1f); + + /* return the value */ + return lookup >> 5; +} + +//------------------------------------------------- +// import_tree_rle - import an RLE-encoded +// huffman tree from a source data stream +//------------------------------------------------- + +enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf) +{ + enum huffman_error error; + int curnode; + // bits per entry depends on the maxbits + int numbits; + if (decoder->maxbits >= 16) + numbits = 5; + else if (decoder->maxbits >= 8) + numbits = 4; + else + numbits = 3; + + // loop until we read all the nodes + for (curnode = 0; curnode < decoder->numcodes; ) + { + // a non-one value is just raw + int nodebits = bitstream_read(bitbuf, numbits); + if (nodebits != 1) + decoder->huffnode[curnode++].numbits = nodebits; + + // a one value is an escape code + else + { + // a double 1 is just a single 1 + nodebits = bitstream_read(bitbuf, numbits); + if (nodebits == 1) + decoder->huffnode[curnode++].numbits = nodebits; + + // otherwise, we need one for value for the repeat count + else + { + int repcount = bitstream_read(bitbuf, numbits) + 3; + while (repcount--) + decoder->huffnode[curnode++].numbits = nodebits; + } + } + } + + // make sure we ended up with the right number + if (curnode != decoder->numcodes) + return HUFFERR_INVALID_DATA; + + // assign canonical codes for all nodes based on their code lengths + error = huffman_assign_canonical_codes(decoder); + if (error != HUFFERR_NONE) + return error; + + // build the lookup table + huffman_build_lookup_table(decoder); + + // determine final input length and report errors + return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; +} + + +//------------------------------------------------- +// import_tree_huffman - import a huffman-encoded +// huffman tree from a source data stream +//------------------------------------------------- + +enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf) +{ + int index; + int start; + int count = 0; + uint8_t rlefullbits = 0; + int last = 0; + int curcode; + enum huffman_error error; + uint32_t temp; + // start by parsing the lengths for the small tree + struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6); + + smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3); + start = bitstream_read(bitbuf, 3) + 1; + + for (index = 1; index < 24; index++) + { + if (index < start || count == 7) + smallhuff->huffnode[index].numbits = 0; + else + { + count = bitstream_read(bitbuf, 3); + smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count; + } + } + + // then regenerate the tree + error = huffman_assign_canonical_codes(smallhuff); + if (error != HUFFERR_NONE) + return error; + huffman_build_lookup_table(smallhuff); + + // determine the maximum length of an RLE count + temp = decoder->numcodes - 9; + while (temp != 0) + temp >>= 1, rlefullbits++; + + // now process the rest of the data + for (curcode = 0; curcode < decoder->numcodes; ) + { + int value = huffman_decode_one(smallhuff, bitbuf); + if (value != 0) + decoder->huffnode[curcode++].numbits = last = value - 1; + else + { + int count = bitstream_read(bitbuf, 3) + 2; + if (count == 7+2) + count += bitstream_read(bitbuf, rlefullbits); + for ( ; count != 0 && curcode < decoder->numcodes; count--) + decoder->huffnode[curcode++].numbits = last; + } + } + + // make sure we ended up with the right number + if (curcode != decoder->numcodes) + return HUFFERR_INVALID_DATA; + + // assign canonical codes for all nodes based on their code lengths + error = huffman_assign_canonical_codes(decoder); + if (error != HUFFERR_NONE) + return error; + + // build the lookup table + huffman_build_lookup_table(decoder); + + // determine final input length and report errors + return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; +} + + +//------------------------------------------------- +// compute_tree_from_histo - common backend for +// computing a tree based on the data histogram +//------------------------------------------------- + +enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder) +{ + int i; + uint32_t upperweight; + uint32_t lowerweight = 0; + // compute the number of data items in the histogram + uint32_t sdatacount = 0; + for (i = 0; i < decoder->numcodes; i++) + sdatacount += decoder->datahisto[i]; + + // binary search to achieve the optimum encoding + upperweight = sdatacount * 2; + while (1) + { + // build a tree using the current weight + uint32_t curweight = (upperweight + lowerweight) / 2; + int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight); + + // apply binary search here + if (curmaxbits <= decoder->maxbits) + { + lowerweight = curweight; + + // early out if it worked with the raw weights, or if we're done searching + if (curweight == sdatacount || (upperweight - lowerweight) <= 1) + break; + } + else + upperweight = curweight; + } + + // assign canonical codes for all nodes based on their code lengths + return huffman_assign_canonical_codes(decoder); +} + + + +//************************************************************************** +// INTERNAL FUNCTIONS +//************************************************************************** + +//------------------------------------------------- +// tree_node_compare - compare two tree nodes +// by weight +//------------------------------------------------- + +static int huffman_tree_node_compare(const void *item1, const void *item2) +{ + const struct node_t *node1 = *(const struct node_t **)item1; + const struct node_t *node2 = *(const struct node_t **)item2; + if (node2->weight != node1->weight) + return node2->weight - node1->weight; + if (node2->bits - node1->bits == 0) + fprintf(stderr, "identical node sort keys, should not happen!\n"); + return (int)node1->bits - (int)node2->bits; +} + + +//------------------------------------------------- +// build_tree - build a huffman tree based on the +// data distribution +//------------------------------------------------- + +int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight) +{ + int curcode; + int nextalloc; + int maxbits = 0; + // make a list of all non-zero nodes + struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2); + int listitems = 0; + memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0])); + for (curcode = 0; curcode < decoder->numcodes; curcode++) + if (decoder->datahisto[curcode] != 0) + { + list[listitems++] = &decoder->huffnode[curcode]; + decoder->huffnode[curcode].count = decoder->datahisto[curcode]; + decoder->huffnode[curcode].bits = curcode; + + // scale the weight by the current effective length, ensuring we don't go to 0 + decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata); + if (decoder->huffnode[curcode].weight == 0) + decoder->huffnode[curcode].weight = 1; + } +/* + fprintf(stderr, "Pre-sort:\n"); + for (int i = 0; i < listitems; i++) { + fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); + } +*/ + // sort the list by weight, largest weight first + qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare); +/* + fprintf(stderr, "Post-sort:\n"); + for (int i = 0; i < listitems; i++) { + fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits); + } + fprintf(stderr, "===================\n"); +*/ + // now build the tree + nextalloc = decoder->numcodes; + + while (listitems > 1) + { + int curitem; + // remove lowest two items + struct node_t* node1 = &(*list[--listitems]); + struct node_t* node0 = &(*list[--listitems]); + + // create new node + struct node_t* newnode = &decoder->huffnode[nextalloc++]; + newnode->parent = NULL; + node0->parent = node1->parent = newnode; + newnode->weight = node0->weight + node1->weight; + + // insert into list at appropriate location + for (curitem = 0; curitem < listitems; curitem++) + if (newnode->weight > list[curitem]->weight) + { + memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0])); + break; + } + list[curitem] = newnode; + listitems++; + } + + // compute the number of bits in each code, and fill in another histogram + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + struct node_t* node = &decoder->huffnode[curcode]; + node->numbits = 0; + node->bits = 0; + + // if we have a non-zero weight, compute the number of bits + if (node->weight > 0) + { + struct node_t *curnode; + // determine the number of bits for this node + for (curnode = node; curnode->parent != NULL; curnode = curnode->parent) + node->numbits++; + if (node->numbits == 0) + node->numbits = 1; + + // keep track of the max + maxbits = MAX(maxbits, ((int)node->numbits)); + } + } + return maxbits; +} + + +//------------------------------------------------- +// assign_canonical_codes - assign canonical codes +// to all the nodes based on the number of bits +// in each +//------------------------------------------------- + +enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder) +{ + int curcode, codelen; + uint32_t curstart = 0; + + // build up a histogram of bit lengths + uint32_t bithisto[33] = { 0 }; + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + struct node_t* node = &decoder->huffnode[curcode]; + if (node->numbits > decoder->maxbits) + return HUFFERR_INTERNAL_INCONSISTENCY; + if (node->numbits <= 32) + bithisto[node->numbits]++; + } + + // for each code length, determine the starting code number + for (codelen = 32; codelen > 0; codelen--) + { + uint32_t nextstart = (curstart + bithisto[codelen]) >> 1; + if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen])) + return HUFFERR_INTERNAL_INCONSISTENCY; + bithisto[codelen] = curstart; + curstart = nextstart; + } + + // now assign canonical codes + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + struct node_t* node = &decoder->huffnode[curcode]; + if (node->numbits > 0) + node->bits = bithisto[node->numbits]++; + } + return HUFFERR_NONE; +} + + +//------------------------------------------------- +// build_lookup_table - build a lookup table for +// fast decoding +//------------------------------------------------- + +void huffman_build_lookup_table(struct huffman_decoder* decoder) +{ + int curcode; + // iterate over all codes + for (curcode = 0; curcode < decoder->numcodes; curcode++) + { + // process all nodes which have non-zero bits + struct node_t* node = &decoder->huffnode[curcode]; + if (node->numbits > 0) + { + int shift; + lookup_value *dest; + lookup_value *destend; + + // set up the entry + lookup_value value = MAKE_LOOKUP(curcode, node->numbits); + + // fill all matching entries + shift = decoder->maxbits - node->numbits; + dest = &decoder->lookup[node->bits << shift]; + destend = &decoder->lookup[((node->bits + 1) << shift) - 1]; + + while (dest <= destend) + *dest++ = value; + } + } +} diff --git a/libretro-common/formats/libchdr/huffman.h b/libretro-common/formats/libchdr/huffman.h new file mode 100644 index 0000000000..71de399971 --- /dev/null +++ b/libretro-common/formats/libchdr/huffman.h @@ -0,0 +1,87 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + huffman.h + + Static Huffman compression and decompression helpers. + +***************************************************************************/ + +#pragma once + +#ifndef __HUFFMAN_H__ +#define __HUFFMAN_H__ + +#include "bitstream.h" + + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +enum huffman_error +{ + HUFFERR_NONE = 0, + HUFFERR_TOO_MANY_BITS, + HUFFERR_INVALID_DATA, + HUFFERR_INPUT_BUFFER_TOO_SMALL, + HUFFERR_OUTPUT_BUFFER_TOO_SMALL, + HUFFERR_INTERNAL_INCONSISTENCY, + HUFFERR_TOO_MANY_CONTEXTS +}; + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +typedef uint16_t lookup_value; + +// a node in the huffman tree +struct node_t +{ + struct node_t* parent; // pointer to parent node + uint32_t count; // number of hits on this node + uint32_t weight; // assigned weight of this node + uint32_t bits; // bits used to encode the node + uint8_t numbits; // number of bits needed for this node +}; + +// ======================> huffman_context_base + +// context class for decoding +struct huffman_decoder +{ + // internal state + uint32_t numcodes; // number of total codes being processed + uint8_t maxbits; // maximum bits per code + uint8_t prevdata; // value of the previous data (for delta-RLE encoding) + int rleremaining; // number of RLE bytes remaining (for delta-RLE encoding) + lookup_value * lookup; // pointer to the lookup table + struct node_t * huffnode; // array of nodes + uint32_t * datahisto; // histogram of data values + + // array versions of the info we need + //node_t* huffnode_array; //[_NumCodes]; + //lookup_value* lookup_array; //[1 << _MaxBits]; +}; + +// ======================> huffman_decoder + +struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits); + +// single item operations +uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf); + +enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf); +enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf); + +int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight); +enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder); +enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder); + +void huffman_build_lookup_table(struct huffman_decoder* decoder); + +#endif diff --git a/libretro-common/include/encodings/win32.h b/libretro-common/include/encodings/win32.h new file mode 100644 index 0000000000..45e7c9a5c3 --- /dev/null +++ b/libretro-common/include/encodings/win32.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2010-2016 The RetroArch team + * + * --------------------------------------------------------------------------------------- + * The following license statement only applies to this file (utf.h). + * --------------------------------------------------------------------------------------- + * + * Permission is hereby granted, free of charge, + * to any person obtaining a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef _LIBRETRO_ENCODINGS_WIN32_H +#define _LIBRETRO_ENCODINGS_WIN32_H + +#ifndef _XBOX +#ifdef _WIN32 +/*#define UNICODE +#include +#include */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifdef __cplusplus +} +#endif + +#endif +#endif + +#ifdef UNICODE +#define CHAR_TO_WCHAR_ALLOC(s, ws) \ + size_t ws##_size = (NULL != s && s[0] ? strlen(s) : 0) + 1; \ + wchar_t *ws = (wchar_t*)calloc(ws##_size, 2); \ + if (NULL != s && s[0]) \ + MultiByteToWideChar(CP_UTF8, 0, s, -1, ws, ws##_size / sizeof(wchar_t)); + +#define WCHAR_TO_CHAR_ALLOC(ws, s) \ + size_t s##_size = ((NULL != ws && ws[0] ? wcslen((const wchar_t*)ws) : 0) / 2) + 1; \ + char *s = (char*)calloc(s##_size, 1); \ + if (NULL != ws && ws[0]) \ + utf16_to_char_string((const uint16_t*)ws, s, s##_size); + +#else +#define CHAR_TO_WCHAR_ALLOC(s, ws) char *ws = (NULL != s && s[0] ? strdup(s) : NULL); +#define WCHAR_TO_CHAR_ALLOC(ws, s) char *s = (NULL != ws && ws[0] ? strdup(ws) : NULL); +#endif + +#endif diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index c9e99bbf05..74820e7a3c 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -923,6 +923,18 @@ enum retro_mod * writeable (and readable). */ +#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* N/A (null) * -- + * The frontend will try to use a 'shared' hardware context (mostly applicable + * to OpenGL) when a hardware context is being set up. + * + * Returns true if the frontend supports shared hardware contexts and false + * if the frontend does not support shared hardware contexts. + * + * This will do nothing on its own until SET_HW_RENDER env callbacks are + * being used. + */ + enum retro_hw_render_interface_type { RETRO_HW_RENDER_INTERFACE_VULKAN = 0, diff --git a/libretro-common/include/string/stdstring.h b/libretro-common/include/string/stdstring.h index 845d636948..98f7aecd03 100644 --- a/libretro-common/include/string/stdstring.h +++ b/libretro-common/include/string/stdstring.h @@ -87,7 +87,7 @@ char *string_trim_whitespace_right(char *const s); /* Remove leading and trailing whitespaces */ char *string_trim_whitespace(char *const s); -char *word_wrap(char* buffer, const char *string, int line_width); +char *word_wrap(char* buffer, const char *string, int line_width, bool unicode); RETRO_END_DECLS diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index c4ffce1d5c..a059bc2f04 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -437,11 +437,18 @@ void scond_free(scond_t *cond) #ifdef USE_WIN32_THREADS static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds) { - static bool beginPeriod = false; - struct QueueEntry myentry; struct QueueEntry **ptr; + +#if _WIN32_WINNT >= 0x0500 + static LARGE_INTEGER performanceCounterFrequency; + LARGE_INTEGER tsBegin; + static bool first_init = true; +#else + static bool beginPeriod = false; DWORD tsBegin; +#endif + DWORD waitResult; DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head, we don't do the hot potato stuff, @@ -453,16 +460,33 @@ static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds /* since this library is meant for realtime game software * I have no problem setting this to 1 and forgetting about it. */ +#if _WIN32_WINNT >= 0x0500 + if (first_init) + { + performanceCounterFrequency.QuadPart = 0; + first_init = false; + } + + if (performanceCounterFrequency.QuadPart == 0) + { + QueryPerformanceFrequency(&performanceCounterFrequency); + } +#else if (!beginPeriod) { beginPeriod = true; timeBeginPeriod(1); } +#endif /* Now we can take a good timestamp for use in faking the timeout ourselves. */ /* But don't bother unless we need to (to save a little time) */ if (dwMilliseconds != INFINITE) +#if _WIN32_WINNT >= 0x0500 + QueryPerformanceCounter(&tsBegin); +#else tsBegin = timeGetTime(); +#endif /* add ourselves to a queue of waiting threads */ ptr = &cond->head; @@ -504,8 +528,16 @@ static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds /* Assess the remaining timeout time */ if (dwMilliseconds != INFINITE) { - DWORD now = timeGetTime(); +#if _WIN32_WINNT >= 0x0500 + LARGE_INTEGER now; + QueryPerformanceCounter(&now); + LONGLONG elapsed = now.QuadPart - tsBegin.QuadPart; + elapsed *= 1000; + elapsed /= performanceCounterFrequency.QuadPart; +#else + DWORD now = timeGetTime(); DWORD elapsed = now - tsBegin; +#endif /* Try one last time with a zero timeout (keeps the code simpler) */ if (elapsed > dwMilliseconds) diff --git a/libretro-common/string/stdstring.c b/libretro-common/string/stdstring.c index ea8d62e70f..88a436f128 100644 --- a/libretro-common/string/stdstring.c +++ b/libretro-common/string/stdstring.c @@ -24,12 +24,13 @@ #include #include +#include char *string_to_upper(char *s) { char *cs = (char *)s; for ( ; *cs != '\0'; cs++) - *cs = toupper(*cs); + *cs = toupper((unsigned char)*cs); return s; } @@ -37,7 +38,7 @@ char *string_to_lower(char *s) { char *cs = (char *)s; for ( ; *cs != '\0'; cs++) - *cs = tolower(*cs); + *cs = tolower((unsigned char)*cs); return s; } @@ -47,10 +48,10 @@ char *string_ucwords(char *s) for ( ; *cs != '\0'; cs++) { if (*cs == ' ') - *(cs+1) = toupper(*(cs+1)); + *(cs+1) = toupper((unsigned char)*(cs+1)); } - s[0] = toupper(s[0]); + s[0] = toupper((unsigned char)s[0]); return s; } @@ -107,7 +108,7 @@ char *string_trim_whitespace_left(char *const s) size_t len = strlen(s); char *cur = s; - while(*cur && isspace(*cur)) + while(*cur && isspace((unsigned char)*cur)) ++cur, --len; if(s != cur) @@ -126,10 +127,10 @@ char *string_trim_whitespace_right(char *const s) size_t len = strlen(s); char *cur = s + len - 1; - while(cur != s && isspace(*cur)) + while(cur != s && isspace((unsigned char)*cur)) --cur, --len; - cur[isspace(*cur) ? 0 : 1] = '\0'; + cur[isspace((unsigned char)*cur) ? 0 : 1] = '\0'; } return s; @@ -144,7 +145,7 @@ char *string_trim_whitespace(char *const s) return s; } -char *word_wrap(char* buffer, const char *string, int line_width) +char *word_wrap(char* buffer, const char *string, int line_width, bool unicode) { unsigned i = 0; unsigned len = (unsigned)strlen(string); @@ -156,20 +157,34 @@ char *word_wrap(char* buffer, const char *string, int line_width) /* copy string until the end of the line is reached */ for (counter = 1; counter <= (unsigned)line_width; counter++) { + const char *character; + unsigned char_len; + unsigned j = i; + + character = utf8skip(&string[i], 1); + char_len = character - &string[i]; + /* check if end of string reached */ - if (i == strlen(string)) + if (i == len) { buffer[i] = 0; return buffer; } - buffer[i] = string[i]; + if (!unicode) + counter += char_len - 1; + + do + { + buffer[i] = string[i]; + char_len--; + i++; + } while(char_len); /* check for newlines embedded in the original input * and reset the index */ - if (buffer[i] == '\n') + if (buffer[j] == '\n') counter = 1; - i++; } /* check for whitespace */ diff --git a/media/android/dark/res/mipmap-hdpi/ic_launcher.png b/media/android/dark/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index b3f9a06868..0000000000 Binary files a/media/android/dark/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-mdpi/ic_launcher.png b/media/android/dark/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index b10decbbe0..0000000000 Binary files a/media/android/dark/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-xhdpi/ic_launcher.png b/media/android/dark/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index a80f62fd9d..0000000000 Binary files a/media/android/dark/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-xxhdpi/ic_launcher.png b/media/android/dark/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 74cd51fc93..0000000000 Binary files a/media/android/dark/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/res/mipmap-xxxhdpi/ic_launcher.png b/media/android/dark/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index ee5c33d461..0000000000 Binary files a/media/android/dark/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/dark/web_hi_res_512.png b/media/android/dark/web_hi_res_512.png deleted file mode 100644 index 9f2a980250..0000000000 Binary files a/media/android/dark/web_hi_res_512.png and /dev/null differ diff --git a/media/android/light/res/mipmap-hdpi/ic_launcher.png b/media/android/light/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 26953bee42..0000000000 Binary files a/media/android/light/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-mdpi/ic_launcher.png b/media/android/light/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index e99b744135..0000000000 Binary files a/media/android/light/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-xhdpi/ic_launcher.png b/media/android/light/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index b779422b8e..0000000000 Binary files a/media/android/light/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-xxhdpi/ic_launcher.png b/media/android/light/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 21ad6ad00e..0000000000 Binary files a/media/android/light/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/res/mipmap-xxxhdpi/ic_launcher.png b/media/android/light/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 8a28e59304..0000000000 Binary files a/media/android/light/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/media/android/light/web_hi_res_512.png b/media/android/light/web_hi_res_512.png deleted file mode 100644 index 4834dd25b5..0000000000 Binary files a/media/android/light/web_hi_res_512.png and /dev/null differ diff --git a/media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt b/media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt new file mode 100644 index 0000000000..8e8e537ae9 --- /dev/null +++ b/media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt @@ -0,0 +1,43 @@ +Attribution-NonCommercial 3.0 Unported + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. +1. Definitions +"Adaptation" means a work based upon the Work, or upon the Work and other pre-existing works, such as a translation, adaptation, derivative work, arrangement of music or other alterations of a literary or artistic work, or phonogram or performance and includes cinematographic adaptations or any other form in which the Work may be recast, transformed, or adapted including in any form recognizably derived from the original, except that a work that constitutes a Collection will not be considered an Adaptation for the purpose of this License. For the avoidance of doubt, where the Work is a musical work, performance or phonogram, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered an Adaptation for the purpose of this License. +"Collection" means a collection of literary or artistic works, such as encyclopedias and anthologies, or performances, phonograms or broadcasts, or other works or subject matter other than works listed in Section 1(f) below, which, by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. A work that constitutes a Collection will not be considered an Adaptation (as defined above) for the purposes of this License. +"Distribute" means to make available to the public the original and copies of the Work or Adaptation, as appropriate, through sale or other transfer of ownership. +"Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License. +"Original Author" means, in the case of a literary or artistic work, the individual, individuals, entity or entities who created the Work or if no individual or entity can be identified, the publisher; and in addition (i) in the case of a performance the actors, singers, musicians, dancers, and other persons who act, sing, deliver, declaim, play in, interpret or otherwise perform literary or artistic works or expressions of folklore; (ii) in the case of a phonogram the producer being the person or legal entity who first fixes the sounds of a performance or other sounds; and, (iii) in the case of broadcasts, the organization that transmits the broadcast. +"Work" means the literary and/or artistic work offered under the terms of this License including without limitation any production in the literary, scientific and artistic domain, whatever may be the mode or form of its expression including digital form, such as a book, pamphlet and other writing; a lecture, address, sermon or other work of the same nature; a dramatic or dramatico-musical work; a choreographic work or entertainment in dumb show; a musical composition with or without words; a cinematographic work to which are assimilated works expressed by a process analogous to cinematography; a work of drawing, painting, architecture, sculpture, engraving or lithography; a photographic work to which are assimilated works expressed by a process analogous to photography; a work of applied art; an illustration, map, plan, sketch or three-dimensional work relative to geography, topography, architecture or science; a performance; a broadcast; a phonogram; a compilation of data to the extent it is protected as a copyrightable work; or a work performed by a variety or circus performer to the extent it is not otherwise considered a literary or artistic work. +"You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. +"Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. +"Reproduce" means to make copies of the Work by any means including without limitation by sound or visual recordings and the right of fixation and reproducing fixations of the Work, including storage of a protected performance or phonogram in digital form or other electronic medium. +2. Fair Dealing Rights. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright or rights arising from limitations or exceptions that are provided for in connection with the copyright protection under copyright law or other applicable laws. +3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: +to Reproduce the Work, to incorporate the Work into one or more Collections, and to Reproduce the Work as incorporated in the Collections; +to create and Reproduce Adaptations provided that any such Adaptation, including any translation in any medium, takes reasonable steps to clearly label, demarcate or otherwise identify that changes were made to the original Work. For example, a translation could be marked "The original work was translated from English to Spanish," or a modification could indicate "The original work has been modified."; +to Distribute and Publicly Perform the Work including as incorporated in Collections; and, +to Distribute and Publicly Perform Adaptations. +The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. Subject to Section 8(f), all rights not expressly granted by Licensor are hereby reserved, including but not limited to the rights set forth in Section 4(d). +4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: +You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from any Licensor You must, to the extent practicable, remove from the Collection any credit as required by Section 4(c), as requested. If You create an Adaptation, upon notice from any Licensor You must, to the extent practicable, remove from the Adaptation any credit as required by Section 4(c), as requested. +You may not exercise any of the rights granted to You in Section 3 above in any manner that is primarily intended for or directed toward commercial advantage or private monetary compensation. The exchange of the Work for other copyrighted works by means of digital file-sharing or otherwise shall not be considered to be intended for or directed toward commercial advantage or private monetary compensation, provided there is no payment of any monetary compensation in connection with the exchange of copyrighted works. +If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) the name of the Original Author (or pseudonym, if applicable) if supplied, and/or if the Original Author and/or Licensor designate another party or parties (e.g., a sponsor institute, publishing entity, journal) for attribution ("Attribution Parties") in Licensor's copyright notice, terms of service or by other reasonable means, the name of such party or parties; (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). The credit required by this Section 4(c) may be implemented in any reasonable manner; provided, however, that in the case of a Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributing authors of the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributing authors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Original Author, Licensor and/or Attribution Parties, as appropriate, of You or Your use of the Work, without the separate, express prior written permission of the Original Author, Licensor and/or Attribution Parties. +For the avoidance of doubt: +Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; +Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License if Your exercise of such rights is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(b) and otherwise waives the right to collect royalties through any statutory or compulsory licensing scheme; and, +Voluntary License Schemes. The Licensor reserves the right to collect royalties, whether individually or, in the event that the Licensor is a member of a collecting society that administers voluntary licensing schemes, via that society, from any exercise by You of the rights granted under this License that is for a purpose or use which is otherwise than noncommercial as permitted under Section 4(c). +Except as otherwise agreed in writing by the Licensor or as may be otherwise permitted by applicable law, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the Original Author's honor or reputation. Licensor agrees that in those jurisdictions (e.g. Japan), in which any exercise of the right granted in Section 3(b) of this License (the right to make Adaptations) would be deemed to be a distortion, mutilation, modification or other derogatory action prejudicial to the Original Author's honor and reputation, the Licensor will waive or not assert, as appropriate, this Section, to the fullest extent permitted by the applicable national law, to enable You to reasonably exercise Your right under Section 3(b) of this License (right to make Adaptations) but not otherwise. +5. Representations, Warranties and Disclaimer +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +7. Termination +This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. +Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. +8. Miscellaneous +Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. +Each time You Distribute or Publicly Perform an Adaptation, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. +If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. +No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. +This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. +The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). These rights and subject matter take effect in the relevant jurisdiction in which the License terms are sought to be enforced according to the corresponding provisions of the implementation of those treaty provisions in the applicable national law. If the standard suite of rights granted under applicable copyright law includes additional rights not granted under this License, such additional rights are deemed to be included in the License; this License is not intended to restrict the license of any rights under applicable law. diff --git a/media/icons/LICENSE/LICENSE.txt b/media/icons/LICENSE/LICENSE.txt new file mode 100644 index 0000000000..6be4822288 --- /dev/null +++ b/media/icons/LICENSE/LICENSE.txt @@ -0,0 +1,20 @@ +License +======= + +Icons generated with the Android Material Icon Generator are licensed under the Creative Commons Attribution-NonCommercial 3.0 License (https://creativecommons.org/licenses/by-nc/3.0/). + +For commercial usage, please submit a request under https://goo.gl/forms/zX8GZ3Jz89SRyHdJ2 or send us an email to material-icons@bitdroid.de. + + +Google Material Icons License +============================= + +This license applies to the Google Material Icons, which can be seen on the front page of the Android Material icon generator. + +(Copied from https://github.com/google/material-design-icons) +We have made these icons available for you to incorporate them into your +products under the Creative Common Attribution 4.0 International License (CC-BY +4.0, https://creativecommons.org/licenses/by/4.0/). Feel free to remix and +re-share these icons and documentation in your products. We'd love attribution +in your app's *about* screen, but it's not required. The only thing we ask is +that you not re-sell the icons themselves. \ No newline at end of file diff --git a/media/icons/icon.svg b/media/icons/icon.svg new file mode 100644 index 0000000000..549cc6f68f --- /dev/null +++ b/media/icons/icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/media/icons/mipmap-hdpi/ic_launcher.png b/media/icons/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..d33d1953f9 Binary files /dev/null and b/media/icons/mipmap-hdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-mdpi/ic_launcher.png b/media/icons/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..a338dfb2f9 Binary files /dev/null and b/media/icons/mipmap-mdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-xhdpi/ic_launcher.png b/media/icons/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..7eb088dc92 Binary files /dev/null and b/media/icons/mipmap-xhdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-xxhdpi/ic_launcher.png b/media/icons/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..c5a7c34b79 Binary files /dev/null and b/media/icons/mipmap-xxhdpi/ic_launcher.png differ diff --git a/media/icons/mipmap-xxxhdpi/ic_launcher.png b/media/icons/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..f6abcb638a Binary files /dev/null and b/media/icons/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/media/icons/playstore/icon.png b/media/icons/playstore/icon.png new file mode 100644 index 0000000000..73fddf683b Binary files /dev/null and b/media/icons/playstore/icon.png differ diff --git a/media/rarch.rc b/media/rarch.rc index 5bad253138..e758160872 100644 --- a/media/rarch.rc +++ b/media/rarch.rc @@ -97,7 +97,7 @@ FONT 8, "Ms Shell Dlg" // Icon resources // LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL -1 ICON "icon_light.ico" +1 ICON "retroarch.ico" diff --git a/media/retroarch.ico b/media/retroarch.ico new file mode 100644 index 0000000000..6355390e3e Binary files /dev/null and b/media/retroarch.ico differ diff --git a/media/src/invader.ico b/media/src/invader.ico new file mode 100644 index 0000000000..6355390e3e Binary files /dev/null and b/media/src/invader.ico differ diff --git a/media/src/invader.png b/media/src/invader.png new file mode 100644 index 0000000000..aa9e8b6a99 Binary files /dev/null and b/media/src/invader.png differ diff --git a/media/src/invader.svg b/media/src/invader.svg new file mode 100644 index 0000000000..e9b1d5a927 --- /dev/null +++ b/media/src/invader.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c index f9681c275c..bbf7d7651b 100644 --- a/menu/cbs/menu_cbs_get_value.c +++ b/menu/cbs/menu_cbs_get_value.c @@ -137,16 +137,13 @@ static void menu_action_setting_disp_set_label_shader_filter_pass( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) struct video_shader_pass *shader_pass = menu_shader_manager_get_pass( type - MENU_SETTINGS_SHADER_PASS_FILTER_0); -#endif *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!shader_pass) return; @@ -165,7 +162,6 @@ static void menu_action_setting_disp_set_label_shader_filter_pass( len); break; } -#endif } static void menu_action_setting_disp_set_label_filter( @@ -251,9 +247,7 @@ static void menu_action_setting_disp_set_label_shader_num_passes( *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) snprintf(s, len, "%u", menu_shader_manager_get_amount_passes()); -#endif } static void menu_action_setting_disp_set_label_shader_pass( @@ -265,23 +259,19 @@ static void menu_action_setting_disp_set_label_shader_pass( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) struct video_shader_pass *shader_pass = menu_shader_manager_get_pass( type - MENU_SETTINGS_SHADER_PASS_0); -#endif *s = '\0'; *w = 19; strlcpy(s2, path, len2); strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), len); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!shader_pass) return; if (!string_is_empty(shader_pass->source.path)) fill_pathname_base(s, shader_pass->source.path, len); -#endif } static void menu_action_setting_disp_set_label_shader_default_filter( @@ -317,15 +307,13 @@ static void menu_action_setting_disp_set_label_shader_parameter( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) video_shader_ctx_t shader_info; const struct video_shader_parameter *param = NULL; -#endif + *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) video_shader_driver_get_current_shader(&shader_info); if (!shader_info.data) @@ -339,7 +327,6 @@ static void menu_action_setting_disp_set_label_shader_parameter( snprintf(s, len, "%.2f [%.2f %.2f]", param->current, param->minimum, param->maximum); -#endif } static void menu_action_setting_disp_set_label_shader_preset_parameter( @@ -351,20 +338,17 @@ static void menu_action_setting_disp_set_label_shader_preset_parameter( const char *path, char *s2, size_t len2) { -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) - const struct video_shader_parameter *param = menu_shader_manager_get_parameters( - type - MENU_SETTINGS_SHADER_PRESET_PARAMETER_0); -#endif + const struct video_shader_parameter *param = + menu_shader_manager_get_parameters( + type - MENU_SETTINGS_SHADER_PRESET_PARAMETER_0); *s = '\0'; *w = 19; strlcpy(s2, path, len2); -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (param) snprintf(s, len, "%.2f [%.2f %.2f]", param->current, param->minimum, param->maximum); -#endif } static void menu_action_setting_disp_set_label_shader_scale_pass( @@ -378,10 +362,8 @@ static void menu_action_setting_disp_set_label_shader_scale_pass( { unsigned pass = 0; unsigned scale_value = 0; -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) struct video_shader_pass *shader_pass = menu_shader_manager_get_pass( type - MENU_SETTINGS_SHADER_PASS_SCALE_0); -#endif *s = '\0'; *w = 19; @@ -390,7 +372,6 @@ static void menu_action_setting_disp_set_label_shader_scale_pass( (void)pass; (void)scale_value; -#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_HLSL) if (!shader_pass) return; @@ -400,7 +381,6 @@ static void menu_action_setting_disp_set_label_shader_scale_pass( strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE), len); else snprintf(s, len, "%ux", scale_value); -#endif } static void menu_action_setting_disp_set_label_menu_file_core( diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index b7ba381edb..a73475adb3 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1,6 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2016-2017 - Brad Parker + * Copyright (C) 2015-2017 - Andrés Suárez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -859,7 +860,7 @@ static bool menu_content_playlist_load(menu_content_ctx_playlist_info_t *info) char *path_tolower = strdup(path); for (i = 0; i < strlen(path_tolower); ++i) - path_tolower[i] = tolower(path_tolower[i]); + path_tolower[i] = tolower((unsigned char)path_tolower[i]); if (strstr(path_tolower, file_path_str(FILE_PATH_ZIP_EXTENSION))) strstr(path_tolower, file_path_str(FILE_PATH_ZIP_EXTENSION))[4] = '\0'; @@ -1085,6 +1086,20 @@ static int action_ok_file_load_with_detect_core_collection(const char *path, path, label, type, false); } +static int set_path_generic(const char *label, const char *action_path) +{ + rarch_setting_t *setting = menu_setting_find(filebrowser_label); + + if (setting) + { + setting_set_with_string_representation( + setting, action_path); + return menu_setting_generic(setting, false); + } + + return 0; +} + static int generic_action_ok(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx, unsigned id, enum msg_hash_enums flush_id) @@ -1219,68 +1234,23 @@ static int generic_action_ok(const char *path, break; case ACTION_OK_SET_DIRECTORY: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_DIRECTORY_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(filebrowser_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(filebrowser_label, action_path); break; case ACTION_OK_SET_PATH_VIDEO_FILTER: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_VIDEO_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(filebrowser_label, action_path); break; case ACTION_OK_SET_PATH_AUDIO_FILTER: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_AUDIO_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(menu_label, action_path); break; case ACTION_OK_SET_PATH_OVERLAY: flush_char = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_ONSCREEN_OVERLAY_SETTINGS_LIST); - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(menu_label, action_path); break; case ACTION_OK_SET_PATH: flush_type = MENU_SETTINGS; - { - rarch_setting_t *setting = menu_setting_find(menu_label); - - if (setting) - { - setting_set_with_string_representation( - setting, action_path); - ret = menu_setting_generic(setting, false); - } - } + ret = set_path_generic(menu_label, action_path); break; default: flush_char = msg_hash_to_str(flush_id); @@ -2090,10 +2060,12 @@ static int action_ok_cheat_file_save_as(const char *path, enum { ACTION_OK_REMAP_FILE_SAVE_CORE = 0, - ACTION_OK_REMAP_FILE_SAVE_GAME + ACTION_OK_REMAP_FILE_SAVE_GAME, + ACTION_OK_REMAP_FILE_REMOVE_CORE, + ACTION_OK_REMAP_FILE_REMOVE_GAME }; -static int generic_action_ok_remap_file_save(const char *path, +static int generic_action_ok_remap_file_operation(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx, unsigned action_type) { @@ -2118,10 +2090,12 @@ static int generic_action_ok_remap_file_save(const char *path, switch (action_type) { case ACTION_OK_REMAP_FILE_SAVE_CORE: + case ACTION_OK_REMAP_FILE_REMOVE_CORE: if (!string_is_empty(core_name)) fill_pathname_join(file, core_name, core_name, sizeof(file)); break; case ACTION_OK_REMAP_FILE_SAVE_GAME: + case ACTION_OK_REMAP_FILE_REMOVE_GAME: if (!string_is_empty(core_name)) fill_pathname_join(file, core_name, path_basename(path_get(RARCH_PATH_BASENAME)), sizeof(file)); @@ -2131,32 +2105,74 @@ static int generic_action_ok_remap_file_save(const char *path, if(!path_file_exists(directory)) path_mkdir(directory); - if(input_remapping_save_file(file)) - runloop_msg_queue_push( - msg_hash_to_str(MSG_REMAP_FILE_SAVED_SUCCESSFULLY), - 1, 100, true); - else - runloop_msg_queue_push( - msg_hash_to_str(MSG_ERROR_SAVING_REMAP_FILE), - 1, 100, true); + if (action_type < ACTION_OK_REMAP_FILE_REMOVE_CORE) + { + if(input_remapping_save_file(file)) + { + if (action_type == ACTION_OK_REMAP_FILE_SAVE_CORE) + rarch_ctl(RARCH_CTL_SET_REMAPS_CORE_ACTIVE, NULL); + else + rarch_ctl(RARCH_CTL_SET_REMAPS_GAME_ACTIVE, NULL); + runloop_msg_queue_push( + msg_hash_to_str(MSG_REMAP_FILE_SAVED_SUCCESSFULLY), + 1, 100, true); + } + else + runloop_msg_queue_push( + msg_hash_to_str(MSG_ERROR_SAVING_REMAP_FILE), + 1, 100, true); + } + else + { + RARCH_LOG("removing %s", file); + if(input_remapping_remove_file(file)) + { + if (action_type == ACTION_OK_REMAP_FILE_REMOVE_CORE) + rarch_ctl(RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE, NULL); + else + rarch_ctl(RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE, NULL); + + runloop_msg_queue_push( + msg_hash_to_str(MSG_REMAP_FILE_REMOVED_SUCCESSFULLY), + 1, 100, true); + } + else + runloop_msg_queue_push( + msg_hash_to_str(MSG_ERROR_REMOVING_REMAP_FILE), + 1, 100, true); + } return 0; } static int action_ok_remap_file_save_core(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - return generic_action_ok_remap_file_save(path, label, type, + return generic_action_ok_remap_file_operation(path, label, type, idx, entry_idx, ACTION_OK_REMAP_FILE_SAVE_CORE); } static int action_ok_remap_file_save_game(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - return generic_action_ok_remap_file_save(path, label, type, + return generic_action_ok_remap_file_operation(path, label, type, idx, entry_idx, ACTION_OK_REMAP_FILE_SAVE_GAME); } +static int action_ok_remap_file_remove_core(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + return generic_action_ok_remap_file_operation(path, label, type, + idx, entry_idx, ACTION_OK_REMAP_FILE_REMOVE_CORE); +} + +static int action_ok_remap_file_remove_game(const char *path, + const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + return generic_action_ok_remap_file_operation(path, label, type, + idx, entry_idx, ACTION_OK_REMAP_FILE_REMOVE_GAME); +} + int action_ok_path_use_directory(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { @@ -3400,7 +3416,7 @@ static int action_ok_netplay_connect_room(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { #ifdef HAVE_NETWORKING - char tmp_hostname[512]; + char tmp_hostname[4115]; tmp_hostname[0] = '\0'; @@ -3611,7 +3627,7 @@ struct netplay_host_list *lan_hosts; int lan_room_count; void netplay_refresh_rooms_menu(file_list_t *list) { - char s[PATH_MAX_LENGTH]; + char s[4115]; int i = 0; int j = 0; @@ -4286,7 +4302,7 @@ static int action_ok_video_resolution(const char *path, msg[0] = '\0'; -#ifdef __CELLOS_LV2__ +#if defined(__CELLOS_LV2__) || defined(_WIN32) command_event(CMD_EVENT_REINIT, NULL); #endif video_driver_set_video_mode(width, height, true); @@ -4402,8 +4418,9 @@ static int action_ok_netplay_enable_client(const char *path, static int action_ok_netplay_disconnect(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) { - settings_t *settings = config_get_ptr(); #ifdef HAVE_NETWORKING + settings_t *settings = config_get_ptr(); + netplay_driver_ctl(RARCH_NETPLAY_CTL_DISCONNECT, NULL); netplay_driver_ctl(RARCH_NETPLAY_CTL_DISABLE, NULL); @@ -4766,6 +4783,12 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME: BIND_ACTION_OK(cbs, action_ok_remap_file_save_game); break; + case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE: + BIND_ACTION_OK(cbs, action_ok_remap_file_remove_core); + break; + case MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME: + BIND_ACTION_OK(cbs, action_ok_remap_file_remove_game); + break; case MENU_ENUM_LABEL_CONTENT_COLLECTION_LIST: BIND_ACTION_OK(cbs, action_ok_content_collection_list); break; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index a81d827515..94de7b9113 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -225,6 +225,8 @@ default_sublabel_macro(action_bind_sublabel_sort_savefiles_enable, MENU_ default_sublabel_macro(action_bind_sublabel_sort_savestates_enable, MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE) default_sublabel_macro(action_bind_sublabel_netplay_client_swap_input, MENU_ENUM_SUBLABEL_NETPLAY_CLIENT_SWAP_INPUT) default_sublabel_macro(action_bind_sublabel_core_updater_buildbot_url, MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL) +default_sublabel_macro(action_bind_sublabel_input_overlay_show_physical_inputs, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS) +default_sublabel_macro(action_bind_sublabel_input_overlay_show_physical_inputs_port, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT) default_sublabel_macro(action_bind_sublabel_core_updater_buildbot_assets_url, MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL) default_sublabel_macro(action_bind_sublabel_core_updater_auto_extract_archive, MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE) default_sublabel_macro(action_bind_sublabel_netplay_refresh_rooms, MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS) @@ -953,6 +955,12 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_hide_in_menu); break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_show_physical_inputs); + break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_overlay_show_physical_inputs_port); + break; case MENU_ENUM_LABEL_VIDEO_FONT_SIZE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_font_size); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 4b91b800d4..2d18de5f2d 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -562,7 +562,7 @@ static void mui_compute_entries_box(mui_handle_t* mui, int width) if (menu_entry_get_sublabel(i, sublabel_str, sizeof(sublabel_str))) { - word_wrap(sublabel_str, sublabel_str, (int)(usable_width / mui->glyph_width2)); + word_wrap(sublabel_str, sublabel_str, (int)(usable_width / mui->glyph_width2), false); lines = mui_count_lines(sublabel_str); } @@ -715,7 +715,7 @@ static void mui_render_label_value(mui_handle_t *mui, mui_node_t *node, if (menu_entry_get_sublabel(i, sublabel_str, sizeof(sublabel_str))) { - word_wrap(sublabel_str, sublabel_str, (int)(usable_width / mui->glyph_width2)); + word_wrap(sublabel_str, sublabel_str, (int)(usable_width / mui->glyph_width2), false); menu_display_draw_text(mui->font2, sublabel_str, mui->margin, diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 3198c7c4a9..555b26c6e6 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -613,7 +613,7 @@ static void xmb_draw_icon( static void xmb_draw_thumbnail( menu_display_frame_info_t menu_disp_info, xmb_handle_t *xmb, float *color, - unsigned width, unsigned height, + unsigned width, unsigned height, float x, float y, float w, float h, uintptr_t texture) { @@ -829,7 +829,7 @@ static void xmb_render_messagebox_internal( { const char *msg = list->elems[i].data; int len = (int)utf8len(msg); - + if (len > longest) { longest = len; @@ -1002,7 +1002,7 @@ static void xmb_update_savestate_thumbnail_path(void *data, unsigned i) || (string_is_equal_fast(entry.label, "loadstate", 9)) || (string_is_equal_fast(entry.label, "savestate", 9)))) { - char path[PATH_MAX_LENGTH]; + char path[8204]; global_t *global = global_get_ptr(); path[0] = '\0'; @@ -1087,7 +1087,7 @@ static void xmb_selection_pointer_changed( { menu_entry_t e; unsigned i, end, height; - menu_animation_ctx_tag_t tag; + menu_animation_ctx_tag tag; size_t num = 0; int threshold = 0; menu_list_t *menu_list = NULL; @@ -1118,7 +1118,7 @@ static void xmb_selection_pointer_changed( video_driver_get_size(NULL, &height); - tag.id = (int)(uintptr_t)menu_list; + tag = (uintptr_t)selection_buf; menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &num); @@ -1190,28 +1190,24 @@ static void xmb_selection_pointer_changed( entry.target_value = ia; entry.subject = &node->alpha; entry.easing_enum = EASING_OUT_QUAD; - entry.tag = tag.id; + entry.tag = tag; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = iz; entry.subject = &node->zoom; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = iy; entry.subject = &node->y; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } } @@ -1261,20 +1257,17 @@ static void xmb_list_open_old(xmb_handle_t *xmb, entry.tag = -1; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 0; entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = xmb->icon.size * dir * -2; entry.subject = &node->x; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } } @@ -1334,19 +1327,16 @@ static void xmb_list_open_new(xmb_handle_t *xmb, entry.tag = -1; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 0; entry.subject = &node->x; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } @@ -1394,7 +1384,7 @@ static xmb_node_t* xmb_get_userdata_from_horizontal_list( menu_entries_get_actiondata_at_offset(xmb->horizontal_list, i); } -static void xmb_push_animations(xmb_node_t *node, float ia, float ix) +static void xmb_push_animations(xmb_node_t *node, uintptr_t tag, float ia, float ix) { menu_animation_ctx_entry_t entry; @@ -1402,22 +1392,19 @@ static void xmb_push_animations(xmb_node_t *node, float ia, float ix) entry.target_value = ia; entry.subject = &node->alpha; entry.easing_enum = EASING_OUT_QUAD; - entry.tag = -1; + entry.tag = tag; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.subject = &node->label_alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = ix; entry.subject = &node->x; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } static void xmb_list_switch_old(xmb_handle_t *xmb, @@ -1435,7 +1422,7 @@ static void xmb_list_switch_old(xmb_handle_t *xmb, if (!node) continue; - xmb_push_animations(node, ia, -xmb->icon.spacing.horizontal * dir); + xmb_push_animations(node, (uintptr_t)list, ia, -xmb->icon.spacing.horizontal * dir); } } @@ -1501,7 +1488,7 @@ static void xmb_list_switch_new(xmb_handle_t *xmb, if (i == current) ia = xmb->items.active.alpha; - xmb_push_animations(node, ia, 0); + xmb_push_animations(node, (uintptr_t)list, ia, 0); } } @@ -1597,14 +1584,12 @@ static void xmb_list_switch_horizontal_list(xmb_handle_t *xmb) entry.tag = -1; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = iz; entry.subject = &node->zoom; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); } } @@ -1615,6 +1600,7 @@ static void xmb_list_switch(xmb_handle_t *xmb) int dir = -1; file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); size_t selection = menu_navigation_get_selection(); + settings_t *settings = config_get_ptr(); if (xmb->categories.selection_ptr > xmb->categories.selection_ptr_old) dir = 1; @@ -1639,7 +1625,10 @@ static void xmb_list_switch(xmb_handle_t *xmb) xmb_list_switch_old(xmb, xmb->selection_buf_old, dir, xmb->selection_ptr_old); - xmb_list_switch_new(xmb, selection_buf, dir, selection); + + /* Check if we are to have horizontal animations. */ + if (settings->bools.menu_horizontal_animation) + xmb_list_switch_new(xmb, selection_buf, dir, selection); xmb->categories.active.idx_old = (unsigned)xmb->categories.selection_ptr; if (!string_is_equal(xmb_thumbnails_ident(), @@ -1962,28 +1951,23 @@ static void xmb_list_open(xmb_handle_t *xmb) entry.tag = -1; entry.cb = NULL; - switch (xmb->depth) { case 1: - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 0; entry.subject = &xmb->textures.arrow.alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); break; case 2: - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); entry.target_value = 1; entry.subject = &xmb->textures.arrow.alpha; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); break; } @@ -2328,7 +2312,7 @@ static void xmb_draw_items( label_offset = - xmb->margins.label.top; - word_wrap(entry_sublabel, entry.sublabel, 50); + word_wrap(entry_sublabel, entry.sublabel, 50, true); xmb_draw_text(menu_disp_info, xmb, entry_sublabel, node->x + xmb->margins.screen.left + @@ -3731,29 +3715,19 @@ static void xmb_list_insert(void *userdata, static void xmb_list_clear(file_list_t *list) { size_t i; - size_t size = list->size; + size_t size = list->size; + menu_animation_ctx_tag tag = (uintptr_t)list; + + menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); for (i = 0; i < size; ++i) { - menu_animation_ctx_subject_t subject; - float *subjects[5]; xmb_node_t *node = (xmb_node_t*) menu_entries_get_userdata_at_offset(list, i); if (!node) continue; - subjects[0] = &node->alpha; - subjects[1] = &node->label_alpha; - subjects[2] = &node->zoom; - subjects[3] = &node->x; - subjects[4] = &node->y; - - subject.count = 5; - subject.data = subjects; - - menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_SUBJECT, &subject); - file_list_free_userdata(list, i); } } @@ -3761,30 +3735,13 @@ static void xmb_list_clear(file_list_t *list) static void xmb_list_deep_copy(const file_list_t *src, file_list_t *dst) { size_t i; - size_t size = dst->size; + menu_animation_ctx_tag tag = (uintptr_t)dst; + size_t size = dst->size; + + menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); for (i = 0; i < size; ++i) { - xmb_node_t *node = (xmb_node_t*) - menu_entries_get_userdata_at_offset(dst, i); - - if (node) - { - menu_animation_ctx_subject_t subject; - float *subjects[5]; - - subjects[0] = &node->alpha; - subjects[1] = &node->label_alpha; - subjects[2] = &node->zoom; - subjects[3] = &node->x; - subjects[4] = &node->y; - - subject.count = 5; - subject.data = subjects; - - menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_SUBJECT, &subject); - } - file_list_free_userdata(dst, i); file_list_free_actiondata(dst, i); /* this one was allocated by us */ } @@ -3800,14 +3757,14 @@ static void xmb_list_deep_copy(const file_list_t *src, file_list_t *dst) if (src_udata) { - void *data = calloc(1, sizeof(xmb_node_t)); + void *data = malloc(sizeof(xmb_node_t)); memcpy(data, src_udata, sizeof(xmb_node_t)); file_list_set_userdata(dst, i, data); } if (src_adata) { - void *data = calloc(1, sizeof(menu_file_list_cbs_t)); + void *data = malloc(sizeof(menu_file_list_cbs_t)); memcpy(data, src_adata, sizeof(menu_file_list_cbs_t)); file_list_set_actiondata(dst, i, data); } @@ -3821,12 +3778,18 @@ static void xmb_list_cache(void *data, enum menu_list_type type, unsigned action file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); file_list_t *selection_buf = menu_entries_get_selection_buf_ptr(0); size_t selection = menu_navigation_get_selection(); + settings_t *settings = config_get_ptr(); if (!xmb) return; - xmb_list_deep_copy(selection_buf, xmb->selection_buf_old); - xmb_list_deep_copy(menu_stack, xmb->menu_stack_old); + /* Check whether to enable the horizontal animation. */ + if (settings->bools.menu_horizontal_animation) + { + xmb_list_deep_copy(selection_buf, xmb->selection_buf_old); + xmb_list_deep_copy(menu_stack, xmb->menu_stack_old); + } + xmb->selection_ptr_old = selection; list_size = xmb_list_get_size(xmb, MENU_LIST_HORIZONTAL) @@ -3985,8 +3948,7 @@ static void xmb_toggle(void *userdata, bool menu_on) entry.tag = -1; entry.cb = NULL; - if (entry.subject) - menu_animation_push(&entry); + menu_animation_push(&entry); tmp = !menu_entries_ctl(MENU_ENTRIES_CTL_NEEDS_REFRESH, NULL); @@ -4080,10 +4042,6 @@ static int xmb_list_push(void *data, void *userdata, entry.enum_idx = MENU_ENUM_LABEL_ADD_CONTENT_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); #if defined(HAVE_NETWORKING) -#ifdef HAVE_LAKKA - entry.enum_idx = MENU_ENUM_LABEL_UPDATE_LAKKA; - menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); -#else { settings_t *settings = config_get_ptr(); if (settings->bools.menu_show_online_updater) @@ -4092,7 +4050,6 @@ static int xmb_list_push(void *data, void *userdata, menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); } } -#endif #endif entry.enum_idx = MENU_ENUM_LABEL_INFORMATION_LIST; menu_displaylist_ctl(DISPLAYLIST_SETTING_ENUM, &entry); diff --git a/menu/menu_animation.c b/menu/menu_animation.c index 47acd52d29..8464a7876c 100644 --- a/menu/menu_animation.c +++ b/menu/menu_animation.c @@ -36,7 +36,7 @@ struct tween float initial_value; float target_value; float *subject; - int tag; + uintptr_t tag; easing_cb easing; tween_cb cb; }; @@ -462,6 +462,32 @@ bool menu_animation_push(menu_animation_ctx_entry_t *entry) return true; } +static int menu_animation_defrag_cmp(const void *a, const void *b) +{ + const struct tween *ta = (const struct tween *)a; + const struct tween *tb = (const struct tween *)b; + + return tb->alive - ta->alive; +} + +/* defragments and shrinks the tween list when possible */ +static void menu_animation_defrag() +{ + size_t i; + + qsort(anim.list, anim.size, sizeof(anim.list[0]), menu_animation_defrag_cmp); + + for (i = anim.size-1; i > 0; i--) + { + if (anim.list[i].alive) + break; + + anim.size--; + } + + anim.first_dead = anim.size; +} + bool menu_animation_update(float delta_time) { unsigned i; @@ -486,9 +512,6 @@ bool menu_animation_update(float delta_time) *tween->subject = tween->target_value; tween->alive = false; - if (i < anim.first_dead) - anim.first_dead = i; - if (tween->cb) tween->cb(); } @@ -497,13 +520,16 @@ bool menu_animation_update(float delta_time) active_tweens += 1; } - if (!active_tweens) + if (active_tweens) + menu_animation_defrag(); + else { anim.size = 0; anim.first_dead = 0; return false; } + animation_is_active = true; return true; @@ -622,14 +648,14 @@ bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data) case MENU_ANIMATION_CTL_KILL_BY_TAG: { unsigned i; - menu_animation_ctx_tag_t *tag = (menu_animation_ctx_tag_t*)data; + menu_animation_ctx_tag *tag = (menu_animation_ctx_tag*)data; - if (!tag || tag->id == -1) + if (!tag || *tag == (uintptr_t)-1) return false; for (i = 0; i < anim.size; ++i) { - if (anim.list[i].tag != tag->id) + if (anim.list[i].tag != *tag) continue; anim.list[i].alive = false; diff --git a/menu/menu_animation.h b/menu/menu_animation.h index 49d154d305..4798b39a67 100644 --- a/menu/menu_animation.h +++ b/menu/menu_animation.h @@ -91,10 +91,7 @@ typedef struct menu_animation_ctx_delta float ideal; } menu_animation_ctx_delta_t; -typedef struct menu_animation_ctx_tag -{ - int id; -} menu_animation_ctx_tag_t; +typedef uintptr_t menu_animation_ctx_tag; typedef struct menu_animation_ctx_subject { @@ -108,7 +105,7 @@ typedef struct menu_animation_ctx_entry float target_value; float *subject; enum menu_animation_easing_type easing_enum; - int tag; + uintptr_t tag; tween_cb cb; } menu_animation_ctx_entry_t; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index ab1cfd0646..636e5bfe6b 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -1,6 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2014-2017 - Jean-André Santoni + * Copyright (C) 2015-2017 - Andrés Suárez * Copyright (C) 2016-2017 - Brad Parker * * RetroArch is free software: you can redistribute it and/or modify it under the terms @@ -3182,6 +3183,23 @@ static int menu_displaylist_parse_netplay_room_list( static int menu_displaylist_parse_options( menu_displaylist_info_t *info) { +#ifdef HAVE_LAKKA + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA), + msg_hash_to_str(MENU_ENUM_LABEL_UPDATE_LAKKA), + MENU_ENUM_LABEL_UPDATE_LAKKA, + MENU_SETTING_ACTION, 0, 0); + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST), + MENU_ENUM_LABEL_THUMBNAILS_UPDATER_LIST, + MENU_SETTING_ACTION, 0, 0); + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT), + msg_hash_to_str(MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS), + MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS, + MENU_SETTING_ACTION, 0, 0); +#else #ifdef HAVE_NETWORKING settings_t *settings = config_get_ptr(); @@ -3279,6 +3297,7 @@ static int menu_displaylist_parse_options( msg_hash_to_str(MENU_ENUM_LABEL_NO_ITEMS), MENU_ENUM_LABEL_NO_ITEMS, MENU_SETTING_NO_ITEM, 0, 0); +#endif #endif return 0; @@ -3377,6 +3396,24 @@ static int menu_displaylist_parse_options_remappings( MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME, MENU_SETTING_ACTION, 0, 0); + if (rarch_ctl(RARCH_CTL_IS_REMAPS_CORE_ACTIVE, NULL)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE), + msg_hash_to_str(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE), + MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE, + MENU_SETTING_ACTION, 0, 0); + } + + if (rarch_ctl(RARCH_CTL_IS_REMAPS_GAME_ACTIVE, NULL)) + { + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME), + msg_hash_to_str(MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME), + MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME, + MENU_SETTING_ACTION, 0, 0); + } + system = runloop_get_system_info(); if (system) @@ -4041,7 +4078,9 @@ static void wifi_scan_callback(void *task_data, bool menu_displaylist_process(menu_displaylist_info_t *info) { size_t idx = 0; +#if defined(HAVE_NETWORKING) settings_t *settings = config_get_ptr(); +#endif if (info->need_navigation_clear) { @@ -4058,7 +4097,7 @@ bool menu_displaylist_process(menu_displaylist_info_t *info) if (info->need_sort) file_list_sort_on_alt(info->list); -#if defined(HAVE_NETWORKING) && !defined(HAVE_LAKKA) +#if defined(HAVE_NETWORKING) if (settings->bools.menu_show_core_updater) if (info->download_core) { @@ -4885,6 +4924,18 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, + PARSE_ONLY_BOOL, false); info->need_refresh = true; info->need_push = true; @@ -4979,6 +5030,12 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + PARSE_ONLY_UINT, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_OVERLAY_PRESET, PARSE_ONLY_PATH, false); @@ -5012,12 +5069,14 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) case DISPLAYLIST_MENU_VIEWS_SETTINGS_LIST: menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list); +#if defined(HAVE_NETWORKING) && !defined(HAVE_LAKKA) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_SHOW_CORE_UPDATER, PARSE_ONLY_BOOL, false); +#endif menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_XMB_SHOW_SETTINGS, PARSE_ONLY_BOOL, false); @@ -5084,6 +5143,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_MENU_LINEAR_FILTER, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_MENU_HORIZONTAL_ANIMATION, + PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_NAVIGATION_WRAPAROUND, PARSE_ONLY_BOOL, false); @@ -6093,16 +6155,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) PARSE_ACTION, false); #endif #if defined(HAVE_NETWORKING) -#ifdef HAVE_LAKKA - menu_displaylist_parse_settings_enum(menu, info, - MENU_ENUM_LABEL_UPDATE_LAKKA, - PARSE_ACTION, false); -#else if (settings->bools.menu_show_online_updater) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_ONLINE_UPDATER, PARSE_ACTION, false); -#endif #endif menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_SETTINGS, PARSE_ACTION, false); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 692c6b3543..2ba3d5b399 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -140,10 +140,10 @@ static void setting_get_string_representation_uint_custom_viewport_width(void *d rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; - + av_info = video_viewport_get_system_av_info(); geom = (struct retro_game_geometry*)&av_info->geometry; - + if (*setting->value.target.unsigned_integer%geom->base_width == 0) snprintf(s, len, "%u (%ux)", *setting->value.target.unsigned_integer, @@ -161,10 +161,10 @@ static void setting_get_string_representation_uint_custom_viewport_height(void * rarch_setting_t *setting = (rarch_setting_t*)data; if (!setting) return; - + av_info = video_viewport_get_system_av_info(); geom = (struct retro_game_geometry*)&av_info->geometry; - + if (*setting->value.target.unsigned_integer%geom->base_height == 0) snprintf(s, len, "%u (%ux)", *setting->value.target.unsigned_integer, @@ -764,7 +764,7 @@ int menu_action_handle_setting(rarch_setting_t *setting, return -1; } -static rarch_setting_t *menu_setting_find_internal(rarch_setting_t *setting, +static rarch_setting_t *menu_setting_find_internal(rarch_setting_t *setting, const char *label) { uint32_t needle = msg_hash_calculate(label); @@ -794,7 +794,7 @@ static rarch_setting_t *menu_setting_find_internal(rarch_setting_t *setting, return NULL; } -static rarch_setting_t *menu_setting_find_internal_enum(rarch_setting_t *setting, +static rarch_setting_t *menu_setting_find_internal_enum(rarch_setting_t *setting, enum msg_hash_enums enum_idx) { rarch_setting_t **list = &setting; @@ -1051,7 +1051,7 @@ static int setting_action_start_libretro_device_type(void *data) if (system) { - /* Only push RETRO_DEVICE_ANALOG as default if we use an + /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!system->ports.size) devices[types++] = RETRO_DEVICE_ANALOG; @@ -1155,7 +1155,7 @@ static int setting_action_left_libretro_device_type( if (system) { - /* Only push RETRO_DEVICE_ANALOG as default if we use an + /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!system->ports.size) devices[types++] = RETRO_DEVICE_ANALOG; @@ -1220,7 +1220,7 @@ static int setting_action_right_libretro_device_type( if (system) { - /* Only push RETRO_DEVICE_ANALOG as default if we use an + /* Only push RETRO_DEVICE_ANALOG as default if we use an * older core which doesn't use SET_CONTROLLER_INFO. */ if (!system->ports.size) devices[types++] = RETRO_DEVICE_ANALOG; @@ -1391,7 +1391,7 @@ static int setting_action_ok_bind_defaults(void *data, bool wraparound) return -1; target = &input_config_binds[setting->index_offset][0]; - def_binds = (setting->index_offset) ? + def_binds = (setting->index_offset) ? retro_keybinds_rest : retro_keybinds_1; lim.min = MENU_SETTINGS_BIND_BEGIN; @@ -1506,7 +1506,7 @@ static void get_string_representation_bind_device(void * data, char *s, * Get associated label of a setting. **/ void menu_setting_get_label(void *data, char *s, - size_t len, unsigned *w, unsigned type, + size_t len, unsigned *w, unsigned type, const char *menu_label, const char *label, unsigned idx) { rarch_setting_t *setting = NULL; @@ -1636,7 +1636,7 @@ void general_write_handler(void *data) file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); info.list = menu_stack; - info.type = 0; + info.type = 0; info.directory_ptr = 0; strlcpy(info.label, msg_hash_to_str(MENU_ENUM_LABEL_HELP), sizeof(info.label)); @@ -1697,14 +1697,14 @@ void general_write_handler(void *data) settings->uints.input_joypad_map[4] = *setting->value.target.integer; break; case MENU_ENUM_LABEL_LOG_VERBOSITY: - if (setting - && setting->value.target.boolean + if (setting + && setting->value.target.boolean && *setting->value.target.boolean) verbosity_enable(); else verbosity_disable(); - if (setting + if (setting && setting->value.target.boolean && *setting->value.target.boolean) retroarch_override_setting_set(RARCH_OVERRIDE_SETTING_VERBOSITY, NULL); @@ -1751,7 +1751,7 @@ void general_write_handler(void *data) { #if defined(__CELLOS_LV2__) && (CELL_SDK_VERSION > 0x340000) cellSysutilEnableBgmPlayback(); -#endif +#endif } else { @@ -2031,7 +2031,7 @@ static bool setting_append_list_input_player_options( (*list)[list_info->index - 1].action_right = &setting_action_right_libretro_device_type; (*list)[list_info->index - 1].action_select = &setting_action_right_libretro_device_type; (*list)[list_info->index - 1].action_start = &setting_action_start_libretro_device_type; - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_libretro_device; menu_settings_list_current_add_enum_idx(list, list_info, (enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE + user)); @@ -2052,7 +2052,7 @@ static bool setting_append_list_input_player_options( (*list)[list_info->index - 1].action_right = &setting_action_right_analog_dpad_mode; (*list)[list_info->index - 1].action_select = &setting_action_right_analog_dpad_mode; (*list)[list_info->index - 1].action_start = &setting_action_start_analog_dpad_mode; - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_analog_dpad_mode; menu_settings_list_current_add_enum_idx(list, list_info, (enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE + user)); @@ -2146,7 +2146,7 @@ static bool setting_append_list_input_player_options( ) { if (system->input_desc_btn[user][i]) - strlcat(label, + strlcat(label, system->input_desc_btn[user][i], sizeof(label)); else @@ -2343,15 +2343,6 @@ static bool setting_append_list( &subgroup_info, parent_group); -#ifdef HAVE_LAKKA - CONFIG_ACTION( - list, list_info, - MENU_ENUM_LABEL_UPDATE_LAKKA, - MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, - &group_info, - &subgroup_info, - parent_group); -#else CONFIG_ACTION( list, list_info, MENU_ENUM_LABEL_ONLINE_UPDATER, @@ -2359,8 +2350,6 @@ static bool setting_append_list( &group_info, &subgroup_info, parent_group); -#endif - #endif CONFIG_ACTION( @@ -3016,7 +3005,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 3, 1.0, true, true); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_libretro_log_level; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); @@ -3048,7 +3037,7 @@ static bool setting_append_list( case SETTINGS_LIST_SAVING: { unsigned i; - struct bool_entry bool_entries[7]; + struct bool_entry bool_entries[11]; START_GROUP(list, list_info, &group_info, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS), parent_group); parent_group = msg_hash_to_str(MENU_ENUM_LABEL_SAVING_SETTINGS); @@ -3098,6 +3087,30 @@ static bool setting_append_list( bool_entries[6].default_value = savestate_thumbnail_enable; bool_entries[6].flags = SD_FLAG_ADVANCED; + bool_entries[7].target = &settings->bools.savefiles_in_content_dir; + bool_entries[7].name_enum_idx = MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[7].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SAVEFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[7].default_value = default_savefiles_in_content_dir; + bool_entries[7].flags = SD_FLAG_ADVANCED; + + bool_entries[8].target = &settings->bools.savestates_in_content_dir; + bool_entries[8].name_enum_idx = MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE; + bool_entries[8].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SAVESTATES_IN_CONTENT_DIR_ENABLE; + bool_entries[8].default_value = default_savestates_in_content_dir; + bool_entries[8].flags = SD_FLAG_ADVANCED; + + bool_entries[9].target = &settings->bools.systemfiles_in_content_dir; + bool_entries[9].name_enum_idx = MENU_ENUM_LABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[9].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SYSTEMFILES_IN_CONTENT_DIR_ENABLE; + bool_entries[9].default_value = default_systemfiles_in_content_dir; + bool_entries[9].flags = SD_FLAG_ADVANCED; + + bool_entries[10].target = &settings->bools.screenshots_in_content_dir; + bool_entries[10].name_enum_idx = MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE; + bool_entries[10].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_SCREENSHOTS_IN_CONTENT_DIR_ENABLE; + bool_entries[10].default_value = default_screenshots_in_content_dir; + bool_entries[10].flags = SD_FLAG_ADVANCED; + for (i = 0; i < ARRAY_SIZE(bool_entries); i++) { CONFIG_BOOL( @@ -3131,7 +3144,7 @@ static bool setting_append_list( menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_AUTOSAVE_INIT); menu_settings_list_current_add_range(list, list_info, 0, 0, 1, true, false); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_autosave_interval; #endif @@ -3258,7 +3271,7 @@ static bool setting_append_list( general_read_handler); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_REINIT); menu_settings_list_current_add_range(list, list_info, 0, 1, 1, true, false); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_video_monitor_index; if (video_driver_has_windowed()) @@ -3356,7 +3369,7 @@ static bool setting_append_list( (*list)[list_info->index - 1].action_start = &setting_action_start_video_refresh_rate_auto; (*list)[list_info->index - 1].action_ok = &setting_action_ok_video_refresh_rate_auto; (*list)[list_info->index - 1].action_select = &setting_action_ok_video_refresh_rate_auto; - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_st_float_video_refresh_rate_auto; settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); @@ -3406,7 +3419,7 @@ static bool setting_append_list( true, true); settings_data_list_current_add_flags(list, list_info, SD_FLAG_CMD_APPLY_AUTO); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_aspect_ratio_index; CONFIG_FLOAT( @@ -3635,7 +3648,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_range(list, list_info, 0, 3, 1, true, true); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_video_rotation; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ADVANCED); @@ -3980,7 +3993,7 @@ static bool setting_append_list( &settings->uints.audio_latency, MENU_ENUM_LABEL_AUDIO_LATENCY, MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - g_defaults.settings.out_latency ? + g_defaults.settings.out_latency ? g_defaults.settings.out_latency : out_latency, &group_info, &subgroup_info, @@ -4655,7 +4668,7 @@ static bool setting_append_list( &retro_keybinds_1[i], &group_info, &subgroup_info, parent_group); (*list)[list_info->index - 1].bind_type = i + MENU_SETTINGS_BIND_BEGIN; - menu_settings_list_current_add_enum_idx(list, list_info, + menu_settings_list_current_add_enum_idx(list, list_info, (enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN + i)); } @@ -4867,6 +4880,34 @@ static bool setting_append_list( ); (*list)[list_info->index - 1].change_handler = overlay_enable_toggle_change_handler; + CONFIG_BOOL( + list, list_info, + &settings->bools.input_overlay_show_physical_inputs, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS, + false, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE + ); + CONFIG_UINT( + list, list_info, + &settings->uints.input_overlay_show_physical_inputs_port, + MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT, + 0, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler + ); + menu_settings_list_current_add_range(list, list_info, 0, MAX_USERS - 1, 1, true, true); CONFIG_PATH( list, list_info, settings->paths.path_overlay, @@ -5051,6 +5092,22 @@ static bool setting_append_list( SD_FLAG_ADVANCED ); + CONFIG_BOOL( + list, list_info, + &settings->bools.menu_horizontal_animation, + MENU_ENUM_LABEL_MENU_HORIZONTAL_ANIMATION, + MENU_ENUM_LABEL_VALUE_MENU_HORIZONTAL_ANIMATION, + true, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_ADVANCED + ); + #ifdef RARCH_MOBILE /* We don't want mobile users being able to switch this off. */ (*list)[list_info->index - 1].action_left = NULL; @@ -5412,7 +5469,7 @@ static bool setting_append_list( general_read_handler, SD_FLAG_NONE); settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); -#endif +#endif } #endif @@ -5674,8 +5731,6 @@ static bool setting_append_list( settings_data_list_current_add_flags(list, list_info, SD_FLAG_LAKKA_ADVANCED); #endif -#if defined(HAVE_NETWORKING) -#ifndef HAVE_LAKKA CONFIG_BOOL( list, list_info, &settings->bools.menu_show_online_updater, @@ -5705,8 +5760,6 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); -#endif -#endif if (string_is_not_equal_fast(ui_companion_driver_get_ident(), "null", 4)) { @@ -5800,7 +5853,7 @@ static bool setting_append_list( menu_settings_list_current_add_range(list, list_info, 0, 0, 1.0, true, false); END_SUB_GROUP(list, list_info, parent_group); - + START_SUB_GROUP(list, list_info, "Playlist", &group_info, &subgroup_info, parent_group); CONFIG_BOOL( @@ -5817,9 +5870,9 @@ static bool setting_append_list( general_write_handler, general_read_handler, SD_FLAG_NONE); - + END_SUB_GROUP(list, list_info, parent_group); - + END_GROUP(list, list_info, parent_group); break; case SETTINGS_LIST_CHEEVOS: @@ -5912,7 +5965,7 @@ static bool setting_append_list( sizeof(settings->paths.network_buildbot_url), MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL, MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, - buildbot_server_url, + buildbot_server_url, &group_info, &subgroup_info, parent_group, @@ -5926,7 +5979,7 @@ static bool setting_append_list( sizeof(settings->paths.network_buildbot_assets_url), MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL, MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, - buildbot_assets_server_url, + buildbot_assets_server_url, &group_info, &subgroup_info, parent_group, @@ -6444,7 +6497,7 @@ static bool setting_append_list( true, true); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_MENU_REFRESH); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_uint_user_language; #endif @@ -6509,7 +6562,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); - (*list)[list_info->index - 1].get_string_representation = + (*list)[list_info->index - 1].get_string_representation = &setting_get_string_representation_cheevos_password; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_INPUT); #endif @@ -6533,13 +6586,14 @@ static bool setting_append_list( sizeof(settings->paths.directory_system), MENU_ENUM_LABEL_SYSTEM_DIRECTORY, MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_SYSTEM], MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6547,7 +6601,7 @@ static bool setting_append_list( sizeof(settings->paths.directory_core_assets), MENU_ENUM_LABEL_CORE_ASSETS_DIRECTORY, MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, &group_info, &subgroup_info, @@ -6577,13 +6631,14 @@ static bool setting_append_list( sizeof(settings->paths.directory_dynamic_wallpapers), MENU_ENUM_LABEL_DYNAMIC_WALLPAPERS_DIRECTORY, MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_WALLPAPERS], MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6591,7 +6646,7 @@ static bool setting_append_list( sizeof(settings->paths.directory_thumbnails), MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY, MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, - g_defaults.dirs[DEFAULT_DIR_THUMBNAILS], + g_defaults.dirs[DEFAULT_DIR_THUMBNAILS], MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, &group_info, &subgroup_info, @@ -6644,6 +6699,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_CORE_INFO_INIT); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6659,6 +6715,7 @@ static bool setting_append_list( general_write_handler, general_read_handler); menu_settings_list_current_add_cmd(list, list_info, CMD_EVENT_CORE_INFO_INIT); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; #ifdef HAVE_LIBRETRODB CONFIG_DIR( @@ -6750,6 +6807,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; if (string_is_not_equal_fast(settings->arrays.record_driver, "null", 4)) { @@ -6797,6 +6855,7 @@ static bool setting_append_list( parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; #endif CONFIG_DIR( @@ -6835,13 +6894,14 @@ static bool setting_append_list( sizeof(settings->paths.directory_input_remapping), MENU_ENUM_LABEL_INPUT_REMAPPING_DIRECTORY, MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_REMAP], MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6864,13 +6924,14 @@ static bool setting_append_list( dir_get_size(RARCH_DIR_SAVEFILE), MENU_ENUM_LABEL_SAVEFILE_DIRECTORY, MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_SRAM], MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -6878,13 +6939,14 @@ static bool setting_append_list( dir_get_size(RARCH_DIR_SAVESTATE), MENU_ENUM_LABEL_SAVESTATE_DIRECTORY, MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, - "", + g_defaults.dirs[DEFAULT_DIR_SAVESTATE], MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, &group_info, &subgroup_info, parent_group, general_write_handler, general_read_handler); + (*list)[list_info->index - 1].action_start = directory_action_start_generic; CONFIG_DIR( list, list_info, @@ -7001,7 +7063,7 @@ static rarch_setting_t *menu_setting_new_internal(rarch_setting_info_t *list_inf { unsigned i; rarch_setting_t* resized_list = NULL; - enum settings_list_type list_types[] = + enum settings_list_type list_types[] = { SETTINGS_LIST_MAIN_MENU, SETTINGS_LIST_DRIVERS, diff --git a/msg_hash.h b/msg_hash.h index 39660d6006..4b37e9923a 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -287,8 +287,10 @@ enum msg_hash_enums MSG_INPUT_PRESET_FILENAME, MSG_INPUT_CHEAT_FILENAME, MSG_REMAP_FILE_SAVED_SUCCESSFULLY, + MSG_REMAP_FILE_REMOVED_SUCCESSFULLY, MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, MSG_ERROR_SAVING_REMAP_FILE, + MSG_ERROR_REMOVING_REMAP_FILE, MSG_ERROR_SAVING_SHADER_PRESET, MSG_FAILED_TO_CREATE_THE_DIRECTORY, MSG_ERROR_SAVING_CORE_OPTIONS_FILE, @@ -596,6 +598,8 @@ enum msg_hash_enums MENU_LABEL(INPUT_OSK_OVERLAY_ENABLE), MENU_LABEL(INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO), MENU_LABEL(INPUT_OVERLAY_HIDE_IN_MENU), + MENU_LABEL(INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS), + MENU_LABEL(INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS_PORT), MENU_LABEL(INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE), MENU_LABEL(INPUT_SMALL_KEYBOARD_ENABLE), MENU_LABEL(INPUT_TOUCH_ENABLE), @@ -668,6 +672,7 @@ enum msg_hash_enums MENU_LABEL(MOUSE_ENABLE), MENU_LABEL(POINTER_ENABLE), MENU_LABEL(MENU_LINEAR_FILTER), + MENU_LABEL(MENU_HORIZONTAL_ANIMATION), MENU_LABEL(NAVIGATION_WRAPAROUND), MENU_LABEL(SHOW_ADVANCED_SETTINGS), MENU_LABEL(THREADED_DATA_RUNLOOP_ENABLE), @@ -1067,6 +1072,10 @@ enum msg_hash_enums MENU_LABEL(NETPLAY_NAT_TRAVERSAL), MENU_LABEL(SORT_SAVEFILES_ENABLE), MENU_LABEL(SORT_SAVESTATES_ENABLE), + MENU_LABEL(SAVEFILES_IN_CONTENT_DIR_ENABLE), + MENU_LABEL(SAVESTATES_IN_CONTENT_DIR_ENABLE), + MENU_LABEL(SYSTEMFILES_IN_CONTENT_DIR_ENABLE), + MENU_LABEL(SCREENSHOTS_IN_CONTENT_DIR_ENABLE), MENU_LABEL(NETPLAY_IP_ADDRESS), MENU_LABEL(NETPLAY_PASSWORD), MENU_LABEL(NETPLAY_SPECTATE_PASSWORD), @@ -1366,6 +1375,8 @@ enum msg_hash_enums MENU_LABEL(REMAP_FILE_SAVE_CORE), MENU_LABEL(REMAP_FILE_SAVE_GAME), + MENU_LABEL(REMAP_FILE_REMOVE_CORE), + MENU_LABEL(REMAP_FILE_REMOVE_GAME), MENU_LABEL(RESTART_CONTENT), MENU_LABEL(RESUME), MENU_LABEL(RESUME_CONTENT), diff --git a/paths.c b/paths.c index b8ba14c0b5..19aabd16c3 100644 --- a/paths.c +++ b/paths.c @@ -67,6 +67,7 @@ void path_set_redirect(void) const char *old_savefile_dir = dir_get(RARCH_DIR_SAVEFILE); const char *old_savestate_dir = dir_get(RARCH_DIR_SAVESTATE); rarch_system_info_t *info = runloop_get_system_info(); + settings_t *settings = config_get_ptr(); new_savefile_dir[0] = new_savestate_dir[0] = '\0'; @@ -93,10 +94,8 @@ void path_set_redirect(void) if (check_library_name_hash) { - settings_t *settings = config_get_ptr(); - /* per-core saves: append the library_name to the save location */ - if ( settings->bools.sort_savefiles_enable + if (settings->bools.sort_savefiles_enable && !string_is_empty(old_savefile_dir)) { fill_pathname_join( @@ -154,13 +153,21 @@ void path_set_redirect(void) } /* Set savefile directory if empty based on content directory */ - if (string_is_empty(new_savefile_dir)) + if (string_is_empty(new_savefile_dir) || settings->bools.savefiles_in_content_dir) { strlcpy(new_savefile_dir, path_main_basename, sizeof(new_savefile_dir)); path_basedir(new_savefile_dir); } + /* Set savestate directory if empty based on content directory */ + if (string_is_empty(new_savestate_dir) || settings->bools.savestates_in_content_dir) + { + strlcpy(new_savestate_dir, path_main_basename, + sizeof(new_savestate_dir)); + path_basedir(new_savestate_dir); + } + if (global) { if(path_is_directory(new_savefile_dir)) diff --git a/pkg/android/phoenix/AndroidManifest.xml b/pkg/android/phoenix/AndroidManifest.xml index cadfcda205..e5a1495129 100644 --- a/pkg/android/phoenix/AndroidManifest.xml +++ b/pkg/android/phoenix/AndroidManifest.xml @@ -1,7 +1,7 @@ diff --git a/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png index 3c1e128429..d33d1953f9 100644 Binary files a/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png and b/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png index 6dbad4942f..a338dfb2f9 100644 Binary files a/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png and b/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-xhdpi/banner.png b/pkg/android/phoenix/res/drawable-xhdpi/banner.png index e04769aa8a..bcf43ef5aa 100644 Binary files a/pkg/android/phoenix/res/drawable-xhdpi/banner.png and b/pkg/android/phoenix/res/drawable-xhdpi/banner.png differ diff --git a/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png index 2949cf0822..7eb088dc92 100644 Binary files a/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png and b/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-xxhdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..c5a7c34b79 Binary files /dev/null and b/pkg/android/phoenix/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable-xxxhdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000..f6abcb638a Binary files /dev/null and b/pkg/android/phoenix/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/pkg/android/phoenix/res/drawable/banner.png b/pkg/android/phoenix/res/drawable/banner.png index e04769aa8a..bcf43ef5aa 100644 Binary files a/pkg/android/phoenix/res/drawable/banner.png and b/pkg/android/phoenix/res/drawable/banner.png differ diff --git a/pkg/emscripten/embed/embed.js b/pkg/emscripten/embed/embed.js index dc3a21e3ca..efbb371870 100644 --- a/pkg/emscripten/embed/embed.js +++ b/pkg/emscripten/embed/embed.js @@ -394,7 +394,7 @@ $(function() { function keyPress(k) { kp(k, "keydown"); - setInterval(function(){kp(k, "keyup")}, 1000); + setTimeout(function(){kp(k, "keyup")}, 50); } kp = function(k, event) { diff --git a/pkg/emscripten/embed/index.html b/pkg/emscripten/embed/index.html index 7d643d177b..f7f01cdabd 100644 --- a/pkg/emscripten/embed/index.html +++ b/pkg/emscripten/embed/index.html @@ -12,7 +12,7 @@ - + diff --git a/pkg/emscripten/itch/index.html b/pkg/emscripten/itch/index.html index e16e0cd527..64320efd92 100644 --- a/pkg/emscripten/itch/index.html +++ b/pkg/emscripten/itch/index.html @@ -13,7 +13,7 @@ - + diff --git a/pkg/emscripten/libretro/index.html b/pkg/emscripten/libretro/index.html index 89ecbe4eef..37cfe0cc30 100644 --- a/pkg/emscripten/libretro/index.html +++ b/pkg/emscripten/libretro/index.html @@ -12,7 +12,7 @@ - + diff --git a/pkg/qnx/bar-descriptor.xml b/pkg/qnx/bar-descriptor.xml index f2f4588b3d..5ce0e2e67e 100644 --- a/pkg/qnx/bar-descriptor.xml +++ b/pkg/qnx/bar-descriptor.xml @@ -2,7 +2,7 @@ com.RetroArch - 1.3.6 + 1.6.4 3 Cross-platform entertainment system Team Libretro diff --git a/pkg/wii/meta.xml b/pkg/wii/meta.xml index 5ac0fbc317..018f8b1fc4 100644 --- a/pkg/wii/meta.xml +++ b/pkg/wii/meta.xml @@ -2,7 +2,7 @@ RetroArch Libretro - 1.6.3 + 1.6.4 2012-2017 The cross-platform entertainment system A port of RetroArch to the GameCube/Wii. diff --git a/pkg/wiiu/meta.xml b/pkg/wiiu/meta.xml index c0007055ef..3838b59b2b 100644 --- a/pkg/wiiu/meta.xml +++ b/pkg/wiiu/meta.xml @@ -2,8 +2,8 @@ Retroarch Libretro - 1.63 - 20170107283000 + 1.64 + 20170108073000 RetroArch diff --git a/retroarch.c b/retroarch.c index 7def51cb4b..95212ace7f 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2,6 +2,7 @@ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2012-2015 - Michael Lelli + * Copyright (C) 2015-2017 - Andrés Suárez * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -236,6 +237,8 @@ static bool runloop_shutdown_initiated = false; static bool runloop_core_shutdown_initiated = false; static bool runloop_perfcnt_enable = false; static bool runloop_overrides_active = false; +static bool runloop_remaps_core_active = false; +static bool runloop_remaps_game_active = false; static bool runloop_game_options_active = false; static bool runloop_missing_bios = false; static bool runloop_autosave = false; @@ -310,6 +313,8 @@ static void global_free(void) rarch_ups_pref = false; rarch_patch_blocked = false; runloop_overrides_active = false; + runloop_remaps_core_active = false; + runloop_remaps_game_active = false; core_unset_input_descriptors(); @@ -1587,6 +1592,22 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) break; case RARCH_CTL_IS_OVERRIDES_ACTIVE: return runloop_overrides_active; + case RARCH_CTL_SET_REMAPS_CORE_ACTIVE: + runloop_remaps_core_active = true; + break; + case RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE: + runloop_remaps_core_active = false; + break; + case RARCH_CTL_IS_REMAPS_CORE_ACTIVE: + return runloop_remaps_core_active; + case RARCH_CTL_SET_REMAPS_GAME_ACTIVE: + runloop_remaps_game_active = true; + break; + case RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE: + runloop_remaps_game_active = false; + break; + case RARCH_CTL_IS_REMAPS_GAME_ACTIVE: + return runloop_remaps_game_active; case RARCH_CTL_SET_MISSING_BIOS: runloop_missing_bios = true; break; @@ -2161,6 +2182,7 @@ bool retroarch_main_quit(void) command_event(CMD_EVENT_AUTOSAVE_STATE, NULL); command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL); command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL); + command_event(CMD_EVENT_RESTORE_REMAPS, NULL); } runloop_shutdown_initiated = true; diff --git a/retroarch.h b/retroarch.h index e01d4985b6..faf8b5a1df 100644 --- a/retroarch.h +++ b/retroarch.h @@ -98,6 +98,14 @@ enum rarch_ctl_state RARCH_CTL_SET_OVERRIDES_ACTIVE, RARCH_CTL_UNSET_OVERRIDES_ACTIVE, + RARCH_CTL_IS_REMAPS_CORE_ACTIVE, + RARCH_CTL_SET_REMAPS_CORE_ACTIVE, + RARCH_CTL_UNSET_REMAPS_CORE_ACTIVE, + + RARCH_CTL_IS_REMAPS_GAME_ACTIVE, + RARCH_CTL_SET_REMAPS_GAME_ACTIVE, + RARCH_CTL_UNSET_REMAPS_GAME_ACTIVE, + RARCH_CTL_IS_MISSING_BIOS, RARCH_CTL_SET_MISSING_BIOS, RARCH_CTL_UNSET_MISSING_BIOS, diff --git a/tasks/task_netplay_find_content.c b/tasks/task_netplay_find_content.c index 1dd9df061e..0adb00ed82 100644 --- a/tasks/task_netplay_find_content.c +++ b/tasks/task_netplay_find_content.c @@ -236,12 +236,14 @@ filename_matching: for (j = 0; j < playlist_size; j++) { + char entry[PATH_MAX_LENGTH]; const char *playlist_path = NULL; + const char *buf = NULL; + playlist_get_index(playlist, j, &playlist_path, NULL, NULL, NULL, NULL, NULL); - char entry[PATH_MAX_LENGTH]; - const char* buf = path_basename(playlist_path); + buf = path_basename(playlist_path); entry[0] = '\0'; strlcpy(entry, buf, sizeof(entry)); diff --git a/tasks/task_screenshot.c b/tasks/task_screenshot.c index 990839e7f6..ac960cd049 100644 --- a/tasks/task_screenshot.c +++ b/tasks/task_screenshot.c @@ -211,7 +211,7 @@ static bool screenshot_dump( screenshot_path[0] = '\0'; - if (string_is_empty(screenshot_dir)) + if (string_is_empty(screenshot_dir) || settings->bools.screenshots_in_content_dir) { fill_pathname_basedir(screenshot_path, name_base, sizeof(screenshot_path)); diff --git a/tools/ps3/ps3py/pkg.py b/tools/ps3/ps3py/pkg.py index 219608bb0d..fa545d8227 100755 --- a/tools/ps3/ps3py/pkg.py +++ b/tools/ps3/ps3py/pkg.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 from __future__ import with_statement import struct, sys diff --git a/ui/drivers/ui_win32.c b/ui/drivers/ui_win32.c index e5943ec2b2..116c7844e6 100644 --- a/ui/drivers/ui_win32.c +++ b/ui/drivers/ui_win32.c @@ -286,7 +286,7 @@ void shader_dlg_params_reload(void) SendMessage(control->trackbar.label_title, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0)); pos_y += SHADER_DLG_LABEL_HEIGHT; - control->trackbar.hwnd = CreateWindowEx(0, TRACKBAR_CLASS, "", + control->trackbar.hwnd = CreateWindowEx(0, (LPCSTR)TRACKBAR_CLASS, "", WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_NOTICKS, pos_x + SHADER_DLG_TRACKBAR_LABEL_WIDTH, pos_y, SHADER_DLG_TRACKBAR_WIDTH, SHADER_DLG_TRACKBAR_HEIGHT, diff --git a/ui/drivers/win32/ui_win32_window.cpp b/ui/drivers/win32/ui_win32_window.cpp index 8a0d1e981a..8a2c4243f5 100644 --- a/ui/drivers/win32/ui_win32_window.cpp +++ b/ui/drivers/win32/ui_win32_window.cpp @@ -75,11 +75,17 @@ static void ui_window_win32_set_title(void *data, char *buf) SetWindowText(window->hwnd, buf); } +extern "C" +{ + VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); +} + void ui_window_win32_set_droppable(void *data, bool droppable) { /* Minimum supported client: Windows XP, minimum supported server: Windows 2000 Server */ ui_window_win32_t *window = (ui_window_win32_t*)data; - DragAcceptFiles(window->hwnd, droppable); + if (DragAcceptFiles_func != NULL) + DragAcceptFiles_func(window->hwnd, droppable); } static bool ui_window_win32_focused(void *data) diff --git a/version.h b/version.h index 4d3f1b14c3..d55f77f791 100644 --- a/version.h +++ b/version.h @@ -18,7 +18,7 @@ #define RARCH_VERSION_H__ #ifndef PACKAGE_VERSION -#define PACKAGE_VERSION "1.6.3" +#define PACKAGE_VERSION "1.6.4" #endif #endif diff --git a/wiiu/system/imports.h b/wiiu/system/imports.h index 0014e7e552..3aa90a6746 100644 --- a/wiiu/system/imports.h +++ b/wiiu/system/imports.h @@ -31,6 +31,12 @@ IMPORT(OSGetSystemTick); IMPORT(OSGetSymbolName); IMPORT(OSGetSharedData); IMPORT(OSEffectiveToPhysical); +IMPORT(OSInitSemaphore); +IMPORT(OSInitSemaphoreEx); +IMPORT(OSGetSemaphoreCount); +IMPORT(OSSignalSemaphore); +IMPORT(OSWaitSemaphore); +IMPORT(OSTryWaitSemaphore); IMPORT(exit); IMPORT(_Exit);