From 24107229fcb612d2a9ce6026e15e7c86a3af4f19 Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Fri, 14 Jul 2017 14:49:41 -0400 Subject: [PATCH 001/133] Remove horizontal slide animation for XMB --- menu/drivers/xmb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 22c7a88f4e..1a99b9fe68 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -610,7 +610,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) { @@ -826,7 +826,7 @@ static void xmb_render_messagebox_internal( { const char *msg = list->elems[i].data; int len = (int)utf8len(msg); - + if (len > longest) { longest = len; @@ -1636,7 +1636,8 @@ 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); + // TODO: Add toggle for settings. + //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(), @@ -3811,8 +3812,9 @@ static void xmb_list_cache(void *data, enum menu_list_type type, unsigned action if (!xmb) return; - xmb_list_deep_copy(selection_buf, xmb->selection_buf_old); - xmb_list_deep_copy(menu_stack, xmb->menu_stack_old); + // TODO: Add toggle for settings. + //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) From 7d71746b218874ad4a262dfacc192a6827dd3fcb Mon Sep 17 00:00:00 2001 From: Rob Loach Date: Fri, 14 Jul 2017 15:11:27 -0400 Subject: [PATCH 002/133] Add Horizontal Animation configuration --- configuration.c | 71 +++++++++++++++---------------- configuration.h | 1 + intl/msg_hash_eo.h | 2 + intl/msg_hash_lbl.h | 2 + intl/msg_hash_us.h | 2 + menu/drivers/xmb.c | 18 +++++--- menu/menu_displaylist.c | 17 ++++---- menu/menu_setting.c | 92 ++++++++++++++++++++++++----------------- msg_hash.h | 1 + 9 files changed, 121 insertions(+), 85 deletions(-) diff --git a/configuration.c b/configuration.c index 1704386fbb..2669396dc5 100644 --- a/configuration.c +++ b/configuration.c @@ -52,7 +52,7 @@ /* All config related settings go here. */ struct config_bool_setting -{ +{ const char *ident; bool *ptr; bool def_enable; @@ -61,7 +61,7 @@ struct config_bool_setting }; struct config_int_setting -{ +{ const char *ident; int *ptr; bool def_enable; @@ -70,7 +70,7 @@ struct config_int_setting }; struct config_uint_setting -{ +{ const char *ident; unsigned *ptr; bool def_enable; @@ -79,7 +79,7 @@ struct config_uint_setting }; struct config_float_setting -{ +{ const char *ident; float *ptr; bool def_enable; @@ -88,7 +88,7 @@ struct config_float_setting }; struct config_array_setting -{ +{ const char *ident; char *ptr; bool def_enable; @@ -97,7 +97,7 @@ struct config_array_setting }; struct config_path_setting -{ +{ const char *ident; char *ptr; bool def_enable; @@ -485,7 +485,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 +1014,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 +1033,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 +1063,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 +1078,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 +1180,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 +1205,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 @@ -1923,7 +1924,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 +2100,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 +2171,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 +2707,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 +2806,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)); @@ -3252,7 +3253,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 +3443,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 +3634,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 +3691,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 +3703,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 +3715,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 +3727,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 +3740,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 +3753,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); diff --git a/configuration.h b/configuration.h index 8d20c8daaf..da3af60ba3 100644 --- a/configuration.h +++ b/configuration.h @@ -119,6 +119,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; diff --git a/intl/msg_hash_eo.h b/intl/msg_hash_eo.h index 4fce47a371..ec290710c3 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_lbl.h b/intl/msg_hash_lbl.h index 4838976479..4820ff6883 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -579,6 +579,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, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 40e9c47eca..fb31a4cf16 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -953,6 +953,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, diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 1a99b9fe68..6bc8bef283 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1612,6 +1612,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; @@ -1636,8 +1637,11 @@ static void xmb_list_switch(xmb_handle_t *xmb) xmb_list_switch_old(xmb, xmb->selection_buf_old, dir, xmb->selection_ptr_old); - // TODO: Add toggle for settings. - //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(), @@ -3808,13 +3812,17 @@ 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; - // TODO: Add toggle for settings. - //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) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index abf2006c1c..3bae315569 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -297,7 +297,7 @@ static void print_buf_lines(file_list_t *list, char *buf, sizeof(core_path)); if ( - path_file_exists(core_path) + path_file_exists(core_path) && core_info_get_display_name( core_path, display_name, sizeof(display_name))) menu_entries_set_alt_at_offset(list, j, display_name); @@ -1843,7 +1843,7 @@ static int menu_displaylist_parse_database_entry(menu_displaylist_info_t *info) strlcpy(thumbnail_content, db_info_entry->name, sizeof(thumbnail_content)); if (!string_is_empty(thumbnail_content)) - menu_driver_set_thumbnail_content(thumbnail_content, sizeof(thumbnail_content)); + menu_driver_set_thumbnail_content(thumbnail_content, sizeof(thumbnail_content)); menu_driver_ctl(RARCH_MENU_CTL_UPDATE_THUMBNAIL_PATH, NULL); menu_driver_ctl(RARCH_MENU_CTL_UPDATE_THUMBNAIL_IMAGE, NULL); @@ -2945,7 +2945,7 @@ static int menu_displaylist_parse_horizontal_content_actions( else { const char *ext = NULL; - + if (!string_is_empty(entry_path)) ext = path_get_extension(entry_path); @@ -2963,8 +2963,8 @@ static int menu_displaylist_parse_horizontal_content_actions( msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN), msg_hash_to_str(MENU_ENUM_LABEL_RUN), MENU_ENUM_LABEL_RUN, FILE_TYPE_PLAYLIST_ENTRY, 0, idx); - - if (settings->bools.playlist_entry_remove) + + if (settings->bools.playlist_entry_remove) menu_entries_append_enum(info->list, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY), msg_hash_to_str(MENU_ENUM_LABEL_DELETE_ENTRY), @@ -4033,7 +4033,7 @@ bool menu_displaylist_process(menu_displaylist_info_t *info) MENU_SETTING_ACTION, 0, 0); } #endif - + if (info->push_builtin_cores) { #if defined(HAVE_VIDEO_PROCESSOR) @@ -4747,7 +4747,7 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) PARSE_ONLY_UINT, false); ret = menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_PLAYLIST_ENTRY_REMOVE, - PARSE_ONLY_BOOL, false); + PARSE_ONLY_BOOL, false); menu_displaylist_parse_playlist_associations(info); info->need_push = true; @@ -5048,6 +5048,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); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index cff3ea5c4f..80a5b6ba92 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); @@ -1752,7 +1752,7 @@ void general_write_handler(void *data) { #if defined(__CELLOS_LV2__) && (CELL_SDK_VERSION > 0x340000) cellSysutilEnableBgmPlayback(); -#endif +#endif } else { @@ -2032,7 +2032,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)); @@ -2053,7 +2053,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)); @@ -2147,7 +2147,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 @@ -3017,7 +3017,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); @@ -3132,7 +3132,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 @@ -3259,7 +3259,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()) @@ -3357,7 +3357,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); @@ -3407,7 +3407,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( @@ -3636,7 +3636,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); @@ -3981,7 +3981,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, @@ -4656,7 +4656,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)); } @@ -5052,6 +5052,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; @@ -5413,7 +5429,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 @@ -5801,7 +5817,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( @@ -5818,9 +5834,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: @@ -5913,7 +5929,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, @@ -5927,7 +5943,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, @@ -6445,7 +6461,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 @@ -6510,7 +6526,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 @@ -6548,7 +6564,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, @@ -6592,7 +6608,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, @@ -7002,7 +7018,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 95a1d7dea7..16d392fc21 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -664,6 +664,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), From 24ae754901dd72c2a16585a2f1879b9e8d645c3b Mon Sep 17 00:00:00 2001 From: Matthew Wang Date: Mon, 24 Jul 2017 17:14:48 +0800 Subject: [PATCH 003/133] add translations --- intl/msg_hash_cht.c | 108 +++---- intl/msg_hash_cht.h | 674 ++++++++++++++++++++++---------------------- 2 files changed, 391 insertions(+), 391 deletions(-) diff --git a/intl/msg_hash_cht.c b/intl/msg_hash_cht.c index d04cfc834d..a4b4a4cef6 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 4a51682c8a..e84e72aade 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, From 9c6b6ee4f0d697404f3d51e66b7ffaa7d45d0ad5 Mon Sep 17 00:00:00 2001 From: Matthew Wang Date: Mon, 24 Jul 2017 17:20:37 +0800 Subject: [PATCH 004/133] fix one translation error --- intl/msg_hash_cht.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intl/msg_hash_cht.c b/intl/msg_hash_cht.c index a4b4a4cef6..a08736ee89 100644 --- a/intl/msg_hash_cht.c +++ b/intl/msg_hash_cht.c @@ -210,7 +210,7 @@ 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" + snprintf(s, len, "你的登入訊息 \n" "Retro Achievements 帳號. \n" " \n" "訪問 retroachievements.org 並註冊 \n" From c8e6a986513c421e7d8b1e8efb6340373d6e1208 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 4 Aug 2017 21:47:46 -0400 Subject: [PATCH 005/133] gdi: enable OSD text drawing --- gfx/drivers/gdi_gfx.c | 2 +- gfx/drivers_font/gdi_font.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) 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_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)) { From b1904bcfa6113664306a6f22f1d77914cf554e7d Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Fri, 4 Aug 2017 21:51:14 -0400 Subject: [PATCH 006/133] caca: enable OSD text drawing --- gfx/drivers/caca_gfx.c | 2 +- gfx/drivers_font/caca_font.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) 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_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)) { From 05c7bdedbed1b16265bb141a86cb4fd68a61544d Mon Sep 17 00:00:00 2001 From: Romain Tisserand Date: Sat, 5 Aug 2017 12:00:20 +0200 Subject: [PATCH 007/133] Proper fix for MOD support --- libretro-common/audio/audio_mixer.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index 489ae7a000..cef6ac4226 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,8 +476,8 @@ 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; + data.buffer = (char*)sound->types.mod.data; + data.length = sound->types.mod.size; module = module_load(&data, message); if (!module) { @@ -527,7 +526,6 @@ error: } #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 +558,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: From 449a33cf17aaf128b674c804040e71dbdf371df7 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 5 Aug 2017 15:24:15 +0200 Subject: [PATCH 008/133] buildfix --- libretro-common/audio/audio_mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index cef6ac4226..9a41b7ec62 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -510,7 +510,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; From 2aa095aa4b400b6e22367f62638502841586df14 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 5 Aug 2017 16:24:33 +0200 Subject: [PATCH 009/133] Fix some Coverity warnings --- libretro-common/audio/audio_mixer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index 9a41b7ec62..749e09206a 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -476,9 +476,10 @@ static bool audio_mixer_play_mod( struct module* module = NULL; struct replay* replay = NULL; - data.buffer = (char*)sound->types.mod.data; - data.length = sound->types.mod.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); @@ -824,6 +825,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); From 32234b44d3998d4b9ff02332cc2ff0fda2fcf71a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sat, 5 Aug 2017 16:42:28 +0200 Subject: [PATCH 010/133] Prevent dereference after null check warning by Coverity --- libretro-common/audio/audio_mixer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index 749e09206a..fc3bcca370 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -522,7 +522,8 @@ static bool audio_mixer_play_mod( error: if (mod_buffer) memalign_free(mod_buffer); - dispose_module(module); + if (module) + dispose_module(module); return false; } From 9862b75b4b3ca5320ecbba4ce97b46f8fc892363 Mon Sep 17 00:00:00 2001 From: radius Date: Fri, 4 Aug 2017 23:56:17 -0500 Subject: [PATCH 011/133] allow specifying libretro device and analog dpad mode on remap files --- CHANGES.md | 2 ++ command.c | 9 +++++++++ command.h | 1 + input/input_remapping.c | 14 ++++++++++++++ retroarch.c | 1 + 5 files changed, 27 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index afb55b0acb..e8de27aadd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,6 +3,8 @@ - ANDROID: Fire Stick & Fire TV remote overrides gamepad port 0 on button press and viceversa like SHIELD devices - AUDIO: Audio mixer supports MOD/S3M/XM file types now! - INPUT: input swap override flag (for remotes) is cleared correctly +- INPUT: allow specifying libretro device in remap files +- INPUT: allow specifying analog dpad mode in remap files - COMMON: Add 'Delete Core'option to Core Information menu. - COMMON: Allow Max Timing Skew to be set to 0. - LOCALIZATION: Update Russian translation diff --git a/command.c b/command.c index ca21d18931..2eedb184a7 100644 --- a/command.c +++ b/command.c @@ -1053,6 +1053,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) @@ -1287,6 +1288,11 @@ static void command_event_restore_default_shader_preset(void) path_clear(RARCH_PATH_DEFAULT_SHADER_PRESET); } +static void command_event_restore_remaps(void) +{ + input_remapping_set_defaults(); +} + static bool command_event_save_auto_state(void) { char savestate_name_auto[PATH_MAX_LENGTH] = {0}; @@ -1797,6 +1803,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 +2596,8 @@ 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(); 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/input/input_remapping.c b/input/input_remapping.c index 17aae07ab3..f86b1a11ea 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -23,6 +23,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. @@ -46,6 +49,9 @@ bool input_remapping_load_file(void *data, const char *path) for (i = 0; i < MAX_USERS; i++) { + old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i]; + old_libretro_device[i] = settings->uints.input_libretro_device[i]; + char buf[64]; char key_ident[RARCH_FIRST_CUSTOM_BIND + 4][128] = {{0}}; char key_strings[RARCH_FIRST_CUSTOM_BIND + 4][128] = @@ -82,6 +88,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); @@ -180,5 +192,7 @@ void input_remapping_set_defaults(void) } for (j = 0; j < 4; j++) settings->uints.input_remap_ids[i][RARCH_FIRST_CUSTOM_BIND + j] = j; + settings->uints.input_analog_dpad_mode[i] = old_analog_dpad_mode[i]; + settings->uints.input_libretro_device[i] = old_libretro_device[i]; } } diff --git a/retroarch.c b/retroarch.c index 7def51cb4b..6ab02a62f4 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2161,6 +2161,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; From a973d5dc8ad2682b7918fb79e21f001117bf1270 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 00:09:46 -0500 Subject: [PATCH 012/133] allow saving analog dpad mode and libretro device to remap files --- CHANGES.md | 2 ++ input/input_remapping.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index e8de27aadd..d83f646e7e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,8 @@ - INPUT: input swap override flag (for remotes) is cleared correctly - 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 - COMMON: Add 'Delete Core'option to Core Information menu. - COMMON: Allow Max Timing Skew to be set to 0. - LOCALIZATION: Update Russian translation diff --git a/input/input_remapping.c b/input/input_remapping.c index f86b1a11ea..1d9bc79af9 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -170,6 +170,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); From 2db79242c94e5582e9ef4f72a0bf477b6d07775b Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 00:37:26 -0500 Subject: [PATCH 013/133] remove remaps --- CHANGES.md | 1 + command.c | 3 +- configuration.c | 3 ++ input/input_remapping.c | 19 ++++++++++ input/input_remapping.h | 2 ++ intl/msg_hash_lbl.h | 4 +++ intl/msg_hash_us.h | 8 +++++ menu/cbs/menu_cbs_ok.c | 77 ++++++++++++++++++++++++++++++++++------- menu/menu_displaylist.c | 19 ++++++++++ msg_hash.h | 4 +++ retroarch.c | 21 +++++++++++ retroarch.h | 8 +++++ 12 files changed, 156 insertions(+), 13 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d83f646e7e..29d33f86a3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,7 @@ - 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: Add 'Delete Core'option to Core Information menu. - COMMON: Allow Max Timing Skew to be set to 0. - LOCALIZATION: Update Russian translation diff --git a/command.c b/command.c index 2eedb184a7..67566fae2c 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 @@ -1227,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(); diff --git a/configuration.c b/configuration.c index 1704386fbb..47c43c49e5 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 @@ -2925,6 +2926,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 +2946,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; } } diff --git a/input/input_remapping.c b/input/input_remapping.c index 1d9bc79af9..80c77d1f8a 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- @@ -182,6 +183,24 @@ bool input_remapping_save_file(const char *path) return ret; } +bool input_remapping_remove_file(const char *path) +{ + bool ret; + char buf[PATH_MAX_LENGTH]; + char remap_file[PATH_MAX_LENGTH]; + config_file_t *conf = NULL; + 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; 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_lbl.h b/intl/msg_hash_lbl.h index 4444ac9ec3..1314edcc6a 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -821,6 +821,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, diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index c14eb00878..b870188f6a 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -1217,6 +1217,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, @@ -1945,6 +1949,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, @@ -2137,6 +2143,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, diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index b7ba381edb..f7c72a85dd 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- @@ -2090,10 +2091,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 +2121,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 +2136,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) { @@ -4766,6 +4813,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/menu_displaylist.c b/menu/menu_displaylist.c index c5c3121493..938ac589b9 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 @@ -3372,6 +3373,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) diff --git a/msg_hash.h b/msg_hash.h index 39660d6006..48a8fc9d2f 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, @@ -1366,6 +1368,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/retroarch.c b/retroarch.c index 6ab02a62f4..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; 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, From 70956dca6fe6dc8c5dda2037a68c119fccf2f657 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 12:31:58 -0500 Subject: [PATCH 014/133] add new variables for "content dir" --- config.def.h | 5 +++++ configuration.c | 5 +++++ configuration.h | 5 +++++ 3 files changed, 15 insertions(+) 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..0e7482f967 100644 --- a/configuration.c +++ b/configuration.c @@ -1258,6 +1258,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); diff --git a/configuration.h b/configuration.h index 8d20c8daaf..4486bd6913 100644 --- a/configuration.h +++ b/configuration.h @@ -209,6 +209,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; From 7af556e200ae4d7ea64b78706e7cefd04166fa43 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 13:14:26 -0500 Subject: [PATCH 015/133] add menu settings --- intl/msg_hash_lbl.h | 8 ++++++++ intl/msg_hash_us.h | 8 ++++++++ menu/menu_displaylist.c | 12 ++++++++++++ menu/menu_setting.c | 26 +++++++++++++++++++++++++- msg_hash.h | 4 ++++ 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 4444ac9ec3..218d75b180 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -909,6 +909,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_us.h b/intl/msg_hash_us.h index c14eb00878..9d56b867a9 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -1323,6 +1323,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, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index c5c3121493..c8bdada29f 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4880,6 +4880,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; diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 692c6b3543..3302aed629 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -3048,7 +3048,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 +3098,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( diff --git a/msg_hash.h b/msg_hash.h index 39660d6006..3d5d7343a8 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1067,6 +1067,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), From 9858b94e87fcd5c1c0361d5ca67fb22ec330f5ac Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 13:41:05 -0500 Subject: [PATCH 016/133] allow savestates and savefiles to go into content dir via bool setting in addition of the empty string --- paths.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) 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)) From a4192bf99b3b591825cff2cf9064b7966c1cfcb6 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 13:48:37 -0500 Subject: [PATCH 017/133] allow systemfiles into content dir via bool setting in addition of the empty string --- dynamic.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dynamic.c b/dynamic.c index 6e07579230..17d67ad17f 100644 --- a/dynamic.c +++ b/dynamic.c @@ -1016,7 +1016,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 +1025,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); } From cf8783644df346e5f7762078fb1d9f0db2adc7e4 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 13:57:24 -0500 Subject: [PATCH 018/133] allow screenshots into content dir via bool setting in addition of the empty string --- tasks/task_screenshot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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)); From 2cd552b7601789ca9779fb453d2b31c161b2827c Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 14:38:50 -0500 Subject: [PATCH 019/133] make all the directories reseteable --- menu/menu_setting.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 3302aed629..868909ca17 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -6557,13 +6557,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, @@ -6601,13 +6602,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, @@ -6668,6 +6670,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, @@ -6683,6 +6686,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( @@ -6774,6 +6778,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)) { @@ -6821,6 +6826,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( @@ -6859,13 +6865,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, @@ -6888,13 +6895,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, @@ -6902,13 +6910,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, From a17e23dc6c723971bf450df12c4d211f93fd854d Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 14:39:17 -0500 Subject: [PATCH 020/133] update win32 platform driver --- frontend/drivers/platform_win32.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/drivers/platform_win32.c b/frontend/drivers/platform_win32.c index 5133f0c27e..854f651771 100644 --- a/frontend/drivers/platform_win32.c +++ b/frontend/drivers/platform_win32.c @@ -278,9 +278,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 +303,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) From 8bb3852944549fdafbdb9521046634487d60bbe3 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 14:52:16 -0500 Subject: [PATCH 021/133] update android platform driver --- frontend/drivers/platform_unix.c | 75 ++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index b53cf33e35..a5fc5f2c5b 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, "saves", + sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], + internal_storage_path, "states", + sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], + internal_storage_path, "system", + sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT], + internal_storage_path, "screenshots", + sizeof(g_defaults.dirs[DEFAULT_DIR_SCREENSHOT])); + fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], + internal_storage_path, "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])); From 27d9b04080543a3249958d0d62b8a460b7496914 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 15:01:43 -0500 Subject: [PATCH 022/133] update CHANGES.md --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index afb55b0acb..e8562f4c35 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,11 +1,14 @@ # 1.6.4 (future) - 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. - 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 - LOCALIZATION: Update Russian translation +- WINDOWS: Provide default save / system / state / screenshot locations - WINDOWS 98/ME/2K: Set default directory for MSVC 2005 RetroArch version. - WIIU: Exception handler rewritten. From a8d3b205ca4dd069e3bae6e6e642d711d596539d Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sat, 5 Aug 2017 20:06:11 +0000 Subject: [PATCH 023/133] update CHANGES.md --- CHANGES.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index afb55b0acb..bb69c5fb77 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -3,14 +3,16 @@ - ANDROID: Fire Stick & Fire TV remote overrides gamepad port 0 on button press and viceversa like SHIELD devices - 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. +- COMMON: Add 'Delete Core' option to Core Information menu. - COMMON: Allow Max Timing Skew to be set to 0. - LOCALIZATION: Update Russian translation +- 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. - 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. From 944eb01fb41da2d2f634230623f0c1e2bd80924d Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 01:29:41 +0200 Subject: [PATCH 024/133] Updates --- libretro-common/rthreads/rthreads.c | 31 ++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index c4ffce1d5c..1abcf1a3ed 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -437,11 +437,17 @@ 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 = { .QuadPart = 0 }; + LARGE_INTEGER tsBegin; +#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 +459,27 @@ 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 (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 +521,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) From e259a8c63bda0de1e89d3fff99bf0f4f15fcdbd0 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 01:44:34 +0200 Subject: [PATCH 025/133] Try to avoid direct initialization --- libretro-common/rthreads/rthreads.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index 1abcf1a3ed..a059bc2f04 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -441,8 +441,9 @@ static bool _scond_wait_win32(scond_t *cond, slock_t *lock, DWORD dwMilliseconds struct QueueEntry **ptr; #if _WIN32_WINNT >= 0x0500 - static LARGE_INTEGER performanceCounterFrequency = { .QuadPart = 0 }; + static LARGE_INTEGER performanceCounterFrequency; LARGE_INTEGER tsBegin; + static bool first_init = true; #else static bool beginPeriod = false; DWORD tsBegin; @@ -460,6 +461,12 @@ 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); From 86f7972aa8af0d2f20b2775e49f0e89a8c918e51 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 04:40:55 +0200 Subject: [PATCH 026/133] (Wii) Backport https://github.com/SuperrSonic/RA-SS/commit/0574b91595a231e15bafa9f2778d1b9b14944ba6 - untested --- gfx/drivers/gx_gfx.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index f7f6cfeef8..1b1e050642 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -92,6 +92,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 +216,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 +258,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 +302,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 +584,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 +1453,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 +1538,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 +1584,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; } From 4387dd7c15a7d5908a8d95f51fbc780596da9163 Mon Sep 17 00:00:00 2001 From: radius Date: Sat, 5 Aug 2017 21:56:52 -0500 Subject: [PATCH 027/133] fix new android paths --- frontend/drivers/platform_unix.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index a5fc5f2c5b..eddd9a99eb 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -1683,19 +1683,19 @@ static void frontend_unix_get_env(int *argc, case INTERNAL_STORAGE_WRITABLE: fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], - internal_storage_path, "saves", + internal_storage_path, "RetroArch/saves", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], - internal_storage_path, "states", + internal_storage_path, "RetroArch/states", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], - internal_storage_path, "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, "screenshots", + 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, "downloads", + internal_storage_path, "RetroArch/downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS])); fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], From 740ad823ab8c1d110be891ac3fd9bea1c98302cf Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 05:52:40 +0200 Subject: [PATCH 028/133] (GX) Buildfix --- gfx/drivers/gx_gfx.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index 1b1e050642..7b43d19a6b 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -42,6 +42,21 @@ #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 + extern syssram* __SYS_LockSram(void); extern u32 __SYS_UnlockSram(u32 write); From 169aea5ae16ba63a3492b39d8ee5543aa7bd3ed2 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 05:54:46 +0200 Subject: [PATCH 029/133] (GX) Another buildfix --- gfx/drivers/gx_gfx.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index 7b43d19a6b..f50a41db9b 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -57,6 +57,22 @@ } #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); From 6b369775cf83e0380aba348ebdbf91540140ae55 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 6 Aug 2017 03:32:04 -0400 Subject: [PATCH 030/133] add unicode-aware option for word_wrap (only needed for xmb) --- libretro-common/include/string/stdstring.h | 2 +- libretro-common/string/stdstring.c | 25 +++++++++++++++++----- menu/drivers/materialui.c | 4 ++-- menu/drivers/xmb.c | 2 +- 4 files changed, 24 insertions(+), 9 deletions(-) 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/string/stdstring.c b/libretro-common/string/stdstring.c index ea8d62e70f..88f0ed92fc 100644 --- a/libretro-common/string/stdstring.c +++ b/libretro-common/string/stdstring.c @@ -24,6 +24,7 @@ #include #include +#include char *string_to_upper(char *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/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..b545efe467 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2328,7 +2328,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 + From 50ba42aa576c71111619fe754fc623d97ea17d80 Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Sun, 6 Aug 2017 10:35:34 +0200 Subject: [PATCH 031/133] Update msg_hash_it.h --- intl/msg_hash_it.h | 50 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 0f363da56f..8add55db3f 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -529,7 +529,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, "Image") 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, @@ -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, @@ -1689,7 +1689,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, 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, @@ -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, @@ -2184,11 +2184,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") @@ -2295,19 +2295,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_VOLUME, - "Audio Mixer Volume Level (dB)" + "Audio Mixer Livello del Volume (dB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Audio Mixer Mute" + "Audio Mixer Muto" ) MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Mute/unmute mixer audio.") + "Muto/disattiva muto sul 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).") From ace34010427d8424eb70332bf7785ad055c63e4f Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Sun, 6 Aug 2017 10:43:56 +0200 Subject: [PATCH 032/133] Update msg_hash_it.h --- intl/msg_hash_it.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 8add55db3f..5fdbd9b744 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -523,11 +523,11 @@ 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, "Informazioni") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, @@ -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, From 5a4b5da68eb470e3b7a6d225d8c5f7d3edb486a8 Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Sun, 6 Aug 2017 10:51:41 +0200 Subject: [PATCH 033/133] Update msg_hash_it.h --- intl/msg_hash_it.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 5fdbd9b744..f2c45c3834 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -2311,3 +2311,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SHOW_CORE_UPDATER, "Visualizza Core Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "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.") From ba360556325100870fe054c2e33a19f734568cf8 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 13:43:01 +0200 Subject: [PATCH 034/133] (GX) Buildfix --- gfx/drivers/gx_gfx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/drivers/gx_gfx.c b/gfx/drivers/gx_gfx.c index f50a41db9b..3f36723efd 100644 --- a/gfx/drivers/gx_gfx.c +++ b/gfx/drivers/gx_gfx.c @@ -1615,7 +1615,7 @@ static bool gx_frame(void *data, const void *frame, VIDEO_SetNextFramebuffer(gx->framebuf[g_current_framebuf]); VIDEO_Flush(); - CPU_ISR_Disable(level); + _CPU_ISR_Disable(level); ++referenceRetraceCount; _CPU_ISR_Restore(level); From e3192ad3c511ed88b999604d904022631117c015 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 13:55:32 +0200 Subject: [PATCH 035/133] Get rid of some incompatible implicit declaration warnings --- libretro-common/file/retro_dirent.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libretro-common/file/retro_dirent.c b/libretro-common/file/retro_dirent.c index c21b2d669c..18370fe942 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 From e52e70aa5ae1f89720f77db9e83ea2293bf3ab0c Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 13:58:17 +0200 Subject: [PATCH 036/133] Add encoding_utf to Salamander --- Makefile.ctr.salamander | 1 + Makefile.ps3.salamander | 1 + Makefile.psp1.salamander | 1 + Makefile.vita.salamander | 1 + Makefile.wii.salamander | 1 + Makefile.wiiu.salamander | 1 + 6 files changed, 6 insertions(+) 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.salamander b/Makefile.ps3.salamander index b6e17aed55..2f541767ab 100644 --- a/Makefile.ps3.salamander +++ b/Makefile.ps3.salamander @@ -29,6 +29,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.o \ libretro-common/compat/compat_strl.c \ libretro-common/compat/compat_strcasestr.c \ libretro-common/streams/file_stream.c \ 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 From 912c7265e6136f97a38e2641fa853d33ad3a56d6 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 14:03:09 +0200 Subject: [PATCH 037/133] Get rid of some warnings --- input/input_remapping.c | 2 -- menu/cbs/menu_cbs_ok.c | 3 ++- menu/menu_displaylist.c | 4 ++++ menu/menu_setting.c | 4 ---- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/input/input_remapping.c b/input/input_remapping.c index 80c77d1f8a..8dca0eb38e 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -185,10 +185,8 @@ bool input_remapping_save_file(const char *path) bool input_remapping_remove_file(const char *path) { - bool ret; char buf[PATH_MAX_LENGTH]; char remap_file[PATH_MAX_LENGTH]; - config_file_t *conf = NULL; settings_t *settings = config_get_ptr(); buf[0] = remap_file[0] = '\0'; diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index f7c72a85dd..b594cfb7f0 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -4449,8 +4449,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); diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 30b017466d..12c0e149e0 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4055,7 +4055,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) && !defined(HAVE_LAKKA) settings_t *settings = config_get_ptr(); +#endif if (info->need_navigation_clear) { @@ -5038,12 +5040,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); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 868909ca17..d7fae987fa 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -5698,8 +5698,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, @@ -5729,8 +5727,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)) { From 6d4d9aa1fb2b26bb905321507ff876ea2e33145f Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 14:05:59 +0200 Subject: [PATCH 038/133] Set PPU_CFLAGS --- Makefile.ps3.salamander | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile.ps3.salamander b/Makefile.ps3.salamander index 2f541767ab..9c3a8d4930 100644 --- a/Makefile.ps3.salamander +++ b/Makefile.ps3.salamander @@ -18,7 +18,8 @@ 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 +PPU_CFLAGS := -I. -Ilibretro-common/include -Ideps/libz -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC +PPU_CXXFLAGS := -I. -Ilibretro-common/include -Ideps/libz -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC PPU_SRCS = frontend/frontend_salamander.c \ frontend/frontend_driver.c \ frontend/drivers/platform_ps3.c \ From 7382a384852efadd5e51fbe9af7f32c2a07cc0e3 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 14:12:09 +0200 Subject: [PATCH 039/133] (PS3) Fix Salamander --- Makefile.ps3.salamander | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Makefile.ps3.salamander b/Makefile.ps3.salamander index 9c3a8d4930..ab51d0db4d 100644 --- a/Makefile.ps3.salamander +++ b/Makefile.ps3.salamander @@ -16,10 +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 -PPU_CXXFLAGS := -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 \ @@ -30,7 +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.o \ + libretro-common/encodings/encoding_utf.c \ libretro-common/compat/compat_strl.c \ libretro-common/compat/compat_strcasestr.c \ libretro-common/streams/file_stream.c \ @@ -62,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 From c7e6f199202b2cc6382e3d747375adaa24a14c69 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 14:21:18 +0200 Subject: [PATCH 040/133] Cleanup retro_dirent_is_dir --- libretro-common/file/retro_dirent.c | 54 +++++------------------------ 1 file changed, 9 insertions(+), 45 deletions(-) diff --git a/libretro-common/file/retro_dirent.c b/libretro-common/file/retro_dirent.c index 18370fe942..26f3e8a897 100644 --- a/libretro-common/file/retro_dirent.c +++ b/libretro-common/file/retro_dirent.c @@ -157,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: @@ -222,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 } From c0e5f28498887460a9e3768d0b6285d89ecfe495 Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Sun, 6 Aug 2017 15:12:43 +0200 Subject: [PATCH 041/133] Update msg_hash_it.h Update italian language --- intl/msg_hash_it.h | 50 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index f2c45c3834..575f329682 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 " @@ -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, @@ -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, @@ -2313,7 +2313,39 @@ MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_CORE_UPDATER, "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, +MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, "Seleziona quale contenuto avviare.") - MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, +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") From c6379a7c626ab8f7d23b9ea3f8f947d740b81dc2 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 15:31:38 +0200 Subject: [PATCH 042/133] Missed break here --- command.c | 1 + 1 file changed, 1 insertion(+) diff --git a/command.c b/command.c index 67566fae2c..981100b122 100644 --- a/command.c +++ b/command.c @@ -2599,6 +2599,7 @@ bool command_event(enum event_command cmd, void *data) 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; From 999fd0f120dde6adb71197d9a4857112e34b772f Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:01:12 +0200 Subject: [PATCH 043/133] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 022e54d8b2..e6e4c82065 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - 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 +- LOCALIZATION: Update Italian translation - LOCALIZATION: Update Russian translation - WINDOWS: Provide default save / system / state / screenshot locations - LOBBIES: Show what country the host is in From b345a4b8601e1c75648ec6805126d43e72ab4567 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:02:03 +0200 Subject: [PATCH 044/133] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index e6e4c82065..d0a7e977a9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,7 @@ - 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 From 5caabab2eb58e002f49236d60d284a1d2db5efc7 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:25:32 +0200 Subject: [PATCH 045/133] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index d0a7e977a9..181cbdb7e8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - 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 +- LOCALIZATION: Update Traditional Chinese translation - LOCALIZATION: Update Italian translation - LOCALIZATION: Update Russian translation - WINDOWS: Provide default save / system / state / screenshot locations From 2cd38297c29bbbe8f994484ce0b7d0403a0a4019 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:27:41 +0200 Subject: [PATCH 046/133] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 181cbdb7e8..d8e8f0ea59 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,6 +12,7 @@ - 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. This can result in a performance boost. - LOCALIZATION: Update Traditional Chinese translation - LOCALIZATION: Update Italian translation - LOCALIZATION: Update Russian translation From 0bc4254ab1f866ab8454005536adc0a5f96f8d9b Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:28:12 +0200 Subject: [PATCH 047/133] Update CHANGES.md --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index d8e8f0ea59..5aee6057cc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,7 +12,7 @@ - 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. This can result in a performance boost. +- GUI: You can turn on/off 'Horizontal Animation' now for the XMB menu. Turning animations off can result in a performance boost. - LOCALIZATION: Update Traditional Chinese translation - LOCALIZATION: Update Italian translation - LOCALIZATION: Update Russian translation From 8f616c13e40abf1dec9fe81d0f51a47a65d92bd2 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Sun, 6 Aug 2017 10:40:28 -0400 Subject: [PATCH 048/133] update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 5aee6057cc..61ef5cbc70 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ - 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 Traditional Chinese translation - LOCALIZATION: Update Italian translation - LOCALIZATION: Update Russian translation From c426f683798dacc506a1cf3035de6df9947446d4 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:40:55 +0200 Subject: [PATCH 049/133] C89 buildfix --- libretro-common/audio/audio_mixer.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index fc3bcca370..57567f8b8f 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -735,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; @@ -742,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) @@ -770,15 +774,13 @@ 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; + samplei = *pcm++ * volume; + samplef = (float)((int)samplei + 32768) / 65535.0f; + samplef = samplef * 2.0f - 1.0f; *buffer++ = samplef; } @@ -790,9 +792,9 @@ 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; + samplei = *pcm++ * volume; + samplef = (float)((int)samplei + 32768) / 65535.0f; + samplef = samplef * 2.0f - 1.0f; *buffer++ = samplef; } From 02db71f529a3af447906c8ae85e3e59c1203219a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:55:28 +0200 Subject: [PATCH 050/133] (Localization) Update Dutch language --- intl/msg_hash_nl.h | 108 ++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 54 deletions(-) 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, From a550f834523ff9b2f99a0293b6b6305531cce431 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 16:56:40 +0200 Subject: [PATCH 051/133] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 61ef5cbc70..94f926dda9 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,7 @@ - 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 From 7c1d3991f8f7848df6629d75084b147497be6d53 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 17:12:57 +0200 Subject: [PATCH 052/133] Some C89 buildfixes --- menu/drivers/xmb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index af28bf63e5..f92070b229 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1641,10 +1641,9 @@ static void xmb_list_switch(xmb_handle_t *xmb) xmb_list_switch_old(xmb, xmb->selection_buf_old, dir, xmb->selection_ptr_old); - // Check if we are to have horizontal animations. - if (settings->bools.menu_horizontal_animation) { + /* 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(), @@ -3831,8 +3830,9 @@ static void xmb_list_cache(void *data, enum menu_list_type type, unsigned action if (!xmb) return; - // Check whether to enable the horizontal animation. - if (settings->bools.menu_horizontal_animation) { + /* 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); } From ab936adf1cf61701484b62c60f33ed670cba028c Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 17:08:29 +0200 Subject: [PATCH 053/133] Some C89 buildfixes --- cheevos/cheevos.c | 45 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 0d3b7ba0f9..e5257d9ad8 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -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); } @@ -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; } } } From 86dbcaf563c87da2145149f1b3660533e0469bc3 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 17:09:30 +0200 Subject: [PATCH 054/133] C89 buildfix --- input/input_remapping.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/input/input_remapping.c b/input/input_remapping.c index 8dca0eb38e..bb5ffa6969 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -50,9 +50,6 @@ bool input_remapping_load_file(void *data, const char *path) for (i = 0; i < MAX_USERS; i++) { - old_analog_dpad_mode[i] = settings->uints.input_analog_dpad_mode[i]; - old_libretro_device[i] = settings->uints.input_libretro_device[i]; - char buf[64]; char key_ident[RARCH_FIRST_CUSTOM_BIND + 4][128] = {{0}}; char key_strings[RARCH_FIRST_CUSTOM_BIND + 4][128] = @@ -61,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++) From af477ff3177362c0ada64bdf1311fa95808c6b4e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 17:11:13 +0200 Subject: [PATCH 055/133] C89 buildfix --- tasks/task_netplay_find_content.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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)); From 0afb629c819ec7514ddca5c53863720a75e0f8ff Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 6 Aug 2017 23:19:11 +0200 Subject: [PATCH 056/133] Buildfix --- Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 56733c6f189073d01dd256172bc184aa81ea7a3a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 7 Aug 2017 00:14:37 +0200 Subject: [PATCH 057/133] (xmb) deep list copy - Use malloc instead of calloc --- menu/drivers/xmb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index f92070b229..004a6d564e 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -3804,14 +3804,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); } From 2e7b4242f710eab90b34095c3374e445c5831d17 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 7 Aug 2017 01:48:03 +0200 Subject: [PATCH 058/133] Cleanup --- input/drivers_joypad/gx_joypad.c | 1 + 1 file changed, 1 insertion(+) 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; } From bf72dafe5c005f70d1d5e4074f78ed1ec5f68317 Mon Sep 17 00:00:00 2001 From: bparker06 Date: Sun, 6 Aug 2017 20:17:00 -0400 Subject: [PATCH 059/133] ps3: use python2 for pkg.py script --- tools/ps3/ps3py/pkg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 5d2ab5bf8297cfbdaba0f91d3a17d64f63fcbb23 Mon Sep 17 00:00:00 2001 From: bparker06 Date: Sun, 6 Aug 2017 20:45:13 -0400 Subject: [PATCH 060/133] ps3: copy data folder to dist-cores when ran --- dist-scripts/dist-cores.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dist-scripts/dist-cores.sh b/dist-scripts/dist-cores.sh index 360eb879b6..4f7acf9b0d 100755 --- a/dist-scripts/dist-cores.sh +++ b/dist-scripts/dist-cores.sh @@ -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. From 7b09cd34dbcf4571f1716c91b1e92372de566f66 Mon Sep 17 00:00:00 2001 From: radius Date: Sun, 6 Aug 2017 19:55:44 -0500 Subject: [PATCH 061/133] fix #5257 --- command.c | 3 ++- input/input_remapping.c | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/command.c b/command.c index 981100b122..878a24f211 100644 --- a/command.c +++ b/command.c @@ -1291,7 +1291,8 @@ static void command_event_restore_default_shader_preset(void) static void command_event_restore_remaps(void) { - input_remapping_set_defaults(); + if (rarch_ctl(RARCH_CTL_IS_REMAPS_GAME_ACTIVE, NULL)) + input_remapping_set_defaults(); } static bool command_event_save_auto_state(void) diff --git a/input/input_remapping.c b/input/input_remapping.c index bb5ffa6969..4f1924a3e3 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -213,7 +213,10 @@ void input_remapping_set_defaults(void) } for (j = 0; j < 4; j++) settings->uints.input_remap_ids[i][RARCH_FIRST_CUSTOM_BIND + j] = j; - settings->uints.input_analog_dpad_mode[i] = old_analog_dpad_mode[i]; - settings->uints.input_libretro_device[i] = old_libretro_device[i]; + + 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]; } } From cfa0d74df95ba95d2acd12c27f8e3950e2038679 Mon Sep 17 00:00:00 2001 From: radius Date: Sun, 6 Aug 2017 22:37:29 -0500 Subject: [PATCH 062/133] fix saving the libretro device in overrides --- configuration.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configuration.c b/configuration.c index 4b02f41fcd..5bebae629e 100644 --- a/configuration.c +++ b/configuration.c @@ -3785,7 +3785,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]); From 09922f5ee7bbb962e48f62ead83ae4a4964baae5 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 7 Aug 2017 11:18:38 -0400 Subject: [PATCH 063/133] msvc2005: use non-unicode stb font driver --- gfx/font_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/font_driver.c b/gfx/font_driver.c index 277a1b2c22..d1b127d10b 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) && _MSC_VER > 1400 &stb_unicode_font_renderer, #else &stb_font_renderer, From 2e1ad9684a371db94260c1167c37bf3e130fc33f Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 7 Aug 2017 11:23:05 -0400 Subject: [PATCH 064/133] ps3: build pkgcrypt.dll and copy it to ps3py folder before running pkg.py --- dist-scripts/dist-cores.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dist-scripts/dist-cores.sh b/dist-scripts/dist-cores.sh index 4f7acf9b0d..3331549d84 100755 --- a/dist-scripts/dist-cores.sh +++ b/dist-scripts/dist-cores.sh @@ -420,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 From 6359fe44af5b04b62cd9d05e5e638994a4808bb6 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Mon, 7 Aug 2017 11:28:35 -0400 Subject: [PATCH 065/133] forgot about mingw not defining _MSC_VER --- gfx/font_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/font_driver.c b/gfx/font_driver.c index d1b127d10b..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) && _MSC_VER > 1400 +#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, From c7615fdf00d676d4e23541c3d81671e5ec62b937 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 7 Aug 2017 18:05:43 +0200 Subject: [PATCH 066/133] Add RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT --- dynamic.c | 18 ++++++++++++++++-- dynamic.h | 2 ++ gfx/drivers/gl.c | 4 ++++ gfx/video_driver.c | 8 ++++++++ libretro-common/include/libretro.h | 12 ++++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/dynamic.c b/dynamic.c index 17d67ad17f..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); @@ -1634,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/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/video_driver.c b/gfx/video_driver.c index d420786bb7..bc6941349e 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 @@ -2463,6 +2465,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 +2487,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/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, From 7649164f5119b373a76b5ca860d775c9c1ab07d9 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 7 Aug 2017 19:11:20 +0200 Subject: [PATCH 067/133] Update CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 94f926dda9..7b32b06307 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,7 @@ - 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 From 08118cb4450766d3d546fe2d258df14cf6b6e473 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Mon, 7 Aug 2017 19:16:09 +0200 Subject: [PATCH 068/133] Bump up to 1.6.4 --- CHANGES.md | 4 +++- Makefile.ps3 | 2 +- Makefile.psl1ght | 2 +- dist-scripts/dist-cores.sh | 2 +- pkg/android/phoenix/AndroidManifest.xml | 4 ++-- pkg/qnx/bar-descriptor.xml | 2 +- pkg/wii/meta.xml | 2 +- pkg/wiiu/meta.xml | 4 ++-- version.h | 2 +- 9 files changed, 13 insertions(+), 11 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7b32b06307..6c0de5561d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,6 @@ -# 1.6.4 (future) +# 1.6.5 (future) + +# 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 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.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/dist-scripts/dist-cores.sh b/dist-scripts/dist-cores.sh index 3331549d84..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 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/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/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 From 10492c1ee7ce7ab6c6c97a5eab5d00e83cfb5a87 Mon Sep 17 00:00:00 2001 From: not6 Date: Mon, 7 Aug 2017 23:25:05 +0200 Subject: [PATCH 069/133] Update imports.h add additional imports (semaphore) --- wiiu/system/imports.h | 6 ++++++ 1 file changed, 6 insertions(+) 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); From c882e64653bf78f45ce607c22c5c9e6700a87534 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Mon, 7 Aug 2017 21:59:05 -0500 Subject: [PATCH 070/133] Added button press lightup on overlay. input_overlay_add_inputs added, still need to implement dpad and analog visuals on overlay. Also still needs to be restructured so input_overlay_post_poll is only called once. --- input/input_driver.c | 12 ++++++++++- input/input_overlay.c | 49 ++++++++++++++++++++++++++++++++++++++++--- input/input_overlay.h | 10 +++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/input/input_driver.c b/input/input_driver.c index 68e2f4a9a1..72e18e7523 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -413,12 +413,22 @@ void input_poll(void) return; #ifdef HAVE_OVERLAY - if (overlay_ptr && input_overlay_is_alive(overlay_ptr)) + if (overlay_ptr && input_overlay_is_alive(overlay_ptr)){ input_poll_overlay( overlay_ptr, settings->floats.input_overlay_opacity, settings->uints.input_analog_dpad_mode[0], input_driver_axis_threshold); + + rarch_joypad_info_t joypad_info; + //TODO: Make this work for an arbitrary joypad, set up in the settings + joypad_info.axis_threshold = input_driver_axis_threshold; + joypad_info.joy_idx = settings->uints.input_joypad_map[0]; + joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; + input_overlay_add_inputs(overlay_ptr, &joypad_info, libretro_input_binds, 0, + RETRO_DEVICE_JOYPAD, settings->uints.input_analog_dpad_mode[0]); + + } #endif #ifdef HAVE_COMMAND diff --git a/input/input_overlay.c b/input/input_overlay.c index 5cb48e6c50..b287c27e78 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) @@ -573,6 +572,7 @@ 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; input_overlay_state_t *ol_state = &ol->overlay_state; @@ -702,7 +702,7 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad default: break; } - + if (polled) input_overlay_post_poll(ol, opacity); else @@ -746,3 +746,46 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret, } } +void input_overlay_add_inputs(input_overlay_t *ol, rarch_joypad_info_t *joy_info, const struct retro_keybind **keybinds, + unsigned port, unsigned device, unsigned analog_dpad_mode) +{ + int i; + uint64_t mask; + int id; + //Only do joypad stuff for now + if(device == RETRO_DEVICE_JOYPAD){ + input_overlay_state_t *ol_state = &ol->overlay_state; + for(i = 0; i < ol->active->size; i++) + { + overlay_desc_t *desc = &(ol->active->descs[i]); + switch(desc->type) + { + case OVERLAY_TYPE_BUTTONS: + //Get the button ID + mask = desc->key_mask; + id = RETRO_DEVICE_ID_JOYPAD_B-1; + while(mask > 0){ + id+=1; + mask = mask >> 1; + } + if(current_input->input_state(current_input_data, *joy_info, + keybinds, + port, device, joy_info->joy_idx, id)){ + RARCH_LOG_OUTPUT("pressed button %d\n", id); + desc->updated = true; + } + break; + case OVERLAY_TYPE_ANALOG_LEFT: + break; + case OVERLAY_TYPE_ANALOG_RIGHT: + break; + case OVERLAY_TYPE_KEYBOARD: + break; + default: + break; + } + } + } + settings_t *settings = config_get_ptr(); + input_overlay_post_poll(ol, settings->floats.input_overlay_opacity); +} diff --git a/input/input_overlay.h b/input/input_overlay.h index 93f3c83e91..f16ea9a603 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 @@ -242,6 +244,14 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad void input_state_overlay(input_overlay_t *ol, int16_t *ret, unsigned port, unsigned device, unsigned idx, unsigned id); +/** + * input_overlay_add_inputs: + * @ol : pointer to overlay + * + * Adds inputs from current_input to the overlay, so it's displayed + */ +void input_overlay_add_inputs(input_overlay_t *ol, rarch_joypad_info_t *joy_info, const struct retro_keybind **keybinds, + unsigned port, unsigned device, unsigned analog_dpad_mode); bool input_overlay_key_pressed(input_overlay_t *ol, int key); From 3d4e36455d110d467dce7f46fc5e31dcc17a4898 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Mon, 7 Aug 2017 22:22:48 -0500 Subject: [PATCH 071/133] use input_state instead of current_input->input_state. --- input/input_overlay.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/input/input_overlay.c b/input/input_overlay.c index b287c27e78..806c738d44 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -768,10 +768,7 @@ void input_overlay_add_inputs(input_overlay_t *ol, rarch_joypad_info_t *joy_info id+=1; mask = mask >> 1; } - if(current_input->input_state(current_input_data, *joy_info, - keybinds, - port, device, joy_info->joy_idx, id)){ - RARCH_LOG_OUTPUT("pressed button %d\n", id); + if(input_state(port, device, 0, id)){ desc->updated = true; } break; From 4c31d419202fdd0f6e355cacdf4c3773f1de8943 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 02:31:26 -0500 Subject: [PATCH 072/133] Moved input_overlay_add_inputs call out of input_driver.c, shortened arguments. --- input/input_driver.c | 11 ++----- input/input_overlay.c | 71 +++++++++++++++++++++++-------------------- input/input_overlay.h | 6 ++-- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/input/input_driver.c b/input/input_driver.c index 72e18e7523..3e2e8b5a61 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -419,15 +419,10 @@ void input_poll(void) settings->floats.input_overlay_opacity, settings->uints.input_analog_dpad_mode[0], input_driver_axis_threshold); - - rarch_joypad_info_t joypad_info; //TODO: Make this work for an arbitrary joypad, set up in the settings - joypad_info.axis_threshold = input_driver_axis_threshold; - joypad_info.joy_idx = settings->uints.input_joypad_map[0]; - joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx]; - input_overlay_add_inputs(overlay_ptr, &joypad_info, libretro_input_binds, 0, - RETRO_DEVICE_JOYPAD, settings->uints.input_analog_dpad_mode[0]); - + /*input_overlay_add_inputs(overlay_ptr, 0, + settings->uints.input_analog_dpad_mode[0]); + */ } #endif diff --git a/input/input_overlay.c b/input/input_overlay.c index 806c738d44..637e30a4f1 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -575,6 +575,7 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad 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 +704,8 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad break; } - if (polled) + button_pressed = input_overlay_add_inputs(ol, 0, analog_dpad_mode); + if (button_pressed || polled) input_overlay_post_poll(ol, opacity); else input_overlay_poll_clear(ol, opacity); @@ -746,43 +748,46 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret, } } -void input_overlay_add_inputs(input_overlay_t *ol, rarch_joypad_info_t *joy_info, const struct retro_keybind **keybinds, - unsigned port, unsigned device, unsigned analog_dpad_mode) +bool input_overlay_add_inputs(input_overlay_t *ol, + unsigned port, unsigned analog_dpad_mode) { int i; uint64_t mask; int id; - //Only do joypad stuff for now - if(device == RETRO_DEVICE_JOYPAD){ - input_overlay_state_t *ol_state = &ol->overlay_state; - for(i = 0; i < ol->active->size; i++) + bool 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) { - overlay_desc_t *desc = &(ol->active->descs[i]); - switch(desc->type) - { - case OVERLAY_TYPE_BUTTONS: - //Get the button ID - mask = desc->key_mask; - id = RETRO_DEVICE_ID_JOYPAD_B-1; - while(mask > 0){ - id+=1; - mask = mask >> 1; - } - if(input_state(port, device, 0, id)){ - desc->updated = true; - } - break; - case OVERLAY_TYPE_ANALOG_LEFT: - break; - case OVERLAY_TYPE_ANALOG_RIGHT: - break; - case OVERLAY_TYPE_KEYBOARD: - break; - default: - break; - } + case OVERLAY_TYPE_BUTTONS: + //Get the button ID + mask = desc->key_mask; + id = RETRO_DEVICE_ID_JOYPAD_B-1; + while(mask > 0){ + id+=1; + mask = mask >> 1; + } + //light up the button if pressed + if(input_state(port, RETRO_DEVICE_JOYPAD, 0, id)){ + desc->updated = true; + button_pressed = true; + } + break; + case OVERLAY_TYPE_ANALOG_LEFT: + case OVERLAY_TYPE_ANALOG_RIGHT: + break; + case OVERLAY_TYPE_KEYBOARD: + break; + default: + break; } } - settings_t *settings = config_get_ptr(); - input_overlay_post_poll(ol, settings->floats.input_overlay_opacity); + + return button_pressed; } diff --git a/input/input_overlay.h b/input/input_overlay.h index f16ea9a603..96fe4f9ef4 100644 --- a/input/input_overlay.h +++ b/input/input_overlay.h @@ -248,10 +248,10 @@ void input_state_overlay(input_overlay_t *ol, * input_overlay_add_inputs: * @ol : pointer to overlay * - * Adds inputs from current_input to the overlay, so it's displayed + * Adds inputs from current_input to the overlay, so it's displayed + * returns true if an input that is pressed will change the overlay */ -void input_overlay_add_inputs(input_overlay_t *ol, rarch_joypad_info_t *joy_info, const struct retro_keybind **keybinds, - unsigned port, unsigned device, unsigned analog_dpad_mode); +bool input_overlay_add_inputs(input_overlay_t *ol, unsigned port, unsigned analog_dpad_mode); bool input_overlay_key_pressed(input_overlay_t *ol, int key); From 0df4186191d729f7991fc292483610faa347525e Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 02:48:46 -0500 Subject: [PATCH 073/133] reduce scope of input_overlay_add_inputs to file. --- input/input_overlay.c | 13 +++++++++++-- input/input_overlay.h | 8 -------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/input/input_overlay.c b/input/input_overlay.c index 637e30a4f1..ac3f5d4a0a 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -68,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. @@ -747,8 +749,15 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret, break; } } - -bool input_overlay_add_inputs(input_overlay_t *ol, +/** + * 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) { int i; diff --git a/input/input_overlay.h b/input/input_overlay.h index 96fe4f9ef4..af4305702a 100644 --- a/input/input_overlay.h +++ b/input/input_overlay.h @@ -244,14 +244,6 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad void input_state_overlay(input_overlay_t *ol, int16_t *ret, unsigned port, unsigned device, unsigned idx, unsigned id); -/** - * input_overlay_add_inputs: - * @ol : pointer to overlay - * - * Adds inputs from current_input to the overlay, so it's displayed - * returns true if an input that is pressed will change the overlay - */ -bool input_overlay_add_inputs(input_overlay_t *ol, unsigned port, unsigned analog_dpad_mode); bool input_overlay_key_pressed(input_overlay_t *ol, int key); From cc06b8b62e7469b698d23b422bef3a73e576c9e3 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 05:10:44 -0500 Subject: [PATCH 074/133] Added analog overlay support to input_overlay_add_inputs. --- input/input_overlay.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/input/input_overlay.c b/input/input_overlay.c index ac3f5d4a0a..37b84cc966 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -790,6 +790,22 @@ static bool input_overlay_add_inputs(input_overlay_t *ol, 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; + + button_pressed = true; + } break; case OVERLAY_TYPE_KEYBOARD: break; From 5a85c531741afeaca479bed40e2b152f09f1f572 Mon Sep 17 00:00:00 2001 From: Romain Tisserand Date: Tue, 8 Aug 2017 12:19:24 +0200 Subject: [PATCH 075/133] Fix MOD support not mixing core provided audio stream --- libretro-common/audio/audio_mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libretro-common/audio/audio_mixer.c b/libretro-common/audio/audio_mixer.c index 57567f8b8f..f9a1a226bc 100644 --- a/libretro-common/audio/audio_mixer.c +++ b/libretro-common/audio/audio_mixer.c @@ -781,7 +781,7 @@ again: samplei = *pcm++ * volume; samplef = (float)((int)samplei + 32768) / 65535.0f; samplef = samplef * 2.0f - 1.0f; - *buffer++ = samplef; + *buffer++ += samplef; } buf_free -= voice->types.mod.samples; @@ -795,7 +795,7 @@ again: samplei = *pcm++ * volume; samplef = (float)((int)samplei + 32768) / 65535.0f; samplef = samplef * 2.0f - 1.0f; - *buffer++ = samplef; + *buffer++ += samplef; } voice->types.mod.position += buf_free; From 23b2e4488ae1f9e4e788eaf5ac33a25e75f78327 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 05:32:34 -0500 Subject: [PATCH 076/133] Add keyboard overlay support to input_overlay_add_inputs. --- input/input_overlay.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/input/input_overlay.c b/input/input_overlay.c index 37b84cc966..9285cbb9d0 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -784,8 +784,8 @@ static bool input_overlay_add_inputs(input_overlay_t *ol, } //light up the button if pressed if(input_state(port, RETRO_DEVICE_JOYPAD, 0, id)){ - desc->updated = true; button_pressed = true; + desc->updated = true; } break; case OVERLAY_TYPE_ANALOG_LEFT: @@ -803,11 +803,19 @@ static bool input_overlay_add_inputs(input_overlay_t *ol, desc->delta_x = dx; desc->delta_y = dy; - - button_pressed = true; + /*Maybe use some option here instead orf 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; From 4ed715d0f391fc729ffb40126de3618645ee84a6 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 05:39:18 -0500 Subject: [PATCH 077/133] Remove commented code in input_driver.c --- input/input_driver.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/input/input_driver.c b/input/input_driver.c index 3e2e8b5a61..68e2f4a9a1 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -413,17 +413,12 @@ void input_poll(void) return; #ifdef HAVE_OVERLAY - if (overlay_ptr && input_overlay_is_alive(overlay_ptr)){ + if (overlay_ptr && input_overlay_is_alive(overlay_ptr)) input_poll_overlay( overlay_ptr, settings->floats.input_overlay_opacity, settings->uints.input_analog_dpad_mode[0], input_driver_axis_threshold); - //TODO: Make this work for an arbitrary joypad, set up in the settings - /*input_overlay_add_inputs(overlay_ptr, 0, - settings->uints.input_analog_dpad_mode[0]); - */ - } #endif #ifdef HAVE_COMMAND From 6a36453f2059b12e5e9b0bc90a80ab9c1f037a0f Mon Sep 17 00:00:00 2001 From: ensra Date: Tue, 8 Aug 2017 12:21:48 +0100 Subject: [PATCH 078/133] Cast ctype args to unsigned char --- cheevos/cheevos.c | 12 ++++++------ libretro-common/formats/json/jsonsax.c | 10 +++++----- libretro-common/string/stdstring.c | 14 +++++++------- menu/cbs/menu_cbs_ok.c | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index e5257d9ad8..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; @@ -2072,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 == '~') { 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/string/stdstring.c b/libretro-common/string/stdstring.c index 88f0ed92fc..88a436f128 100644 --- a/libretro-common/string/stdstring.c +++ b/libretro-common/string/stdstring.c @@ -30,7 +30,7 @@ char *string_to_upper(char *s) { char *cs = (char *)s; for ( ; *cs != '\0'; cs++) - *cs = toupper(*cs); + *cs = toupper((unsigned char)*cs); return s; } @@ -38,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; } @@ -48,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; } @@ -108,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) @@ -127,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; diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index b594cfb7f0..1da5432123 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -860,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'; From f0606d60d2568211d96caef8a1955d0f32216713 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 06:50:39 -0500 Subject: [PATCH 079/133] Add option and menu setting for viewing inputs on overlay. --- configuration.c | 1 + configuration.h | 1 + input/input_overlay.c | 8 ++++---- intl/msg_hash_lbl.h | 2 ++ intl/msg_hash_us.c | 5 +++++ intl/msg_hash_us.h | 2 ++ menu/menu_displaylist.c | 3 +++ menu/menu_setting.c | 16 ++++++++++++++++ msg_hash.h | 1 + 9 files changed, 35 insertions(+), 4 deletions(-) diff --git a/configuration.c b/configuration.c index 5bebae629e..4ec67a48c5 100644 --- a/configuration.c +++ b/configuration.c @@ -1226,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 diff --git a/configuration.h b/configuration.h index f5dddca28a..4942464c76 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; diff --git a/input/input_overlay.c b/input/input_overlay.c index 9285cbb9d0..ae656751dc 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -705,8 +705,9 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad default: break; } - - button_pressed = input_overlay_add_inputs(ol, 0, analog_dpad_mode); + if(settings->bools.input_overlay_show_physical_inputs){ + button_pressed = input_overlay_add_inputs(ol, 0, analog_dpad_mode); + } if (button_pressed || polled) input_overlay_post_poll(ol, opacity); else @@ -803,7 +804,7 @@ static bool input_overlay_add_inputs(input_overlay_t *ol, desc->delta_x = dx; desc->delta_y = dy; - /*Maybe use some option here instead orf 0, only display + /*Maybe use some option here instead of 0, only display changes greater than some magnitude. */ if((dx*dx) > 0 || (dy*dy) > 0) @@ -815,7 +816,6 @@ static bool input_overlay_add_inputs(input_overlay_t *ol, desc->updated = true; button_pressed = true; } - break; default: break; diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 8b25495454..9305c1b051 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -479,6 +479,8 @@ 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_PLAYER_ANALOG_DPAD_MODE, "input_player%u_analog_dpad_mode") MSG_HASH(MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR, diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 45f4d19841..52ad99010b 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -572,6 +572,11 @@ 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 controller button presses on \n" + "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 04e4a5ba52..74e7f3f9c0 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -827,6 +827,8 @@ 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_POLL_TYPE_BEHAVIOR, "Poll Type Behavior") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 5e5538b6c4..ced6c3b1fa 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -5007,6 +5007,9 @@ 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_OVERLAY_PRESET, PARSE_ONLY_PATH, false); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index cbeaf4012d..7664b20c6f 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -4891,6 +4891,22 @@ 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_PATH( list, list_info, settings->paths.path_overlay, diff --git a/msg_hash.h b/msg_hash.h index de83221198..044d5a48e6 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -598,6 +598,7 @@ 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_KEYBOARD_GAMEPAD_MAPPING_TYPE), MENU_LABEL(INPUT_SMALL_KEYBOARD_ENABLE), MENU_LABEL(INPUT_TOUCH_ENABLE), From 8e69a348e6c7e2d89ec95ebac2182bb4f6616064 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 07:49:02 -0500 Subject: [PATCH 080/133] Add support for buttons that are multiple inputs. --- input/input_overlay.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/input/input_overlay.c b/input/input_overlay.c index ae656751dc..a364c1629a 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -765,7 +765,7 @@ static bool input_overlay_add_inputs(input_overlay_t *ol, uint64_t mask; int id; bool button_pressed = false; - + bool current_button_pressed; input_overlay_state_t *ol_state = &ol->overlay_state; if(!ol_state) return false; @@ -776,18 +776,31 @@ static bool input_overlay_add_inputs(input_overlay_t *ol, switch(desc->type) { case OVERLAY_TYPE_BUTTONS: - //Get the button ID mask = desc->key_mask; - id = RETRO_DEVICE_ID_JOYPAD_B-1; - while(mask > 0){ - id+=1; - mask = mask >> 1; - } - //light up the button if pressed - if(input_state(port, RETRO_DEVICE_JOYPAD, 0, id)){ - button_pressed = true; - desc->updated = true; + 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: From c07380293e99281fe2e15c6ccaa2f9ae676bd881 Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 09:05:03 -0500 Subject: [PATCH 081/133] Added sublabel to Show Inputs On Overlay --- intl/msg_hash_us.c | 2 +- intl/msg_hash_us.h | 2 ++ menu/cbs/menu_cbs_sublabel.c | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 52ad99010b..369187449f 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -574,7 +574,7 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) { break; case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_PHYSICAL_INPUTS: snprintf(s, len, - "Show controller button presses on \n" + "Show keyboard/controller button presses on \n" "the onscreen overlay."); break; case MENU_ENUM_LABEL_OVERLAY_PRESET: diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 74e7f3f9c0..8498fc8db2 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -2514,6 +2514,8 @@ 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_CONTENT_COLLECTION_LIST, "Scanned content will appear here." diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index cde6bd4a4c..5e067b8e41 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -225,6 +225,7 @@ 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_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) @@ -949,6 +950,9 @@ 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_VIDEO_FONT_SIZE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_font_size); break; From c5b36320df47e154fcc9e13387391dbaf0a1ee5b Mon Sep 17 00:00:00 2001 From: denu8thell Date: Tue, 8 Aug 2017 09:56:27 -0500 Subject: [PATCH 082/133] Added option to change controller port to listen to for showing overlay input. --- configuration.c | 1 + configuration.h | 2 ++ input/input_overlay.c | 2 +- intl/msg_hash_lbl.h | 2 ++ intl/msg_hash_us.c | 5 +++++ intl/msg_hash_us.h | 4 ++++ menu/cbs/menu_cbs_sublabel.c | 4 ++++ menu/menu_displaylist.c | 3 +++ menu/menu_setting.c | 14 +++++++++++++- msg_hash.h | 1 + 10 files changed, 36 insertions(+), 2 deletions(-) diff --git a/configuration.c b/configuration.c index 4ec67a48c5..62bb385401 100644 --- a/configuration.c +++ b/configuration.c @@ -1374,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; diff --git a/configuration.h b/configuration.h index 4942464c76..9018d965dd 100644 --- a/configuration.h +++ b/configuration.h @@ -329,6 +329,8 @@ typedef struct settings unsigned camera_width; unsigned camera_height; + + unsigned input_overlay_show_physical_inputs_port; } uints; struct diff --git a/input/input_overlay.c b/input/input_overlay.c index a364c1629a..f67a8432ac 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -706,7 +706,7 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad break; } if(settings->bools.input_overlay_show_physical_inputs){ - button_pressed = input_overlay_add_inputs(ol, 0, analog_dpad_mode); + 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); diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 9305c1b051..bb670bbbf1 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -481,6 +481,8 @@ 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, diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 369187449f..61b32fe093 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -577,6 +577,11 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t 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 8498fc8db2..b647b2a679 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -829,6 +829,8 @@ 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, @@ -2516,6 +2518,8 @@ 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/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 5e067b8e41..6cc0bd459a 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -226,6 +226,7 @@ default_sublabel_macro(action_bind_sublabel_sort_savestates_enable, MENU_ 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 +954,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, 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/menu_displaylist.c b/menu/menu_displaylist.c index ced6c3b1fa..f96521cac2 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -5010,6 +5010,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) 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); diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 7664b20c6f..1f9f377b39 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -4906,7 +4906,19 @@ static bool setting_append_list( 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, diff --git a/msg_hash.h b/msg_hash.h index 044d5a48e6..4b37e9923a 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -599,6 +599,7 @@ enum msg_hash_enums 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), From 86a107afc909753fbf4b9fc051f02a107eab1187 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 8 Aug 2017 17:42:28 +0200 Subject: [PATCH 083/133] msg_hash_it.h - fix build --- intl/msg_hash_it.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index b987370092..d709b434ab 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -2151,7 +2151,7 @@ MSG_HASH( "Check if all the required firmware is present before attempting to load content." ) 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".") + "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." From 383d810fd49b4104a079b6abecbd1183c86aad01 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 8 Aug 2017 17:45:27 +0200 Subject: [PATCH 084/133] Update CHANGES.md --- CHANGES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 6c0de5561d..85e5e4267c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,8 @@ # 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 From e979eece1c02e250252fbb864dcd7ac3ca70627d Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 8 Aug 2017 18:45:56 +0200 Subject: [PATCH 085/133] Updates --- .../audio/dsp_filters/Crystalizer.dsp | 4 + .../audio/dsp_filters/crystalizer.c | 93 + libretro-common/formats/libchdr/bitstream.c | 119 + libretro-common/formats/libchdr/bitstream.h | 42 + libretro-common/formats/libchdr/cdrom.c | 419 +++ libretro-common/formats/libchdr/cdrom.h | 108 + libretro-common/formats/libchdr/chd.c | 2453 +++++++++++++++++ libretro-common/formats/libchdr/chd.h | 399 +++ libretro-common/formats/libchdr/coretypes.h | 36 + libretro-common/formats/libchdr/flac.c | 331 +++ libretro-common/formats/libchdr/flac.h | 50 + libretro-common/formats/libchdr/huffman.c | 528 ++++ libretro-common/formats/libchdr/huffman.h | 87 + libretro-common/include/encodings/win32.h | 63 + 14 files changed, 4732 insertions(+) create mode 100644 libretro-common/audio/dsp_filters/Crystalizer.dsp create mode 100644 libretro-common/audio/dsp_filters/crystalizer.c create mode 100644 libretro-common/formats/libchdr/bitstream.c create mode 100644 libretro-common/formats/libchdr/bitstream.h create mode 100644 libretro-common/formats/libchdr/cdrom.c create mode 100644 libretro-common/formats/libchdr/cdrom.h create mode 100644 libretro-common/formats/libchdr/chd.c create mode 100644 libretro-common/formats/libchdr/chd.h create mode 100644 libretro-common/formats/libchdr/coretypes.h create mode 100644 libretro-common/formats/libchdr/flac.c create mode 100644 libretro-common/formats/libchdr/flac.h create mode 100644 libretro-common/formats/libchdr/huffman.c create mode 100644 libretro-common/formats/libchdr/huffman.h create mode 100644 libretro-common/include/encodings/win32.h 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/formats/libchdr/bitstream.c b/libretro-common/formats/libchdr/bitstream.c new file mode 100644 index 0000000000..3f78731ed8 --- /dev/null +++ b/libretro-common/formats/libchdr/bitstream.c @@ -0,0 +1,119 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + bitstream.c + + Helper classes for reading/writing at the bit level. + +***************************************************************************/ + +#include "bitstream.h" +#include +#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..98be2e47b6 --- /dev/null +++ b/libretro-common/formats/libchdr/cdrom.c @@ -0,0 +1,419 @@ +// 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 + +#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 INLINE 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 From 3c758609b5a0cf2704c90ff900803d0354ec742f Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 8 Aug 2017 18:51:01 +0200 Subject: [PATCH 086/133] Updates --- libretro-common/formats/libchdr/bitstream.c | 1 - libretro-common/formats/libchdr/cdrom.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/libretro-common/formats/libchdr/bitstream.c b/libretro-common/formats/libchdr/bitstream.c index 3f78731ed8..735b97f4b1 100644 --- a/libretro-common/formats/libchdr/bitstream.c +++ b/libretro-common/formats/libchdr/bitstream.c @@ -10,7 +10,6 @@ #include "bitstream.h" #include -#include //************************************************************************** // INLINE FUNCTIONS diff --git a/libretro-common/formats/libchdr/cdrom.c b/libretro-common/formats/libchdr/cdrom.c index 98be2e47b6..6c120cbc2a 100644 --- a/libretro-common/formats/libchdr/cdrom.c +++ b/libretro-common/formats/libchdr/cdrom.c @@ -19,8 +19,6 @@ #include #include -#include - #include "cdrom.h" /*************************************************************************** @@ -309,7 +307,7 @@ static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] = // particular to a mode //------------------------------------------------- -static INLINE uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset) +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]; From 3f3b30b5dc2e4f8a0acea7579e02ca03f4d3b412 Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Tue, 8 Aug 2017 19:18:40 +0200 Subject: [PATCH 087/133] Update msg_hash_it.h --- intl/msg_hash_it.h | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 575f329682..b987370092 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -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." @@ -2341,7 +2339,7 @@ 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, +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.") @@ -2349,3 +2347,17 @@ 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.") From ee76e54617a649a1736470cbd4bcf22799d89ce4 Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Tue, 8 Aug 2017 20:49:55 +0200 Subject: [PATCH 088/133] Update msg_hash_it.h --- intl/msg_hash_it.h | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index b987370092..3fd1e3b1a9 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -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, @@ -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, @@ -1685,7 +1685,7 @@ 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, @@ -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." @@ -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, @@ -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, @@ -2273,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") @@ -2285,22 +2285,22 @@ 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 Livello del Volume (dB)" + "Livello del Volume del mixer audio (dB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_MIXER_MUTE, - "Audio Mixer Muto" + "Disattiva Mixer Audio" ) MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MIXER_MUTE, - "Muto/disattiva muto sul mixer audio.") + "Attiva/disattiva Mixer audio.") MSG_HASH(MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, "Visualizza Online Updater") MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SHOW_ONLINE_UPDATER, @@ -2361,3 +2361,22 @@ 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.") + From c0cb042998450c50685886646ebdad8a780a3788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Higor=20Eur=C3=ADpedes?= Date: Tue, 8 Aug 2017 21:05:00 -0300 Subject: [PATCH 089/133] (xmb) Improve responsiveness while browsing horizontally --- menu/drivers/xmb.c | 47 +++++++++---------------------------------- menu/menu_animation.c | 4 ++-- menu/menu_animation.h | 4 ++-- 3 files changed, 14 insertions(+), 41 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 004a6d564e..a97d05ed8c 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1394,7 +1394,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,7 +1402,7 @@ 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) @@ -1435,7 +1435,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 +1501,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); } } @@ -3736,28 +3736,18 @@ static void xmb_list_clear(file_list_t *list) { size_t i; size_t size = list->size; + menu_animation_ctx_tag_t 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); } } @@ -3766,29 +3756,12 @@ 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_t tag = { (uintptr_t)dst }; + + 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 */ } diff --git a/menu/menu_animation.c b/menu/menu_animation.c index 47acd52d29..b6746597b4 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; }; @@ -624,7 +624,7 @@ bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data) unsigned i; menu_animation_ctx_tag_t *tag = (menu_animation_ctx_tag_t*)data; - if (!tag || tag->id == -1) + if (!tag || tag->id == (uintptr_t)-1) return false; for (i = 0; i < anim.size; ++i) diff --git a/menu/menu_animation.h b/menu/menu_animation.h index 49d154d305..c010c3971e 100644 --- a/menu/menu_animation.h +++ b/menu/menu_animation.h @@ -93,7 +93,7 @@ typedef struct menu_animation_ctx_delta typedef struct menu_animation_ctx_tag { - int id; + uintptr_t id; } menu_animation_ctx_tag_t; typedef struct menu_animation_ctx_subject @@ -108,7 +108,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; From 8d358899df509cde33d45d4a1a84aeed39bc4198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Higor=20Eur=C3=ADpedes?= Date: Tue, 8 Aug 2017 22:34:54 -0300 Subject: [PATCH 090/133] (xmb) Fix segfault when entering certain lists --- menu/drivers/xmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index a97d05ed8c..34a5516a9a 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1118,7 +1118,7 @@ static void xmb_selection_pointer_changed( video_driver_get_size(NULL, &height); - tag.id = (int)(uintptr_t)menu_list; + tag.id = (uintptr_t)selection_buf; menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); menu_entries_ctl(MENU_ENTRIES_CTL_SET_START, &num); From 63c0cae3265f88b103818096a4e73b0c57c7ce4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Higor=20Eur=C3=ADpedes?= Date: Tue, 8 Aug 2017 22:37:37 -0300 Subject: [PATCH 091/133] (xmb) Defragment and shrink tween list after updates --- menu/menu_animation.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/menu/menu_animation.c b/menu/menu_animation.c index b6746597b4..bd9cdc0850 100644 --- a/menu/menu_animation.c +++ b/menu/menu_animation.c @@ -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; From 3a5a2d9de6431fac32284a69e62a453cf5c4c980 Mon Sep 17 00:00:00 2001 From: bparker06 Date: Tue, 8 Aug 2017 22:18:27 -0400 Subject: [PATCH 092/133] emscripten: only fire keyup once, and don't wait so long to do so --- pkg/emscripten/embed/embed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) { From ca80f13b2befcd04687ed9c6031deae4c7db4b69 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 02:42:19 +0200 Subject: [PATCH 093/133] Try to be somewhat safer here in case of null pointer derefences --- input/drivers/wiiu_input.c | 2 +- input/input_remapping.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) 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/input_remapping.c b/input/input_remapping.c index 4f1924a3e3..6ca86e7270 100644 --- a/input/input_remapping.c +++ b/input/input_remapping.c @@ -208,8 +208,9 @@ 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; From b943060797ef26671ddf1cf9948c4fd1c0b7200d Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 03:44:03 +0200 Subject: [PATCH 094/133] Add win32_get_video_output_size --- gfx/common/win32_common.cpp | 14 ++++++++++++++ gfx/common/win32_common.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.cpp index 3801f92700..818cf3588e 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.cpp @@ -1053,3 +1053,17 @@ void win32_destroy_window(void) #endif main_window.hwnd = NULL; } + +void win32_get_video_output_size(void *data, + 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..2f92598e8a 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -113,6 +113,9 @@ 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(void *data, + unsigned *width, unsigned *height); + void win32_window_reset(void); void win32_destroy_window(void); From 1ecdbf40500eb1b8b361f15e2c9b20ca1eca2c9e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 03:53:19 +0200 Subject: [PATCH 095/133] Add win32_get_video_output_prev --- gfx/common/win32_common.cpp | 33 ++++++++++++++++++++++++++++++++- gfx/common/win32_common.h | 5 ++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.cpp index 818cf3588e..1492b6cd83 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.cpp @@ -1054,8 +1054,39 @@ void win32_destroy_window(void) main_window.hwnd = NULL; } -void win32_get_video_output_size(void *data, +void win32_get_video_output_prev( unsigned *width, unsigned *height) +{ + DEVMODE dm; + int iModeNum; + 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) + { + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + break; + } + } + + prev_width = dm.dmPelsWidth; + prev_height = dm.dmPelsHeight; + } +} + +void win32_get_video_output_size(unsigned *width, unsigned *height) { DEVMODE dm; memset(&dm, 0, sizeof(dm)); diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index 2f92598e8a..2c8e3d6818 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -113,7 +113,10 @@ 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(void *data, +void win32_get_video_output_size( + unsigned *width, unsigned *height); + +void win32_get_video_output_prev( unsigned *width, unsigned *height); void win32_window_reset(void); From 97de6deb5690c586146ac20b4a8047f44c0b4926 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 04:07:41 +0200 Subject: [PATCH 096/133] Fix logic in win32_get_video_output_next --- gfx/common/win32_common.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.cpp index 1492b6cd83..92e8bdf322 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.cpp @@ -1059,6 +1059,7 @@ void win32_get_video_output_prev( { DEVMODE dm; int iModeNum; + bool found = false; unsigned prev_width = 0; unsigned prev_height = 0; unsigned curr_width = 0; @@ -1075,8 +1076,7 @@ void win32_get_video_output_prev( { if (prev_width != curr_width && prev_height != curr_height) { - *width = dm.dmPelsWidth; - *height = dm.dmPelsHeight; + found = true; break; } } @@ -1084,6 +1084,12 @@ void win32_get_video_output_prev( prev_width = dm.dmPelsWidth; prev_height = dm.dmPelsHeight; } + + if (found) + { + *width = prev_width; + *height = prev_height; + } } void win32_get_video_output_size(unsigned *width, unsigned *height) From cea3cab3f43637940676e402ddce929870a15f07 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 04:09:44 +0200 Subject: [PATCH 097/133] Create win32_get_video_output_next --- gfx/common/win32_common.cpp | 28 ++++++++++++++++++++++++++++ gfx/common/win32_common.h | 3 +++ 2 files changed, 31 insertions(+) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.cpp index 92e8bdf322..fb40c7658c 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.cpp @@ -1092,6 +1092,34 @@ void win32_get_video_output_prev( } } +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; diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index 2c8e3d6818..10c5f91d5a 100644 --- a/gfx/common/win32_common.h +++ b/gfx/common/win32_common.h @@ -119,6 +119,9 @@ void win32_get_video_output_size( 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); From 9272d262693d7441be1799fc35c7c0b992563395 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 04:17:32 +0200 Subject: [PATCH 098/133] Start filling in more resolution functionality for Windows --- gfx/drivers_context/wgl_ctx.cpp | 20 +++++++++++++++++--- menu/cbs/menu_cbs_ok.c | 2 +- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/gfx/drivers_context/wgl_ctx.cpp b/gfx/drivers_context/wgl_ctx.cpp index 9e6ebef484..eb7545b548 100644 --- a/gfx/drivers_context/wgl_ctx.cpp +++ b/gfx/drivers_context/wgl_ctx.cpp @@ -702,6 +702,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 +723,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/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 1da5432123..8168241b55 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -4333,7 +4333,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); From 365cfd22ee2d26f1aed2566944a545ef09ac03ea Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 10:33:36 +0200 Subject: [PATCH 099/133] Don't hide 'Resolution' setting behind compile-time ifdefs anymore --- gfx/video_driver.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/gfx/video_driver.c b/gfx/video_driver.c index bc6941349e..02125f91e1 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -1431,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; @@ -1443,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, From dccc9711d9f547777e59278b0ebc77499fb2eee5 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 10:58:43 +0200 Subject: [PATCH 100/133] Start hooking up more resolution functions - not working properly yet --- gfx/common/win32_common.cpp | 28 ++++++++++++++++++++-------- gfx/drivers_context/wgl_ctx.cpp | 6 ++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.cpp index fb40c7658c..79837dd2ef 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.cpp @@ -30,6 +30,9 @@ #include "../../tasks/tasks_internal.h" #include "../../core_info.h" +static unsigned current_window_width = 0; +static unsigned current_window_height = 0; + #if !defined(_XBOX) #define IDI_ICON 1 @@ -752,8 +755,8 @@ static bool win32_monitor_set_fullscreen(unsigned width, unsigned height, memset(&devmode, 0, sizeof(devmode)); devmode.dmSize = sizeof(DEVMODE); - devmode.dmPelsWidth = width; - devmode.dmPelsHeight = height; + devmode.dmPelsWidth = (current_window_width == 0) ? width : current_window_width; + devmode.dmPelsHeight = (current_window_height == 0) ? height : current_window_height; devmode.dmDisplayFrequency = refresh; devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; @@ -1051,7 +1054,7 @@ void win32_destroy_window(void) #ifndef _XBOX UnregisterClass("RetroArch", GetModuleHandle(NULL)); #endif - main_window.hwnd = NULL; + main_window.hwnd = NULL; } void win32_get_video_output_prev( @@ -1087,8 +1090,10 @@ void win32_get_video_output_prev( if (found) { - *width = prev_width; - *height = prev_height; + *width = prev_width; + *height = prev_height; + current_window_width = prev_width; + current_window_height = prev_height; } } @@ -1110,8 +1115,10 @@ void win32_get_video_output_next( { if (found) { - *width = dm.dmPelsWidth; - *height = dm.dmPelsHeight; + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; + current_window_width = *width; + current_window_height = *height; break; } @@ -1126,7 +1133,12 @@ void win32_get_video_output_size(unsigned *width, unsigned *height) memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) + if (current_window_width != 0 && current_window_height != 0) + { + *width = current_window_width; + *height = current_window_height; + } + else if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) { *width = dm.dmPelsWidth; *height = dm.dmPelsHeight; diff --git a/gfx/drivers_context/wgl_ctx.cpp b/gfx/drivers_context/wgl_ctx.cpp index eb7545b548..28e8edad37 100644 --- a/gfx/drivers_context/wgl_ctx.cpp +++ b/gfx/drivers_context/wgl_ctx.cpp @@ -710,10 +710,16 @@ static void gfx_ctx_wgl_get_video_output_size(void *data, static void gfx_ctx_wgl_get_video_output_prev(void *data) { + unsigned width = 0; + unsigned height = 0; + win32_get_video_output_prev(&width, &height); } static void gfx_ctx_wgl_get_video_output_next(void *data) { + unsigned width = 0; + unsigned height = 0; + win32_get_video_output_next(&width, &height); } const gfx_ctx_driver_t gfx_ctx_wgl = { From 3bac7cc7ef71ae8d1dc4e49c8ac5c5a6e835aed3 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 11:19:27 +0200 Subject: [PATCH 101/133] Revert "Start hooking up more resolution functions - not working properly yet" This reverts commit dccc9711d9f547777e59278b0ebc77499fb2eee5. --- gfx/common/win32_common.cpp | 28 ++++++++-------------------- gfx/drivers_context/wgl_ctx.cpp | 6 ------ 2 files changed, 8 insertions(+), 26 deletions(-) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.cpp index 79837dd2ef..fb40c7658c 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.cpp @@ -30,9 +30,6 @@ #include "../../tasks/tasks_internal.h" #include "../../core_info.h" -static unsigned current_window_width = 0; -static unsigned current_window_height = 0; - #if !defined(_XBOX) #define IDI_ICON 1 @@ -755,8 +752,8 @@ static bool win32_monitor_set_fullscreen(unsigned width, unsigned height, memset(&devmode, 0, sizeof(devmode)); devmode.dmSize = sizeof(DEVMODE); - devmode.dmPelsWidth = (current_window_width == 0) ? width : current_window_width; - devmode.dmPelsHeight = (current_window_height == 0) ? height : current_window_height; + devmode.dmPelsWidth = width; + devmode.dmPelsHeight = height; devmode.dmDisplayFrequency = refresh; devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; @@ -1054,7 +1051,7 @@ void win32_destroy_window(void) #ifndef _XBOX UnregisterClass("RetroArch", GetModuleHandle(NULL)); #endif - main_window.hwnd = NULL; + main_window.hwnd = NULL; } void win32_get_video_output_prev( @@ -1090,10 +1087,8 @@ void win32_get_video_output_prev( if (found) { - *width = prev_width; - *height = prev_height; - current_window_width = prev_width; - current_window_height = prev_height; + *width = prev_width; + *height = prev_height; } } @@ -1115,10 +1110,8 @@ void win32_get_video_output_next( { if (found) { - *width = dm.dmPelsWidth; - *height = dm.dmPelsHeight; - current_window_width = *width; - current_window_height = *height; + *width = dm.dmPelsWidth; + *height = dm.dmPelsHeight; break; } @@ -1133,12 +1126,7 @@ void win32_get_video_output_size(unsigned *width, unsigned *height) memset(&dm, 0, sizeof(dm)); dm.dmSize = sizeof(dm); - if (current_window_width != 0 && current_window_height != 0) - { - *width = current_window_width; - *height = current_window_height; - } - else if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) != 0) { *width = dm.dmPelsWidth; *height = dm.dmPelsHeight; diff --git a/gfx/drivers_context/wgl_ctx.cpp b/gfx/drivers_context/wgl_ctx.cpp index 28e8edad37..eb7545b548 100644 --- a/gfx/drivers_context/wgl_ctx.cpp +++ b/gfx/drivers_context/wgl_ctx.cpp @@ -710,16 +710,10 @@ static void gfx_ctx_wgl_get_video_output_size(void *data, static void gfx_ctx_wgl_get_video_output_prev(void *data) { - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_prev(&width, &height); } static void gfx_ctx_wgl_get_video_output_next(void *data) { - unsigned width = 0; - unsigned height = 0; - win32_get_video_output_next(&width, &height); } const gfx_ctx_driver_t gfx_ctx_wgl = { From 05558697ca2c5b5e0ee89a6186654f72c04cb974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Andr=C3=A9=20Santoni?= Date: Wed, 9 Aug 2017 15:16:15 +0200 Subject: [PATCH 102/133] (Lakka) Fix Online Updater --- menu/drivers/xmb.c | 5 ----- menu/menu_displaylist.c | 28 ++++++++++++++++++++-------- menu/menu_setting.c | 11 ----------- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 34a5516a9a..f18655383e 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -4063,10 +4063,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) @@ -4075,7 +4071,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_displaylist.c b/menu/menu_displaylist.c index f96521cac2..31c6456cd2 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -3178,6 +3178,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(); @@ -3275,6 +3292,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; @@ -4055,7 +4073,7 @@ 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) && !defined(HAVE_LAKKA) +#if defined(HAVE_NETWORKING) settings_t *settings = config_get_ptr(); #endif @@ -4074,7 +4092,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) { @@ -6132,16 +6150,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 1f9f377b39..2ba3d5b399 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -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( From 535dbe0aaaedfbc9efbfd9be975c0d305d11fd67 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 13:28:31 +0200 Subject: [PATCH 103/133] win32_common.cpp - style nits --- gfx/common/win32_common.cpp | 120 +++++++++++++++++++++--------------- 1 file changed, 70 insertions(+), 50 deletions(-) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.cpp index fb40c7658c..c51fc96660 100644 --- a/gfx/common/win32_common.cpp +++ b/gfx/common/win32_common.cpp @@ -184,10 +184,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 +216,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) @@ -236,16 +239,16 @@ void win32_monitor_get_info(void) 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]) @@ -480,14 +483,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; @@ -538,7 +541,8 @@ LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message, 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 +572,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; @@ -585,7 +590,8 @@ LRESULT CALLBACK WndProcGL(HWND hwnd, UINT message, } #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); @@ -670,7 +676,8 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, } #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 +688,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 +746,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 +765,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 +808,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 +857,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. */ @@ -949,10 +957,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 +972,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 +1031,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) @@ -1066,15 +1078,20 @@ void win32_get_video_output_prev( unsigned curr_height = 0; memset(&dm, 0, sizeof(dm)); - dm.dmSize = sizeof(dm); + + dm.dmSize = sizeof(dm); win32_get_video_output_size(&curr_width, &curr_height); - for (iModeNum = 0; EnumDisplaySettings(NULL, iModeNum, &dm) != 0; iModeNum++) + for (iModeNum = 0; + EnumDisplaySettings(NULL, iModeNum, &dm) != 0; + iModeNum++) { - if (dm.dmPelsWidth == curr_width && dm.dmPelsHeight == curr_height) + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) { - if (prev_width != curr_width && prev_height != curr_height) + if ( prev_width != curr_width + && prev_height != curr_height) { found = true; break; @@ -1106,7 +1123,9 @@ void win32_get_video_output_next( win32_get_video_output_size(&curr_width, &curr_height); - for (iModeNum = 0; EnumDisplaySettings(NULL, iModeNum, &dm) != 0; iModeNum++) + for (iModeNum = 0; + EnumDisplaySettings(NULL, iModeNum, &dm) != 0; + iModeNum++) { if (found) { @@ -1115,7 +1134,8 @@ void win32_get_video_output_next( break; } - if (dm.dmPelsWidth == curr_width && dm.dmPelsHeight == curr_height) + if ( dm.dmPelsWidth == curr_width + && dm.dmPelsHeight == curr_height) found = true; } } From c3851d42e62aa5c5d066a23fbd3fcf394da72c1e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 13:39:14 +0200 Subject: [PATCH 104/133] Convert win32_common.cpp to C - gets rid of all the extern "C" references as well. Note to bparker - DragAcceptFiles has a minimum dependency for WinXP, might have to go through a function pointer there or have a compilation-time ifdef --- .../{win32_common.cpp => win32_common.c} | 46 ++++++++----------- gfx/common/win32_common.h | 26 +++++------ griffin/griffin.c | 7 +++ griffin/griffin_cpp.cpp | 2 - 4 files changed, 37 insertions(+), 44 deletions(-) rename gfx/common/{win32_common.cpp => win32_common.c} (97%) diff --git a/gfx/common/win32_common.cpp b/gfx/common/win32_common.c similarity index 97% rename from gfx/common/win32_common.cpp rename to gfx/common/win32_common.c index c51fc96660..5a338b3441 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) @@ -232,7 +221,7 @@ 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); } @@ -270,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 */ @@ -498,7 +487,10 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, return 0; } -extern void ui_window_win32_set_droppable(void *data, bool droppable); +static void win32_set_droppable(ui_window_win32_t *window, bool droppable) +{ + DragAcceptFiles(window->hwnd, droppable); +} #ifdef HAVE_D3D9 LRESULT CALLBACK WndProcD3D(HWND hwnd, UINT message, @@ -536,7 +528,7 @@ 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; } @@ -584,7 +576,7 @@ 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; } @@ -670,7 +662,7 @@ 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; } @@ -895,7 +887,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; } } diff --git a/gfx/common/win32_common.h b/gfx/common/win32_common.h index 10c5f91d5a..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); @@ -143,4 +135,8 @@ LRESULT CALLBACK WndProcGDI(HWND hwnd, UINT message, BOOL IsIconic(HWND hwnd); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/griffin/griffin.c b/griffin/griffin.c index 77570f40f9..23d9421dd9 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -153,6 +153,13 @@ 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 ============================================================ */ diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index 2a5a6c8733..d77594cf55 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -101,8 +101,6 @@ AUDIO 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 From a4a027be6782da3da46dc13be6761b5ab2dcc957 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 13:51:33 +0200 Subject: [PATCH 105/133] Convert wgl_ctx into C - also take care of serious warning --- gfx/drivers_context/{wgl_ctx.cpp => wgl_ctx.c} | 13 ++++++++++--- griffin/griffin.c | 6 ++++++ griffin/griffin_cpp.cpp | 3 --- 3 files changed, 16 insertions(+), 6 deletions(-) rename gfx/drivers_context/{wgl_ctx.cpp => wgl_ctx.c} (98%) diff --git a/gfx/drivers_context/wgl_ctx.cpp b/gfx/drivers_context/wgl_ctx.c similarity index 98% rename from gfx/drivers_context/wgl_ctx.cpp rename to gfx/drivers_context/wgl_ctx.c index eb7545b548..5c0d7b4e49 100644 --- a/gfx/drivers_context/wgl_ctx.cpp +++ b/gfx/drivers_context/wgl_ctx.c @@ -270,14 +270,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 } diff --git a/griffin/griffin.c b/griffin/griffin.c index 23d9421dd9..5f84ebff04 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -165,6 +165,12 @@ 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 +#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 d77594cf55..bfef83a896 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -101,9 +101,6 @@ AUDIO UI COMMON CONTEXT ============================================================ */ #if defined(_WIN32) && !defined(_XBOX) -#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" From 795ae524e959144f86d3487be97d42fb36581f1a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 13:56:47 +0200 Subject: [PATCH 106/133] Convert gdi_ctx.cpp to C --- gfx/drivers_context/{gdi_ctx.cpp => gdi_ctx.c} | 3 ++- griffin/griffin.c | 12 ++++++++++++ griffin/griffin_cpp.cpp | 18 ------------------ 3 files changed, 14 insertions(+), 19 deletions(-) rename gfx/drivers_context/{gdi_ctx.cpp => gdi_ctx.c} (98%) 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/griffin/griffin.c b/griffin/griffin.c index 5f84ebff04..df49afc43a 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -166,9 +166,21 @@ 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__) diff --git a/griffin/griffin_cpp.cpp b/griffin/griffin_cpp.cpp index bfef83a896..53a538109e 100644 --- a/griffin/griffin_cpp.cpp +++ b/griffin/griffin_cpp.cpp @@ -97,24 +97,6 @@ AUDIO #include "../audio/drivers/xaudio.cpp" #endif -/*============================================================ -UI COMMON CONTEXT -============================================================ */ -#if defined(_WIN32) && !defined(_XBOX) - -#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 ============================================================ */ From ee275c85d8b46eb25a70b4c55f3356bfc9c772a4 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 15:51:27 +0200 Subject: [PATCH 107/133] (dinput.c) Cleanups --- input/drivers/dinput.c | 47 +++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/input/drivers/dinput.c b/input/drivers/dinput.c index 4f78febd2f..8ad5115c54 100644 --- a/input/drivers/dinput.c +++ b/input/drivers/dinput.c @@ -109,15 +109,14 @@ bool dinput_init_context(void) CoInitialize(NULL); /* Who said we shouldn't have same call signature in a COM API? <_< */ + context_initialized = (SUCCEEDED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, #ifdef __cplusplus - context_initialized = (SUCCEEDED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, - (void**)&g_dinput_ctx, NULL))); + IID_IDirectInput8, #else - context_initialized = (SUCCEEDED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8, - (void**)&g_dinput_ctx, NULL))); + &IID_IDirectInput8, #endif + (void**)&g_dinput_ctx, NULL))); if (!context_initialized) goto error; @@ -148,30 +147,29 @@ static void *dinput_init(const char *joypad_driver) if (!string_is_empty(joypad_driver)) di->joypad_driver_name = strdup(joypad_driver); + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, #ifdef __cplusplus - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, GUID_SysKeyboard, &di->keyboard, NULL))) + GUID_SysKeyboard, +#else + &GUID_SysKeyboard, +#endif + &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))) - { - RARCH_ERR("[DINPUT]: Failed to create mouse device.\n"); - di->mouse = NULL; - } + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, +#ifdef __cplusplus + GUID_SysMouse, #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))) + &GUID_SysMouse, +#endif + &di->mouse, NULL))) { RARCH_ERR("[DINPUT]: Failed to create mouse device.\n"); di->mouse = NULL; } -#endif if (di->keyboard) { @@ -195,17 +193,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 +591,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; From 4e49155147c3cdedc5776ca8ceaec9d622db670e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 15:54:24 +0200 Subject: [PATCH 108/133] Cleanup --- input/drivers/dinput.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/input/drivers/dinput.c b/input/drivers/dinput.c index 8ad5115c54..c28ca3babb 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,23 +101,20 @@ void dinput_destroy_context(void) bool dinput_init_context(void) { - bool context_initialized = false; if (g_dinput_ctx) return true; CoInitialize(NULL); /* Who said we shouldn't have same call signature in a COM API? <_< */ - context_initialized = (SUCCEEDED(DirectInput8Create( + if (!(SUCCEEDED(DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, #ifdef __cplusplus IID_IDirectInput8, #else &IID_IDirectInput8, #endif - (void**)&g_dinput_ctx, NULL))); - - if (!context_initialized) + (void**)&g_dinput_ctx, NULL)))) goto error; return true; From 2f832d145fd06685d8087fca33306d602c9379c4 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 16:25:23 +0200 Subject: [PATCH 109/133] Make DragAcceptFiles go through function pointer --- frontend/drivers/platform_win32.c | 22 +++++++++++++++++++--- gfx/common/win32_common.c | 5 ++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/frontend/drivers/platform_win32.c b/frontend/drivers/platform_win32.c index 854f651771..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"); diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index 5a338b3441..cfeb717de2 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -487,9 +487,12 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message, return 0; } +extern VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); + static void win32_set_droppable(ui_window_win32_t *window, bool droppable) { - DragAcceptFiles(window->hwnd, droppable); + if (DragAcceptFiles_func != NULL) + DragAcceptFiles_func(window->hwnd, droppable); } #ifdef HAVE_D3D9 From dfd2c45454990ade4c6fd3c6b604185d0fbfa3f4 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 16:32:08 +0200 Subject: [PATCH 110/133] Go through DragAcceptFiles function pointer for ui_win32_window too --- ui/drivers/win32/ui_win32_window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/drivers/win32/ui_win32_window.cpp b/ui/drivers/win32/ui_win32_window.cpp index 8a0d1e981a..f868344fed 100644 --- a/ui/drivers/win32/ui_win32_window.cpp +++ b/ui/drivers/win32/ui_win32_window.cpp @@ -75,11 +75,14 @@ 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) From 5101895cc9b0c49e067b53c8658432d55178f2ae Mon Sep 17 00:00:00 2001 From: twinaphex Date: Wed, 9 Aug 2017 16:53:06 +0200 Subject: [PATCH 111/133] (dinput) Buildfix --- input/drivers/dinput.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/input/drivers/dinput.c b/input/drivers/dinput.c index c28ca3babb..4314ce04f5 100644 --- a/input/drivers/dinput.c +++ b/input/drivers/dinput.c @@ -107,14 +107,17 @@ bool dinput_init_context(void) CoInitialize(NULL); /* Who said we shouldn't have same call signature in a COM API? <_< */ - if (!(SUCCEEDED(DirectInput8Create( - GetModuleHandle(NULL), DIRECTINPUT_VERSION, #ifdef __cplusplus - IID_IDirectInput8, + if (!(SUCCEEDED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, + IID_IDirectInput8, + (void**)&g_dinput_ctx, NULL)))) #else - &IID_IDirectInput8, + if (!(SUCCEEDED(DirectInput8Create( + GetModuleHandle(NULL), DIRECTINPUT_VERSION, + &IID_IDirectInput8, + (void**)&g_dinput_ctx, NULL)))) #endif - (void**)&g_dinput_ctx, NULL)))) goto error; return true; @@ -143,25 +146,29 @@ static void *dinput_init(const char *joypad_driver) if (!string_is_empty(joypad_driver)) di->joypad_driver_name = strdup(joypad_driver); - if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, #ifdef __cplusplus + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, GUID_SysKeyboard, -#else - &GUID_SysKeyboard, -#endif &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, #ifdef __cplusplus + if (FAILED(IDirectInput8_CreateDevice(g_dinput_ctx, GUID_SysMouse, -#else - &GUID_SysMouse, -#endif &di->mouse, NULL))) +#else + 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; From 34236932a372397443a830598b6e5b006eac4bdd Mon Sep 17 00:00:00 2001 From: radius Date: Wed, 9 Aug 2017 12:49:57 -0500 Subject: [PATCH 112/133] update icons --- media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt | 43 ++++++++++++ media/icons/LICENSE/LICENSE.txt | 20 ++++++ media/icons/icon.svg | 1 + media/icons/mipmap-hdpi/ic_launcher.png | Bin 0 -> 1329 bytes media/icons/mipmap-mdpi/ic_launcher.png | Bin 0 -> 853 bytes media/icons/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 1678 bytes media/icons/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 2524 bytes media/icons/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 3412 bytes media/icons/playstore/icon.png | Bin 0 -> 11502 bytes media/rarch.rc | 2 +- media/retroarch.ico | Bin 0 -> 298345 bytes media/src/invader.ico | Bin 0 -> 298345 bytes media/src/invader.png | Bin 0 -> 24570 bytes media/src/invader.svg | 78 +++++++++++++++++++++ 14 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 media/icons/LICENSE/LICENSE.CC_BY_NC_3.txt create mode 100644 media/icons/LICENSE/LICENSE.txt create mode 100644 media/icons/icon.svg create mode 100644 media/icons/mipmap-hdpi/ic_launcher.png create mode 100644 media/icons/mipmap-mdpi/ic_launcher.png create mode 100644 media/icons/mipmap-xhdpi/ic_launcher.png create mode 100644 media/icons/mipmap-xxhdpi/ic_launcher.png create mode 100644 media/icons/mipmap-xxxhdpi/ic_launcher.png create mode 100644 media/icons/playstore/icon.png create mode 100644 media/retroarch.ico create mode 100644 media/src/invader.ico create mode 100644 media/src/invader.png create mode 100644 media/src/invader.svg 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 0000000000000000000000000000000000000000..d33d1953f9b1d04db50391c6bac98141921050f0 GIT binary patch literal 1329 zcmV-118o96bJC*&m?vdG;s?A1&Va=AVSc+q`1m}h5(UaFI@x+=ww0YDhORV$Qlx$h!nI1 zT9}?|dFo>B6@kut0lt7<;J(1=AYS(JLo!M8ODYfWpG1+oKizvs37`PVDyyur$|`G< zYs=2Iot-rg9|s@TqiP!fb`?c=C(H7WilTgwW%=VeM^TgycHRNNu06)sID7Sa{ZCa@ zaT8Oo*Z%>4y*Nl)0I*9beV_Lr(hjBcy*-m6Ew^m|*e8Vil=lEK0QwmKo=f4F^8%xSWLM?LdYcV0i+#5$OHfmA;L1_K+pe2K+j>(tV09s0l*7F z$mhHVkO9zV0C-UXl|Us>2~+|VFeOk4v;jcPW)siP&z;2GPZIkmB#^4AXcz|a8jVJg z-#?j5ocHUxjwdH4n+4QtHqo-ISV*JM2pMCDh-g_BHX042l%g!ln*+p=_&^a6d%fO+ z@9A_p&U+YR*lxFxQtITfNQDAYRTX=^o&&@f!;6cHP&kN){eIttlLS&KK&ELTV+);%Qm4~#ow#Y5czJp0OVsN3``GPvT@eS5xR@bcq`SL2=XG7zoxa795(hF( z({<7!5FrG|(jr;q1U%XeIEP)tfsO!2f;yLj?#8a(Se@hHV>_1^EOQ0|% z_Myaq#QqbuEX%^{>uXmuO^duAP1AhwHt8_s?L&zHdDrqfm)M6A0}}hsx|i685(Db> zdVx)uC(iOqs|>>kY}P!f0I8~ql+wV4O9;W?aG1A?Q{w&5LrD~96_WS;uI1{RaI0J zr4TrU1xgcXV}Q~?ii-1CpiG_@OA09tjt%r{9H3nQIFuymyR?ClK#Gea%Q8xm)P=)&2&6ui(FDRzm}A!{SNcF96`{N~Q8cwOakXTCM(( zW+X|{DwWDjlt_}K#mM#X@$vUZM@N!9#>h`S^JR7b0IvYx4FG%t0B-@{+cnQydn|A4 zu^m8+=jH+Ie_jB9X8`ch-q~vaI9l_(w#V|)9$Tz`UJ#LX0bm~%)9|Ui({;{Mdo26# n$p7x(wFTwBzm!#0S?ScjE;XFU#%3qB00000NkvXXu0mjfLn3pG literal 0 HcmV?d00001 diff --git a/media/icons/mipmap-mdpi/ic_launcher.png b/media/icons/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..a338dfb2f9e9657505c316aeb70254359fbe6d09 GIT binary patch literal 853 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 GV*d?_DN<+v literal 0 HcmV?d00001 diff --git a/media/icons/playstore/icon.png b/media/icons/playstore/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..73fddf683bbdc11aa26a6a49c1adf3ad12537b0f GIT binary patch literal 11502 zcmeHtXH-*LwC>tTfCy-UB48mDLB$3tihz)K1c9Rn78H&^qM~ptfJCK}jRov*z`{`w zJSr$6AXq?3qS#QRh|;SdASIxbKuEIh+B=?m?-=*}dGF5~8JlD9+2}9(d7Y0#lsw)nwz)P{^}#kH4M?H#UVuPy?cM-2hTT= zXLB0*@qg)$6*F!a=k*t9OQ|$+zQdatc{W0tfkTeRa!vqm+&=ExnVT~@*8lXjk9)nC zO8?EI$04BSTqN?TOMvZ*^Xhx5M(&|Mii!}@Ryzc&+-rv@?~A|H+IezhR-9Lr?`(>G z%E=5%Nv-x6|F^g@Vd|D_Uup_{&s3RXwA9-nuJpo8MaT6liu!wt*6|yv(qoE~S#but zxXsS4W{Nhfb%!j*HK$1*?97VT8yY%UG1%WP`I3~B)Y{V6I9cD)(o%6eFc6D1aC>TL zY01yc%^jv0XSVZabw$6((V~-1KYBmJHXSz(FX4xb_L?0(emsKf=Ql_j8yk}iwzPQK z#`Rz1Wfv7mZ<|;uYMe%?3r`)3#$LYQ2g;_lRxT*rJ)WDrmIB?#SSit*CL0(S(1HJ? zStRQV2BlXI2ibAH&{lD_VE?6^-@^g+d1*O~+wHRzX1lCVlv+J@m)A9-mCYdjTLD@Of%?avwmm$8_s#3x{ zHIxsd<6oOBv5D)y3O(ViJT){y@7@e{aFTXm#;TZEYuNA;t7kHYxCfKxi7zHhlEwff zPbC}ayE)0TkgTUBx3;v%>=eSz*vDxf4Ga{Cpe56b(3LqkJ&o8uTx??rcG0XQD7>PE z=@39}4eGd9ThdSUSEv7d%unjXs2_Jzk}C)}Ua($5gya@09VW4~TON z2t@R&ItfJ;(ZlS|nt_l2YeY)X2K9%D$5TVEhxSlR&6Vk3s@u0lEMpgzJPo72yoM(| zP)M8RkTWdPKQ(k0y54Jt2uT?Z7j|K6RlTt9H4k?UY7E`da~KmeKJ()-*T$g1lR!v1 z#Cq(9?b@}Ae`S)qKCV9+CT;=rCpst)alTzTfVs8G*jh69OU#Db$(=Gmtij~&rQoWz z0>njed9jpdl!%=uUNQS(gqcVw%AlSWc>FlyG`)CwlY;%rMM(BgBahmC7t%V0%j4L` zN&O*gt|kJ^ox^eqz22Vl=IM-XeUH&_j@Rfc1b9l=JiAdk}w5&~sBLn@5h z<{)BXu9)yd$pjbq*jFnE-gIMnr?T*QVT+Ka>X4)3NfFep&$UAL4U*|V^AL2t9OG;J zGMO-!{81ar>r<6y}yiu>3G!HemAQ&1;Oa1!V`Y&Z%5WuE?k znADT+@ipphqlc7 zjyg!;2!%z5h@63*J-AgL4@fD9BZ(u%fUB6wAtcJ^c*bmSu?3+Mey${Oei{h=0YeMh zNIRr#ps6588wAu}Hck4ru#ier3mJO35j{b8xd>b@RDn6%eFY?lX18g2lGJ|%d}efo zE<&%Nq4|D@s$SuIU?2CWkc!rx0B1JjfI2u-&GMNh2Bi@T!Pj|E_}X#-NM$Q60XuX{ zc@()8lCCv0?N&II%&Fp04L~aH^VgZ+2cGBu|M~wi4x4&I2a9%Eg^im$7Y(*n$Z~(= zz)z>21rdWqq8#i{Sr#}G12_T6*5QBLZ5tn7Gg^|{_(WU`1=voEGs`52HCGYPGWi$yJ= z4pBBPE?;6IMsD{rTb-rtG@k3lw;etF>K{Sw%|)T2>ULui!QHy+Oxcf^+q83~+2b#0 z5wX(lIoIz;@nGkZN;FR`nLeiu4l^ovdLX^=b;pl9u}s8IhK7K?@GjUg7g;BsRvoBlQpdcMCiv3J>tJRt{_cl8@#Y?6+ZQi^rY4SYStd8ftY)|@K zL3Q;uwb;s&Cr^4IaB{B+8b6P=8{tDL;Whqa_gkl%Yt@jmlJSn1cuD!2jw8pq%ag7| z@u^x@iQ!eh>500li_2)0oz7YGU1~$?z4Y|wfrBl7l&~qPb_iVu5oB1yG}Jo>54A;7 z&v?CW$HsqjT*Ng*$u(G+n>(y_w;pdJt7YFZ(h(iZ`C&}Td$s^<)djAn?q4On?KmJ>9~>;&*F_Eej)n zT2g*_VJxrCoyKKQhgA<<8nBsifl_~XZsoOaV-JAv~&-EX-vmn+`iohT#Q2>qKAem;6! zYDtRHKz@Z~ZeAK8g!tSh@L8~_NPP|7RbO{BS7vS|vt=;}w)bCv+;XT$Uoc43`i*iY ztcJIiu`^KERBGL1%ifr3b-m%Y(h%b$x@>o&d_@AA?7Of)c|0q0YtN>&hMwG(NQZSXkKH z=1I|@H&)*zE!2q^Z+|b7bTirY$FPCTn>X)R@y&xshrmuJeB{27webw5Y`nuDRc2;k zX}N1cbUYv+r-onE@iwORXHSoh;b3#YPA^ImpT{iq?rblKuID}72Z2|$09%VF`+oLT zH!<1GpJOVK@Vz`9KaZNn!y@96k3qEHw!WTMY>PKu4W><-7AMhzqvZSHjyMQ*2ba~F zAW_<2Xv=!vR|82~rKSsGr~~#cpGIrnUsXr$>tH1D2I*gKVDm55Z#&EP-T&2Oe4>JP zvoq$NY;``AeLKjGwEj8ry;@(ByshZ*?)Bf%b40Af1Y51na!wPhH z^WdLEgLlBEL&Cp9^_S5y-g?ne?ojQEl$;MxsLTKl+6i7J z-tW+x3@fxrt+EU6jR&3w-UZ8&=i&BlRCV&#l&c|!g~(+(0w;)*Dri$TcGwOb=5bbP z3?Q8s(5E60U?5=x93)F#f%|gA=ebhlaY||vV@9Jx5yO7uu^JKH6f`ptdwY)1SyNB;nMeA)o@}rEOSUWt^P7#7W09sAxk|AX zq~9CJ_Ol2X6$ziV>B44R&W+#NvfoFQE_rLP-%V8d$c#z-93PR3Y1IVF8{ zE7@KRxhq6o5g4^7vDoF|DaENcdGn28yKC|luf_HW=-;Znv*((kS0I#WF0 z5FHS{7E9Jd%y0gep7cdR1}lTw^O7N$j}x!D5A+OAU`qyDif;6GCq)A-jr{0vBZMAG z)7?Nhx{tQe;S@2vVaPC?Z}!E*hS#i5{&a4U<

|`( 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 literal 0 HcmV?d00001 diff --git a/media/src/invader.ico b/media/src/invader.ico new file mode 100644 index 0000000000000000000000000000000000000000..6355390e3e928e463c0db538098efabab4ed1f0c GIT binary patch literal 298345 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 literal 0 HcmV?d00001 diff --git a/media/src/invader.png b/media/src/invader.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9e8b6a994071ea50fd4590d3f901a1179c597f GIT binary patch literal 24570 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 literal 0 HcmV?d00001 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 + + + + + + + + + From 3310939983ed5f71f85017a344aec114b65765c6 Mon Sep 17 00:00:00 2001 From: radius Date: Wed, 9 Aug 2017 12:50:29 -0500 Subject: [PATCH 113/133] update icons --- pkg/emscripten/embed/index.html | 2 +- pkg/emscripten/itch/index.html | 2 +- pkg/emscripten/libretro/index.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 @@ - + From 23d9637dc0516d825a9a03b6509d8764c0a3e38c Mon Sep 17 00:00:00 2001 From: radius Date: Wed, 9 Aug 2017 13:04:00 -0500 Subject: [PATCH 114/133] update icons --- .../dark/res/mipmap-hdpi/ic_launcher.png | Bin 1644 -> 0 bytes .../dark/res/mipmap-mdpi/ic_launcher.png | Bin 1053 -> 0 bytes .../dark/res/mipmap-xhdpi/ic_launcher.png | Bin 2241 -> 0 bytes .../dark/res/mipmap-xxhdpi/ic_launcher.png | Bin 3624 -> 0 bytes .../dark/res/mipmap-xxxhdpi/ic_launcher.png | Bin 5191 -> 0 bytes media/android/dark/web_hi_res_512.png | Bin 23353 -> 0 bytes .../light/res/mipmap-hdpi/ic_launcher.png | Bin 2247 -> 0 bytes .../light/res/mipmap-mdpi/ic_launcher.png | Bin 1377 -> 0 bytes .../light/res/mipmap-xhdpi/ic_launcher.png | Bin 3162 -> 0 bytes .../light/res/mipmap-xxhdpi/ic_launcher.png | Bin 5307 -> 0 bytes .../light/res/mipmap-xxxhdpi/ic_launcher.png | Bin 7899 -> 0 bytes media/android/light/web_hi_res_512.png | Bin 31987 -> 0 bytes .../phoenix/res/drawable-hdpi/ic_launcher.png | Bin 1543 -> 1329 bytes .../phoenix/res/drawable-mdpi/ic_launcher.png | Bin 756 -> 853 bytes .../phoenix/res/drawable-xhdpi/banner.png | Bin 17058 -> 7369 bytes .../res/drawable-xhdpi/ic_launcher.png | Bin 2922 -> 1678 bytes pkg/android/phoenix/res/drawable/banner.png | Bin 17058 -> 7369 bytes 17 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 media/android/dark/res/mipmap-hdpi/ic_launcher.png delete mode 100644 media/android/dark/res/mipmap-mdpi/ic_launcher.png delete mode 100644 media/android/dark/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 media/android/dark/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 media/android/dark/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 media/android/dark/web_hi_res_512.png delete mode 100644 media/android/light/res/mipmap-hdpi/ic_launcher.png delete mode 100644 media/android/light/res/mipmap-mdpi/ic_launcher.png delete mode 100644 media/android/light/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 media/android/light/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 media/android/light/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 media/android/light/web_hi_res_512.png 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 b3f9a0686872f1a1ba888a40127f3da92f8dff6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1644 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 X9}~~dFIe^x00000NkvXXu0mjfx-{yq 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 a80f62fd9da10d8b81ddfacdd3214c33ed6d8e19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2241 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 X$G2N7KPm5kH$dQ)9!j@b$2s~x2Qb*) 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 ee5c33d46169423d6867c1a903ff31b54c64938e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5191 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 R7I;AjT)l$TDb>bB{vQ`#csT$7 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 9f2a980250997ff0023f441acae0f5d2ee3b141d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23353 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 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 8a28e593048c1569605f569a8ae949535addbb25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7899 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 AQ~&?~ diff --git a/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-hdpi/ic_launcher.png index 3c1e128429e996cd52f7983b5219872ffc2d5eb6..d33d1953f9b1d04db50391c6bac98141921050f0 100644 GIT binary patch delta 1311 zcmV+)1>pLJ46zE3BYy<=Nkl8o96bJC*&m?vdG;s?A1&Va=AVSc+q`1m} zh5(UaFI@x+=ww0YDhORV$Qlx$h!nI1T9}?|dFo>B6@kut0lt7<;J(1=AYS(JLo!M8 zODYfWpG1+oKizvs37`PVDyyur$|`GphMLPiSj8gh3?*U{0^a%hC>@kO`Em%ysLqfMv>n?nM|Db>$;97CnuW))ND4g2IVg#uDl6??s& z1H>4^i;Ig;IEaY-e&2jnC?REo~#C$$?!nYM8R?zEVwiAzWb#>)C zkHKKz+O}S=rw`O@HeDy(YPFD3>e@zZ$XS(P7`~b0J=fFIQy)^|K!d@+IiO`(NC-hf zhzn^xpMPiVgN(7j);%Qm4~#ow#Y5czJp0OVsN3 z``GPvT@eS5xR@bcq`SL2=XG7zoxa795(hF(({<7!5FrG|+5S*G);@VA5GJI z@iyr&0eRQ*I+xgo5(5(Z&$^e`hY|zo^?HF#nJ3QjOREgS2yE6osQ{^}ij>m8 zhJQ;4!QpV2w~JHa{m?^66lfKa_x>l(^4V;mY4P<{^hmNX!!0|G))Wr3G;Y+9Ahl-<}qqg1zLr~ zalCiC)9Ez!V02w~?aQ*P;sXUCEyEFiaDR^*?`$+pGxok@SRwyWMsrX&iATMLkyTK;lv>TD&;90TmG`2q#ydA|Wlq$sMQ&NPnwv z3IUWi(pmuJh4c_kp@6bR3WHNPpsbL>;uI1{RaI0Jr4TrU1xgcXV}Q~?ii-1CpiG_@ zOA09tjt%r{9H3nQIFuymyR?ClK#Gea%Q8xm)P= z)&2&6ui(FDRzm}A!{SNcF96`{N`IyDL$zA{y;`mQk!B=G(khk8O_WHIq{Ybf@$vEZ zM@L7JJ;umSJ@aLD006H5;0*wL0|0LU;M+CNTYD^T?6Dm{jOXS7?0;SWfM)>k(%#u? z061Fnytc>k(jHr^e_jxgb^%}?7Sr&lz0-BhQ+q7?@W}t};I#$izrU1KRv207)W0q@ VoXEyzC$<0p002ovPDHLkV1iJ2bmRa4 delta 1526 zcmVO%@@p#>k>63CW9B5f#zk~XDO)PFTlBrHS%X+caQ8d9s< zYJ*Q=)6$3*U0v&beQ-u*XJ>}p+100FoF%n2dBPtgARsy(5K3qUr2`$CApj9{JQ z7_IS90(O^d?0eD6wwzs!y$uv2zcbjB{y{*e6$)1cGyCnCJ{C8kr zAR?iQ7cXi_y&8wDFKx*AA!8dH$!e1Hdc6^e4Gs=!$sLTr#=AD;jPGcZCV39Pn%Zc? z>g6Q>H-!+?={*mi6u>%wO`SXhFbJTcwzd`{BO}|kSASMkke8PS0LKBWn8ZQ=hXGtO z-n+QCh=PIw0Qd~RWdM5s?9xdNfS-gAtGXBu0;teU7%o+JQ3!Fv$&q z!Wdvt1-58uX>oKP$v#6q12($5oe=bmF{$gW%Z8(-v9U3;>-P+Q9|eG+p`o9o}L~vz2B|4P%N&WvfRhsU}%#pmK$^=QeTrNiyQCwWC z+5DO0s49P0`S0lHAj#W?cx!A%MtM90t@{1`2qS*KpCmsw=)D;ZhwTWeG3d{^-EKz& zd4D_}lAJf#J7PspQBjc=L$=|bnSJ~AnZ^2XJOo)K{13^mNPbPSm*m3u__!rOCU)=V z<>fgdsI;_{Bm-u#T2-ZryXs2(8p-cSa%yVIOz(b7J&0tZnWEqCM|O60k)kNgilRUW z0Yyl+s^#TnEH5u(b#)b^ zqoWaer%#_oe}8{jtkvVQDq9D$NR`3%tkWU3ckf=3oHN)fOGd1^c#p(FP`IzY(cUteF;Bw)G!deX=Nz{<)>(|?I2 zrk7GrikS7ysNr???Aa%spk6C-b}mVV-Cdp<1K>+{hWJCA43g8%k zOIG`@G<~xPA;d2LJ_N7;zzrZv&0qV}zHcPz>~N;_sav;hMXjMy`7~NGv5~7d6mPyx z*8Q(%@Ih&1N(mxasJ(q7X)CR*t$&vNz^Qb1cRRMJ;$%vXo=Ii__yWM+>alW2*TjSB z6KYnQzG))rDT!A-$xw7B3_=%=HZ;QO=|~vBa{$`w>+3N*JRD)Su&@x19z6npc>tfP z`dK>32JjSsyNMosC)%GbS@ox(p&_jg6eM83!^-}dGiNmWC)09pll;Ug_(IxYBy zB>1^u<;UywYJO_djhy#LGCx1xZU*rt(cgjkmL*LLe5(xdE&$gJ92I&*=G(( z1_A+7pP^8QBp;G2-f419kz`w2n;kiSrpWhElDu%?f}QVKlDRuY&M~VaWdK}TThspi zYzkv|ha}6(%cK04l$2=x?{BHI?_(wBX_7NB?EC5;Lo8Qg*;_lcuQR diff --git a/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-mdpi/ic_launcher.png index 6dbad4942fdcbc05bf659eaaa6cc3a0f4592ef68..a338dfb2f9e9657505c316aeb70254359fbe6d09 100644 GIT binary patch delta 831 zcmV-F1Hk8nu6oqdbAO)Jj0Wx=KQy@TqkP?YbF^~)$ zk_U(q&xUs;=xTVk_xJ&%?C}FcLp!odr+O_~y#Qa}bcjjFv7;YHvRyzII15RO=i|L3 z4UnjgI_g*yTSU|#qU{Y)W9lhaG#tnIEQI(erNkyk2=UEz-G47rkj$0e5kh=lx9J7? zO+-6cnP?Ev+YK-Fr!cXxNToiUaP zU^Xx39D~8Ywhsma+kSd_Iyc^R-Qoc4cH4ePDP@%`pRxeVJ~K*Y%#1G#VCp|D9v>g! z`@U6H^m;uzHVnhe@uSgbc>q)Y>kP9GmIg?s^?CV}9dR7b&8L*IWmgzL2r*ONj4?bs zJX8jdTz~CFDh#j)qRI@I`=C^SB*e+d34$P)QSvO;S|bd@R3&fZMg7TBsx*L?%Bj_A z*^REXhVT2SE66!Vr_-?jN~z58MvmjW{?A+zf^$A|3??t4EG3WIthz51z(72|gu*b) zZQdwZdRf1B9H%@0DJ8nyu07(SC`zr{EC}-*&wuk$&6f%wrCiEzQ6R$2?=~ z7v*^1Xb{o6!^1;Q2=R9n5P8fWA0PiXIy(AFIi8rdi0BOw?Gw>^BKk-~2SoH~O*$Z= z4>(gV`%`b3&#eu5dJWvAr}O&|SwW;~$6YxcE5n@O%IO002ov JPDHLkV1m6&h!Ow* delta 733 zcmV<30wVp@2J{7xBYyw}VoOIv0RI600RN!9r;`8x010qNS#tmY4c7nw4c7reD4Tcy z000McNliru-3uHS5C*lQe)a$W0)a_HK~!ko?U%oc8bK7tzjG|Rpdd&h2#FR}VZntI z{s$rfJCUn2O&~>xIXFRx5|mUzz{5gP1Oj3s99)q!!8B>orhhvu0v29pF5RWD@tbBn zR^45H+^%;a^MPS;XWyIm-hAJ<3rHjqi9{liNd8&Gu7)JJ;!FtPx2>m`fe-*2jRx%k zbF(pj@>aLd8qjDoat(+iHBIw0c*SNB9l*Ke)_Wnu3(NdDfL{Qv09=^&AcR07kpM}M z{0ZRH>J~sX9)FKxI-Sn_%-JOB^?5D`K=a+2CcG9$@+KF?Gt#Zsw6lHaUz$z+n@ zaF~HWfU2re(=>*|;RRVlqfzR*PQx&07zTA+UzlGWilQ(W3^J3+kmQkdJ;N{vfM;iC zB>8D8NwnK-y6M-CVXZpJldb#38sxIUz7qg|@p!y>0)He=y4|i*HNIA>)$6%htwxhK zBpaJ1XY#?cd%Nybax189^&^o80r2qfa5;g6g*u%MNs4WEXWg#W>vhL>dlkw_#G$^XD#RYbLFhpfoA P00000NkvXXu0mjfMTu2w diff --git a/pkg/android/phoenix/res/drawable-xhdpi/banner.png b/pkg/android/phoenix/res/drawable-xhdpi/banner.png index e04769aa8a84f2273b60b2db2c3db6f0c2a2c8f3..b13639088ccc8d49c4e6e3b1343fb7208f222899 100644 GIT binary patch literal 7369 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 PMv$(ip+=<|GV=cb?n4CL literal 17058 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 G$o~U}>pF@6 diff --git a/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png b/pkg/android/phoenix/res/drawable-xhdpi/ic_launcher.png index 2949cf082232be06ca69a7083ae06cc22f7a0918..7eb088dc92430c280f73fefbc27acb048035b0e2 100644 GIT binary patch delta 1662 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 PMv$(ip+=<|GV=cb?n4CL literal 17058 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 G$o~U}>pF@6 From d2f870a2a184a89b31f7bdbb954921872c5354e8 Mon Sep 17 00:00:00 2001 From: radius Date: Wed, 9 Aug 2017 13:11:57 -0500 Subject: [PATCH 115/133] update banner --- .../phoenix/res/drawable-xhdpi/banner.png | Bin 7369 -> 4423 bytes .../res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 2524 bytes .../res/drawable-xxxhdpi/ic_launcher.png | Bin 0 -> 3412 bytes pkg/android/phoenix/res/drawable/banner.png | Bin 7369 -> 4423 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 pkg/android/phoenix/res/drawable-xxhdpi/ic_launcher.png create mode 100644 pkg/android/phoenix/res/drawable-xxxhdpi/ic_launcher.png diff --git a/pkg/android/phoenix/res/drawable-xhdpi/banner.png b/pkg/android/phoenix/res/drawable-xhdpi/banner.png index b13639088ccc8d49c4e6e3b1343fb7208f222899..bcf43ef5aae716ad41a273bad6688c3a3e4fe558 100644 GIT binary patch literal 4423 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 DnS>gY literal 7369 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 PMv$(ip+=<|GV=cb?n4CL 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 0000000000000000000000000000000000000000..c5a7c34b79e07f18e2cc054dd0f9fc021be08284 GIT binary patch literal 2524 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 GV*d?_DN<+v literal 0 HcmV?d00001 diff --git a/pkg/android/phoenix/res/drawable/banner.png b/pkg/android/phoenix/res/drawable/banner.png index b13639088ccc8d49c4e6e3b1343fb7208f222899..bcf43ef5aae716ad41a273bad6688c3a3e4fe558 100644 GIT binary patch literal 4423 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 DnS>gY literal 7369 zcmZ`;cOYBc|4z)-Zmrm*rM75@*n2Bgdz6IN2!fh5O3+ZdS|zo&s#2{{qX9ipK~2JAahZDs0spoPNu#+a7L13fU|32UsH^%P(C)xZo zE&WWqoc#h(K29KS6x!2I+|$YLj+8i5ToPJAMMVICIAwJ;R861RZOvR-FljeZ?w%k2 ziEVftPq?AQMRtpSanl$z3iwo+YDQ6DJXYh(d4aq!g ztfa_$(YRZ03Xv*NSU$w``Ak`i?7vWTf3w5Enf=hP-FnZG#t)4xGiJjQ`}Wrz5MMDm zsH1on*txe8K}cwTP~s(7mq4%;2To*{Z31a8KK?0|%~$gOZPb%vtj3eXG2#)w)?vU- zInGY=MKhk|@{^`boyXtvOH&O_JmTr%51w#?#B_N0RcL>e87H#mOLa8|JNwl@!O+mq z$cU+M`|tx8%-!9+Y+~rchYwmwoU)-O-om)<1yH$V6|(K}{20B~y}rJFda*z7=Jo6M zH+ARU4k#YaHNO`Xh#>t)0&8~aN%Ic~7y_j--XN>%q*Mm-Z3izWT&`u*jt^W&XTNx_Qp^3CkP*}uQn zGz#IE$rn*f(q?o+En%0zdKeys^tA6_^VR*+BpzkY!xvHe0Vq`dj|T}IY(6Jz#Jg@q zoJE&}2+|Wo@sVy8ij5N~1`J!qb2{&@U`1IOdSj%_?&t1K`1N^G5}jL4%}&d?xR6ln zo*ctJ_|+leQ>_2;>grsBZ%lMijm=ljAb}3w)qb-zFz1PY0bWHnQAIQX4fD9eiF|Tn zLFCi7$WAd@12n6I9jB~M(G*M}XzzDdmzLXWsjSM?zRdfNg`?nI?cP{g9Rq{u&yGKq zek7xx{cKx29Vs&@)JpX6ioOg}E@>O#Mq3JhviuxbAQZDYl;Vx;BUo>r{9Te#s}K|t zYFjhV(aDRPzAGlSHQnGlLL+jtJrgfrB2_U@6SD;3c$1TpWF<-a7(FvH10=m|(C^op zfuZ5m`P{YVA;&X8F|miby7?N`5r@!l39ckkkD*i{6KiX0*Y|oI(;+jB{*XM+?kdX% zmd(GZ4-XF=yAtv>J{0Ix-Jz?})tMhE)}NZ1LKF0w0(WNhC7OSy(R{LNwqDSe=bYTz z+Y`in_#QO=q?+00DYnn1HLSUPqO7*ozb%rSZUDMb641>WAt5ZRwkh~B_?b9YI~Xn@ zBve*Zq=9<=?DFjJCZhmCwgd4U`9)>)ZM1YduuMN5b&g`c2jMrE<`9HB9ew@sj~|Qv zx@%%EV&<`Qz0eI<*u_b1_|-dMx6W9``&Aw#yYD)D(et1w{`>c}G4<(h-xe1YA;da# zc3Q6vB|a1|r;9&fR}7YN>KBycEj{ZLp{shrplpDcnw)gKqu+66Wy=|082wzyUQ-j- zUXTZ@k)a}8KCh#E>n?t}szip?gg*E>WGe?s3 z)9*Bt;{j+i+GQZ8_$fwHTl>dEr9V!;1xpSSnB}vU)T&M9IHEuZ2?G@)7f0o!E`Q*7NMq+(53fkr_>+_dFgN_y@=$k(-_t*M$($k}qbz3V5%edrx9RD*O3&GwB!2(yeq((9TAQXM4evFhU`p8r2`O<->2h_MzhHWe0=_fq=_Vf z{rYcmc+J_C2#K=Stb%+?UE2cV{l}9u`!(SgOFZz37>kdVs6*-?n)S|jRt}y4-T-ol zivo^v`f2^%X(%57=`Eg}lQTOxsh5e$3AjA-7p>m6TVeO(Y7wD+cAi=q2Z7zXes-`{zsC#ascXiiU~OeY-rG;)9aVl3)-T@=6eddVZ(%ItSjdNJzP>4fW7)CNudQ zwBIMgyj>o$njQF_Ta{vUsE!OG!hlO>o^9~G4*<(Ocve5%?)fE^S0ieBG?0x`tx(m- z&@icenGi)u|Cm2g>W8m=9T@@!t8Qp`w;^8f<;&w5vD?dV~UG6uASyXtXm^0{$*)hNcMNfA$vU#@)8 z#6lYVWyrn$NFKENmz0uj(76ajf=@|NeY>U}E{;(mxGt>pWtJ@t4KAIYp7IqFtuU~w z^ZnIzNuI*ZRTMj?o{z6Db6Q)-@isGk@j=wzk8e=> z;4Z#}(%i5DYkd(B5ypkodvhz1ktDbuR_~_#{r#7J|9+%Lp|;e~SX6Y6lgkx0RB77~ zIWSb$A?PyhjWtd#Gby#ErCAx^knt>X)qA5rzcW!C10<(6j#&h1D9A^e&+CxgK05y+ znMeCtTC4W3Y5`PunJvY86)@#BOHiL zJ1ynj(vaMO3avbEZa62hSNvyBPg%=QMrP(RE8$YZYrp>K(g?Sk6Za!~du503H>kA9 z+%{3QPTsBMZ41zxikui)N`#`~B>+UG_UP4tTy5nz72%gdE9BHHyUg?T%`>48)+U@s|FwbXiD5&VRk7WhLhIIEw36{w5xo{ zi<;*5zv%@9NE0gfpyt0Q#?@0iBkJyb>$~A?X2y)s>Mqt#7nr;wFCVf#R9r)A^lYp4 zmllo<=G;3D4Qu6zLfDR}3|d%xvMa_2%7$Gax+ppwpi-W{nV6ZaxHb@9#q7S};c!Sd z4Tln`h%MOD&5a$X_&4%P!d4d&5@`Bt@+7~O79_U&-Ib6?u3NY%(R%S9QGQt5zQthb z(d}h7Z{=}`wC&-a-QC7`t>;G*F5?UsALs*L^c%32(M-$pOgG^z0Ln78CfZUIyi+Ojeo%^VgFmDE(Iqyi=ebdP__TQeC6(+uDiLv`%C!`KqPFAXpat{(d zf1M51UvR5>wwl9l+}|NUYHMt)>Yp00+MjJ)s6_Umv~y}Al(8;f0*9; z$&)81)osLBMd`I*h>0Q2;vd{>gNtqv4F|QimR5AT7$d%L!xo(60D#$s_F3l@9*#b_)%22pO1a|*1h}p=jxwE!SB+Ftg3oRunl4iIQxp$<+4P0e&3p`?+VS^_i<n0R>4yWL$iFncI+@ygX2^9(GI%nwB*-X21(ezkSQ1sue%uj3pKAHpS9&$-T%{ z!@1oUsA{Jd0MiL(9Jc*<$}ZzeakY}^_1HN*WJ)QimaW|Z)dwvHMeu!dFIt^Zf-v5M?OAplULDFrvK_R49FkwFo3w_ zglx+Sn{v=z<^kdbr(NQ$(&kczprs)B=DnbXbHOT~{$`YCAqbi*WGkg0omH3h7!wO- z6BGV-e@Jk!d8Mr`E`uRM-;q0HcV2Zep$35NL>}dwpF?>ZNU5d5WTh`>ZzZlmvhH`j zl-ZPNJxxpzAw;TSBO2ktKnhL3(I%ya-3Ceba5+ILWOmOF%_gI304U~Imm&o#0Uu68&mBSNf=aRNu)yFrWhnq-X?lctjpFiK~QDnC-_vy zLHZ9MNE#Z>X>^`t#JV``PbB~;(I<7ayv6o^ z=Bv(}NL>ojKT?2bSo&?3!i+P=KE1H~>d9sHBVIH+qD*_)8_OSrARy2HU(1>-(-R@Y z#>N&G7n^cPyjCVP3DjEx>F;@C7j_pqMhwlY!CfTdBVvsGFFF{>rGz*1MSxj;he6pB5IU0fxN1H2h^m00MehWmIOoxa1pZF z3e-xs54S5|yE0>55drCf;IVJ~SRj8>;OHk!0VssAdxZ%-l!cI(m}p9!9Ook;MOiOF zSM?<$gB`f<5VX3wYV(|8+`m9!(CD%>4!9Gj$PW-_I~3Zb5Tq#fSLG9Zv)xMYoL*Vb zHZw3-1s%aW-t&mB{KQ1mVPELvRKWT1HIH8m1o=)D5KMyqY4sbiT3 zMpPw1#iG|wN4wr#gHpjh^bc1I zrdSJBl3!emi%umqwXj$+&|ObO@)BOXdIbe+j*E4&P}O+0r+>yJX-ZuM$e631|^pzRcQ0CsqMc{{u@P-vyM?X_BEc zLqDb0x4+RZUo@>zSgNQpNu2W%T>7)}lU#aV0aTCebhI1-W1P3liFxzp%_$WWwmnv1 z1L@{t_KZN_Z$iI|b_4|lUFh6}RRXo7KTDPmBJLncAkizznot+Tmi4f~+?Ki$`I!4- zMCS(9o0dofk!^lL!yRqTn!lQEm z$-5g`6SQ9>2@c|l9^+NW0~!@$Gcz-w#YA3F(f0+5D53gh4;m=`3H^Df(v=yjb2(4= z1+lva30Ol%6qbbO!+{P#)JpHWP)h!4vpWoUfE4M(7v3RZnz-M|N6_l;Fj71m0RmB$ z$yVLhmB=AEtKq?^HWI^kUIZ-fgI^tjzb{VrM}8zstbC7UyrBg}Bw^cSDeaesh&;Oig7n8Q_(Xl1c!|T;0}9KoDuMAP`D?9{9G$ zrP`WP=FGh>eNj3lnuY8cps4o+ss$5pUBE^H96xmGdeF%(uQQ`*Wz0wG+7H#$Z`jMg zY_kB*+S6U`;+M=3Dm13G!XCD!Z;On(HRWA!$p=6hC;`VKN$v+#XF)=Jo$%((#oZfH+ zhr^kAUgZ1fL4Ja$-&gJhL3o&G>u$o0O-*0uO3;cZvWnXh7)lEi-451>($dl+NX5Rs zK45i^lbia5s)Pt-_(UraGFDMUkIddI*?mB?NaY=j{QBkM?EJVP2mbub&m?dH%CWQxm=lU%DFJ~lCVco|F`y?4ITYP8&y_%IXxuJLb4K|%YzK7E858W%+( zs+?XIvM%p7B4|R-eSB~by4QVw%~e>=GXWyG*dx(eWH%T9;86mD@MJvngXWzIpGR0# zfsTMuR)2)g@0Te(ypPPySB7|Ih%rm^^vV}1T=|su_W?x}bV3~(SLokQ1=Sd+vb-M; zp90(bP?0>GtY~bMYn?OF{K505EGvuCWCuwwd`fh;U(Qb#jMw92MXE}9s1!^Ds4M^i zqGXmmd}p@#9n9r1@#)9By!o~$$`PU9$*HMyQ7eZ{$Vu$bR&BhRodR)Bz}Z!RV`~!AIW{)NYWFN6E}&ul<&i5E_vkJ;(L+AZn}*tC zfWz_2F;Sbxm?&BgmGz#-mVILOoN2_plV#rWNmZjwqJ!q8=%mls+XCclc7*il?x=-* zY(_Oh?m*x|JNd>POuB?Uw|syo^OhlGlu1?5klx!>Tr2}aS#{RUL3H0`yHQuy4NFNLiD%;X%exhl=4sK z517tT46#i|-BK{IWkfEW-%OM_OqD=FpPwwmm`cUd%(MjV*lkE-05K$D{xPrM2_IhG z5ooCrZS1%~fpH)ED7lv^aiQ3T|GUyz-`VgH;kg9BH$y&?SIYP=r9CK z^m~V8@IR@*3xampIf2RGZRTk%V{glrl9GbjSiaA2gDhZs zdi@p6)K?%dfmqc)AJ$e;HNF6mE)hR%PgcG{cupgPv(Y{M{qU3FElUeW^j&4?>g0d% z6}CJ`uvoqlb=39dLDTL?w^{qH0g1WtPt{K zGRXVYc2S$U-hYk4ZXgmr**3h6b6!D;R$5he&5M>*RA5{s7+zv0`sBfM_Vi1F`1Ev_ z4X#dX!$cC7{ChuVYalK_{Ak0Bh=YUBpuK;D73(w_9SHJZmcgRI-*6e3B>;NDt*`*7Jm77HY4FFFuAR}pNN8M{}qy&a$Yzh?oyEjGG2}650|MM>QECAO(j9uSkpce|07DMcKQe43o+jwaDLka!4K) zB0J+KNfSE6(jM0w8$1JWbjqt$EZ}y0;^Lx16e}G`1Odn-rg_s@XNcO4dKWgJQ0=>F z7-jDq;O~!u#%6zaKm*~XXdP@{K<=;fnbx4y-`ee3V=u$5fl8?i1vfkayyd;+9xfjn zqi?$U`Zl$0%mHnHI(1E7vuX;ccqlW#OGqun@6R)_!-@x4i3yz`99r<%zP@NbG(M46 z;h1Wc2I?JcJLtJqJg@M4E PMv$(ip+=<|GV=cb?n4CL From 530d79f8e3f954d76e6c4ee0693bb49cd1e5fd3b Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 9 Aug 2017 18:25:45 -0400 Subject: [PATCH 116/133] d3d9: only use wide char on msvc if UNICODE is defined --- gfx/drivers_font/d3d_w32_font.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gfx/drivers_font/d3d_w32_font.cpp b/gfx/drivers_font/d3d_w32_font.cpp index 1eff6798c0..8a7b903765 100644 --- a/gfx/drivers_font/d3d_w32_font.cpp +++ b/gfx/drivers_font/d3d_w32_font.cpp @@ -47,10 +47,10 @@ 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* */ +#if defined(_MSC_VER) && defined(UNICODE) /* MSVC needs w_char* if using Unicode */ L"Verdana" /* Hardcode FTL */ #else - "Verdana" + "Verdana" #endif }; From ff98730906402d0b52c487a216289c142581dbb7 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Wed, 9 Aug 2017 23:33:57 -0400 Subject: [PATCH 118/133] don't define UNICODE for msvc2005 --- gfx/drivers_context/wgl_ctx.c | 3 +++ gfx/drivers_font/d3d_w32_font.cpp | 8 +++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/gfx/drivers_context/wgl_ctx.c b/gfx/drivers_context/wgl_ctx.c index 5c0d7b4e49..5e19fbfa67 100644 --- a/gfx/drivers_context/wgl_ctx.c +++ 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 diff --git a/gfx/drivers_font/d3d_w32_font.cpp b/gfx/drivers_font/d3d_w32_font.cpp index 8a7b903765..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) && defined(UNICODE) /* MSVC needs w_char* if using Unicode */ - L"Verdana" /* Hardcode FTL */ -#else - "Verdana" -#endif + _T("Verdana") /* Hardcode FTL */ }; d3dfonts = (d3dfonts_t*)calloc(1, sizeof(*d3dfonts)); From 5d12368c83b5ecdfad54dccd2cc0823e13293559 Mon Sep 17 00:00:00 2001 From: Brad Parker Date: Thu, 10 Aug 2017 11:42:47 -0400 Subject: [PATCH 119/133] fix extern C usage for msvc2005 --- ui/drivers/win32/ui_win32_window.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/drivers/win32/ui_win32_window.cpp b/ui/drivers/win32/ui_win32_window.cpp index f868344fed..8a2c4243f5 100644 --- a/ui/drivers/win32/ui_win32_window.cpp +++ b/ui/drivers/win32/ui_win32_window.cpp @@ -75,7 +75,10 @@ static void ui_window_win32_set_title(void *data, char *buf) SetWindowText(window->hwnd, buf); } -extern "C" VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); +extern "C" +{ + VOID (WINAPI *DragAcceptFiles_func)(HWND, BOOL); +} void ui_window_win32_set_droppable(void *data, bool droppable) { From 805c2ad529f2637b51c45c1b8329ea3065e767bd Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 10 Aug 2017 21:22:30 +0200 Subject: [PATCH 120/133] Buildfixes --- audio/drivers/dsound.c | 2 +- input/drivers_joypad/dinput_joypad.c | 8 ++++---- input/input_overlay.c | 7 ++++--- ui/drivers/ui_win32.c | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c index 2f0acb88b1..6d82972144 100644 --- a/audio/drivers/dsound.c +++ b/audio/drivers/dsound.c @@ -322,7 +322,7 @@ static void *dsound_init(const char *device, unsigned rate, unsigned latency, RARCH_LOG("DirectSound devices:\n"); #ifndef _XBOX - DirectSoundEnumerate(enumerate_cb, &dev); + DirectSoundEnumerate((LPDSENUMCALLBACKW)enumerate_cb, &dev); #endif if (DirectSoundCreate(dev.guid, &ds->ds, NULL) != DS_OK) 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/input_overlay.c b/input/input_overlay.c index f67a8432ac..94611c110c 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -761,12 +761,13 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret, static bool input_overlay_add_inputs(input_overlay_t *ol, unsigned port, unsigned analog_dpad_mode) { - int i; + unsigned i; uint64_t mask; int id; - bool button_pressed = false; - bool current_button_pressed; + bool button_pressed = false; + bool current_button_pressed = false; input_overlay_state_t *ol_state = &ol->overlay_state; + if(!ol_state) return false; 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, From 7a490aa6d6bd49aad878d3383704af488453a46e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 10 Aug 2017 21:25:30 +0200 Subject: [PATCH 121/133] Use C-style comments --- input/input_overlay.c | 153 ++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 72 deletions(-) diff --git a/input/input_overlay.c b/input/input_overlay.c index 94611c110c..131db8feb6 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -705,7 +705,9 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad default: break; } - if(settings->bools.input_overlay_show_physical_inputs){ + + 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) @@ -760,81 +762,88 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret, */ 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; +{ + 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++) + if(!ol_state) + return false; + + for(i = 0; i < ol->active->size; i++) + { + overlay_desc_t *desc = &(ol->active->descs[i]); + switch(desc->type) { - 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) { - 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; + /* 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; + 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; - return button_pressed; + 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; } From edb70936ae328b6a608c7638215727048a31e0df Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 10 Aug 2017 21:27:05 +0200 Subject: [PATCH 122/133] Silence warning --- audio/drivers/dsound.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/audio/drivers/dsound.c b/audio/drivers/dsound.c index 6d82972144..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 +#ifdef UNICODE DirectSoundEnumerate((LPDSENUMCALLBACKW)enumerate_cb, &dev); +#else + DirectSoundEnumerate((LPDSENUMCALLBACKA)enumerate_cb, &dev); +#endif #endif if (DirectSoundCreate(dev.guid, &ds->ds, NULL) != DS_OK) From 16f59aba963e2e3646ccf5373646472f465f66b8 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 10 Aug 2017 21:38:57 +0200 Subject: [PATCH 123/133] Some C89_BUILD fixes --- menu/drivers/xmb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index f18655383e..071bcb80f4 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -3735,8 +3735,10 @@ static void xmb_list_insert(void *userdata, static void xmb_list_clear(file_list_t *list) { size_t i; + menu_animation_ctx_tag_t tag; size_t size = list->size; - menu_animation_ctx_tag_t tag = { (uintptr_t)list }; + + tag.id = (uintptr_t)list; menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); @@ -3755,8 +3757,10 @@ 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; + menu_animation_ctx_tag_t tag; size_t size = dst->size; - menu_animation_ctx_tag_t tag = { (uintptr_t)dst }; + + tag.id = (uintptr_t)dst; menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); From 29af83f8e3dc889ad3503c5ee0c5c3a4241faf2f Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 10 Aug 2017 23:07:27 +0200 Subject: [PATCH 124/133] Fix some format-truncation warnings --- gfx/drivers_shader/shader_glsl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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'; From 4a9c7384c7bbebef3c4f89724de7f5631832a289 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 10 Aug 2017 23:14:03 +0200 Subject: [PATCH 125/133] Silence more format truncation warnings --- menu/cbs/menu_cbs_ok.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 8168241b55..973072f00e 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -3447,7 +3447,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'; @@ -3658,7 +3658,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; From 4e66ec28cbd13c5b8395b7bffa7621a219e494ac Mon Sep 17 00:00:00 2001 From: twinaphex Date: Thu, 10 Aug 2017 23:19:54 +0200 Subject: [PATCH 126/133] Some more truncation fixes --- menu/drivers/xmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 071bcb80f4..76b051633a 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -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'; From 22139dc4a08f9789489bec2acfdc74d33c0f6b47 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 11 Aug 2017 01:16:03 +0200 Subject: [PATCH 127/133] Turn menu_animation_ctx_tag into typedef --- menu/drivers/xmb.c | 18 +++++++----------- menu/menu_animation.c | 6 +++--- menu/menu_animation.h | 5 +---- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 76b051633a..2095f40ba9 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -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 = (uintptr_t)selection_buf; + 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,7 +1190,7 @@ 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) @@ -3735,11 +3735,9 @@ static void xmb_list_insert(void *userdata, static void xmb_list_clear(file_list_t *list) { size_t i; - menu_animation_ctx_tag_t tag; - size_t size = list->size; + size_t size = list->size; + menu_animation_ctx_tag tag = (uintptr_t)list; - tag.id = (uintptr_t)list; - menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); for (i = 0; i < size; ++i) @@ -3757,10 +3755,8 @@ 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; - menu_animation_ctx_tag_t tag; - size_t size = dst->size; - - tag.id = (uintptr_t)dst; + menu_animation_ctx_tag tag = (uintptr_t)dst; + size_t size = dst->size; menu_animation_ctl(MENU_ANIMATION_CTL_KILL_BY_TAG, &tag); diff --git a/menu/menu_animation.c b/menu/menu_animation.c index bd9cdc0850..8464a7876c 100644 --- a/menu/menu_animation.c +++ b/menu/menu_animation.c @@ -648,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 == (uintptr_t)-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 c010c3971e..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 -{ - uintptr_t id; -} menu_animation_ctx_tag_t; +typedef uintptr_t menu_animation_ctx_tag; typedef struct menu_animation_ctx_subject { From dad0fcbbe8e77fd4f22cefdacd773ddcd2ff6e6c Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 11 Aug 2017 01:20:57 +0200 Subject: [PATCH 128/133] Get rid of the conditionals --- menu/drivers/xmb.c | 61 +++++++++++++++------------------------------- 1 file changed, 20 insertions(+), 41 deletions(-) diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 2095f40ba9..555b26c6e6 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -1193,25 +1193,21 @@ static void xmb_selection_pointer_changed( 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); } } @@ -1405,19 +1395,16 @@ static void xmb_push_animations(xmb_node_t *node, uintptr_t tag, float ia, float 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, @@ -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); } } @@ -1966,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; } @@ -3968,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); From a5bb61684cd48a7045a25943bb0559315ff3217a Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 11 Aug 2017 02:30:23 +0200 Subject: [PATCH 129/133] Get rid of these conditionals --- menu/cbs/menu_cbs_get_value.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) 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( From a443196726533fabaefb6c6634620fb82ae6ad56 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 11 Aug 2017 02:51:09 +0200 Subject: [PATCH 130/133] Cut down on code duplication --- menu/cbs/menu_cbs_ok.c | 69 ++++++++++++------------------------------ 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 973072f00e..a73475adb3 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -1086,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) @@ -1220,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); From e3015088c2f00ebf3fafd9a75359a546fa7e4917 Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Fri, 11 Aug 2017 20:56:29 +0200 Subject: [PATCH 131/133] Update msg_hash_it.h (#5283) --- intl/msg_hash_it.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index d4ccceb59f..e94e56c133 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -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, @@ -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, @@ -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, @@ -2244,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, @@ -2379,4 +2379,18 @@ 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_LABEL_VALUE_INPUT_USER_BINDS, + "Impostazione dei controlli per l'utente %u") +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.") From cb635845118769be5032495f88056112391ccf6c Mon Sep 17 00:00:00 2001 From: theheroGAC Date: Fri, 11 Aug 2017 21:28:31 +0200 Subject: [PATCH 132/133] Update msg_hash_it.h (#5284) --- intl/msg_hash_it.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index e94e56c133..22279a099e 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -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, @@ -2393,4 +2393,11 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, "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") From 74a22169acf045d4ff692c2b830a3f9571ef024f Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 11 Aug 2017 21:37:00 +0200 Subject: [PATCH 133/133] Buildfixes --- intl/msg_hash_it.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 22279a099e..8417b5701c 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -2381,8 +2381,6 @@ 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_LABEL_VALUE_INPUT_USER_BINDS, - "Impostazione dei controlli per l'utente %u") 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, @@ -2390,7 +2388,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, 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".") + "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,