diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000000..3c5065c92f --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,22 @@ +# 1.4.2 (future) +- ANDROID: Autoconf fallback +- ANDROID: Mouse support / Emulated mouse support +- AUTOCONF: Fix partial matches for pad name +- CHEEVOS: Fix crashes in the cheevos description menu +- CHEEVOS: WIP leaderboards support +- COMMON: Threading fixes +- DOS: Add keyboard driver +- DOS: Improve color accuracy and scalines +- GUI: Various settings are now only visible when advanced settings is enabled +- LOCALIZATION: Rewrite german translation +- LOCALIZATION: Update several english sublabels +- NET: Allow manual netplay content loading +- NET: Announcing network games to the public lobby is optional now +- NET: Bake in miniupnpc +- NET: Fix netplay join for contentless cores +- SCANNER: Always add 7z & zip to supported extensions +- VULKAN: Find supported composite alpha in swapchain +- WIIU: Keyboard support +- WINDOWS: Logging to file no longer spawns an empty window + +# 1.4.1 diff --git a/Makefile b/Makefile index 15cb1d3254..c1b418d90d 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ ifneq ($(findstring DOS,$(OS)),) endif ifneq ($(findstring Win32,$(OS)),) - LDFLAGS += -static-libgcc + LDFLAGS += -static-libgcc -lwinmm endif include Makefile.common diff --git a/Makefile.common b/Makefile.common index 42f0a0d8af..34c0b4a719 100644 --- a/Makefile.common +++ b/Makefile.common @@ -1197,7 +1197,7 @@ ifeq ($(HAVE_NETWORKING), 1) ifeq ($(HAVE_CHEEVOS), 1) ifeq ($(HAVE_THREADS), 1) DEFINES += -DHAVE_CHEEVOS - OBJ += cheevos.o \ + OBJ += cheevos/cheevos.o \ $(LIBRETRO_COMM_DIR)/utils/md5.o endif endif @@ -1208,7 +1208,26 @@ ifeq ($(HAVE_NETWORKING), 1) endif ifeq ($(HAVE_MINIUPNPC), 1) - LIBS += -lminiupnpc + ifeq ($(HAVE_BUILTINMINIUPNPC), 1) + DEFINES += -DHAVE_BUILTINMINIUPNPC -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR + DEFINES += -I$(DEPS_DIR)/miniupnpc + OBJ += \ + $(DEPS_DIR)/miniupnpc/igd_desc_parse.o \ + $(DEPS_DIR)/miniupnpc/upnpreplyparse.o \ + $(DEPS_DIR)/miniupnpc/upnpcommands.o \ + $(DEPS_DIR)/miniupnpc/upnperrors.o \ + $(DEPS_DIR)/miniupnpc/connecthostport.o \ + $(DEPS_DIR)/miniupnpc/portlistingparse.o \ + $(DEPS_DIR)/miniupnpc/receivedata.o \ + $(DEPS_DIR)/miniupnpc/upnpdev.o \ + $(DEPS_DIR)/miniupnpc/minissdpc.o \ + $(DEPS_DIR)/miniupnpc/miniwget.o \ + $(DEPS_DIR)/miniupnpc/miniupnpc.o \ + $(DEPS_DIR)/miniupnpc/minixml.o \ + $(DEPS_DIR)/miniupnpc/minisoap.o + else + LIBS += -lminiupnpc + endif endif endif @@ -1273,7 +1292,7 @@ endif ifneq ($(findstring DOS,$(OS)),) OBJ += gfx/drivers/vga_gfx.o gfx/drivers_font/vga_font.o \ input/drivers/dos_input.o input/drivers_joypad/dos_joypad.o \ - frontend/drivers/platform_dos.o + frontend/drivers/platform_dos.o input/drivers_keyboard/keyboard_event_dos.o ifeq ($(HAVE_MENU_COMMON), 1) OBJ += menu/drivers_display/menu_display_vga.o diff --git a/cheevos.c b/cheevos/cheevos.c similarity index 85% rename from cheevos.c rename to cheevos/cheevos.c index d7eb8c5e4e..6ada9611b8 100644 --- a/cheevos.c +++ b/cheevos/cheevos.c @@ -23,26 +23,28 @@ #include #ifdef HAVE_CONFIG_H -#include "config.h" +#include "../config.h" #endif #ifdef HAVE_MENU -#include "menu/menu_driver.h" -#include "menu/menu_entries.h" +#include "../menu/menu_driver.h" +#include "../menu/menu_entries.h" #endif #include "cheevos.h" -#include "command.h" -#include "dynamic.h" -#include "network/net_http_special.h" -#include "tasks/tasks_internal.h" -#include "configuration.h" -#include "performance_counters.h" -#include "msg_hash.h" -#include "runloop.h" -#include "core.h" -#include "verbosity.h" +#include "../command.h" +#include "../dynamic.h" +#include "../configuration.h" +#include "../performance_counters.h" +#include "../msg_hash.h" +#include "../runloop.h" +#include "../core.h" + +#include "../network/net_http_special.h" +#include "../tasks/tasks_internal.h" + +#include "../verbosity.h" /* Define this macro to prevent cheevos from being deactivated. */ #undef CHEEVOS_DONT_DEACTIVATE @@ -82,6 +84,9 @@ #define CHEEVOS_JSON_KEY_CONSOLE_ID 0x071656e5U #define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U #define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U +#define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU +#define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U +#define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU enum { @@ -241,9 +246,11 @@ typedef struct typedef struct { int in_cheevos; + int in_lboards; uint32_t field_hash; unsigned core_count; unsigned unofficial_count; + unsigned lboard_count; } cheevos_countud_t; typedef struct @@ -255,13 +262,15 @@ typedef struct typedef struct { int in_cheevos; + int in_lboards; int is_console_id; unsigned core_count; unsigned unofficial_count; + unsigned lboard_count; cheevos_field_t *field; cheevos_field_t id, memaddr, title, desc, points, author; - cheevos_field_t modified, created, badge, flags; + cheevos_field_t modified, created, badge, flags, format; } cheevos_readud_t; typedef struct @@ -271,6 +280,32 @@ typedef struct const uint32_t *ext_hashes; } cheevos_finder_t; +typedef struct +{ + cheevos_var_t var; + int multiplier; +} cheevos_term_t; + +typedef struct +{ + cheevos_term_t *terms; + unsigned count; +} cheevos_expr_t; + +typedef struct +{ + unsigned id; + const char *title; + const char *description; + int active; + int last_value; + + cheevos_condition_t start; + cheevos_condition_t cancel; + cheevos_condition_t submit; + cheevos_expr_t value; +} cheevos_leaderboard_t; + typedef struct { int console_id; @@ -278,25 +313,34 @@ typedef struct cheevoset_t core; cheevoset_t unofficial; + cheevos_leaderboard_t *leaderboards; + unsigned lboard_count; char token[32]; retro_ctx_memory_info_t meminfo[4]; } cheevos_locals_t; - static cheevos_locals_t cheevos_locals = { - 0, - true, - {NULL, 0}, - {NULL, 0}, - {0} + /* console_id */ 0, + /* core_supports */ true, + /* core */ {NULL, 0}, + /* unofficial */ {NULL, 0}, + /* leaderboards */ NULL, + /* lboard_count */ 0, + /* token */ {0}, + { + /* meminfo[0] */ {NULL, 0, 0}, + /* meminfo[1] */ {NULL, 0, 0}, + /* meminfo[2] */ {NULL, 0, 0}, + /* meminfo[3] */ {NULL, 0, 0} + } }; -bool cheevos_loaded = false; -int cheats_are_enabled = 0; -int cheats_were_enabled = 0; +bool cheevos_loaded = false; +int cheats_are_enabled = 0; +int cheats_were_enabled = 0; /***************************************************************************** Supporting functions. @@ -405,6 +449,16 @@ static void cheevos_add_uint(char** aux, size_t* left, unsigned v) cheevos_add_string(aux, left, buffer); } +static void cheevos_add_int(char** aux, size_t* left, int v) +{ + char buffer[32]; + + snprintf(buffer, sizeof(buffer), "%d", v); + buffer[sizeof(buffer) - 1] = 0; + + cheevos_add_string(aux, left, buffer); +} + static void cheevos_log_var(const cheevos_var_t* var) { RARCH_LOG("CHEEVOS size: %s\n", @@ -608,6 +662,43 @@ static void cheevos_post_log_cheevo(const cheevo_t* cheevo) cheevos_build_memaddr(&cheevo->condition, memaddr, sizeof(memaddr)); RARCH_LOG("CHEEVOS memaddr (computed): %s\n", memaddr); } + +static void cheevos_log_lboard(const cheevos_leaderboard_t* lb) +{ + char mem[256]; + char* aux; + size_t left; + unsigned i; + + RARCH_LOG("CHEEVOS leaderboard %p\n", lb); + RARCH_LOG("CHEEVOS id: %u\n", lb->id); + RARCH_LOG("CHEEVOS title: %s\n", lb->title); + RARCH_LOG("CHEEVOS desc: %s\n", lb->description); + + cheevos_build_memaddr(&lb->start, mem, sizeof(mem)); + RARCH_LOG("CHEEVOS start: %s\n", mem); + + cheevos_build_memaddr(&lb->cancel, mem, sizeof(mem)); + RARCH_LOG("CHEEVOS cancel: %s\n", mem); + + cheevos_build_memaddr(&lb->submit, mem, sizeof(mem)); + RARCH_LOG("CHEEVOS submit: %s\n", mem); + + left = sizeof(mem); + aux = mem; + + for (i = 0; i < lb->value.count; i++) + { + if (i != 0) + cheevos_add_char(&aux, &left, '_'); + + cheevos_add_var(&lb->value.terms[i].var, &aux, &left); + cheevos_add_char(&aux, &left, '*'); + cheevos_add_int(&aux, &left, lb->value.terms[i].multiplier); + } + + RARCH_LOG("CHEEVOS value: %s\n", mem); +} #endif static uint32_t cheevos_djb2(const char* str, size_t length) @@ -633,11 +724,19 @@ static int cheevos_http_get(const char **result, size_t *size, int ret = net_http_get(result, size, url, timeout); #endif + if (ret == NET_HTTP_GET_OK) + { + if (*result != NULL) + { + return ret; + } + + RARCH_ERR("CHEEVOS error during HTTP GET: ok.\n"); + return NET_HTTP_GET_CONNECT_ERROR; + } + switch (ret) { - case NET_HTTP_GET_OK: - return ret; - case NET_HTTP_GET_MALFORMED_URL: msg = "malformed url"; break; @@ -651,11 +750,11 @@ static int cheevos_http_get(const char **result, size_t *size, break; default: - msg = "?"; + msg = "unknown error"; break; } - RARCH_ERR("CHEEVOS error getting %s: %s.\n", url, msg); + RARCH_ERR("CHEEVOS error during HTTP GET: %s.\n", msg); return ret; } @@ -756,6 +855,7 @@ static int cheevos_count__json_end_array(void *userdata) { cheevos_countud_t* ud = (cheevos_countud_t*)userdata; ud->in_cheevos = 0; + ud->in_lboards = 0; return 0; } @@ -767,6 +867,8 @@ static int cheevos_count__json_key(void *userdata, if (ud->field_hash == CHEEVOS_JSON_KEY_ACHIEVEMENTS) ud->in_cheevos = 1; + else if (ud->field_hash == CHEEVOS_JSON_KEY_LEADERBOARDS) + ud->in_lboards = 1; return 0; } @@ -785,12 +887,15 @@ static int cheevos_count__json_number(void *userdata, else if (flags == 5) ud->unofficial_count++; /* Unofficial achievements */ } + else if (ud->in_lboards && ud->field_hash == CHEEVOS_JSON_KEY_ID) + ud->lboard_count++; return 0; } static int cheevos_count_cheevos(const char *json, - unsigned *core_count, unsigned *unofficial_count) + unsigned *core_count, unsigned *unofficial_count, + unsigned *lboard_count) { static const jsonsax_handlers_t handlers = { @@ -813,11 +918,13 @@ static int cheevos_count_cheevos(const char *json, ud.in_cheevos = 0; ud.core_count = 0; ud.unofficial_count = 0; + ud.lboard_count = 0; res = jsonsax_parse(json, &handlers, (void*)&ud); *core_count = ud.core_count; *unofficial_count = ud.unofficial_count; + *lboard_count = ud.lboard_count; return res; } @@ -1061,7 +1168,12 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr) if (toupper(*str) == 'H') str++; else + { + if (toupper(*str) == 'V') + str++; + base = 10; + } } if (var->type != CHEEVOS_VAR_TYPE_VALUE_COMP) @@ -1256,6 +1368,117 @@ static int cheevos_parse_condition(cheevos_condition_t *condition, const char* m return 0; } +#ifdef CHEEVOS_ENABLE_LBOARDS +static void cheevos_free_condition(cheevos_condition_t* condition) +{ + unsigned i; + + if (condition->condsets) + { + for (i = 0; i < condition->count; i++) + { + free((void*)condition->condsets[i].conds); + } + + free((void*)condition->condsets); + } +} +#endif + +/***************************************************************************** +Parse the Mem field of leaderboards. +*****************************************************************************/ + +#ifdef CHEEVOS_ENABLE_LBOARDS +static int cheevos_parse_expression(cheevos_expr_t *expr, const char* mem) +{ + const char* aux; + char* end; + unsigned i; + expr->count = 1; + + for (aux = mem; *aux != '"'; aux++) + { + expr->count += *aux == '_'; + } + + expr->terms = (cheevos_term_t*)calloc(expr->count, sizeof(cheevos_term_t)); + + if (!expr->terms) + return -1; + + for (i = 0, aux = mem; i < expr->count; i++) + { + cheevos_parse_var(&expr->terms[i].var, &aux); + + if (*aux != '*') + { + free((void*)expr->terms); + return -1; + } + + expr->terms[i].multiplier = (int)strtol(aux + 1, &end, 10); + aux = end + 1; + } + + return 0; +} +#endif + +#ifdef CHEEVOS_ENABLE_LBOARDS +static int cheevos_parse_mem(cheevos_leaderboard_t *lb, const char* mem) +{ + lb->start.condsets = NULL; + lb->cancel.condsets = NULL; + lb->submit.condsets = NULL; + lb->value.terms = NULL; + + for (;;) + { + if (*mem == 'S' && mem[1] == 'T' && mem[2] == 'A' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->start, mem + 4)) + goto error; + } + else if (*mem == 'C' && mem[1] == 'A' && mem[2] == 'N' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->cancel, mem + 4)) + goto error; + } + else if (*mem == 'S' && mem[1] == 'U' && mem[2] == 'B' && mem[3] == ':') + { + if (cheevos_parse_condition(&lb->submit, mem + 4)) + goto error; + } + else if (*mem == 'V' && mem[1] == 'A' && mem[2] == 'L' && mem[3] == ':') + { + if (cheevos_parse_expression(&lb->value, mem + 4)) + goto error; + } + else + goto error; + + for (mem += 4;; mem++) + { + if (*mem == ':' && mem[1] == ':') + { + mem += 2; + break; + } + else if (*mem == '"') + return 0; + } + } + +error: + cheevos_free_condition(&lb->start); + cheevos_free_condition(&lb->cancel); + cheevos_free_condition(&lb->submit); + free((void*)lb->value.terms); + return -1; +} +#endif + /***************************************************************************** Load achievements from a JSON string. *****************************************************************************/ @@ -1317,11 +1540,40 @@ error: return -1; } +#ifdef CHEEVOS_ENABLE_LBOARDS +static int cheevos_new_lboard(cheevos_readud_t *ud) +{ + cheevos_leaderboard_t *lboard = cheevos_locals.leaderboards + ud->lboard_count++; + + lboard->id = strtol(ud->id.string, NULL, 10); + lboard->title = cheevos_dupstr(&ud->title); + lboard->description = cheevos_dupstr(&ud->desc); + + if (!lboard->title || !lboard->description) + goto error; + + if (cheevos_parse_mem(lboard, ud->memaddr.string)) + goto error; + +#ifdef CHEEVOS_VERBOSE + cheevos_log_lboard(lboard); +#endif + + return 0; + +error: + free((void*)lboard->title); + free((void*)lboard->description); + return -1; +} +#endif + static int cheevos_read__json_key( void *userdata, const char *name, size_t length) { cheevos_readud_t *ud = (cheevos_readud_t*)userdata; uint32_t hash = cheevos_djb2(name, length); + int common = ud->in_cheevos || ud->in_lboards; ud->field = NULL; @@ -1330,23 +1582,30 @@ static int cheevos_read__json_key( void *userdata, case CHEEVOS_JSON_KEY_ACHIEVEMENTS: ud->in_cheevos = 1; break; + case CHEEVOS_JSON_KEY_LEADERBOARDS: + ud->in_lboards = 1; + break; case CHEEVOS_JSON_KEY_CONSOLE_ID: ud->is_console_id = 1; break; case CHEEVOS_JSON_KEY_ID: - if (ud->in_cheevos) + if (common) ud->field = &ud->id; break; case CHEEVOS_JSON_KEY_MEMADDR: if (ud->in_cheevos) ud->field = &ud->memaddr; break; + case CHEEVOS_JSON_KEY_MEM: + if (ud->in_lboards) + ud->field = &ud->memaddr; + break; case CHEEVOS_JSON_KEY_TITLE: - if (ud->in_cheevos) + if (common) ud->field = &ud->title; break; case CHEEVOS_JSON_KEY_DESCRIPTION: - if (ud->in_cheevos) + if (common) ud->field = &ud->desc; break; case CHEEVOS_JSON_KEY_POINTS: @@ -1373,6 +1632,10 @@ static int cheevos_read__json_key( void *userdata, if (ud->in_cheevos) ud->field = &ud->flags; break; + case CHEEVOS_JSON_KEY_FORMAT: + if (ud->in_lboards) + ud->field = &ud->format; + break; default: break; } @@ -1419,6 +1682,10 @@ static int cheevos_read__json_end_object(void *userdata) if (ud->in_cheevos) return cheevos_new_cheevo(ud); +#ifdef CHEEVOS_ENABLE_LBOARDS + else if (ud->in_lboards) + return cheevos_new_lboard(ud); +#endif return 0; } @@ -1427,6 +1694,7 @@ static int cheevos_read__json_end_array(void *userdata) { cheevos_readud_t *ud = (cheevos_readud_t*)userdata; ud->in_cheevos = 0; + ud->in_lboards = 0; return 0; } @@ -1448,7 +1716,7 @@ static int cheevos_parse(const char *json) NULL }; - unsigned core_count, unofficial_count; + unsigned core_count, unofficial_count, lboard_count; int res; cheevos_readud_t ud; settings_t *settings = config_get_ptr(); @@ -1458,7 +1726,8 @@ static int cheevos_parse(const char *json) return 0; /* Count the number of achievements in the JSON file. */ - res = cheevos_count_cheevos(json, &core_count, &unofficial_count); + res = cheevos_count_cheevos(json, &core_count, &unofficial_count, + &lboard_count); if (res != JSONSAX_OK) return -1; @@ -1473,21 +1742,30 @@ static int cheevos_parse(const char *json) calloc(unofficial_count, sizeof(cheevo_t)); cheevos_locals.unofficial.count = unofficial_count; - if (!cheevos_locals.core.cheevos || !cheevos_locals.unofficial.cheevos) + cheevos_locals.leaderboards = (cheevos_leaderboard_t*) + calloc(lboard_count, sizeof(cheevos_leaderboard_t)); + cheevos_locals.lboard_count = lboard_count; + + if ( !cheevos_locals.core.cheevos || !cheevos_locals.unofficial.cheevos + || !cheevos_locals.leaderboards) { free((void*)cheevos_locals.core.cheevos); free((void*)cheevos_locals.unofficial.cheevos); - cheevos_locals.core.count = cheevos_locals.unofficial.count = 0; + free((void*)cheevos_locals.leaderboards); + cheevos_locals.core.count = cheevos_locals.unofficial.count = + cheevos_locals.lboard_count = 0; return -1; } /* Load the achievements. */ ud.in_cheevos = 0; + ud.in_lboards = 0; ud.is_console_id = 0; ud.field = NULL; ud.core_count = 0; ud.unofficial_count = 0; + ud.lboard_count = 0; if (jsonsax_parse(json, &handlers, (void*)&ud) != JSONSAX_OK) goto error; @@ -1535,7 +1813,6 @@ static unsigned cheevos_get_var_value(cheevos_var_t *var) if ( var->type == CHEEVOS_VAR_TYPE_ADDRESS || var->type == CHEEVOS_VAR_TYPE_DELTA_MEM) { - /* TODO Check with Scott if the bank id is needed */ const uint8_t *memory = cheevos_get_memory(var); unsigned live_val = 0; @@ -1950,6 +2227,162 @@ static void cheevos_test_cheevo_set(const cheevoset_t *set) } } +#ifdef CHEEVOS_ENABLE_LBOARDS +static int cheevos_test_lboard_condition(const cheevos_condition_t* condition) +{ + int dirty_conds = 0; + int reset_conds = 0; + int ret_val = 0; + int ret_val_sub_cond = condition->count == 1; + cheevos_condset_t *condset = condition->condsets; + const cheevos_condset_t *end = condset + condition->count; + + if (condset < end) + { + ret_val = cheevos_test_cond_set(condset, &dirty_conds, &reset_conds, 0); + condset++; + } + + while (condset < end) + { + ret_val_sub_cond |= cheevos_test_cond_set(condset, &dirty_conds, &reset_conds, 0); + condset++; + } + + if (reset_conds) + { + for (condset = condition->condsets; condset < end; condset++) + cheevos_reset_cond_set(condset, 0); + } + + return ret_val && ret_val_sub_cond; +} + +static int cheevos_expr_value(cheevos_expr_t* expr) +{ + cheevos_term_t* term = expr->terms; + unsigned i; + int value = 0; + + for (i = expr->count; i != 0; i--, term++) + { + value += cheevos_get_var_value(&term->var) * term->multiplier; + } + + return value; +} + +static void cheevos_make_lboard_url(const cheevos_leaderboard_t *lboard, + char* url, size_t url_size) +{ + settings_t *settings = config_get_ptr(); + char signature[64]; + MD5_CTX ctx; + uint8_t hash[16]; + + hash[0] = '\0'; + + snprintf(signature, sizeof(signature), "%u%s%u", lboard->id, + settings->cheevos.username, lboard->id); + + MD5_Init(&ctx); + MD5_Update(&ctx, (void*)signature, strlen(signature)); + MD5_Final(hash, &ctx); + + snprintf( + url, url_size, + "http://retroachievements.org/dorequest.php?r=submitlbentry&u=%s&t=%s&i=%u&s=%d" + "&v=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + settings->cheevos.username, cheevos_locals.token, lboard->id, + lboard->last_value, + hash[ 0], hash[ 1], hash[ 2], hash[ 3], + hash[ 4], hash[ 5], hash[ 6], hash[ 7], + hash[ 8], hash[ 9], hash[10], hash[11], + hash[12], hash[13], hash[14], hash[15] + ); + + url[url_size - 1] = 0; + +#ifdef CHEEVOS_LOG_URLS + cheevos_log_url("CHEEVOS url to submit the leaderboard: %s\n", url); +#endif +} +#endif + +#ifdef CHEEVOS_ENABLE_LBOARDS +static void cheevos_lboard_submit(void *task_data, void *user_data, const char *error) +{ + cheevos_leaderboard_t *lboard = (cheevos_leaderboard_t *)user_data; + + if (error == NULL) + { + RARCH_LOG("CHEEVOS submitted leaderboard %u.\n", lboard->id); + } + else + RARCH_ERR("CHEEVOS error submitting leaderboard %u\n", lboard->id); +#if 0 + { + char url[256]; + url[0] = '\0'; + + RARCH_ERR("CHEEVOS error submitting leaderboard %u, retrying...\n", lboard->id); + + cheevos_make_lboard_url(lboard, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, cheevos_lboard_submit, lboard); + } +#endif +} +#endif + +#ifdef CHEEVOS_ENABLE_LBOARDS +static void cheevos_test_leaderboards(void) +{ + cheevos_leaderboard_t* lboard = cheevos_locals.leaderboards; + unsigned i; + + for (i = cheevos_locals.lboard_count; i != 0; i--, lboard++) + { + if (lboard->active) + { + int value = cheevos_expr_value(&lboard->value); + + if (value != lboard->last_value) + { +#ifdef CHEEVOS_VERBOSE + RARCH_LOG("CHEEVOS value lboard %s %u\n", lboard->title, value); +#endif + lboard->last_value = value; + } + + if (cheevos_test_lboard_condition(&lboard->submit)) + { + char url[256]; + + cheevos_make_lboard_url(lboard, url, sizeof(url)); + task_push_http_transfer(url, true, NULL, cheevos_lboard_submit, lboard); + + RARCH_LOG("CHEEVOS submit lboard %s\n", lboard->title); + } + + if (cheevos_test_lboard_condition(&lboard->cancel)) + { + RARCH_LOG("CHEEVOS cancel lboard %s\n", lboard->title); + lboard->active = 0; + } + } + else + { + if (cheevos_test_lboard_condition(&lboard->start)) + { + RARCH_LOG("CHEEVOS start lboard %s\n", lboard->title); + lboard->active = 1; + lboard->last_value = -1; + } + } + } +} +#endif + /***************************************************************************** Free the loaded achievements. *****************************************************************************/ @@ -2698,13 +3131,17 @@ void cheevos_reset_game(void) const cheevo_t *end = cheevo + cheevos_locals.core.count; for (; cheevo < end; cheevo++) + { cheevo->last = 1; + } cheevo = cheevos_locals.unofficial.cheevos; end = cheevo + cheevos_locals.unofficial.count; for (; cheevo < end; cheevo++) + { cheevo->last = 1; + } } void cheevos_populate_menu(void *data, bool hardcore) @@ -2814,15 +3251,23 @@ void cheevos_populate_menu(void *data, bool hardcore) bool cheevos_get_description(cheevos_ctx_desc_t *desc) { - cheevo_t *cheevos = cheevos_locals.core.cheevos; - - if (desc->idx >= cheevos_locals.core.count) + if (cheevos_loaded) { - cheevos = cheevos_locals.unofficial.cheevos; - desc->idx -= cheevos_locals.unofficial.count; - } + cheevo_t *cheevos = cheevos_locals.core.cheevos; - strlcpy(desc->s, cheevos[desc->idx].description, desc->len); + if (desc->idx >= cheevos_locals.core.count) + { + cheevos = cheevos_locals.unofficial.cheevos; + desc->idx -= cheevos_locals.unofficial.count; + } + + strlcpy(desc->s, cheevos[desc->idx].description, desc->len); + } + else + { + *desc->s = 0; + } + return true; } @@ -2842,7 +3287,7 @@ bool cheevos_unload(void) cheevos_free_cheevo_set(&cheevos_locals.core); cheevos_free_cheevo_set(&cheevos_locals.unofficial); - cheevos_loaded = false; + cheevos_loaded = 0; return true; } @@ -2881,7 +3326,7 @@ void cheevos_test(void) if (settings->cheevos.test_unofficial) cheevos_test_cheevo_set(&cheevos_locals.unofficial); -#if 0 +#ifdef CHEEVOS_ENABLE_LBOARDS cheevos_test_leaderboards(); #endif } diff --git a/cheevos.h b/cheevos/cheevos.h similarity index 100% rename from cheevos.h rename to cheevos/cheevos.h diff --git a/command.c b/command.c index 03e8dd4f37..9dc14b11cd 100644 --- a/command.c +++ b/command.c @@ -43,7 +43,7 @@ #endif #ifdef HAVE_CHEEVOS -#include "cheevos.h" +#include "cheevos/cheevos.h" #endif #ifdef HAVE_MENU @@ -1350,15 +1350,6 @@ static bool event_init_content(void) content_get_status(&contentless, &is_inited); - if (contentless) - { -#ifdef HAVE_NETWORKING - if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)) - RARCH_ERR("%s\n", msg_hash_to_str(MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY)); -#endif - return true; - } - command_event_set_savestate_auto_index(); if (event_load_save_files()) @@ -1927,6 +1918,9 @@ bool command_event(enum event_command cmd, void *data) core_reset(); #ifdef HAVE_CHEEVOS cheevos_reset_game(); +#endif +#if HAVE_NETWORKING + netplay_driver_ctl(RARCH_NETPLAY_CTL_RESET, NULL); #endif break; case CMD_EVENT_SAVE_STATE: diff --git a/config.def.h b/config.def.h index 0866e35bda..6b01bc9e59 100644 --- a/config.def.h +++ b/config.def.h @@ -815,6 +815,9 @@ static const bool pause_nonactive = true; * It is measured in seconds. A value of 0 disables autosave. */ static const unsigned autosave_interval = 0; +/* Publicly announce netplay */ +static const bool netplay_public_announce = true; + /* Netplay without savestates/rewind */ static const bool netplay_stateless_mode = false; diff --git a/configuration.c b/configuration.c index 0954be6433..b40de26d25 100644 --- a/configuration.c +++ b/configuration.c @@ -728,6 +728,7 @@ static struct config_bool_setting *populate_settings_bool(settings_t *settings, SETTING_BOOL("all_users_control_menu", &settings->input.all_users_control_menu, true, all_users_control_menu, false); SETTING_BOOL("menu_swap_ok_cancel_buttons", &settings->input.menu_swap_ok_cancel_buttons, true, menu_swap_ok_cancel_buttons, false); #ifdef HAVE_NETWORKING + SETTING_BOOL("netplay_public_announce", &settings->netplay.public_announce, true, netplay_public_announce, false); SETTING_BOOL("netplay_stateless_mode", &settings->netplay.stateless_mode, false, netplay_stateless_mode, false); SETTING_BOOL("netplay_client_swap_input", &settings->netplay.swap_input, true, netplay_client_swap_input, false); #endif @@ -1671,7 +1672,7 @@ static bool check_shader_compatibility(enum file_path_enum enum_idx) } if (string_is_equal("gl", settings->video.driver) || - string_is_equal("d3d9", settings->video.driver)) + string_is_equal("d3d", settings->video.driver)) { if (enum_idx == FILE_PATH_SLANGP_EXTENSION) return false; diff --git a/configuration.h b/configuration.h index b851db61c0..a8f1e20e64 100644 --- a/configuration.h +++ b/configuration.h @@ -403,6 +403,7 @@ typedef struct settings #ifdef HAVE_NETWORKING struct { + bool public_announce; char server[255]; unsigned port; bool stateless_mode; diff --git a/core_info.c b/core_info.c index 2525fc5b11..1d91ecd444 100644 --- a/core_info.c +++ b/core_info.c @@ -59,6 +59,8 @@ static void core_info_list_resolve_all_extensions( (strlen(core_info_list->list[i].supported_extensions) + 2); } + all_ext_len += strlen("7z|") + strlen("zip|"); + if (all_ext_len) all_ext = (char*)calloc(1, all_ext_len); @@ -76,6 +78,12 @@ static void core_info_list_resolve_all_extensions( core_info_list->list[i].supported_extensions, all_ext_len); strlcat(core_info_list->all_ext, "|", all_ext_len); } +#ifdef HAVE_7ZIP + strlcat(core_info_list->all_ext, "7z|", all_ext_len); +#endif +#ifdef HAVE_ZLIB + strlcat(core_info_list->all_ext, "zip|", all_ext_len); +#endif } static void core_info_list_resolve_all_firmware( diff --git a/deps/miniupnpc/Changelog.txt b/deps/miniupnpc/Changelog.txt new file mode 100644 index 0000000000..76d947b202 --- /dev/null +++ b/deps/miniupnpc/Changelog.txt @@ -0,0 +1,684 @@ +$Id: Changelog.txt,v 1.226 2016/12/16 08:57:19 nanard Exp $ +miniUPnP client Changelog. + +2016/11/11: + check strlen before memcmp in XML parsing portlistingparse.c + fix build under SOLARIS and CYGWIN + +2016/10/11: + Add python 3 compatibility to IGD test + +VERSION 2.0 : released 2016/04/19 + +2016/01/24: + change miniwget to return HTTP status code + increments API_VERSION to 16 + +2016/01/22: + Improve UPNPIGD_IsConnected() to check if WAN address is not private. + parse HTTP response status line in miniwget.c + +2015/10/26: + snprintf() overflow check. check overflow in simpleUPnPcommand2() + +2015/10/25: + fix compilation with old macs + fix compilation with mingw32 (for Appveyor) + fix python module for python <= 2.3 + +2015/10/08: + Change sameport to localport + see https://github.com/miniupnp/miniupnp/pull/120 + increments API_VERSION to 15 + +2015/09/15: + Fix buffer overflow in igd_desc_parse.c/IGDstartelt() + Discovered by Aleksandar Nikolic of Cisco Talos + +2015/08/28: + move ssdpDiscoverDevices() to minissdpc.c + +2015/08/27: + avoid unix socket leak in getDevicesFromMiniSSDPD() + +2015/08/16: + Also accept "Up" as ConnectionStatus value + +2015/07/23: + split getDevicesFromMiniSSDPD + add ttl argument to upnpDiscover() functions + increments API_VERSION to 14 + +2015/07/22: + Read USN from SSDP messages. + +2015/07/15: + Check malloc/calloc + +2015/06/16: + update getDevicesFromMiniSSDPD() to process longer minissdpd + responses + +2015/05/22: + add searchalltypes param to upnpDiscoverDevices() + increments API_VERSION to 13 + +2015/04/30: + upnpc: output version on the terminal + +2015/04/27: + _BSD_SOURCE is deprecated in favor of _DEFAULT_SOURCE + fix CMakeLists.txt COMPILE_DEFINITIONS + fix getDevicesFromMiniSSDPD() not setting scope_id + improve -r command of upnpc command line tool + +2014/11/17: + search all : + upnpDiscoverDevices() / upnpDiscoverAll() functions + listdevices executable + increment API_VERSION to 12 + validate igd_desc_parse + +2014/11/13: + increment API_VERSION to 11 + +2014/11/05: + simplified function GetUPNPUrls() + +2014/09/11: + use remoteHost arg of DeletePortMapping + +2014/09/06: + Fix python3 build + +2014/07/01: + Fix parsing of IGD2 root descriptions + +2014/06/10: + rename LIBSPEC to MINIUPNP_LIBSPEC + +2014/05/15: + Add support for IGD2 AddAnyPortMapping and DeletePortMappingRange + +2014/02/05: + handle EINPROGRESS after connect() + +2014/02/03: + minixml now handle XML comments + +VERSION 1.9 : released 2014/01/31 + +2014/01/31: + added argument remoteHost to UPNP_GetSpecificPortMappingEntry() + increment API_VERSION to 10 + +2013/12/09: + --help and -h arguments in upnpc.c + +2013/10/07: + fixed potential buffer overrun in miniwget.c + Modified UPNP_GetValidIGD() to check for ExternalIpAddress + +2013/08/01: + define MAXHOSTNAMELEN if not already done + +2013/06/06: + update upnpreplyparse to allow larger values (128 chars instead of 64) + +2013/05/14: + Update upnpreplyparse to take into account "empty" elements + validate upnpreplyparse.c code with "make check" + +2013/05/03: + Fix Solaris build thanks to Maciej Małecki + +2013/04/27: + Fix testminiwget.sh for BSD + +2013/03/23: + Fixed Makefile for *BSD + +2013/03/11: + Update Makefile to use JNAerator version 0.11 + +2013/02/11: + Fix testminiwget.sh for use with dash + Use $(DESTDIR) in Makefile + +VERSION 1.8 : released 2013/02/06 + +2012/10/16: + fix testminiwget with no IPv6 support + +2012/09/27: + Rename all include guards to not clash with C99 + (7.1.3 Reserved identifiers). + +2012/08/30: + Added -e option to upnpc program (set description for port mappings) + +2012/08/29: + Python 3 support (thanks to Christopher Foo) + +2012/08/11: + Fix a memory link in UPNP_GetValidIGD() + Try to handle scope id in link local IPv6 URL under MS Windows + +2012/07/20: + Disable HAS_IP_MREQN on DragonFly BSD + +2012/06/28: + GetUPNPUrls() now inserts scope into link-local IPv6 addresses + +2012/06/23: + More error return checks in upnpc.c + #define MINIUPNPC_GET_SRC_ADDR enables receivedata() to get scope_id + parseURL() now parses IPv6 addresses scope + new parameter for miniwget() : IPv6 address scope + increment API_VERSION to 9 + +2012/06/20: + fixed CMakeLists.txt + +2012/05/29 + Improvements in testminiwget.sh + +VERSION 1.7 : released 2012/05/24 + +2012/05/01: + Cleanup settings of CFLAGS in Makefile + Fix signed/unsigned integer comparaisons + +2012/04/20: + Allow to specify protocol with TCP or UDP for -A option + +2012/04/09: + Only try to fetch XML description once in UPNP_GetValidIGD() + Added -ansi flag to compilation, and fixed C++ comments to ANSI C comments. + +2012/04/05: + minor improvements to minihttptestserver.c + +2012/03/15: + upnperrors.c returns valid error string for unrecognized error codes + +2012/03/08: + make minihttptestserver listen on loopback interface instead of 0.0.0.0 + +2012/01/25: + Maven installation thanks to Alexey Kuznetsov + +2012/01/21: + Replace WIN32 macro by _WIN32 + +2012/01/19: + Fixes in java wrappers thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/fix-javatest/miniupnpc + Make and install .deb packages (python) thanks to Alexey Kuznetsov : + https://github.com/axet/miniupnp/tree/feature-debbuild/miniupnpc + +2012/01/07: + The multicast interface can now be specified by name with IPv4. + +2012/01/02: + Install man page + +2011/11/25: + added header to Port Mappings list in upnpc.c + +2011/10/09: + Makefile : make clean now removes jnaerator generated files. + MINIUPNPC_VERSION in miniupnpc.h (updated by make) + +2011/09/12: + added rootdescURL to UPNPUrls structure. + +VERSION 1.6 : released 2011/07/25 + +2011/07/25: + Update doc for version 1.6 release + +2011/06/18: + Fix for windows in miniwget.c + +2011/06/04: + display remote host in port mapping listing + +2011/06/03: + Fix in make install : there were missing headers + +2011/05/26: + Fix the socket leak in miniwget thanks to Richard Marsh. + Permit to add leaseduration in -a command. Display lease duration. + +2011/05/15: + Try both LinkLocal and SiteLocal multicast address for SSDP in IPv6 + +2011/05/09: + add a test in testminiwget.sh. + more error checking in miniwget.c + +2011/05/06: + Adding some tool to test and validate miniwget.c + simplified and debugged miniwget.c + +2011/04/11: + moving ReceiveData() to a receivedata.c file. + parsing presentation url + adding IGD v2 WANIPv6FirewallControl commands + +2011/04/10: + update of miniupnpcmodule.c + comments in miniwget.c, update in testminiwget + Adding errors codes from IGD v2 + new functions in upnpc.c for IGD v2 + +2011/04/09: + Support for litteral ip v6 address in miniwget + +2011/04/08: + Adding support for urn:schemas-upnp-org:service:WANIPv6FirewallControl:1 + Updating APIVERSION + Supporting IPV6 in upnpDiscover() + Adding a -6 option to upnpc command line tool + +2011/03/18: + miniwget/parseURL() : return an error when url param is null. + fixing GetListOfPortMappings() + +2011/03/14: + upnpDiscover() now reporting an error code. + improvements in comments. + +2011/03/11: + adding miniupnpcstrings.h.cmake and CMakeLists.txt files. + +2011/02/15: + Implementation of GetListOfPortMappings() + +2011/02/07: + updates to minixml to support character data starting with spaces + minixml now support CDATA + upnpreplyparse treats specificaly + change in simpleUPnPcommand to return the buffer (simplification) + +2011/02/06: + Added leaseDuration argument to AddPortMapping() + Starting to implement GetListOfPortMappings() + +2011/01/11: + updating wingenminiupnpcstrings.c + +2011/01/04: + improving updateminiupnpcstrings.sh + +VERSION 1.5 : released 2011/01/01 + +2010/12/21: + use NO_GETADDRINFO macro to disable the use of getaddrinfo/freeaddrinfo + +2010/12/11: + Improvements on getHTTPResponse() code. + +2010/12/09: + new code for miniwget that handle Chunked transfer encoding + using getHTTPResponse() in SOAP call code + Adding MANIFEST.in for 'python setup.py bdist_rpm' + +2010/11/25: + changes to minissdpc.c to compile under Win32. + see http://miniupnp.tuxfamily.org/forum/viewtopic.php?t=729 + +2010/09/17: + Various improvement to Makefile from Michał Górny + +2010/08/05: + Adding the script "external-ip.sh" from Reuben Hawkins + +2010/06/09: + update to python module to match modification made on 2010/04/05 + update to Java test code to match modification made on 2010/04/05 + all UPNP_* function now return an error if the SOAP request failed + at HTTP level. + +2010/04/17: + Using GetBestRoute() under win32 in order to find the + right interface to use. + +2010/04/12: + Retrying with HTTP/1.1 if HTTP/1.0 failed. see + http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1703 + +2010/04/07: + avoid returning duplicates in upnpDiscover() + +2010/04/05: + Create a connecthostport.h/.c with connecthostport() function + and use it in miniwget and miniupnpc. + Use getnameinfo() instead of inet_ntop or inet_ntoa + Work to make miniupnpc IPV6 compatible... + Add java test code. + Big changes in order to support device having both WANIPConnection + and WANPPPConnection. + +2010/04/04: + Use getaddrinfo() instead of gethostbyname() in miniwget. + +2010/01/06: + #define _DARWIN_C_SOURCE for Mac OS X + +2009/12/19: + Improve MinGW32 build + +2009/12/11: + adding a MSVC9 project to build the static library and executable + +2009/12/10: + Fixing some compilation stuff for Windows/MinGW + +2009/12/07: + adaptations in Makefile and updateminiupnpcstring.sh for AmigaOS + some fixes for Windows when using virtual ethernet adapters (it is the + case with VMWare installed). + +2009/12/04: + some fixes for AmigaOS compilation + Changed HTTP version to HTTP/1.0 for Soap too (to prevent chunked + transfer encoding) + +2009/12/03: + updating printIDG and testigddescparse.c for debug. + modifications to compile under AmigaOS + adding a testminiwget program + Changed miniwget to advertise itself as HTTP/1.0 to prevent chunked + transfer encoding + +2009/11/26: + fixing updateminiupnpcstrings.sh to take into account + which command that does not return an error code. + +VERSION 1.4 : released 2009/10/30 + +2009/10/16: + using Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS in python module. + +2009/10/10: + Some fixes for compilation under Solaris + compilation fixes : http://miniupnp.tuxfamily.org/forum/viewtopic.php?p=1464 + +2009/09/21: + fixing the code to ignore EINTR during connect() calls. + +2009/08/07: + Set socket timeout for connect() + Some cleanup in miniwget.c + +2009/08/04: + remove multiple redirections with -d in upnpc.c + Print textual error code in upnpc.c + Ignore EINTR during the connect() and poll() calls. + +2009/07/29: + fix in updateminiupnpcstrings.sh if OS name contains "/" + Sending a correct value for MX: field in SSDP request + +2009/07/20: + Change the Makefile to compile under Mac OS X + Fixed a stackoverflow in getDevicesFromMiniSSDPD() + +2009/07/09: + Compile under Haiku + generate miniupnpcstrings.h.in from miniupnpcstrings.h + +2009/06/04: + patching to compile under CygWin and cross compile for minGW + +VERSION 1.3 : + +2009/04/17: + updating python module + Use strtoull() when using C99 + +2009/02/28: + Fixed miniwget.c for compiling under sun + +2008/12/18: + cleanup in Makefile (thanks to Paul de Weerd) + minissdpc.c : win32 compatibility + miniupnpc.c : changed xmlns prefix from 'm' to 'u' + Removed NDEBUG (using DEBUG) + +2008/10/14: + Added the ExternalHost argument to DeletePortMapping() + +2008/10/11: + Added the ExternalHost argument to AddPortMapping() + Put a correct User-Agent: header in HTTP requests. + +VERSION 1.2 : + +2008/10/07: + Update docs + +2008/09/25: + Integrated sameport patch from Dario Meloni : Added a "sameport" + argument to upnpDiscover(). + +2008/07/18: + small modif to make Clang happy :) + +2008/07/17: + #define SOAPPREFIX "s" in miniupnpc.c in order to remove SOAP-ENV... + +2008/07/14: + include declspec.h in installation (to /usr/include/miniupnpc) + +VERSION 1.1 : + +2008/07/04: + standard options for install/ln instead of gnu-specific stuff. + +2008/07/03: + now builds a .dll and .lib with win32. (mingw32) + +2008/04/28: + make install now install the binary of the upnpc tool + +2008/04/27: + added testupnpigd.py + added error strings for miniupnpc "internal" errors + improved python module error/exception reporting. + +2008/04/23: + Completely rewrite igd_desc_parse.c in order to be compatible with + Linksys WAG200G + Added testigddescparse + updated python module + +VERSION 1.0 : + +2008/02/21: + put some #ifdef DEBUG around DisplayNameValueList() + +2008/02/18: + Improved error reporting in upnpcommands.c + UPNP_GetStatusInfo() returns LastConnectionError + +2008/02/16: + better error handling in minisoap.c + improving display of "valid IGD found" in upnpc.c + +2008/02/03: + Fixing UPNP_GetValidIGD() + improved make install :) + +2007/12/22: + Adding upnperrors.c/h to provide a strupnperror() function + used to translate UPnP error codes to string. + +2007/12/19: + Fixing getDevicesFromMiniSSDPD() + improved error reporting of UPnP functions + +2007/12/18: + It is now possible to specify a different location for MiniSSDPd socket. + working with MiniSSDPd is now more efficient. + python module improved. + +2007/12/16: + improving error reporting + +2007/12/13: + Try to improve compatibility by using HTTP/1.0 instead of 1.1 and + XML a bit different for SOAP. + +2007/11/25: + fixed select() call for linux + +2007/11/15: + Added -fPIC to CFLAG for better shared library code. + +2007/11/02: + Fixed a potential socket leak in miniwget2() + +2007/10/16: + added a parameter to upnpDiscover() in order to allow the use of another + interface than the default multicast interface. + +2007/10/12: + Fixed the creation of symbolic link in Makefile + +2007/10/08: + Added man page + +2007/10/02: + fixed memory bug in GetUPNPUrls() + +2007/10/01: + fixes in the Makefile + Added UPNP_GetIGDFromUrl() and adapted the sample program accordingly. + Added SONAME in the shared library to please debian :) + fixed MS Windows compilation (minissdpd is not available under MS Windows). + +2007/09/25: + small change to Makefile to be able to install in a different location + (default is /usr) + +2007/09/24: + now compiling both shared and static library + +2007/09/19: + Cosmetic changes on upnpc.c + +2007/09/02: + adapting to new miniSSDPd (release version ?) + +2007/08/31: + Usage of miniSSDPd to skip discovery process. + +2007/08/27: + fixed python module to allow compilation with Python older than Python 2.4 + +2007/06/12: + Added a python module. + +2007/05/19: + Fixed compilation under MinGW + +2007/05/15: + fixed a memory leak in AddPortMapping() + Added testupnpreplyparse executable to check the parsing of + upnp soap messages + minixml now ignore namespace prefixes. + +2007/04/26: + upnpc now displays external ip address with -s or -l + +2007/04/11: + changed MINIUPNPC_URL_MAXSIZE to 128 to accomodate the "BT Voyager 210" + +2007/03/19: + cleanup in miniwget.c + +2007/03/01: + Small typo fix... + +2007/01/30: + Now parsing the HTTP header from SOAP responses in order to + get content-length value. + +2007/01/29: + Fixed the Soap Query to speedup the HTTP request. + added some Win32 DLL stuff... + +2007/01/27: + Fixed some WIN32 compatibility issues + +2006/12/14: + Added UPNPIGD_IsConnected() function in miniupnp.c/.h + Added UPNP_GetValidIGD() in miniupnp.c/.h + cleaned upnpc.c main(). now using UPNP_GetValidIGD() + +2006/12/07: + Version 1.0-RC1 released + +2006/12/03: + Minor changes to compile under SunOS/Solaris + +2006/11/30: + made a minixml parser validator program + updated minixml to handle attributes correctly + +2006/11/22: + Added a -r option to the upnpc sample thanks to Alexander Hubmann. + +2006/11/19: + Cleanup code to make it more ANSI C compliant + +2006/11/10: + detect and display local lan address. + +2006/11/04: + Packets and Bytes Sent/Received are now unsigned int. + +2006/11/01: + Bug fix thanks to Giuseppe D'Angelo + +2006/10/31: + C++ compatibility for .h files. + Added a way to get ip Address on the LAN used to reach the IGD. + +2006/10/25: + Added M-SEARCH to the services in the discovery process. + +2006/10/22: + updated the Makefile to use makedepend, added a "make install" + update Makefile + +2006/10/20: + fixing the description url parsing thanks to patch sent by + Wayne Dawe. + Fixed/translated some comments. + Implemented a better discover process, first looking + for IGD then for root devices (as some devices only reply to + M-SEARCH for root devices). + +2006/09/02: + added freeUPNPDevlist() function. + +2006/08/04: + More command line arguments checking + +2006/08/01: + Added the .bat file to compile under Win32 with minGW32 + +2006/07/31: + Fixed the rootdesc parser (igd_desc_parse.c) + +2006/07/20: + parseMSEARCHReply() is now returning the ST: line as well + starting changes to detect several UPnP devices on the network + +2006/07/19: + using GetCommonLinkProperties to get down/upload bitrate + diff --git a/deps/miniupnpc/LICENSE b/deps/miniupnpc/LICENSE new file mode 100644 index 0000000000..0816733704 --- /dev/null +++ b/deps/miniupnpc/LICENSE @@ -0,0 +1,27 @@ +MiniUPnPc +Copyright (c) 2005-2016, Thomas BERNARD +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. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. + diff --git a/deps/miniupnpc/MANIFEST.in b/deps/miniupnpc/MANIFEST.in new file mode 100644 index 0000000000..54b86f95e3 --- /dev/null +++ b/deps/miniupnpc/MANIFEST.in @@ -0,0 +1,5 @@ +include README +include miniupnpcmodule.c +include setup.py +include *.h +include libminiupnpc.a diff --git a/deps/miniupnpc/Makefile b/deps/miniupnpc/Makefile new file mode 100644 index 0000000000..aea07e7d52 --- /dev/null +++ b/deps/miniupnpc/Makefile @@ -0,0 +1,274 @@ +# $Id: Makefile,v 1.134 2016/10/07 09:04:36 nanard Exp $ +# MiniUPnP Project +# http://miniupnp.free.fr/ +# http://miniupnp.tuxfamily.org/ +# https://github.com/miniupnp/miniupnp +# (c) 2005-2016 Thomas Bernard +# to install use : +# $ make DESTDIR=/tmp/dummylocation install +# or +# $ INSTALLPREFIX=/usr/local make install +# or +# $ make install (default INSTALLPREFIX is /usr) +OS = $(shell uname -s) +VERSION = $(shell cat VERSION) + +ifeq ($(OS), Darwin) +JARSUFFIX=mac +LIBTOOL ?= $(shell which libtool) +endif +ifeq ($(OS), Linux) +JARSUFFIX=linux +endif +ifneq (,$(findstring NT-5.1,$(OS))) +JARSUFFIX=win32 +endif + +HAVE_IPV6 ?= yes +export HAVE_IPV6 + +CC ?= gcc +#AR = gar +#CFLAGS = -O -g -DDEBUG +CFLAGS ?= -O +CFLAGS += -Wall +CFLAGS += -W -Wstrict-prototypes +CFLAGS += -fno-common +CFLAGS += -DMINIUPNPC_SET_SOCKET_TIMEOUT +CFLAGS += -DMINIUPNPC_GET_SRC_ADDR +CFLAGS += -D_BSD_SOURCE +CFLAGS += -D_DEFAULT_SOURCE +ifeq ($(OS), NetBSD) +CFLAGS += -D_NETBSD_SOURCE +endif +ifneq ($(OS), FreeBSD) +ifneq ($(OS), Darwin) +#CFLAGS += -D_POSIX_C_SOURCE=200112L +CFLAGS += -D_XOPEN_SOURCE=600 +endif +endif +#CFLAGS += -ansi +# -DNO_GETADDRINFO +INSTALL = install +SH = /bin/sh + +ifeq (SunOS, $(OS)) + LDLIBS=-lsocket -lnsl -lresolv + CFLAGS += -D__EXTENSIONS__ + CFLAGS += -std=c99 +endif + +# APIVERSION is used to build SONAME +APIVERSION = 16 + +SRCS = igd_desc_parse.c miniupnpc.c minixml.c minisoap.c miniwget.c \ + upnpcommands.c upnpreplyparse.c \ + minixmlvalid.c minissdpc.c \ + upnperrors.c \ + connecthostport.c portlistingparse.c receivedata.c \ + upnpdev.c miniupnpcmodule.c + +LIBOBJS = miniwget.o minixml.o igd_desc_parse.o minisoap.o \ + miniupnpc.o upnpreplyparse.o upnpcommands.o upnperrors.o \ + connecthostport.o portlistingparse.o receivedata.o upnpdev.o + +ifneq ($(OS), AmigaOS) +ifeq (,$(findstring CYGWIN,$(OS))) +CFLAGS := -fPIC $(CFLAGS) +endif +LIBOBJS := $(LIBOBJS) minissdpc.o +endif + +OBJS = $(patsubst %.c,%.o,$(SRCS)) + +# HEADERS to install +HEADERS = miniupnpc.h miniwget.h upnpcommands.h igd_desc_parse.h \ + upnpreplyparse.h upnperrors.h miniupnpctypes.h \ + portlistingparse.h \ + upnpdev.h \ + miniupnpc_declspec.h + +# library names +LIBRARY = libminiupnpc.a +ifeq ($(OS), Darwin) + SHAREDLIBRARY = libminiupnpc.dylib + SONAME = $(basename $(SHAREDLIBRARY)).$(APIVERSION).dylib + CFLAGS := -D_DARWIN_C_SOURCE $(CFLAGS) +else +ifeq ($(JARSUFFIX), win32) + SHAREDLIBRARY = miniupnpc.dll +else + # Linux/BSD/etc. + SHAREDLIBRARY = libminiupnpc.so + SONAME = $(SHAREDLIBRARY).$(APIVERSION) +endif +endif + +EXECUTABLES = upnpc-static + +ifneq ($(OS), AmigaOS) +EXECUTABLES := $(EXECUTABLES) upnpc-shared +endif + +LIBDIR ?= lib +# install directories +ifeq ($(strip $(PREFIX)),) +INSTALLPREFIX ?= /usr +else +INSTALLPREFIX ?= $(PREFIX) +endif +INSTALLDIRINC = $(INSTALLPREFIX)/include/miniupnpc +INSTALLDIRLIB = $(INSTALLPREFIX)/$(LIBDIR) +INSTALLDIRBIN = $(INSTALLPREFIX)/bin +INSTALLDIRMAN = $(INSTALLPREFIX)/share/man + +FILESTOINSTALL = $(LIBRARY) $(EXECUTABLES) +ifneq ($(OS), AmigaOS) +FILESTOINSTALL := $(FILESTOINSTALL) $(SHAREDLIBRARY) +endif + + +.PHONY: install clean depend all check test everything \ + updateversion +# validateminixml validateminiwget + +all: $(LIBRARY) $(EXECUTABLES) + +test: check + +check: validateminixml validateminiwget validateupnpreplyparse \ + validateportlistingparse validateigddescparse + +everything: all + +validateminixml: minixmlvalid + @echo "minixml validation test" + ./minixmlvalid + touch $@ + +validateminiwget: testminiwget minihttptestserver testminiwget.sh + @echo "miniwget validation test" + ./testminiwget.sh + touch $@ + +validateupnpreplyparse: testupnpreplyparse testupnpreplyparse.sh + @echo "upnpreplyparse validation test" + ./testupnpreplyparse.sh + touch $@ + +validateportlistingparse: testportlistingparse + @echo "portlistingparse validation test" + ./testportlistingparse + touch $@ + +validateigddescparse: testigddescparse + @echo "igd desc parse validation test" + ./testigddescparse testdesc/new_LiveBox_desc.xml testdesc/new_LiveBox_desc.values + ./testigddescparse testdesc/linksys_WAG200G_desc.xml testdesc/linksys_WAG200G_desc.values + touch $@ + +clean: + $(RM) $(LIBRARY) $(SHAREDLIBRARY) $(EXECUTABLES) $(OBJS) miniupnpcstrings.h + +distclean: clean + +updateversion: miniupnpc.h + cp miniupnpc.h miniupnpc.h.bak + sed 's/\(.*MINIUPNPC_API_VERSION\s\+\)[0-9]\+/\1$(APIVERSION)/' < miniupnpc.h.bak > miniupnpc.h + +install: updateversion $(FILESTOINSTALL) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC) + $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB) + $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB) +ifneq ($(OS), AmigaOS) + $(INSTALL) -m 644 $(SHAREDLIBRARY) $(DESTDIR)$(INSTALLDIRLIB)/$(SONAME) + ln -fs $(SONAME) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY) +endif + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN) +ifeq ($(OS), AmigaOS) + $(INSTALL) -m 755 upnpc-static $(DESTDIR)$(INSTALLDIRBIN)/upnpc +else + $(INSTALL) -m 755 upnpc-shared $(DESTDIR)$(INSTALLDIRBIN)/upnpc +endif + $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip +ifneq ($(OS), AmigaOS) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRMAN)/man3 + $(INSTALL) -m 644 man3/miniupnpc.3 $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 +ifeq ($(OS), Linux) + gzip -f $(DESTDIR)$(INSTALLDIRMAN)/man3/miniupnpc.3 +endif +endif + +install-static: updateversion $(FILESTOINSTALL) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRINC) + $(INSTALL) -m 644 $(HEADERS) $(DESTDIR)$(INSTALLDIRINC) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRLIB) + $(INSTALL) -m 644 $(LIBRARY) $(DESTDIR)$(INSTALLDIRLIB) + $(INSTALL) -d $(DESTDIR)$(INSTALLDIRBIN) + $(INSTALL) -m 755 external-ip.sh $(DESTDIR)$(INSTALLDIRBIN)/external-ip + +cleaninstall: + $(RM) -r $(DESTDIR)$(INSTALLDIRINC) + $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(LIBRARY) + $(RM) $(DESTDIR)$(INSTALLDIRLIB)/$(SHAREDLIBRARY) + +depend: + makedepend -Y -- $(CFLAGS) -- $(SRCS) 2>/dev/null + +$(LIBRARY): $(LIBOBJS) +ifeq ($(OS), Darwin) + $(LIBTOOL) -static -o $@ $? +else + $(AR) crs $@ $? +endif + +$(SHAREDLIBRARY): $(LIBOBJS) +ifeq ($(OS), Darwin) +# $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(SONAME) -o $@ $^ + $(CC) -dynamiclib $(LDFLAGS) -Wl,-install_name,$(INSTALLDIRLIB)/$(SONAME) -o $@ $^ +else + $(CC) -shared $(LDFLAGS) -Wl,-soname,$(SONAME) -o $@ $^ +endif + +upnpc-static: $(LIBRARY) + $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) + +upnpc-shared: $(SHAREDLIBRARY) + $(CC) $(LDFLAGS) -o $@ $^ $(LOADLIBES) $(LDLIBS) + +minixmlvalid: minixml.o minixmlvalid.o + +miniupnpcstrings.h: miniupnpcstrings.h.in updateminiupnpcstrings.sh VERSION + $(SH) updateminiupnpcstrings.sh + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +igd_desc_parse.o: igd_desc_parse.h +miniupnpc.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h upnpdev.h +miniupnpc.o: minissdpc.h miniwget.h minisoap.h minixml.h upnpcommands.h +miniupnpc.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h +miniupnpc.o: connecthostport.h +minixml.o: minixml.h +minisoap.o: minisoap.h miniupnpcstrings.h +miniwget.o: miniupnpcstrings.h miniwget.h miniupnpc_declspec.h +miniwget.o: connecthostport.h receivedata.h +upnpcommands.o: upnpcommands.h upnpreplyparse.h portlistingparse.h +upnpcommands.o: miniupnpc_declspec.h miniupnpctypes.h miniupnpc.h +upnpcommands.o: igd_desc_parse.h upnpdev.h +upnpreplyparse.o: upnpreplyparse.h minixml.h +minixmlvalid.o: minixml.h +minissdpc.o: minissdpc.h miniupnpc_declspec.h upnpdev.h miniupnpc.h +minissdpc.o: igd_desc_parse.h receivedata.h codelength.h +upnperrors.o: upnperrors.h miniupnpc_declspec.h upnpcommands.h +upnperrors.o: upnpreplyparse.h portlistingparse.h miniupnpctypes.h +upnperrors.o: miniupnpc.h igd_desc_parse.h upnpdev.h +connecthostport.o: connecthostport.h +portlistingparse.o: portlistingparse.h miniupnpc_declspec.h miniupnpctypes.h +portlistingparse.o: minixml.h +receivedata.o: receivedata.h +upnpdev.o: upnpdev.h miniupnpc_declspec.h +testportlistingparse.o: miniupnpctypes.h +miniupnpcmodule.o: miniupnpc.h miniupnpc_declspec.h igd_desc_parse.h +miniupnpcmodule.o: upnpdev.h upnpcommands.h upnpreplyparse.h +miniupnpcmodule.o: portlistingparse.h miniupnpctypes.h upnperrors.h diff --git a/deps/miniupnpc/README b/deps/miniupnpc/README new file mode 100644 index 0000000000..91535dbc8b --- /dev/null +++ b/deps/miniupnpc/README @@ -0,0 +1,64 @@ +Project: miniupnp +Project web page: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ +github: https://github.com/miniupnp/miniupnp +freecode: http://freecode.com/projects/miniupnp +Author: Thomas Bernard +Copyright (c) 2005-2016 Thomas Bernard +This software is subject to the conditions detailed in the +LICENSE file provided within this distribution. + + +* miniUPnP Client - miniUPnPc * + +To compile, simply run 'gmake' (could be 'make' on your system). +Under win32, to compile with MinGW, type "mingw32make.bat". +MS Visual C solution and project files are supplied in the msvc/ subdirectory. + +The compilation is known to work under linux, FreeBSD, +OpenBSD, MacOS X, AmigaOS and cygwin. +The official AmigaOS4.1 SDK was used for AmigaOS4 and GeekGadgets for AmigaOS3. +upx (http://upx.sourceforge.net) is used to compress the win32 .exe files. + +To install the library and headers on the system use : +> su +> make install +> exit + +alternatively, to install into a specific location, use : +> INSTALLPREFIX=/usr/local make install + +upnpc.c is a sample client using the libminiupnpc. +To use the libminiupnpc in your application, link it with +libminiupnpc.a (or .so) and use the following functions found in miniupnpc.h, +upnpcommands.h and miniwget.h : +- upnpDiscover() +- UPNP_GetValidIGD() +- miniwget() +- parserootdesc() +- GetUPNPUrls() +- UPNP_* (calling UPNP methods) + +Note : use #include etc... for the includes +and -lminiupnpc for the link + +Discovery process is speeded up when MiniSSDPd is running on the machine. + + +* Python module * + +you can build a python module with 'make pythonmodule' +and install it with 'make installpythonmodule'. +setup.py (and setupmingw32.py) are included in the distribution. + + +Feel free to contact me if you have any problem : +e-mail : miniupnp@free.fr + +If you are using libminiupnpc in your application, please +send me an email ! + +For any question, you can use the web forum : +http://miniupnp.tuxfamily.org/forum/ + +Bugs should be reported on github : +https://github.com/miniupnp/miniupnp/issues diff --git a/deps/miniupnpc/VERSION b/deps/miniupnpc/VERSION new file mode 100644 index 0000000000..cd5ac039d6 --- /dev/null +++ b/deps/miniupnpc/VERSION @@ -0,0 +1 @@ +2.0 diff --git a/deps/miniupnpc/apiversions.txt b/deps/miniupnpc/apiversions.txt new file mode 100644 index 0000000000..9464a86759 --- /dev/null +++ b/deps/miniupnpc/apiversions.txt @@ -0,0 +1,172 @@ +$Id: apiversions.txt,v 1.9 2016/01/24 17:24:36 nanard Exp $ + +Differences in API between miniUPnPc versions + +API version 16 + added "status_code" argument to getHTTPResponse(), miniwget() and miniwget_getaddr() + updated macro : + #define MINIUPNPC_API_VERSION 16 + +API version 15 + changed "sameport" argument of upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() + to "localport". When 0 or 1, behaviour is not changed, but it can take + any other value between 2 and 65535 + Existing programs should be compatible + updated macro : + #define MINIUPNPC_API_VERSION 15 + +API version 14 +miniupnpc.h + add ttl argument to upnpDiscover() upnpDiscoverAll() upnpDiscoverDevice() + upnpDiscoverDevices() + getDevicesFromMiniSSDPD() : + connectToMiniSSDPD() / disconnectFromMiniSSDPD() + requestDevicesFromMiniSSDPD() / receiveDevicesFromMiniSSDPD() + updated macro : + #define MINIUPNPC_API_VERSION 14 + +API version 13 +miniupnpc.h: + add searchalltype param to upnpDiscoverDevices() function + updated macro : + #define MINIUPNPC_API_VERSION 13 + +API version 12 +miniupnpc.h : + add upnpDiscoverAll() / upnpDiscoverDevice() / upnpDiscoverDevices() + functions + updated macros : + #define MINIUPNPC_API_VERSION 12 + +API version 11 + +upnpreplyparse.h / portlistingparse.h : + removed usage of sys/queue.h / bsdqueue.h + +miniupnpc.h: + updated macros : + #define MINIUPNPC_API_VERSION 11 + +====================== miniUPnPc version 1.9 ====================== +API version 10 + +upnpcommands.h: + added argument remoteHost to UPNP_GetSpecificPortMappingEntry() + +miniupnpc.h: + updated macros : + #define MINIUPNPC_VERSION "1.9" + #define MINIUPNPC_API_VERSION 10 + +====================== miniUPnPc version 1.8 ====================== +API version 9 + +miniupnpc.h: + updated macros : + #define MINIUPNPC_VERSION "1.8" + #define MINIUPNPC_API_VERSION 9 + added "unsigned int scope_id;" to struct UPNPDev + added scope_id argument to GetUPNPUrls() + + + +====================== miniUPnPc version 1.7 ====================== +API version 8 + +miniupnpc.h : + add new macros : + #define MINIUPNPC_VERSION "1.7" + #define MINIUPNPC_API_VERSION 8 + add rootdescURL to struct UPNPUrls + + + +====================== miniUPnPc version 1.6 ====================== +API version 8 + +Adding support for IPv6. +igd_desc_parse.h : + struct IGDdatas_service : + add char presentationurl[MINIUPNPC_URL_MAXSIZE]; + struct IGDdatas : + add struct IGDdatas_service IPv6FC; +miniupnpc.h : + new macros : + #define UPNPDISCOVER_SUCCESS (0) + #define UPNPDISCOVER_UNKNOWN_ERROR (-1) + #define UPNPDISCOVER_SOCKET_ERROR (-101) + #define UPNPDISCOVER_MEMORY_ERROR (-102) + simpleUPnPcommand() prototype changed (but is normaly not used by API users) + add arguments ipv6 and error to upnpDiscover() : + struct UPNPDev * + upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error); + add controlURL_6FC member to struct UPNPUrls : + struct UPNPUrls { + char * controlURL; + char * ipcondescURL; + char * controlURL_CIF; + char * controlURL_6FC; + }; + +upnpcommands.h : + add leaseDuration argument to UPNP_AddPortMapping() + add desc, enabled and leaseDuration arguments to UPNP_GetSpecificPortMappingEntry() + add UPNP_GetListOfPortMappings() function (IGDv2) + add IGDv2 IPv6 related functions : + UPNP_GetFirewallStatus() + UPNP_GetOutboundPinholeTimeout() + UPNP_AddPinhole() + UPNP_UpdatePinhole() + UPNP_DeletePinhole() + UPNP_CheckPinholeWorking() + UPNP_GetPinholePackets() + + + +====================== miniUPnPc version 1.5 ====================== +API version 5 + +new function : +int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); +new macro in upnpcommands.h : +#define UPNPCOMMAND_HTTP_ERROR + +====================== miniUPnPc version 1.4 ====================== +Same API as version 1.3 + +====================== miniUPnPc version 1.3 ====================== +API version 4 + +Use UNSIGNED_INTEGER type for +UPNP_GetTotalBytesSent(), UPNP_GetTotalBytesReceived(), +UPNP_GetTotalPacketsSent(), UPNP_GetTotalPacketsReceived() +Add remoteHost argument to UPNP_AddPortMapping() and UPNP_DeletePortMapping() + +====================== miniUPnPc version 1.2 ====================== +API version 3 + +added sameport argument to upnpDiscover() +struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport); + +====================== miniUPnPc Version 1.1 ====================== +Same API as 1.0 + + +====================== miniUPnPc Version 1.0 ====================== +API version 2 + + +struct UPNPDev { + struct UPNPDev * pNext; + char * descURL; + char * st; + char buffer[2]; +}; +struct UPNPDev * upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock); + diff --git a/deps/miniupnpc/codelength.h b/deps/miniupnpc/codelength.h new file mode 100644 index 0000000000..ea0b005ffe --- /dev/null +++ b/deps/miniupnpc/codelength.h @@ -0,0 +1,54 @@ +/* $Id: codelength.h,v 1.3 2011/07/30 13:10:05 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2015 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef CODELENGTH_H_INCLUDED +#define CODELENGTH_H_INCLUDED + +/* Encode length by using 7bit per Byte : + * Most significant bit of each byte specifies that the + * following byte is part of the code */ + +/* n : unsigned + * p : unsigned char * + */ +#define DECODELENGTH(n, p) n = 0; \ + do { n = (n << 7) | (*p & 0x7f); } \ + while((*(p++)&0x80) && (n<(1<<25))); + +/* n : unsigned + * READ : function/macro to read one byte (unsigned char) + */ +#define DECODELENGTH_READ(n, READ) \ + n = 0; \ + do { \ + unsigned char c; \ + READ(c); \ + n = (n << 7) | (c & 0x07f); \ + if(!(c&0x80)) break; \ + } while(n<(1<<25)); + +/* n : unsigned + * p : unsigned char * + * p_limit : unsigned char * + */ +#define DECODELENGTH_CHECKLIMIT(n, p, p_limit) \ + n = 0; \ + do { \ + if((p) >= (p_limit)) break; \ + n = (n << 7) | (*(p) & 0x7f); \ + } while((*((p)++)&0x80) && (n<(1<<25))); + + +/* n : unsigned + * p : unsigned char * + */ +#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ + if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ + if(n>=16384) *(p++) = (n >> 14) | 0x80; \ + if(n>=128) *(p++) = (n >> 7) | 0x80; \ + *(p++) = n & 0x7f; + +#endif /* CODELENGTH_H_INCLUDED */ diff --git a/deps/miniupnpc/connecthostport.c b/deps/miniupnpc/connecthostport.c new file mode 100644 index 0000000000..e3c17d36be --- /dev/null +++ b/deps/miniupnpc/connecthostport.c @@ -0,0 +1,264 @@ +/* $Id: connecthostport.c,v 1.15 2015/10/09 16:26:19 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2010-2016 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +/* use getaddrinfo() or gethostbyname() + * uncomment the following line in order to use gethostbyname() */ +#ifdef NO_GETADDRINFO +#define USE_GETHOSTBYNAME +#endif + +#include +#include +#ifdef _WIN32 +#include +#include +#include +#define MAXHOSTNAMELEN 64 +#define snprintf _snprintf +#define herror +#define socklen_t int +#else /* #ifdef _WIN32 */ +#include +#include +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +#include +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ +#include +#include +#include +#define closesocket close +#include +#include +/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions + * during the connect() call */ +#define MINIUPNPC_IGNORE_EINTR +#ifndef USE_GETHOSTBYNAME +#include +#include +#endif /* #ifndef USE_GETHOSTBYNAME */ +#endif /* #else _WIN32 */ + +/* definition of PRINT_SOCKET_ERROR */ +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#if defined(__amigaos__) || defined(__amigaos4__) +#define herror(A) printf("%s\n", A) +#endif + +#include "connecthostport.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port, + unsigned int scope_id) +{ + int s, n; +#ifdef USE_GETHOSTBYNAME + struct sockaddr_in dest; + struct hostent *hp; +#else /* #ifdef USE_GETHOSTBYNAME */ + char tmp_host[MAXHOSTNAMELEN+1]; + char port_str[8]; + struct addrinfo *ai, *p; + struct addrinfo hints; +#endif /* #ifdef USE_GETHOSTBYNAME */ +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + struct timeval timeout; +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + +#ifdef USE_GETHOSTBYNAME + hp = gethostbyname(host); + if(hp == NULL) + { + herror(host); + return -1; + } + memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); + memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); + s = socket(PF_INET, SOCK_STREAM, 0); + if(s < 0) + { + PRINT_SOCKET_ERROR("socket"); + return -1; + } +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + /* setting a 3 seconds timeout for the connect() call */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt SO_RCVTIMEO"); + } + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt SO_SNDTIMEO"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + dest.sin_family = AF_INET; + dest.sin_port = htons(port); + n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); +#ifdef MINIUPNPC_IGNORE_EINTR + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) + { + socklen_t len; + fd_set wset; + int err; + FD_ZERO(&wset); + FD_SET(s, &wset); + if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) + continue; + /*len = 0;*/ + /*n = getpeername(s, NULL, &len);*/ + len = sizeof(err); + if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + PRINT_SOCKET_ERROR("getsockopt"); + closesocket(s); + return -1; + } + if(err != 0) { + errno = err; + n = -1; + } + } +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ + if(n<0) + { + PRINT_SOCKET_ERROR("connect"); + closesocket(s); + return -1; + } +#else /* #ifdef USE_GETHOSTBYNAME */ + /* use getaddrinfo() instead of gethostbyname() */ + memset(&hints, 0, sizeof(hints)); + /* hints.ai_flags = AI_ADDRCONFIG; */ +#ifdef AI_NUMERICSERV + hints.ai_flags = AI_NUMERICSERV; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ + /* hints.ai_protocol = IPPROTO_TCP; */ + snprintf(port_str, sizeof(port_str), "%hu", port); + if(host[0] == '[') + { + /* literal ip v6 address */ + int i, j; + for(i = 0, j = 1; host[j] && (host[j] != ']') && i < MAXHOSTNAMELEN; i++, j++) + { + tmp_host[i] = host[j]; + if(0 == memcmp(host+j, "%25", 3)) /* %25 is just url encoding for '%' */ + j+=2; /* skip "25" */ + } + tmp_host[i] = '\0'; + } + else + { + strncpy(tmp_host, host, MAXHOSTNAMELEN); + } + tmp_host[MAXHOSTNAMELEN] = '\0'; + n = getaddrinfo(tmp_host, port_str, &hints, &ai); + if(n != 0) + { +#ifdef _WIN32 + fprintf(stderr, "getaddrinfo() error : %d\n", n); +#else + fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); +#endif + return -1; + } + s = -1; + for(p = ai; p; p = p->ai_next) + { + s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if(s < 0) + continue; + if(p->ai_addr->sa_family == AF_INET6 && scope_id > 0) { + struct sockaddr_in6 * addr6 = (struct sockaddr_in6 *)p->ai_addr; + addr6->sin6_scope_id = scope_id; + } +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + /* setting a 3 seconds timeout for the connect() call */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + n = connect(s, p->ai_addr, p->ai_addrlen); +#ifdef MINIUPNPC_IGNORE_EINTR + /* EINTR The system call was interrupted by a signal that was caught + * EINPROGRESS The socket is nonblocking and the connection cannot + * be completed immediately. */ + while(n < 0 && (errno == EINTR || errno == EINPROGRESS)) + { + socklen_t len; + fd_set wset; + int err; + FD_ZERO(&wset); + FD_SET(s, &wset); + if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) + continue; + /*len = 0;*/ + /*n = getpeername(s, NULL, &len);*/ + len = sizeof(err); + if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + PRINT_SOCKET_ERROR("getsockopt"); + closesocket(s); + freeaddrinfo(ai); + return -1; + } + if(err != 0) { + errno = err; + n = -1; + } + } +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ + if(n < 0) + { + closesocket(s); + continue; + } + else + { + break; + } + } + freeaddrinfo(ai); + if(s < 0) + { + PRINT_SOCKET_ERROR("socket"); + return -1; + } + if(n < 0) + { + PRINT_SOCKET_ERROR("connect"); + return -1; + } +#endif /* #ifdef USE_GETHOSTBYNAME */ + return s; +} + diff --git a/deps/miniupnpc/connecthostport.h b/deps/miniupnpc/connecthostport.h new file mode 100644 index 0000000000..f3b2d2a842 --- /dev/null +++ b/deps/miniupnpc/connecthostport.h @@ -0,0 +1,18 @@ +/* $Id: connecthostport.h,v 1.2 2012/06/23 22:32:33 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2010-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef CONNECTHOSTPORT_H_INCLUDED +#define CONNECTHOSTPORT_H_INCLUDED + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port, + unsigned int scope_id); + +#endif + diff --git a/deps/miniupnpc/igd_desc_parse.c b/deps/miniupnpc/igd_desc_parse.c new file mode 100644 index 0000000000..d2999ad011 --- /dev/null +++ b/deps/miniupnpc/igd_desc_parse.c @@ -0,0 +1,123 @@ +/* $Id: igd_desc_parse.c,v 1.17 2015/09/15 13:30:04 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include "igd_desc_parse.h" +#include +#include + +/* Start element handler : + * update nesting level counter and copy element name */ +void IGDstartelt(void * d, const char * name, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + if(l >= MINIUPNPC_URL_MAXSIZE) + l = MINIUPNPC_URL_MAXSIZE-1; + memcpy(datas->cureltname, name, l); + datas->cureltname[l] = '\0'; + datas->level++; + if( (l==7) && !memcmp(name, "service", l) ) { + datas->tmp.controlurl[0] = '\0'; + datas->tmp.eventsuburl[0] = '\0'; + datas->tmp.scpdurl[0] = '\0'; + datas->tmp.servicetype[0] = '\0'; + } +} + +#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) + +/* End element handler : + * update nesting level counter and update parser state if + * service element is parsed */ +void IGDendelt(void * d, const char * name, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + datas->level--; + /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ + if( (l==7) && !memcmp(name, "service", l) ) + { + if(COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { + memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); + } else if(COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPv6FirewallControl:")) { + memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); + } else if(COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPConnection:") + || COMPARE(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANPPPConnection:") ) { + if(datas->first.servicetype[0] == '\0') { + memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); + } else { + memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); + } + } + } +} + +/* Data handler : + * copy data depending on the current element name and state */ +void IGDdata(void * d, const char * data, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + char * dstmember = 0; + /*printf("%2d %s : %.*s\n", + datas->level, datas->cureltname, l, data); */ + if( !strcmp(datas->cureltname, "URLBase") ) + dstmember = datas->urlbase; + else if( !strcmp(datas->cureltname, "presentationURL") ) + dstmember = datas->presentationurl; + else if( !strcmp(datas->cureltname, "serviceType") ) + dstmember = datas->tmp.servicetype; + else if( !strcmp(datas->cureltname, "controlURL") ) + dstmember = datas->tmp.controlurl; + else if( !strcmp(datas->cureltname, "eventSubURL") ) + dstmember = datas->tmp.eventsuburl; + else if( !strcmp(datas->cureltname, "SCPDURL") ) + dstmember = datas->tmp.scpdurl; +/* else if( !strcmp(datas->cureltname, "deviceType") ) + dstmember = datas->devicetype_tmp;*/ + if(dstmember) + { + if(l>=MINIUPNPC_URL_MAXSIZE) + l = MINIUPNPC_URL_MAXSIZE-1; + memcpy(dstmember, data, l); + dstmember[l] = '\0'; + } +} + +#ifdef DEBUG +void printIGD(struct IGDdatas * d) +{ + printf("urlbase = '%s'\n", d->urlbase); + printf("WAN Device (Common interface config) :\n"); + /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ + printf(" serviceType = '%s'\n", d->CIF.servicetype); + printf(" controlURL = '%s'\n", d->CIF.controlurl); + printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); + printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); + printf("primary WAN Connection Device (IP or PPP Connection):\n"); + /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ + printf(" servicetype = '%s'\n", d->first.servicetype); + printf(" controlURL = '%s'\n", d->first.controlurl); + printf(" eventSubURL = '%s'\n", d->first.eventsuburl); + printf(" SCPDURL = '%s'\n", d->first.scpdurl); + printf("secondary WAN Connection Device (IP or PPP Connection):\n"); + /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ + printf(" servicetype = '%s'\n", d->second.servicetype); + printf(" controlURL = '%s'\n", d->second.controlurl); + printf(" eventSubURL = '%s'\n", d->second.eventsuburl); + printf(" SCPDURL = '%s'\n", d->second.scpdurl); + printf("WAN IPv6 Firewall Control :\n"); + /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ + printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); + printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); + printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); + printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); +} +#endif /* DEBUG */ + diff --git a/deps/miniupnpc/igd_desc_parse.h b/deps/miniupnpc/igd_desc_parse.h new file mode 100644 index 0000000000..0de546b697 --- /dev/null +++ b/deps/miniupnpc/igd_desc_parse.h @@ -0,0 +1,49 @@ +/* $Id: igd_desc_parse.h,v 1.12 2014/11/17 17:19:13 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef IGD_DESC_PARSE_H_INCLUDED +#define IGD_DESC_PARSE_H_INCLUDED + +/* Structure to store the result of the parsing of UPnP + * descriptions of Internet Gateway Devices */ +#define MINIUPNPC_URL_MAXSIZE (128) +struct IGDdatas_service { + char controlurl[MINIUPNPC_URL_MAXSIZE]; + char eventsuburl[MINIUPNPC_URL_MAXSIZE]; + char scpdurl[MINIUPNPC_URL_MAXSIZE]; + char servicetype[MINIUPNPC_URL_MAXSIZE]; + /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ +}; + +struct IGDdatas { + char cureltname[MINIUPNPC_URL_MAXSIZE]; + char urlbase[MINIUPNPC_URL_MAXSIZE]; + char presentationurl[MINIUPNPC_URL_MAXSIZE]; + int level; + /*int state;*/ + /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ + struct IGDdatas_service CIF; + /* "urn:schemas-upnp-org:service:WANIPConnection:1" + * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ + struct IGDdatas_service first; + /* if both WANIPConnection and WANPPPConnection are present */ + struct IGDdatas_service second; + /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ + struct IGDdatas_service IPv6FC; + /* tmp */ + struct IGDdatas_service tmp; +}; + +void IGDstartelt(void *, const char *, int); +void IGDendelt(void *, const char *, int); +void IGDdata(void *, const char *, int); +#ifdef DEBUG +void printIGD(struct IGDdatas *); +#endif /* DEBUG */ + +#endif /* IGD_DESC_PARSE_H_INCLUDED */ diff --git a/deps/miniupnpc/minisoap.c b/deps/miniupnpc/minisoap.c new file mode 100644 index 0000000000..5c9a11438f --- /dev/null +++ b/deps/miniupnpc/minisoap.c @@ -0,0 +1,123 @@ +/* $Id: minisoap.c,v 1.23 2014/11/04 22:31:55 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * + * Minimal SOAP implementation for UPnP protocol. + */ +#include +#include +#ifdef _WIN32 +#include +#include +#define snprintf _snprintf +#else +#include +#include +#include +#endif +#include "minisoap.h" +#include "miniupnpcstrings.h" + +/* only for malloc */ +#include + +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +/* httpWrite sends the headers and the body to the socket + * and returns the number of bytes sent */ +static int +httpWrite(int fd, const char * body, int bodysize, + const char * headers, int headerssize) +{ + int n = 0; + /*n = write(fd, headers, headerssize);*/ + /*if(bodysize>0) + n += write(fd, body, bodysize);*/ + /* Note : my old linksys router only took into account + * soap request that are sent into only one packet */ + char * p; + /* TODO: AVOID MALLOC, we could use writev() for that */ + p = malloc(headerssize+bodysize); + if(!p) + return -1; + memcpy(p, headers, headerssize); + memcpy(p+headerssize, body, bodysize); + /*n = write(fd, p, headerssize+bodysize);*/ + n = send(fd, p, headerssize+bodysize, 0); + if(n<0) { + PRINT_SOCKET_ERROR("send"); + } + /* disable send on the socket */ + /* draytek routers dont seems to like that... */ +#if 0 +#ifdef _WIN32 + if(shutdown(fd, SD_SEND)<0) { +#else + if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ +#endif + PRINT_SOCKET_ERROR("shutdown"); + } +#endif + free(p); + return n; +} + +/* self explanatory */ +int soapPostSubmit(int fd, + const char * url, + const char * host, + unsigned short port, + const char * action, + const char * body, + const char * httpversion) +{ + int bodysize; + char headerbuf[512]; + int headerssize; + char portstr[8]; + bodysize = (int)strlen(body); + /* We are not using keep-alive HTTP connections. + * HTTP/1.1 needs the header Connection: close to do that. + * This is the default with HTTP/1.0 + * Using HTTP/1.1 means we need to support chunked transfer-encoding : + * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked + * transfer encoding. */ + /* Connection: Close is normally there only in HTTP/1.1 but who knows */ + portstr[0] = '\0'; + if(port != 80) + snprintf(portstr, sizeof(portstr), ":%hu", port); + headerssize = snprintf(headerbuf, sizeof(headerbuf), + "POST %s HTTP/%s\r\n" + "Host: %s%s\r\n" + "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + "Content-Length: %d\r\n" + "Content-Type: text/xml\r\n" + "SOAPAction: \"%s\"\r\n" + "Connection: Close\r\n" + "Cache-Control: no-cache\r\n" /* ??? */ + "Pragma: no-cache\r\n" + "\r\n", + url, httpversion, host, portstr, bodysize, action); + if ((unsigned int)headerssize >= sizeof(headerbuf)) + return -1; +#ifdef DEBUG + /*printf("SOAP request : headersize=%d bodysize=%d\n", + headerssize, bodysize); + */ + printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", + url, httpversion, host, portstr); + printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); + printf("Headers :\n%s", headerbuf); + printf("Body :\n%s\n", body); +#endif + return httpWrite(fd, body, bodysize, headerbuf, headerssize); +} + + diff --git a/deps/miniupnpc/minisoap.h b/deps/miniupnpc/minisoap.h new file mode 100644 index 0000000000..60554f5c39 --- /dev/null +++ b/deps/miniupnpc/minisoap.h @@ -0,0 +1,15 @@ +/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ +#ifndef MINISOAP_H_INCLUDED +#define MINISOAP_H_INCLUDED + +/*int httpWrite(int, const char *, int, const char *);*/ +int soapPostSubmit(int, const char *, const char *, unsigned short, + const char *, const char *, const char *); + +#endif + diff --git a/deps/miniupnpc/minissdpc.c b/deps/miniupnpc/minissdpc.c new file mode 100644 index 0000000000..89b9d249ae --- /dev/null +++ b/deps/miniupnpc/minissdpc.c @@ -0,0 +1,876 @@ +/* $Id: minissdpc.c,v 1.32 2016/10/07 09:04:36 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2017 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +/*#include */ +#include +#include +#include +#include +#if defined (__NetBSD__) +#include +#endif +#if defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) +#ifdef _WIN32 +#include +#include +#include +#include +#include +#define snprintf _snprintf +#if !defined(_MSC_VER) +#include +#else /* !defined(_MSC_VER) */ +typedef unsigned short uint16_t; +#endif /* !defined(_MSC_VER) */ +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#endif /* _WIN32 */ +#if defined(__amigaos__) || defined(__amigaos4__) +#include +#endif /* defined(__amigaos__) || defined(__amigaos4__) */ +#if defined(__amigaos__) +#define uint16_t unsigned short +#endif /* defined(__amigaos__) */ +/* Hack */ +#define UNIX_PATH_LEN 108 +struct sockaddr_un { + uint16_t sun_family; + char sun_path[UNIX_PATH_LEN]; +}; +#else /* defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__) */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define closesocket close +#endif + +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#if !defined(__DragonFly__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__sun) && !defined(__GNU__) && !defined(__FreeBSD_kernel__) +#define HAS_IP_MREQN +#endif + +#if !defined(HAS_IP_MREQN) && !defined(_WIN32) +#include +#if defined(__sun) +#include +#endif +#endif + +#if defined(HAS_IP_MREQN) && defined(NEED_STRUCT_IP_MREQN) +/* Several versions of glibc don't define this structure, + * define it here and compile with CFLAGS NEED_STRUCT_IP_MREQN */ +struct ip_mreqn +{ + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_address; /* local IP address of interface */ + int imr_ifindex; /* Interface index */ +}; +#endif + +#if defined(__amigaos__) || defined(__amigaos4__) +/* Amiga OS specific stuff */ +#define TIMEVAL struct timeval +#endif + +#include "minissdpc.h" +#include "miniupnpc.h" +#include "receivedata.h" + +#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) + +#include "codelength.h" + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error) +{ + struct UPNPDev * devlist = NULL; + int s; + int res; + + s = connectToMiniSSDPD(socketpath); + if (s < 0) { + if (error) + *error = s; + return NULL; + } + res = requestDevicesFromMiniSSDPD(s, devtype); + if (res < 0) { + if (error) + *error = res; + } else { + devlist = receiveDevicesFromMiniSSDPD(s, error); + } + disconnectFromMiniSSDPD(s); + return devlist; +} + +/* macros used to read from unix socket */ +#define READ_BYTE_BUFFER(c) \ + if((int)bufferindex >= n) { \ + n = read(s, buffer, sizeof(buffer)); \ + if(n<=0) break; \ + bufferindex = 0; \ + } \ + c = buffer[bufferindex++]; + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ + +#define READ_COPY_BUFFER(dst, len) \ + for(l = len, p = (unsigned char *)dst; l > 0; ) { \ + unsigned int lcopy; \ + if((int)bufferindex >= n) { \ + n = read(s, buffer, sizeof(buffer)); \ + if(n<=0) break; \ + bufferindex = 0; \ + } \ + lcopy = MIN(l, (n - bufferindex)); \ + memcpy(p, buffer + bufferindex, lcopy); \ + l -= lcopy; \ + p += lcopy; \ + bufferindex += lcopy; \ + } + +#define READ_DISCARD_BUFFER(len) \ + for(l = len; l > 0; ) { \ + unsigned int lcopy; \ + if(bufferindex >= n) { \ + n = read(s, buffer, sizeof(buffer)); \ + if(n<=0) break; \ + bufferindex = 0; \ + } \ + lcopy = MIN(l, (n - bufferindex)); \ + l -= lcopy; \ + bufferindex += lcopy; \ + } + +int +connectToMiniSSDPD(const char * socketpath) +{ + int s; + struct sockaddr_un addr; +#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun) + struct timeval timeout; +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if(s < 0) + { + /*syslog(LOG_ERR, "socket(unix): %m");*/ + perror("socket(unix)"); + return MINISSDPC_SOCKET_ERROR; + } +#if defined(MINIUPNPC_SET_SOCKET_TIMEOUT) && !defined(__sun) + /* setting a 3 seconds timeout */ + /* not supported for AF_UNIX sockets under Solaris */ + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + perror("setsockopt SO_RCVTIMEO unix"); + } + timeout.tv_sec = 3; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + perror("setsockopt SO_SNDTIMEO unix"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + if(!socketpath) + socketpath = "/var/run/minissdpd.sock"; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); + /* TODO : check if we need to handle the EINTR */ + if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) + { + /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ + close(s); + return MINISSDPC_SOCKET_ERROR; + } + return s; +} + +int +disconnectFromMiniSSDPD(int s) +{ + if (close(s) < 0) + return MINISSDPC_SOCKET_ERROR; + return MINISSDPC_SUCCESS; +} + +int +requestDevicesFromMiniSSDPD(int s, const char * devtype) +{ + unsigned char buffer[256]; + unsigned char * p; + unsigned int stsize, l; + + stsize = strlen(devtype); + if(stsize == 8 && 0 == memcmp(devtype, "ssdp:all", 8)) + { + buffer[0] = 3; /* request type 3 : everything */ + } + else + { + buffer[0] = 1; /* request type 1 : request devices/services by type */ + } + p = buffer + 1; + l = stsize; CODELENGTH(l, p); + if(p + stsize > buffer + sizeof(buffer)) + { + /* devtype is too long ! */ +#ifdef DEBUG + fprintf(stderr, "devtype is too long ! stsize=%u sizeof(buffer)=%u\n", + stsize, (unsigned)sizeof(buffer)); +#endif /* DEBUG */ + return MINISSDPC_INVALID_INPUT; + } + memcpy(p, devtype, stsize); + p += stsize; + if(write(s, buffer, p - buffer) < 0) + { + /*syslog(LOG_ERR, "write(): %m");*/ + perror("minissdpc.c: write()"); + return MINISSDPC_SOCKET_ERROR; + } + return MINISSDPC_SUCCESS; +} + +struct UPNPDev * +receiveDevicesFromMiniSSDPD(int s, int * error) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = NULL; + unsigned char buffer[256]; + ssize_t n; + unsigned char * p; + unsigned char * url; + unsigned char * st; + unsigned int bufferindex; + unsigned int i, ndev; + unsigned int urlsize, stsize, usnsize, l; + + n = read(s, buffer, sizeof(buffer)); + if(n<=0) + { + perror("minissdpc.c: read()"); + if (error) + *error = MINISSDPC_SOCKET_ERROR; + return NULL; + } + ndev = buffer[0]; + bufferindex = 1; + for(i = 0; i < ndev; i++) + { + DECODELENGTH_READ(urlsize, READ_BYTE_BUFFER); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + return devlist; + } +#ifdef DEBUG + printf(" urlsize=%u", urlsize); +#endif /* DEBUG */ + url = malloc(urlsize); + if(url == NULL) { + if (error) + *error = MINISSDPC_MEMORY_ERROR; + return devlist; + } + READ_COPY_BUFFER(url, urlsize); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_return; + } + DECODELENGTH_READ(stsize, READ_BYTE_BUFFER); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_return; + } +#ifdef DEBUG + printf(" stsize=%u", stsize); +#endif /* DEBUG */ + st = malloc(stsize); + if (st == NULL) { + if (error) + *error = MINISSDPC_MEMORY_ERROR; + goto free_url_and_return; + } + READ_COPY_BUFFER(st, stsize); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_st_and_return; + } + DECODELENGTH_READ(usnsize, READ_BYTE_BUFFER); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_url_and_st_and_return; + } +#ifdef DEBUG + printf(" usnsize=%u\n", usnsize); +#endif /* DEBUG */ + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); + if(tmp == NULL) { + if (error) + *error = MINISSDPC_MEMORY_ERROR; + goto free_url_and_st_and_return; + } + tmp->pNext = devlist; + tmp->descURL = tmp->buffer; + tmp->st = tmp->buffer + 1 + urlsize; + memcpy(tmp->buffer, url, urlsize); + tmp->buffer[urlsize] = '\0'; + memcpy(tmp->st, st, stsize); + tmp->buffer[urlsize+1+stsize] = '\0'; + free(url); + free(st); + url = NULL; + st = NULL; + tmp->usn = tmp->buffer + 1 + urlsize + 1 + stsize; + READ_COPY_BUFFER(tmp->usn, usnsize); + if(n<=0) { + if (error) + *error = MINISSDPC_INVALID_SERVER_REPLY; + goto free_tmp_and_return; + } + tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; + tmp->scope_id = 0; /* default value. scope_id is not available with MiniSSDPd */ + devlist = tmp; + } + if (error) + *error = MINISSDPC_SUCCESS; + return devlist; + +free_url_and_st_and_return: + free(st); +free_url_and_return: + free(url); + return devlist; + +free_tmp_and_return: + free(tmp); + return devlist; +} + +#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ + +/* parseMSEARCHReply() + * the last 4 arguments are filled during the parsing : + * - location/locationsize : "location:" field of the SSDP reply packet + * - st/stsize : "st:" field of the SSDP reply packet. + * The strings are NOT null terminated */ +static void +parseMSEARCHReply(const char * reply, int size, + const char * * location, int * locationsize, + const char * * st, int * stsize, + const char * * usn, int * usnsize) +{ + int a, b, i; + i = 0; + a = i; /* start of the line */ + b = 0; /* end of the "header" (position of the colon) */ + while(isin6_family = AF_INET6; + if(localport > 0 && localport < 65536) + p->sin6_port = htons((unsigned short)localport); + p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; + p->sin_family = AF_INET; + if(localport > 0 && localport < 65536) + p->sin_port = htons((unsigned short)localport); + p->sin_addr.s_addr = INADDR_ANY; + } +#ifdef _WIN32 +/* This code could help us to use the right Network interface for + * SSDP multicast traffic */ +/* Get IP associated with the index given in the ip_forward struct + * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ + if(!ipv6 + && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { + DWORD dwRetVal = 0; + PMIB_IPADDRTABLE pIPAddrTable; + DWORD dwSize = 0; +#ifdef DEBUG + IN_ADDR IPAddr; +#endif + int i; +#ifdef DEBUG + printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); +#endif + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); + if(pIPAddrTable) { + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIPAddrTable); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); + } + } + if(pIPAddrTable) { + dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); + if (dwRetVal == NO_ERROR) { +#ifdef DEBUG + printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); +#endif + for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { +#ifdef DEBUG + printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; + printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; + printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; + printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); + printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); + printf("\tType and State[%d]:", i); + printf("\n"); +#endif + if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { + /* Set the address of this interface to be used */ + struct in_addr mc_if; + memset(&mc_if, 0, sizeof(mc_if)); + mc_if.s_addr = pIPAddrTable->table[i].dwAddr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { + PRINT_SOCKET_ERROR("setsockopt"); + } + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; +#ifndef DEBUG + break; +#endif + } + } + } + free(pIPAddrTable); + pIPAddrTable = NULL; + } + } +#endif /* _WIN32 */ + +#ifdef _WIN32 + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) +#else + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) +#endif + { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + PRINT_SOCKET_ERROR("setsockopt(SO_REUSEADDR,...)"); + return NULL; + } + +#ifdef _WIN32 + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, (const char *)&_ttl, sizeof(_ttl)) < 0) +#else /* _WIN32 */ + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) +#endif /* _WIN32 */ + { + /* not a fatal error */ + PRINT_SOCKET_ERROR("setsockopt(IP_MULTICAST_TTL,...)"); + } + + if(multicastif) + { + if(ipv6) { +#if !defined(_WIN32) + /* according to MSDN, if_nametoindex() is supported since + * MS Windows Vista and MS Windows Server 2008. + * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ + unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ + if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IPV6_MULTICAST_IF"); + } +#else +#ifdef DEBUG + printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); +#endif +#endif + } else { + struct in_addr mc_if; + mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ + if(mc_if.s_addr != INADDR_NONE) + { + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); + } + } else { +#ifdef HAS_IP_MREQN + /* was not an ip address, try with an interface name */ + struct ip_mreqn reqn; /* only defined with -D_BSD_SOURCE or -D_GNU_SOURCE */ + memset(&reqn, 0, sizeof(struct ip_mreqn)); + reqn.imr_ifindex = if_nametoindex(multicastif); + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&reqn, sizeof(reqn)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); + } +#elif !defined(_WIN32) + struct ifreq ifr; + int ifrlen = sizeof(ifr); + strncpy(ifr.ifr_name, multicastif, IFNAMSIZ); + ifr.ifr_name[IFNAMSIZ-1] = '\0'; + if(ioctl(sudp, SIOCGIFADDR, &ifr, &ifrlen) < 0) + { + PRINT_SOCKET_ERROR("ioctl(...SIOCGIFADDR...)"); + } + mc_if.s_addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt IP_MULTICAST_IF"); + } +#else /* _WIN32 */ +#ifdef DEBUG + printf("Setting of multicast interface not supported with interface name.\n"); +#endif +#endif /* #ifdef HAS_IP_MREQN / !defined(_WIN32) */ + } + } + } + + /* Before sending the packed, we first "bind" in order to be able + * to receive the response */ + if (bind(sudp, (const struct sockaddr *)&sockudp_r, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) + { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + PRINT_SOCKET_ERROR("bind"); + closesocket(sudp); + return NULL; + } + + if(error) + *error = MINISSDPC_SUCCESS; + /* Calculating maximum response time in seconds */ + mx = ((unsigned int)delay) / 1000u; + if(mx == 0) { + mx = 1; + delay = 1000; + } + /* receiving SSDP response packet */ + for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { + /* sending the SSDP M-SEARCH packet */ + n = snprintf(bufr, sizeof(bufr), + MSearchMsgFmt, + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, + deviceTypes[deviceIndex], mx); + if ((unsigned int)n >= sizeof(bufr)) { + if(error) + *error = MINISSDPC_MEMORY_ERROR; + goto error; + } +#ifdef DEBUG + /*printf("Sending %s", bufr);*/ + printf("Sending M-SEARCH request to %s with ST: %s\n", + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, + deviceTypes[deviceIndex]); +#endif +#ifdef NO_GETADDRINFO + /* the following code is not using getaddrinfo */ + /* emission */ + memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; + p->sin6_family = AF_INET6; + p->sin6_port = htons(SSDP_PORT); + inet_pton(AF_INET6, + linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, + &(p->sin6_addr)); + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; + p->sin_family = AF_INET; + p->sin_port = htons(SSDP_PORT); + p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); + } + n = sendto(sudp, bufr, n, 0, &sockudp_w, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (n < 0) { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + PRINT_SOCKET_ERROR("sendto"); + break; + } +#else /* #ifdef NO_GETADDRINFO */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; /* AF_INET6 or AF_INET */ + hints.ai_socktype = SOCK_DGRAM; + /*hints.ai_flags = */ + if ((rv = getaddrinfo(ipv6 + ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) + : UPNP_MCAST_ADDR, + XSTR(SSDP_PORT), &hints, &servinfo)) != 0) { + if(error) + *error = MINISSDPC_SOCKET_ERROR; +#ifdef _WIN32 + fprintf(stderr, "getaddrinfo() failed: %d\n", rv); +#else + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +#endif + break; + } + for(p = servinfo; p; p = p->ai_next) { + n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); + if (n < 0) { +#ifdef DEBUG + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + if (getnameinfo(p->ai_addr, p->ai_addrlen, hbuf, sizeof(hbuf), sbuf, + sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) == 0) { + fprintf(stderr, "host:%s port:%s\n", hbuf, sbuf); + } +#endif + PRINT_SOCKET_ERROR("sendto"); + continue; + } + } + freeaddrinfo(servinfo); + if(n < 0) { + if(error) + *error = MINISSDPC_SOCKET_ERROR; + break; + } +#endif /* #ifdef NO_GETADDRINFO */ + /* Waiting for SSDP REPLY packet to M-SEARCH + * if searchalltypes is set, enter the loop only + * when the last deviceType is reached */ + if(!searchalltypes || !deviceTypes[deviceIndex + 1]) do { + n = receivedata(sudp, bufr, sizeof(bufr), delay, &scope_id); + if (n < 0) { + /* error */ + if(error) + *error = MINISSDPC_SOCKET_ERROR; + goto error; + } else if (n == 0) { + /* no data or Time Out */ +#ifdef DEBUG + printf("NODATA or TIMEOUT\n"); +#endif /* DEBUG */ + if (devlist && !searchalltypes) { + /* found some devices, stop now*/ + if(error) + *error = MINISSDPC_SUCCESS; + goto error; + } + } else { + const char * descURL=NULL; + int urlsize=0; + const char * st=NULL; + int stsize=0; + const char * usn=NULL; + int usnsize=0; + parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize, &usn, &usnsize); + if(st&&descURL) { +#ifdef DEBUG + printf("M-SEARCH Reply:\n ST: %.*s\n USN: %.*s\n Location: %.*s\n", + stsize, st, usnsize, (usn?usn:""), urlsize, descURL); +#endif /* DEBUG */ + for(tmp=devlist; tmp; tmp = tmp->pNext) { + if(memcmp(tmp->descURL, descURL, urlsize) == 0 && + tmp->descURL[urlsize] == '\0' && + memcmp(tmp->st, st, stsize) == 0 && + tmp->st[stsize] == '\0' && + (usnsize == 0 || memcmp(tmp->usn, usn, usnsize) == 0) && + tmp->usn[usnsize] == '\0') + break; + } + /* at the exit of the loop above, tmp is null if + * no duplicate device was found */ + if(tmp) + continue; + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize+usnsize); + if(!tmp) { + /* memory allocation error */ + if(error) + *error = MINISSDPC_MEMORY_ERROR; + goto error; + } + tmp->pNext = devlist; + tmp->descURL = tmp->buffer; + tmp->st = tmp->buffer + 1 + urlsize; + tmp->usn = tmp->st + 1 + stsize; + memcpy(tmp->buffer, descURL, urlsize); + tmp->buffer[urlsize] = '\0'; + memcpy(tmp->st, st, stsize); + tmp->buffer[urlsize+1+stsize] = '\0'; + if(usn != NULL) + memcpy(tmp->usn, usn, usnsize); + tmp->buffer[urlsize+1+stsize+1+usnsize] = '\0'; + tmp->scope_id = scope_id; + devlist = tmp; + } + } + } while(n > 0); + if(ipv6) { + /* switch linklocal flag */ + if(linklocal) { + linklocal = 0; + --deviceIndex; + } else { + linklocal = 1; + } + } + } +error: + closesocket(sudp); + return devlist; +} + diff --git a/deps/miniupnpc/minissdpc.h b/deps/miniupnpc/minissdpc.h new file mode 100644 index 0000000000..167d897cb6 --- /dev/null +++ b/deps/miniupnpc/minissdpc.h @@ -0,0 +1,58 @@ +/* $Id: minissdpc.h,v 1.6 2015/09/18 12:45:16 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINISSDPC_H_INCLUDED +#define MINISSDPC_H_INCLUDED + +#include "miniupnpc_declspec.h" +#include "upnpdev.h" + +/* error codes : */ +#define MINISSDPC_SUCCESS (0) +#define MINISSDPC_UNKNOWN_ERROR (-1) +#define MINISSDPC_SOCKET_ERROR (-101) +#define MINISSDPC_MEMORY_ERROR (-102) +#define MINISSDPC_INVALID_INPUT (-103) +#define MINISSDPC_INVALID_SERVER_REPLY (-104) + +#ifdef __cplusplus +extern "C" { +#endif + +#if !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) + +MINIUPNP_LIBSPEC struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath, int * error); + +MINIUPNP_LIBSPEC int +connectToMiniSSDPD(const char * socketpath); + +MINIUPNP_LIBSPEC int +disconnectFromMiniSSDPD(int fd); + +MINIUPNP_LIBSPEC int +requestDevicesFromMiniSSDPD(int fd, const char * devtype); + +MINIUPNP_LIBSPEC struct UPNPDev * +receiveDevicesFromMiniSSDPD(int fd, int * error); + +#endif /* !(defined(_WIN32) || defined(__amigaos__) || defined(__amigaos4__)) */ + +MINIUPNP_LIBSPEC struct UPNPDev * +ssdpDiscoverDevices(const char * const deviceTypes[], + int delay, const char * multicastif, + int localport, + int ipv6, unsigned char ttl, + int * error, + int searchalltypes); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/deps/miniupnpc/miniupnpc.c b/deps/miniupnpc/miniupnpc.c new file mode 100644 index 0000000000..5eb9500e30 --- /dev/null +++ b/deps/miniupnpc/miniupnpc.c @@ -0,0 +1,722 @@ +/* $Id: miniupnpc.c,v 1.148 2016/01/24 17:24:36 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2016 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#include +#include +#include +#ifdef _WIN32 +/* Win32 Specific includes and defines */ +#include +#include +#include +#include +#define snprintf _snprintf +#define strdup _strdup +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#define MAXHOSTNAMELEN 64 +#else /* #ifdef _WIN32 */ +/* Standard POSIX includes */ +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +/* Amiga OS 3 specific stuff */ +#define socklen_t int +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include +#endif +#include +#include +#define closesocket close +#endif /* #else _WIN32 */ +#ifdef __GNU__ +#define MAXHOSTNAMELEN 64 +#endif + + +#include "miniupnpc.h" +#include "minissdpc.h" +#include "miniwget.h" +#include "minisoap.h" +#include "minixml.h" +#include "upnpcommands.h" +#include "connecthostport.h" + +/* compare the begining of a string with a constant string */ +#define COMPARE(str, cstr) (0==memcmp(str, cstr, sizeof(cstr) - 1)) + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#define SOAPPREFIX "s" +#define SERVICEPREFIX "u" +#define SERVICEPREFIX2 'u' + +/* check if an ip address is a private (LAN) address + * see https://tools.ietf.org/html/rfc1918 */ +static int is_rfc1918addr(const char * addr) +{ + /* 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) */ + if(COMPARE(addr, "192.168.")) + return 1; + /* 10.0.0.0 - 10.255.255.255 (10/8 prefix) */ + if(COMPARE(addr, "10.")) + return 1; + /* 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) */ + if(COMPARE(addr, "172.")) { + int i = atoi(addr + 4); + if((16 <= i) && (i <= 31)) + return 1; + } + return 0; +} + +/* root description parsing */ +MINIUPNP_LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) +{ + struct xmlparser parser; + /* xmlparser object */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = data; + parser.starteltfunc = IGDstartelt; + parser.endeltfunc = IGDendelt; + parser.datafunc = IGDdata; + parser.attfunc = 0; + parsexml(&parser); +#ifdef DEBUG + printIGD(data); +#endif +} + +/* simpleUPnPcommand2 : + * not so simple ! + * return values : + * pointer - OK + * NULL - error */ +char * simpleUPnPcommand2(int s, const char * url, const char * service, + const char * action, struct UPNParg * args, + int * bufsize, const char * httpversion) +{ + char hostname[MAXHOSTNAMELEN+1]; + unsigned short port = 0; + char * path; + char soapact[128]; + char soapbody[2048]; + int soapbodylen; + char * buf; + int n; + int status_code; + + *bufsize = 0; + snprintf(soapact, sizeof(soapact), "%s#%s", service, action); + if(args==NULL) + { + soapbodylen = snprintf(soapbody, sizeof(soapbody), + "\r\n" + "<" SOAPPREFIX ":Envelope " + "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " + SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<" SOAPPREFIX ":Body>" + "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" + "" + "" + "\r\n", action, service, action); + if ((unsigned int)soapbodylen >= sizeof(soapbody)) + return NULL; + } + else + { + char * p; + const char * pe, * pv; + const char * const pend = soapbody + sizeof(soapbody); + soapbodylen = snprintf(soapbody, sizeof(soapbody), + "\r\n" + "<" SOAPPREFIX ":Envelope " + "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " + SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<" SOAPPREFIX ":Body>" + "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", + action, service); + if ((unsigned int)soapbodylen >= sizeof(soapbody)) + return NULL; + p = soapbody + soapbodylen; + while(args->elt) + { + if(p >= pend) /* check for space to write next byte */ + return NULL; + *(p++) = '<'; + + pe = args->elt; + while(p < pend && *pe) + *(p++) = *(pe++); + + if(p >= pend) /* check for space to write next byte */ + return NULL; + *(p++) = '>'; + + if((pv = args->val)) + { + while(p < pend && *pv) + *(p++) = *(pv++); + } + + if((p+2) > pend) /* check for space to write next 2 bytes */ + return NULL; + *(p++) = '<'; + *(p++) = '/'; + + pe = args->elt; + while(p < pend && *pe) + *(p++) = *(pe++); + + if(p >= pend) /* check for space to write next byte */ + return NULL; + *(p++) = '>'; + + args++; + } + if((p+4) > pend) /* check for space to write next 4 bytes */ + return NULL; + *(p++) = '<'; + *(p++) = '/'; + *(p++) = SERVICEPREFIX2; + *(p++) = ':'; + + pe = action; + while(p < pend && *pe) + *(p++) = *(pe++); + + strncpy(p, ">\r\n", + pend - p); + if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */ + return NULL; + } + if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; + if(s < 0) { + s = connecthostport(hostname, port, 0); + if(s < 0) { + /* failed to connect */ + return NULL; + } + } + + n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); + if(n<=0) { +#ifdef DEBUG + printf("Error sending SOAP request\n"); +#endif + closesocket(s); + return NULL; + } + + buf = getHTTPResponse(s, bufsize, &status_code); +#ifdef DEBUG + if(*bufsize > 0 && buf) + { + printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf); + } + else + { + printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize); + } +#endif + closesocket(s); + return buf; +} + +/* simpleUPnPcommand : + * not so simple ! + * return values : + * pointer - OK + * NULL - error */ +char * simpleUPnPcommand(int s, const char * url, const char * service, + const char * action, struct UPNParg * args, + int * bufsize) +{ + char * buf; + +#if 1 + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); +#else + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); + if (!buf || *bufsize == 0) + { +#if DEBUG + printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); +#endif + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); + } +#endif + return buf; +} + +/* upnpDiscoverDevices() : + * return a chained list of all devices found or NULL if + * no devices was found. + * It is up to the caller to free the chained list + * delay is in millisecond (poll). + * UDA v1.1 says : + * The TTL for the IP packet SHOULD default to 2 and + * SHOULD be configurable. */ +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevices(const char * const deviceTypes[], + int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error, + int searchalltypes) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = 0; +#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) + int deviceIndex; +#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ + + if(error) + *error = UPNPDISCOVER_UNKNOWN_ERROR; +#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) + /* first try to get infos from minissdpd ! */ + if(!minissdpdsock) + minissdpdsock = "/var/run/minissdpd.sock"; + for(deviceIndex = 0; deviceTypes[deviceIndex]; deviceIndex++) { + struct UPNPDev * minissdpd_devlist; + int only_rootdevice = 1; + minissdpd_devlist = getDevicesFromMiniSSDPD(deviceTypes[deviceIndex], + minissdpdsock, 0); + if(minissdpd_devlist) { +#ifdef DEBUG + printf("returned by MiniSSDPD: %s\t%s\n", + minissdpd_devlist->st, minissdpd_devlist->descURL); +#endif /* DEBUG */ + if(!strstr(minissdpd_devlist->st, "rootdevice")) + only_rootdevice = 0; + for(tmp = minissdpd_devlist; tmp->pNext != NULL; tmp = tmp->pNext) { +#ifdef DEBUG + printf("returned by MiniSSDPD: %s\t%s\n", + tmp->pNext->st, tmp->pNext->descURL); +#endif /* DEBUG */ + if(!strstr(tmp->st, "rootdevice")) + only_rootdevice = 0; + } + tmp->pNext = devlist; + devlist = minissdpd_devlist; + if(!searchalltypes && !only_rootdevice) + break; + } + } + for(tmp = devlist; tmp != NULL; tmp = tmp->pNext) { + /* We return what we have found if it was not only a rootdevice */ + if(!strstr(tmp->st, "rootdevice")) { + if(error) + *error = UPNPDISCOVER_SUCCESS; + return devlist; + } + } +#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ + + /* direct discovery if minissdpd responses are not sufficient */ + { + struct UPNPDev * discovered_devlist; + discovered_devlist = ssdpDiscoverDevices(deviceTypes, delay, multicastif, localport, + ipv6, ttl, error, searchalltypes); + if(devlist == NULL) + devlist = discovered_devlist; + else { + for(tmp = devlist; tmp->pNext != NULL; tmp = tmp->pNext); + tmp->pNext = discovered_devlist; + } + } + return devlist; +} + +/* upnpDiscover() Discover IGD device */ +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error) +{ + static const char * const deviceList[] = { +#if 0 + "urn:schemas-upnp-org:device:InternetGatewayDevice:2", + "urn:schemas-upnp-org:service:WANIPConnection:2", +#endif + "urn:schemas-upnp-org:device:InternetGatewayDevice:1", + "urn:schemas-upnp-org:service:WANIPConnection:1", + "urn:schemas-upnp-org:service:WANPPPConnection:1", + "upnp:rootdevice", + /*"ssdp:all",*/ + 0 + }; + return upnpDiscoverDevices(deviceList, + delay, multicastif, minissdpdsock, localport, + ipv6, ttl, error, 0); +} + +/* upnpDiscoverAll() Discover all UPnP devices */ +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverAll(int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error) +{ + static const char * const deviceList[] = { + /*"upnp:rootdevice",*/ + "ssdp:all", + 0 + }; + return upnpDiscoverDevices(deviceList, + delay, multicastif, minissdpdsock, localport, + ipv6, ttl, error, 0); +} + +/* upnpDiscoverDevice() Discover a specific device */ +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevice(const char * device, int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error) +{ + const char * const deviceList[] = { + device, + 0 + }; + return upnpDiscoverDevices(deviceList, + delay, multicastif, minissdpdsock, localport, + ipv6, ttl, error, 0); +} + +static char * +build_absolute_url(const char * baseurl, const char * descURL, + const char * url, unsigned int scope_id) +{ + int l, n; + char * s; + const char * base; + char * p; +#if defined(IF_NAMESIZE) && !defined(_WIN32) + char ifname[IF_NAMESIZE]; +#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + char scope_str[8]; +#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + + if( (url[0] == 'h') + &&(url[1] == 't') + &&(url[2] == 't') + &&(url[3] == 'p') + &&(url[4] == ':') + &&(url[5] == '/') + &&(url[6] == '/')) + return strdup(url); + base = (baseurl[0] == '\0') ? descURL : baseurl; + n = strlen(base); + if(n > 7) { + p = strchr(base + 7, '/'); + if(p) + n = p - base; + } + l = n + strlen(url) + 1; + if(url[0] != '/') + l++; + if(scope_id != 0) { +#if defined(IF_NAMESIZE) && !defined(_WIN32) + if(if_indextoname(scope_id, ifname)) { + l += 3 + strlen(ifname); /* 3 == strlen(%25) */ + } +#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + /* under windows, scope is numerical */ + l += 3 + snprintf(scope_str, sizeof(scope_str), "%u", scope_id); +#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + } + s = malloc(l); + if(s == NULL) return NULL; + memcpy(s, base, n); + if(scope_id != 0) { + s[n] = '\0'; + if(0 == memcmp(s, "http://[fe80:", 13)) { + /* this is a linklocal IPv6 address */ + p = strchr(s, ']'); + if(p) { + /* insert %25 into URL */ +#if defined(IF_NAMESIZE) && !defined(_WIN32) + memmove(p + 3 + strlen(ifname), p, strlen(p) + 1); + memcpy(p, "%25", 3); + memcpy(p + 3, ifname, strlen(ifname)); + n += 3 + strlen(ifname); +#else /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + memmove(p + 3 + strlen(scope_str), p, strlen(p) + 1); + memcpy(p, "%25", 3); + memcpy(p + 3, scope_str, strlen(scope_str)); + n += 3 + strlen(scope_str); +#endif /* defined(IF_NAMESIZE) && !defined(_WIN32) */ + } + } + } + if(url[0] != '/') + s[n++] = '/'; + memcpy(s + n, url, l - n); + return s; +} + +/* Prepare the Urls for usage... + */ +MINIUPNP_LIBSPEC void +GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, + const char * descURL, unsigned int scope_id) +{ + /* strdup descURL */ + urls->rootdescURL = strdup(descURL); + + /* get description of WANIPConnection */ + urls->ipcondescURL = build_absolute_url(data->urlbase, descURL, + data->first.scpdurl, scope_id); + urls->controlURL = build_absolute_url(data->urlbase, descURL, + data->first.controlurl, scope_id); + urls->controlURL_CIF = build_absolute_url(data->urlbase, descURL, + data->CIF.controlurl, scope_id); + urls->controlURL_6FC = build_absolute_url(data->urlbase, descURL, + data->IPv6FC.controlurl, scope_id); + +#ifdef DEBUG + printf("urls->ipcondescURL='%s'\n", urls->ipcondescURL); + printf("urls->controlURL='%s'\n", urls->controlURL); + printf("urls->controlURL_CIF='%s'\n", urls->controlURL_CIF); + printf("urls->controlURL_6FC='%s'\n", urls->controlURL_6FC); +#endif +} + +MINIUPNP_LIBSPEC void +FreeUPNPUrls(struct UPNPUrls * urls) +{ + if(!urls) + return; + free(urls->controlURL); + urls->controlURL = 0; + free(urls->ipcondescURL); + urls->ipcondescURL = 0; + free(urls->controlURL_CIF); + urls->controlURL_CIF = 0; + free(urls->controlURL_6FC); + urls->controlURL_6FC = 0; + free(urls->rootdescURL); + urls->rootdescURL = 0; +} + +int +UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) +{ + char status[64]; + unsigned int uptime; + status[0] = '\0'; + UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, + status, &uptime, NULL); + if(0 == strcmp("Connected", status)) + return 1; + else if(0 == strcmp("Up", status)) /* Also accept "Up" */ + return 1; + else + return 0; +} + + +/* UPNP_GetValidIGD() : + * return values : + * -1 = Internal error + * 0 = NO IGD found + * 1 = A valid connected IGD has been found + * 2 = A valid IGD has been found but it reported as + * not connected + * 3 = an UPnP device has been found but was not recognized as an IGD + * + * In any positive non zero return case, the urls and data structures + * passed as parameters are set. Dont forget to call FreeUPNPUrls(urls) to + * free allocated memory. + */ +MINIUPNP_LIBSPEC int +UPNP_GetValidIGD(struct UPNPDev * devlist, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen) +{ + struct xml_desc { + char * xml; + int size; + int is_igd; + } * desc = NULL; + struct UPNPDev * dev; + int ndev = 0; + int i; + int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ + int n_igd = 0; + char extIpAddr[16]; + char myLanAddr[40]; + int status_code = -1; + + if(!devlist) + { +#ifdef DEBUG + printf("Empty devlist\n"); +#endif + return 0; + } + /* counting total number of devices in the list */ + for(dev = devlist; dev; dev = dev->pNext) + ndev++; + if(ndev > 0) + { + desc = calloc(ndev, sizeof(struct xml_desc)); + if(!desc) + return -1; /* memory allocation error */ + } + /* Step 1 : downloading descriptions and testing type */ + for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) + { + /* we should choose an internet gateway device. + * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ + desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), + myLanAddr, sizeof(myLanAddr), + dev->scope_id, &status_code); +#ifdef DEBUG + if(!desc[i].xml) + { + printf("error getting XML description %s\n", dev->descURL); + } +#endif + if(desc[i].xml) + { + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(desc[i].xml, desc[i].size, data); + if(COMPARE(data->CIF.servicetype, + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) + { + desc[i].is_igd = 1; + n_igd++; + if(lanaddr) + strncpy(lanaddr, myLanAddr, lanaddrlen); + } + } + } + /* iterate the list to find a device depending on state */ + for(state = 1; state <= 3; state++) + { + for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) + { + if(desc[i].xml) + { + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(desc[i].xml, desc[i].size, data); + if(desc[i].is_igd || state >= 3 ) + { + int is_connected; + + GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); + + /* in state 2 and 3 we dont test if device is connected ! */ + if(state >= 2) + goto free_and_return; + is_connected = UPNPIGD_IsConnected(urls, data); +#ifdef DEBUG + printf("UPNPIGD_IsConnected(%s) = %d\n", + urls->controlURL, is_connected); +#endif + /* checks that status is connected AND there is a external IP address assigned */ + if(is_connected && + (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { + if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') + && (0 != strcmp(extIpAddr, "0.0.0.0"))) + goto free_and_return; + } + FreeUPNPUrls(urls); + if(data->second.servicetype[0] != '\0') { +#ifdef DEBUG + printf("We tried %s, now we try %s !\n", + data->first.servicetype, data->second.servicetype); +#endif + /* swaping WANPPPConnection and WANIPConnection ! */ + memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); + memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); + memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); + GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); + is_connected = UPNPIGD_IsConnected(urls, data); +#ifdef DEBUG + printf("UPNPIGD_IsConnected(%s) = %d\n", + urls->controlURL, is_connected); +#endif + if(is_connected && + (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { + if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') + && (0 != strcmp(extIpAddr, "0.0.0.0"))) + goto free_and_return; + } + FreeUPNPUrls(urls); + } + } + memset(data, 0, sizeof(struct IGDdatas)); + } + } + } + state = 0; +free_and_return: + if(desc) { + for(i = 0; i < ndev; i++) { + if(desc[i].xml) { + free(desc[i].xml); + } + } + free(desc); + } + return state; +} + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * return value : + * 0 - Not ok + * 1 - OK */ +int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen) +{ + char * descXML; + int descXMLsize = 0; + + descXML = miniwget_getaddr(rootdescurl, &descXMLsize, + lanaddr, lanaddrlen, 0, NULL); + if(descXML) { + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(descXML, descXMLsize, data); + free(descXML); + descXML = NULL; + GetUPNPUrls(urls, data, rootdescurl, 0); + return 1; + } else { + return 0; + } +} + diff --git a/deps/miniupnpc/miniupnpc.def b/deps/miniupnpc/miniupnpc.def new file mode 100644 index 0000000000..60e0bbe423 --- /dev/null +++ b/deps/miniupnpc/miniupnpc.def @@ -0,0 +1,45 @@ +LIBRARY +; miniupnpc library + miniupnpc + +EXPORTS +; miniupnpc + upnpDiscover + freeUPNPDevlist + parserootdesc + UPNP_GetValidIGD + UPNP_GetIGDFromUrl + GetUPNPUrls + FreeUPNPUrls +; miniwget + miniwget + miniwget_getaddr +; upnpcommands + UPNP_GetTotalBytesSent + UPNP_GetTotalBytesReceived + UPNP_GetTotalPacketsSent + UPNP_GetTotalPacketsReceived + UPNP_GetStatusInfo + UPNP_GetConnectionTypeInfo + UPNP_GetExternalIPAddress + UPNP_GetLinkLayerMaxBitRates + UPNP_AddPortMapping + UPNP_AddAnyPortMapping + UPNP_DeletePortMapping + UPNP_DeletePortMappingRange + UPNP_GetPortMappingNumberOfEntries + UPNP_GetSpecificPortMappingEntry + UPNP_GetGenericPortMappingEntry + UPNP_GetListOfPortMappings + UPNP_AddPinhole + UPNP_CheckPinholeWorking + UPNP_UpdatePinhole + UPNP_GetPinholePackets + UPNP_DeletePinhole + UPNP_GetFirewallStatus + UPNP_GetOutboundPinholeTimeout +; upnperrors + strupnperror +; portlistingparse + ParsePortListing + FreePortListing diff --git a/deps/miniupnpc/miniupnpc.h b/deps/miniupnpc/miniupnpc.h new file mode 100644 index 0000000000..0b5b473295 --- /dev/null +++ b/deps/miniupnpc/miniupnpc.h @@ -0,0 +1,152 @@ +/* $Id: miniupnpc.h,v 1.50 2016/04/19 21:06:21 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2005-2016 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPC_H_INCLUDED +#define MINIUPNPC_H_INCLUDED + +#include "miniupnpc_declspec.h" +#include "igd_desc_parse.h" +#include "upnpdev.h" + +/* error codes : */ +#define UPNPDISCOVER_SUCCESS (0) +#define UPNPDISCOVER_UNKNOWN_ERROR (-1) +#define UPNPDISCOVER_SOCKET_ERROR (-101) +#define UPNPDISCOVER_MEMORY_ERROR (-102) + +/* versions : */ +#define MINIUPNPC_VERSION "2.0" +#define MINIUPNPC_API_VERSION 16 + +/* Source port: + Using "1" as an alias for 1900 for backwards compatability + (presuming one would have used that for the "sameport" parameter) */ +#define UPNP_LOCAL_PORT_ANY 0 +#define UPNP_LOCAL_PORT_SAME 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structures definitions : */ +struct UPNParg { const char * elt; const char * val; }; + +char * +simpleUPnPcommand(int, const char *, const char *, + const char *, struct UPNParg *, + int *); + +/* upnpDiscover() + * discover UPnP devices on the network. + * The discovered devices are returned as a chained list. + * It is up to the caller to free the list with freeUPNPDevlist(). + * delay (in millisecond) is the maximum time for waiting any device + * response. + * If available, device list will be obtained from MiniSSDPd. + * Default path for minissdpd socket will be used if minissdpdsock argument + * is NULL. + * If multicastif is not NULL, it will be used instead of the default + * multicast interface for sending SSDP discover packets. + * If localport is set to UPNP_LOCAL_PORT_SAME(1) SSDP packets will be sent + * from the source port 1900 (same as destination port), if set to + * UPNP_LOCAL_PORT_ANY(0) system assign a source port, any other value will + * be attempted as the source port. + * "searchalltypes" parameter is useful when searching several types, + * if 0, the discovery will stop with the first type returning results. + * TTL should default to 2. */ +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverAll(int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevice(const char * device, int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error); + +MINIUPNP_LIBSPEC struct UPNPDev * +upnpDiscoverDevices(const char * const deviceTypes[], + int delay, const char * multicastif, + const char * minissdpdsock, int localport, + int ipv6, unsigned char ttl, + int * error, + int searchalltypes); + +/* parserootdesc() : + * parse root XML description of a UPnP device and fill the IGDdatas + * structure. */ +MINIUPNP_LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); + +/* structure used to get fast access to urls + * controlURL: controlURL of the WANIPConnection + * ipcondescURL: url of the description of the WANIPConnection + * controlURL_CIF: controlURL of the WANCommonInterfaceConfig + * controlURL_6FC: controlURL of the WANIPv6FirewallControl + */ +struct UPNPUrls { + char * controlURL; + char * ipcondescURL; + char * controlURL_CIF; + char * controlURL_6FC; + char * rootdescURL; +}; + +/* UPNP_GetValidIGD() : + * return values : + * 0 = NO IGD found + * 1 = A valid connected IGD has been found + * 2 = A valid IGD has been found but it reported as + * not connected + * 3 = an UPnP device has been found but was not recognized as an IGD + * + * In any non zero return case, the urls and data structures + * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to + * free allocated memory. + */ +MINIUPNP_LIBSPEC int +UPNP_GetValidIGD(struct UPNPDev * devlist, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * When succeding, urls, data, and lanaddr arguments are set. + * return value : + * 0 - Not ok + * 1 - OK */ +MINIUPNP_LIBSPEC int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +MINIUPNP_LIBSPEC void +GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, + const char *, unsigned int); + +MINIUPNP_LIBSPEC void +FreeUPNPUrls(struct UPNPUrls *); + +/* return 0 or 1 */ +MINIUPNP_LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/deps/miniupnpc/miniupnpc_declspec.h b/deps/miniupnpc/miniupnpc_declspec.h new file mode 100644 index 0000000000..e0a624d275 --- /dev/null +++ b/deps/miniupnpc/miniupnpc_declspec.h @@ -0,0 +1,12 @@ +#ifndef MINIUPNPC_DECLSPEC_H_INCLUDED +#define MINIUPNPC_DECLSPEC_H_INCLUDED + +#if defined(__GNUC__) && __GNUC__ >= 4 +/* fix dynlib for OS X 10.9.2 and Apple LLVM version 5.0 */ +#define MINIUPNP_LIBSPEC __attribute__ ((visibility ("default"))) +#else +#define MINIUPNP_LIBSPEC +#endif + +#endif /* MINIUPNPC_DECLSPEC_H_INCLUDED */ + diff --git a/deps/miniupnpc/miniupnpcstrings.h b/deps/miniupnpc/miniupnpcstrings.h new file mode 100644 index 0000000000..68bf4293df --- /dev/null +++ b/deps/miniupnpc/miniupnpcstrings.h @@ -0,0 +1,23 @@ +/* $Id: miniupnpcstrings.h.in,v 1.6 2014/11/04 22:31:55 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2014 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef MINIUPNPCSTRINGS_H_INCLUDED +#define MINIUPNPCSTRINGS_H_INCLUDED + +#define OS_STRING "OS/version" +#define MINIUPNPC_VERSION_STRING "version" + +#if 0 +/* according to "UPnP Device Architecture 1.0" */ +#define UPNP_VERSION_STRING "UPnP/1.0" +#else +/* according to "UPnP Device Architecture 1.1" */ +#define UPNP_VERSION_STRING "UPnP/1.1" +#endif + +#endif + diff --git a/deps/miniupnpc/miniupnpctypes.h b/deps/miniupnpc/miniupnpctypes.h new file mode 100644 index 0000000000..307ce39699 --- /dev/null +++ b/deps/miniupnpc/miniupnpctypes.h @@ -0,0 +1,19 @@ +/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef MINIUPNPCTYPES_H_INCLUDED +#define MINIUPNPCTYPES_H_INCLUDED + +#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) +#define UNSIGNED_INTEGER unsigned long long +#define STRTOUI strtoull +#else +#define UNSIGNED_INTEGER unsigned int +#define STRTOUI strtoul +#endif + +#endif + diff --git a/deps/miniupnpc/miniwget.c b/deps/miniupnpc/miniwget.c new file mode 100644 index 0000000000..84b392b372 --- /dev/null +++ b/deps/miniupnpc/miniwget.c @@ -0,0 +1,661 @@ +/* $Id: miniwget.c,v 1.75 2016/01/24 17:24:36 nanard Exp $ */ +/* Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2016 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#include +#define MAXHOSTNAMELEN 64 +#define snprintf _snprintf +#define socklen_t int +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#else /* #ifdef _WIN32 */ +#include +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#include +#include +#include +#include +#define closesocket close +#include +#endif /* #else _WIN32 */ +#ifdef __GNU__ +#define MAXHOSTNAMELEN 64 +#endif /* __GNU__ */ + +#ifndef MIN +#define MIN(x,y) (((x)<(y))?(x):(y)) +#endif /* MIN */ + + +#include "miniupnpcstrings.h" +#include "miniwget.h" +#include "connecthostport.h" +#include "receivedata.h" + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +/* + * Read a HTTP response from a socket. + * Process Content-Length and Transfer-encoding headers. + * return a pointer to the content buffer, which length is saved + * to the length parameter. + */ +void * +getHTTPResponse(int s, int * size, int * status_code) +{ + char buf[2048]; + int n; + int endofheaders = 0; + int chunked = 0; + int content_length = -1; + unsigned int chunksize = 0; + unsigned int bytestocopy = 0; + /* buffers : */ + char * header_buf; + unsigned int header_buf_len = 2048; + unsigned int header_buf_used = 0; + char * content_buf; + unsigned int content_buf_len = 2048; + unsigned int content_buf_used = 0; + char chunksize_buf[32]; + unsigned int chunksize_buf_index; +#ifdef DEBUG + char * reason_phrase = NULL; + int reason_phrase_len = 0; +#endif + + if(status_code) *status_code = -1; + header_buf = malloc(header_buf_len); + if(header_buf == NULL) + { +#ifdef DEBUG + fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse"); +#endif /* DEBUG */ + *size = -1; + return NULL; + } + content_buf = malloc(content_buf_len); + if(content_buf == NULL) + { + free(header_buf); +#ifdef DEBUG + fprintf(stderr, "%s: Memory allocation error\n", "getHTTPResponse"); +#endif /* DEBUG */ + *size = -1; + return NULL; + } + chunksize_buf[0] = '\0'; + chunksize_buf_index = 0; + + while((n = receivedata(s, buf, 2048, 5000, NULL)) > 0) + { + if(endofheaders == 0) + { + int i; + int linestart=0; + int colon=0; + int valuestart=0; + if(header_buf_used + n > header_buf_len) { + char * tmp = realloc(header_buf, header_buf_used + n); + if(tmp == NULL) { + /* memory allocation error */ + free(header_buf); + free(content_buf); + *size = -1; + return NULL; + } + header_buf = tmp; + header_buf_len = header_buf_used + n; + } + memcpy(header_buf + header_buf_used, buf, n); + header_buf_used += n; + /* search for CR LF CR LF (end of headers) + * recognize also LF LF */ + i = 0; + while(i < ((int)header_buf_used-1) && (endofheaders == 0)) { + if(header_buf[i] == '\r') { + i++; + if(header_buf[i] == '\n') { + i++; + if(i < (int)header_buf_used && header_buf[i] == '\r') { + i++; + if(i < (int)header_buf_used && header_buf[i] == '\n') { + endofheaders = i+1; + } + } + } + } else if(header_buf[i] == '\n') { + i++; + if(header_buf[i] == '\n') { + endofheaders = i+1; + } + } + i++; + } + if(endofheaders == 0) + continue; + /* parse header lines */ + for(i = 0; i < endofheaders - 1; i++) { + if(linestart > 0 && colon <= linestart && header_buf[i]==':') + { + colon = i; + while(i < (endofheaders-1) + && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) + i++; + valuestart = i + 1; + } + /* detecting end of line */ + else if(header_buf[i]=='\r' || header_buf[i]=='\n') + { + if(linestart == 0 && status_code) + { + /* Status line + * HTTP-Version SP Status-Code SP Reason-Phrase CRLF */ + int sp; + for(sp = 0; sp < i; sp++) + if(header_buf[sp] == ' ') + { + if(*status_code < 0) + *status_code = atoi(header_buf + sp + 1); + else + { +#ifdef DEBUG + reason_phrase = header_buf + sp + 1; + reason_phrase_len = i - sp - 1; +#endif + break; + } + } +#ifdef DEBUG + printf("HTTP status code = %d, Reason phrase = %.*s\n", + *status_code, reason_phrase_len, reason_phrase); +#endif + } + else if(colon > linestart && valuestart > colon) + { +#ifdef DEBUG + printf("header='%.*s', value='%.*s'\n", + colon-linestart, header_buf+linestart, + i-valuestart, header_buf+valuestart); +#endif + if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) + { + content_length = atoi(header_buf+valuestart); +#ifdef DEBUG + printf("Content-Length: %d\n", content_length); +#endif + } + else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) + && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) + { +#ifdef DEBUG + printf("chunked transfer-encoding!\n"); +#endif + chunked = 1; + } + } + while((i < (int)header_buf_used) && (header_buf[i]=='\r' || header_buf[i] == '\n')) + i++; + linestart = i; + colon = linestart; + valuestart = 0; + } + } + /* copy the remaining of the received data back to buf */ + n = header_buf_used - endofheaders; + memcpy(buf, header_buf + endofheaders, n); + /* if(headers) */ + } + if(endofheaders) + { + /* content */ + if(chunked) + { + int i = 0; + while(i < n) + { + if(chunksize == 0) + { + /* reading chunk size */ + if(chunksize_buf_index == 0) { + /* skipping any leading CR LF */ + if(i= '0' + && chunksize_buf[j] <= '9') + chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); + else + chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); + } + chunksize_buf[0] = '\0'; + chunksize_buf_index = 0; + i++; + } else { + /* not finished to get chunksize */ + continue; + } +#ifdef DEBUG + printf("chunksize = %u (%x)\n", chunksize, chunksize); +#endif + if(chunksize == 0) + { +#ifdef DEBUG + printf("end of HTTP content - %d %d\n", i, n); + /*printf("'%.*s'\n", n-i, buf+i);*/ +#endif + goto end_of_stream; + } + } + bytestocopy = ((int)chunksize < (n - i))?chunksize:(unsigned int)(n - i); + if((content_buf_used + bytestocopy) > content_buf_len) + { + char * tmp; + if(content_length >= (int)(content_buf_used + bytestocopy)) { + content_buf_len = content_length; + } else { + content_buf_len = content_buf_used + bytestocopy; + } + tmp = realloc(content_buf, content_buf_len); + if(tmp == NULL) { + /* memory allocation error */ + free(content_buf); + free(header_buf); + *size = -1; + return NULL; + } + content_buf = tmp; + } + memcpy(content_buf + content_buf_used, buf + i, bytestocopy); + content_buf_used += bytestocopy; + i += bytestocopy; + chunksize -= bytestocopy; + } + } + else + { + /* not chunked */ + if(content_length > 0 + && (int)(content_buf_used + n) > content_length) { + /* skipping additional bytes */ + n = content_length - content_buf_used; + } + if(content_buf_used + n > content_buf_len) + { + char * tmp; + if(content_length >= (int)(content_buf_used + n)) { + content_buf_len = content_length; + } else { + content_buf_len = content_buf_used + n; + } + tmp = realloc(content_buf, content_buf_len); + if(tmp == NULL) { + /* memory allocation error */ + free(content_buf); + free(header_buf); + *size = -1; + return NULL; + } + content_buf = tmp; + } + memcpy(content_buf + content_buf_used, buf, n); + content_buf_used += n; + } + } + /* use the Content-Length header value if available */ + if(content_length > 0 && (int)content_buf_used >= content_length) + { +#ifdef DEBUG + printf("End of HTTP content\n"); +#endif + break; + } + } +end_of_stream: + free(header_buf); header_buf = NULL; + *size = content_buf_used; + if(content_buf_used == 0) + { + free(content_buf); + content_buf = NULL; + } + return content_buf; +} + +/* miniwget3() : + * do all the work. + * Return NULL if something failed. */ +static void * +miniwget3(const char * host, + unsigned short port, const char * path, + int * size, char * addr_str, int addr_str_len, + const char * httpversion, unsigned int scope_id, + int * status_code) +{ + char buf[2048]; + int s; + int n; + int len; + int sent; + void * content; + + *size = 0; + s = connecthostport(host, port, scope_id); + if(s < 0) + return NULL; + + /* get address for caller ! */ + if(addr_str) + { + struct sockaddr_storage saddr; + socklen_t saddrlen; + + saddrlen = sizeof(saddr); + if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) + { + perror("getsockname"); + } + else + { +#if defined(__amigaos__) && !defined(__amigaos4__) + /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); + * But his function make a string with the port : nn.nn.nn.nn:port */ +/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), + NULL, addr_str, (DWORD *)&addr_str_len)) + { + printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); + }*/ + /* the following code is only compatible with ip v4 addresses */ + strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); +#else +#if 0 + if(saddr.sa_family == AF_INET6) { + inet_ntop(AF_INET6, + &(((struct sockaddr_in6 *)&saddr)->sin6_addr), + addr_str, addr_str_len); + } else { + inet_ntop(AF_INET, + &(((struct sockaddr_in *)&saddr)->sin_addr), + addr_str, addr_str_len); + } +#endif + /* getnameinfo return ip v6 address with the scope identifier + * such as : 2a01:e35:8b2b:7330::%4281128194 */ + n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, + addr_str, addr_str_len, + NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if(n != 0) { +#ifdef _WIN32 + fprintf(stderr, "getnameinfo() failed : %d\n", n); +#else + fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); +#endif + } +#endif + } +#ifdef DEBUG + printf("address miniwget : %s\n", addr_str); +#endif + } + + len = snprintf(buf, sizeof(buf), + "GET %s HTTP/%s\r\n" + "Host: %s:%d\r\n" + "Connection: Close\r\n" + "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + + "\r\n", + path, httpversion, host, port); + if ((unsigned int)len >= sizeof(buf)) + { + closesocket(s); + return NULL; + } + sent = 0; + /* sending the HTTP request */ + while(sent < len) + { + n = send(s, buf+sent, len-sent, 0); + if(n < 0) + { + perror("send"); + closesocket(s); + return NULL; + } + else + { + sent += n; + } + } + content = getHTTPResponse(s, size, status_code); + closesocket(s); + return content; +} + +/* miniwget2() : + * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ +static void * +miniwget2(const char * host, + unsigned short port, const char * path, + int * size, char * addr_str, int addr_str_len, + unsigned int scope_id, int * status_code) +{ + char * respbuffer; + +#if 1 + respbuffer = miniwget3(host, port, path, size, + addr_str, addr_str_len, "1.1", + scope_id, status_code); +#else + respbuffer = miniwget3(host, port, path, size, + addr_str, addr_str_len, "1.0", + scope_id, status_code); + if (*size == 0) + { +#ifdef DEBUG + printf("Retrying with HTTP/1.1\n"); +#endif + free(respbuffer); + respbuffer = miniwget3(host, port, path, size, + addr_str, addr_str_len, "1.1", + scope_id, status_code); + } +#endif + return respbuffer; +} + + + + +/* parseURL() + * arguments : + * url : source string not modified + * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) + * port : port (destination) + * path : pointer to the path part of the URL + * + * Return values : + * 0 - Failure + * 1 - Success */ +int +parseURL(const char * url, + char * hostname, unsigned short * port, + char * * path, unsigned int * scope_id) +{ + char * p1, *p2, *p3; + if(!url) + return 0; + p1 = strstr(url, "://"); + if(!p1) + return 0; + p1 += 3; + if( (url[0]!='h') || (url[1]!='t') + ||(url[2]!='t') || (url[3]!='p')) + return 0; + memset(hostname, 0, MAXHOSTNAMELEN + 1); + if(*p1 == '[') + { + /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ + char * scope; + scope = strchr(p1, '%'); + p2 = strchr(p1, ']'); + if(p2 && scope && scope < p2 && scope_id) { + /* parse scope */ +#ifdef IF_NAMESIZE + char tmp[IF_NAMESIZE]; + int l; + scope++; + /* "%25" is just '%' in URL encoding */ + if(scope[0] == '2' && scope[1] == '5') + scope += 2; /* skip "25" */ + l = p2 - scope; + if(l >= IF_NAMESIZE) + l = IF_NAMESIZE - 1; + memcpy(tmp, scope, l); + tmp[l] = '\0'; + *scope_id = if_nametoindex(tmp); + if(*scope_id == 0) { + *scope_id = (unsigned int)strtoul(tmp, NULL, 10); + } +#else + /* under windows, scope is numerical */ + char tmp[8]; + int l; + scope++; + /* "%25" is just '%' in URL encoding */ + if(scope[0] == '2' && scope[1] == '5') + scope += 2; /* skip "25" */ + l = p2 - scope; + if(l >= sizeof(tmp)) + l = sizeof(tmp) - 1; + memcpy(tmp, scope, l); + tmp[l] = '\0'; + *scope_id = (unsigned int)strtoul(tmp, NULL, 10); +#endif + } + p3 = strchr(p1, '/'); + if(p2 && p3) + { + p2++; + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); + if(*p2 == ':') + { + *port = 0; + p2++; + while( (*p2 >= '0') && (*p2 <= '9')) + { + *port *= 10; + *port += (unsigned short)(*p2 - '0'); + p2++; + } + } + else + { + *port = 80; + } + *path = p3; + return 1; + } + } + p2 = strchr(p1, ':'); + p3 = strchr(p1, '/'); + if(!p3) + return 0; + if(!p2 || (p2>p3)) + { + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); + *port = 80; + } + else + { + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); + *port = 0; + p2++; + while( (*p2 >= '0') && (*p2 <= '9')) + { + *port *= 10; + *port += (unsigned short)(*p2 - '0'); + p2++; + } + } + *path = p3; + return 1; +} + +void * +miniwget(const char * url, int * size, + unsigned int scope_id, int * status_code) +{ + unsigned short port; + char * path; + /* protocol://host:port/chemin */ + char hostname[MAXHOSTNAMELEN+1]; + *size = 0; + if(!parseURL(url, hostname, &port, &path, &scope_id)) + return NULL; +#ifdef DEBUG + printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", + hostname, port, path, scope_id); +#endif + return miniwget2(hostname, port, path, size, 0, 0, scope_id, status_code); +} + +void * +miniwget_getaddr(const char * url, int * size, + char * addr, int addrlen, unsigned int scope_id, + int * status_code) +{ + unsigned short port; + char * path; + /* protocol://host:port/path */ + char hostname[MAXHOSTNAMELEN+1]; + *size = 0; + if(addr) + addr[0] = '\0'; + if(!parseURL(url, hostname, &port, &path, &scope_id)) + return NULL; +#ifdef DEBUG + printf("parsed url : hostname='%s' port=%hu path='%s' scope_id=%u\n", + hostname, port, path, scope_id); +#endif + return miniwget2(hostname, port, path, size, addr, addrlen, scope_id, status_code); +} + diff --git a/deps/miniupnpc/miniwget.h b/deps/miniupnpc/miniwget.h new file mode 100644 index 0000000000..0701494d0c --- /dev/null +++ b/deps/miniupnpc/miniwget.h @@ -0,0 +1,30 @@ +/* $Id: miniwget.h,v 1.12 2016/01/24 17:24:36 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2016 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef MINIWGET_H_INCLUDED +#define MINIWGET_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +MINIUPNP_LIBSPEC void * getHTTPResponse(int s, int * size, int * status_code); + +MINIUPNP_LIBSPEC void * miniwget(const char *, int *, unsigned int, int *); + +MINIUPNP_LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int, unsigned int, int *); + +int parseURL(const char *, char *, unsigned short *, char * *, unsigned int *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/deps/miniupnpc/minixml.c b/deps/miniupnpc/minixml.c new file mode 100644 index 0000000000..1f2227343c --- /dev/null +++ b/deps/miniupnpc/minixml.c @@ -0,0 +1,229 @@ +/* $Id: minixml.c,v 1.10 2012/03/05 19:42:47 nanard Exp $ */ +/* minixml.c : the minimum size a xml parser can be ! */ +/* Project : miniupnp + * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author : Thomas Bernard + +Copyright (c) 2005-2014, Thomas BERNARD +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. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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. +*/ +#include +#include "minixml.h" + +/* parseatt : used to parse the argument list + * return 0 (false) in case of success and -1 (true) if the end + * of the xmlbuffer is reached. */ +static int parseatt(struct xmlparser * p) +{ + const char * attname; + int attnamelen; + const char * attvalue; + int attvaluelen; + while(p->xml < p->xmlend) + { + if(*p->xml=='/' || *p->xml=='>') + return 0; + if( !IS_WHITE_SPACE(*p->xml) ) + { + char sep; + attname = p->xml; + attnamelen = 0; + while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) + { + attnamelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + while(*(p->xml++) != '=') + { + if(p->xml >= p->xmlend) + return -1; + } + while(IS_WHITE_SPACE(*p->xml)) + { + p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + sep = *p->xml; + if(sep=='\'' || sep=='\"') + { + p->xml++; + if(p->xml >= p->xmlend) + return -1; + attvalue = p->xml; + attvaluelen = 0; + while(*p->xml != sep) + { + attvaluelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + } + else + { + attvalue = p->xml; + attvaluelen = 0; + while( !IS_WHITE_SPACE(*p->xml) + && *p->xml != '>' && *p->xml != '/') + { + attvaluelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + } + /*printf("%.*s='%.*s'\n", + attnamelen, attname, attvaluelen, attvalue);*/ + if(p->attfunc) + p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); + } + p->xml++; + } + return -1; +} + +/* parseelt parse the xml stream and + * call the callback functions when needed... */ +static void parseelt(struct xmlparser * p) +{ + int i; + const char * elementname; + while(p->xml < (p->xmlend - 1)) + { + if((p->xml + 4) <= p->xmlend && (0 == memcmp(p->xml, "", 3) != 0); + p->xml += 3; + } + else if((p->xml)[0]=='<' && (p->xml)[1]!='?') + { + i = 0; elementname = ++p->xml; + while( !IS_WHITE_SPACE(*p->xml) + && (*p->xml!='>') && (*p->xml!='/') + ) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + /* to ignore namespace : */ + if(*p->xml==':') + { + i = 0; + elementname = ++p->xml; + } + } + if(i>0) + { + if(p->starteltfunc) + p->starteltfunc(p->data, elementname, i); + if(parseatt(p)) + return; + if(*p->xml!='/') + { + const char * data; + i = 0; data = ++p->xml; + if (p->xml >= p->xmlend) + return; + while( IS_WHITE_SPACE(*p->xml) ) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + } + if(memcmp(p->xml, "xml += 9; + data = p->xml; + i = 0; + while(memcmp(p->xml, "]]>", 3) != 0) + { + i++; p->xml++; + if ((p->xml + 3) >= p->xmlend) + return; + } + if(i>0 && p->datafunc) + p->datafunc(p->data, data, i); + while(*p->xml!='<') + { + p->xml++; + if (p->xml >= p->xmlend) + return; + } + } + else + { + while(*p->xml!='<') + { + i++; p->xml++; + if ((p->xml + 1) >= p->xmlend) + return; + } + if(i>0 && p->datafunc && *(p->xml + 1) == '/') + p->datafunc(p->data, data, i); + } + } + } + else if(*p->xml == '/') + { + i = 0; elementname = ++p->xml; + if (p->xml >= p->xmlend) + return; + while((*p->xml != '>')) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + } + if(p->endeltfunc) + p->endeltfunc(p->data, elementname, i); + p->xml++; + } + } + else + { + p->xml++; + } + } +} + +/* the parser must be initialized before calling this function */ +void parsexml(struct xmlparser * parser) +{ + parser->xml = parser->xmlstart; + parser->xmlend = parser->xmlstart + parser->xmlsize; + parseelt(parser); +} + + diff --git a/deps/miniupnpc/minixml.h b/deps/miniupnpc/minixml.h new file mode 100644 index 0000000000..19e6f513bf --- /dev/null +++ b/deps/miniupnpc/minixml.h @@ -0,0 +1,37 @@ +/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */ +/* minimal xml parser + * + * Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef MINIXML_H_INCLUDED +#define MINIXML_H_INCLUDED +#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) + +/* if a callback function pointer is set to NULL, + * the function is not called */ +struct xmlparser { + const char *xmlstart; + const char *xmlend; + const char *xml; /* pointer to current character */ + int xmlsize; + void * data; + void (*starteltfunc) (void *, const char *, int); + void (*endeltfunc) (void *, const char *, int); + void (*datafunc) (void *, const char *, int); + void (*attfunc) (void *, const char *, int, const char *, int); +}; + +/* parsexml() + * the xmlparser structure must be initialized before the call + * the following structure members have to be initialized : + * xmlstart, xmlsize, data, *func + * xml is for internal usage, xmlend is computed automatically */ +void parsexml(struct xmlparser *); + +#endif + diff --git a/deps/miniupnpc/portlistingparse.c b/deps/miniupnpc/portlistingparse.c new file mode 100644 index 0000000000..55859f2714 --- /dev/null +++ b/deps/miniupnpc/portlistingparse.c @@ -0,0 +1,172 @@ +/* $Id: portlistingparse.c,v 1.9 2015/07/15 12:41:13 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011-2016 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#include +#include +#ifdef DEBUG +#include +#endif /* DEBUG */ +#include "portlistingparse.h" +#include "minixml.h" + +/* list of the elements */ +static const struct { + const portMappingElt code; + const char * const str; +} elements[] = { + { PortMappingEntry, "PortMappingEntry"}, + { NewRemoteHost, "NewRemoteHost"}, + { NewExternalPort, "NewExternalPort"}, + { NewProtocol, "NewProtocol"}, + { NewInternalPort, "NewInternalPort"}, + { NewInternalClient, "NewInternalClient"}, + { NewEnabled, "NewEnabled"}, + { NewDescription, "NewDescription"}, + { NewLeaseTime, "NewLeaseTime"}, + { PortMappingEltNone, NULL} +}; + +/* Helper function */ +static UNSIGNED_INTEGER +atoui(const char * p, int l) +{ + UNSIGNED_INTEGER r = 0; + while(l > 0 && *p) + { + if(*p >= '0' && *p <= '9') + r = r*10 + (*p - '0'); + else + break; + p++; + l--; + } + return r; +} + +/* Start element handler */ +static void +startelt(void * d, const char * name, int l) +{ + int i; + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + pdata->curelt = PortMappingEltNone; + for(i = 0; elements[i].str; i++) + { + if(strlen(elements[i].str) == (size_t)l && memcmp(name, elements[i].str, l) == 0) + { + pdata->curelt = elements[i].code; + break; + } + } + if(pdata->curelt == PortMappingEntry) + { + struct PortMapping * pm; + pm = calloc(1, sizeof(struct PortMapping)); + if(pm == NULL) + { + /* malloc error */ +#ifdef DEBUG + fprintf(stderr, "%s: error allocating memory", + "startelt"); +#endif /* DEBUG */ + return; + } + pm->l_next = pdata->l_head; /* insert in list */ + pdata->l_head = pm; + } +} + +/* End element handler */ +static void +endelt(void * d, const char * name, int l) +{ + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + (void)name; + (void)l; + pdata->curelt = PortMappingEltNone; +} + +/* Data handler */ +static void +data(void * d, const char * data, int l) +{ + struct PortMapping * pm; + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + pm = pdata->l_head; + if(!pm) + return; + if(l > 63) + l = 63; + switch(pdata->curelt) + { + case NewRemoteHost: + memcpy(pm->remoteHost, data, l); + pm->remoteHost[l] = '\0'; + break; + case NewExternalPort: + pm->externalPort = (unsigned short)atoui(data, l); + break; + case NewProtocol: + if(l > 3) + l = 3; + memcpy(pm->protocol, data, l); + pm->protocol[l] = '\0'; + break; + case NewInternalPort: + pm->internalPort = (unsigned short)atoui(data, l); + break; + case NewInternalClient: + memcpy(pm->internalClient, data, l); + pm->internalClient[l] = '\0'; + break; + case NewEnabled: + pm->enabled = (unsigned char)atoui(data, l); + break; + case NewDescription: + memcpy(pm->description, data, l); + pm->description[l] = '\0'; + break; + case NewLeaseTime: + pm->leaseTime = atoui(data, l); + break; + default: + break; + } +} + + +/* Parse the PortMappingList XML document for IGD version 2 + */ +void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata) +{ + struct xmlparser parser; + + memset(pdata, 0, sizeof(struct PortMappingParserData)); + /* init xmlparser */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = pdata; + parser.starteltfunc = startelt; + parser.endeltfunc = endelt; + parser.datafunc = data; + parser.attfunc = 0; + parsexml(&parser); +} + +void +FreePortListing(struct PortMappingParserData * pdata) +{ + struct PortMapping * pm; + while((pm = pdata->l_head) != NULL) + { + /* remove from list */ + pdata->l_head = pm->l_next; + free(pm); + } +} + diff --git a/deps/miniupnpc/portlistingparse.h b/deps/miniupnpc/portlistingparse.h new file mode 100644 index 0000000000..e3957a3f4c --- /dev/null +++ b/deps/miniupnpc/portlistingparse.h @@ -0,0 +1,65 @@ +/* $Id: portlistingparse.h,v 1.10 2014/11/01 10:37:32 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011-2015 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#ifndef PORTLISTINGPARSE_H_INCLUDED +#define PORTLISTINGPARSE_H_INCLUDED + +#include "miniupnpc_declspec.h" +/* for the definition of UNSIGNED_INTEGER */ +#include "miniupnpctypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* sample of PortMappingEntry : + + 202.233.2.1 + 2345 + TCP + 2345 + 192.168.1.137 + 1 + dooom + 345 + + */ +typedef enum { PortMappingEltNone, + PortMappingEntry, NewRemoteHost, + NewExternalPort, NewProtocol, + NewInternalPort, NewInternalClient, + NewEnabled, NewDescription, + NewLeaseTime } portMappingElt; + +struct PortMapping { + struct PortMapping * l_next; /* list next element */ + UNSIGNED_INTEGER leaseTime; + unsigned short externalPort; + unsigned short internalPort; + char remoteHost[64]; + char internalClient[64]; + char description[64]; + char protocol[4]; + unsigned char enabled; +}; + +struct PortMappingParserData { + struct PortMapping * l_head; /* list head */ + portMappingElt curelt; +}; + +MINIUPNP_LIBSPEC void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata); + +MINIUPNP_LIBSPEC void +FreePortListing(struct PortMappingParserData * pdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/miniupnpc/receivedata.c b/deps/miniupnpc/receivedata.c new file mode 100644 index 0000000000..ef85a3db41 --- /dev/null +++ b/deps/miniupnpc/receivedata.c @@ -0,0 +1,105 @@ +/* $Id: receivedata.c,v 1.7 2015/11/09 21:51:41 nanard Exp $ */ +/* Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2011-2014 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include +#include +#ifdef _WIN32 +#include +#include +#else /* _WIN32 */ +#include +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#include +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include +#endif /* !defined(__amigaos__) && !defined(__amigaos4__) */ +#include +#define MINIUPNPC_IGNORE_EINTR +#endif /* _WIN32 */ + +#ifdef _WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#include "receivedata.h" + +int +receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id) +{ +#ifdef MINIUPNPC_GET_SRC_ADDR + struct sockaddr_storage src_addr; + socklen_t src_addr_len = sizeof(src_addr); +#endif /* MINIUPNPC_GET_SRC_ADDR */ + int n; +#if !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) + /* using poll */ + struct pollfd fds[1]; /* for the poll */ +#ifdef MINIUPNPC_IGNORE_EINTR + do { +#endif /* MINIUPNPC_IGNORE_EINTR */ + fds[0].fd = socket; + fds[0].events = POLLIN; + n = poll(fds, 1, timeout); +#ifdef MINIUPNPC_IGNORE_EINTR + } while(n < 0 && errno == EINTR); +#endif /* MINIUPNPC_IGNORE_EINTR */ + if(n < 0) { + PRINT_SOCKET_ERROR("poll"); + return -1; + } else if(n == 0) { + /* timeout */ + return 0; + } +#else /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ + /* using select under _WIN32 and amigaos */ + fd_set socketSet; + TIMEVAL timeval; + FD_ZERO(&socketSet); + FD_SET(socket, &socketSet); + timeval.tv_sec = timeout / 1000; + timeval.tv_usec = (timeout % 1000) * 1000; + n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); + if(n < 0) { + PRINT_SOCKET_ERROR("select"); + return -1; + } else if(n == 0) { + return 0; + } +#endif /* !defined(_WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ +#ifdef MINIUPNPC_GET_SRC_ADDR + memset(&src_addr, 0, sizeof(src_addr)); + n = recvfrom(socket, data, length, 0, + (struct sockaddr *)&src_addr, &src_addr_len); +#else /* MINIUPNPC_GET_SRC_ADDR */ + n = recv(socket, data, length, 0); +#endif /* MINIUPNPC_GET_SRC_ADDR */ + if(n<0) { + PRINT_SOCKET_ERROR("recv"); + } +#ifdef MINIUPNPC_GET_SRC_ADDR + if (src_addr.ss_family == AF_INET6) { + const struct sockaddr_in6 * src_addr6 = (struct sockaddr_in6 *)&src_addr; +#ifdef DEBUG + printf("scope_id=%u\n", src_addr6->sin6_scope_id); +#endif /* DEBUG */ + if(scope_id) + *scope_id = src_addr6->sin6_scope_id; + } +#endif /* MINIUPNPC_GET_SRC_ADDR */ + return n; +} + diff --git a/deps/miniupnpc/receivedata.h b/deps/miniupnpc/receivedata.h new file mode 100644 index 0000000000..cb85c33177 --- /dev/null +++ b/deps/miniupnpc/receivedata.h @@ -0,0 +1,19 @@ +/* $Id: receivedata.h,v 1.3 2012/06/23 22:34:47 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2011-2012 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef RECEIVEDATA_H_INCLUDED +#define RECEIVEDATA_H_INCLUDED + +/* Reads data from the specified socket. + * Returns the number of bytes read if successful, zero if no bytes were + * read or if we timed out. Returns negative if there was an error. */ +int receivedata(int socket, + char * data, int length, + int timeout, unsigned int * scope_id); + +#endif + diff --git a/deps/miniupnpc/updateminiupnpcstrings.sh b/deps/miniupnpc/updateminiupnpcstrings.sh new file mode 100755 index 0000000000..dde4354a8a --- /dev/null +++ b/deps/miniupnpc/updateminiupnpcstrings.sh @@ -0,0 +1,53 @@ +#! /bin/sh +# $Id: updateminiupnpcstrings.sh,v 1.7 2011/01/04 11:41:53 nanard Exp $ +# project miniupnp : http://miniupnp.free.fr/ +# (c) 2009 Thomas Bernard + +FILE=miniupnpcstrings.h +TMPFILE=miniupnpcstrings.h.tmp +TEMPLATE_FILE=${FILE}.in + +# detecting the OS name and version +OS_NAME=`uname -s` +OS_VERSION=`uname -r` +if [ -f /etc/debian_version ]; then + OS_NAME=Debian + OS_VERSION=`cat /etc/debian_version` +fi +# use lsb_release (Linux Standard Base) when available +LSB_RELEASE=`which lsb_release` +if [ 0 -eq $? -a -x "${LSB_RELEASE}" ]; then + OS_NAME=`${LSB_RELEASE} -i -s` + OS_VERSION=`${LSB_RELEASE} -r -s` + case $OS_NAME in + Debian) + #OS_VERSION=`${LSB_RELEASE} -c -s` + ;; + Ubuntu) + #OS_VERSION=`${LSB_RELEASE} -c -s` + ;; + esac +fi + +# on AmigaOS 3, uname -r returns "unknown", so we use uname -v +if [ "$OS_NAME" = "AmigaOS" ]; then + if [ "$OS_VERSION" = "unknown" ]; then + OS_VERSION=`uname -v` + fi +fi + +echo "Detected OS [$OS_NAME] version [$OS_VERSION]" +MINIUPNPC_VERSION=`cat VERSION` +echo "MiniUPnPc version [${MINIUPNPC_VERSION}]" + +EXPR="s|OS_STRING \".*\"|OS_STRING \"${OS_NAME}/${OS_VERSION}\"|" +#echo $EXPR +test -f ${FILE}.in +echo "setting OS_STRING macro value to ${OS_NAME}/${OS_VERSION} in $FILE." +sed -e "$EXPR" < $TEMPLATE_FILE > $TMPFILE + +EXPR="s|MINIUPNPC_VERSION_STRING \".*\"|MINIUPNPC_VERSION_STRING \"${MINIUPNPC_VERSION}\"|" +echo "setting MINIUPNPC_VERSION_STRING macro value to ${MINIUPNPC_VERSION} in $FILE." +sed -e "$EXPR" < $TMPFILE > $FILE +rm $TMPFILE + diff --git a/deps/miniupnpc/upnpcommands.c b/deps/miniupnpc/upnpcommands.c new file mode 100644 index 0000000000..9f704496fb --- /dev/null +++ b/deps/miniupnpc/upnpcommands.c @@ -0,0 +1,1240 @@ +/* $Id: upnpcommands.c,v 1.46 2015/07/15 12:19:00 nanard Exp $ */ +/* vim: tabstop=4 shiftwidth=4 noexpandtab + * Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2017 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#include +#include +#include +#include "upnpcommands.h" +#include "miniupnpc.h" +#include "portlistingparse.h" + +static UNSIGNED_INTEGER +my_atoui(const char * s) +{ + return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; +} + +/* + * */ +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalBytesSent", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalBytesReceived", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalPacketsSent", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalPacketsReceived", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* UPNP_GetStatusInfo() call the corresponding UPNP method + * returns the current status and uptime */ +MINIUPNP_LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + char * up; + char * err; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!status && !uptime) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetStatusInfo", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + up = GetValueFromNameValueList(&pdata, "NewUptime"); + p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); + err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); + if(p && up) + ret = UPNPCOMMAND_SUCCESS; + + if(status) { + if(p){ + strncpy(status, p, 64 ); + status[63] = '\0'; + }else + status[0]= '\0'; + } + + if(uptime) { + if(up) + sscanf(up,"%u",uptime); + else + *uptime = 0; + } + + if(lastconnerror) { + if(err) { + strncpy(lastconnerror, err, 64 ); + lastconnerror[63] = '\0'; + } else + lastconnerror[0] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method + * returns the connection type */ +MINIUPNP_LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!connectionType) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetConnectionTypeInfo", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewConnectionType"); + /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ + /* PossibleConnectionTypes will have several values.... */ + if(p) { + strncpy(connectionType, p, 64 ); + connectionType[63] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + connectionType[0] = '\0'; + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. + * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. + * One of the values can be null + * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only + * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */ +MINIUPNP_LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char * controlURL, + const char * servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + char * down; + char * up; + char * p; + + if(!bitrateDown && !bitrateUp) + return UPNPCOMMAND_INVALID_ARGS; + + /* shouldn't we use GetCommonLinkProperties ? */ + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetCommonLinkProperties", 0, &bufsize))) { + /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ + /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ + down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); + up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); + /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ + /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ + if(down && up) + ret = UPNPCOMMAND_SUCCESS; + + if(bitrateDown) { + if(down) + sscanf(down,"%u",bitrateDown); + else + *bitrateDown = 0; + } + + if(bitrateUp) { + if(up) + sscanf(up,"%u",bitrateUp); + else + *bitrateUp = 0; + } + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + + +/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. + * if the third arg is not null the value is copied to it. + * at least 16 bytes must be available + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + */ +MINIUPNP_LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, + const char * servicetype, + char * extIpAdd) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!extIpAdd || !controlURL || !servicetype) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetExternalIPAddress", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ + p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); + if(p) { + strncpy(extIpAdd, p, 16 ); + extIpAdd[15] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + extIpAdd[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_AddPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration) +{ + struct UPNParg * AddPortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!inPort || !inClient || !proto || !extPort) + return UPNPCOMMAND_INVALID_ARGS; + + AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); + if(AddPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + AddPortMappingArgs[0].elt = "NewRemoteHost"; + AddPortMappingArgs[0].val = remoteHost; + AddPortMappingArgs[1].elt = "NewExternalPort"; + AddPortMappingArgs[1].val = extPort; + AddPortMappingArgs[2].elt = "NewProtocol"; + AddPortMappingArgs[2].val = proto; + AddPortMappingArgs[3].elt = "NewInternalPort"; + AddPortMappingArgs[3].val = inPort; + AddPortMappingArgs[4].elt = "NewInternalClient"; + AddPortMappingArgs[4].val = inClient; + AddPortMappingArgs[5].elt = "NewEnabled"; + AddPortMappingArgs[5].val = "1"; + AddPortMappingArgs[6].elt = "NewPortMappingDescription"; + AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; + AddPortMappingArgs[7].elt = "NewLeaseDuration"; + AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddPortMapping", AddPortMappingArgs, + &bufsize); + free(AddPortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + /*buffer[bufsize] = '\0';*/ + /*puts(buffer);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration, + char * reservedPort) +{ + struct UPNParg * AddPortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!inPort || !inClient || !proto || !extPort) + return UPNPCOMMAND_INVALID_ARGS; + + AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); + if(AddPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + AddPortMappingArgs[0].elt = "NewRemoteHost"; + AddPortMappingArgs[0].val = remoteHost; + AddPortMappingArgs[1].elt = "NewExternalPort"; + AddPortMappingArgs[1].val = extPort; + AddPortMappingArgs[2].elt = "NewProtocol"; + AddPortMappingArgs[2].val = proto; + AddPortMappingArgs[3].elt = "NewInternalPort"; + AddPortMappingArgs[3].val = inPort; + AddPortMappingArgs[4].elt = "NewInternalClient"; + AddPortMappingArgs[4].val = inClient; + AddPortMappingArgs[5].elt = "NewEnabled"; + AddPortMappingArgs[5].val = "1"; + AddPortMappingArgs[6].elt = "NewPortMappingDescription"; + AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; + AddPortMappingArgs[7].elt = "NewLeaseDuration"; + AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddAnyPortMapping", AddPortMappingArgs, + &bufsize); + free(AddPortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + char *p; + + p = GetValueFromNameValueList(&pdata, "NewReservedPort"); + if(p) { + strncpy(reservedPort, p, 6); + reservedPort[5] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else { + ret = UPNPCOMMAND_INVALID_RESPONSE; + } + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost) +{ + /*struct NameValueParserData pdata;*/ + struct UPNParg * DeletePortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!extPort || !proto) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); + if(DeletePortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + DeletePortMappingArgs[0].elt = "NewRemoteHost"; + DeletePortMappingArgs[0].val = remoteHost; + DeletePortMappingArgs[1].elt = "NewExternalPort"; + DeletePortMappingArgs[1].val = extPort; + DeletePortMappingArgs[2].elt = "NewProtocol"; + DeletePortMappingArgs[2].val = proto; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePortMapping", + DeletePortMappingArgs, &bufsize); + free(DeletePortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, + const char * extPortStart, const char * extPortEnd, + const char * proto, + const char * manage) +{ + struct UPNParg * DeletePortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!extPortStart || !extPortEnd || !proto || !manage) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePortMappingArgs = calloc(5, sizeof(struct UPNParg)); + if(DeletePortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + DeletePortMappingArgs[0].elt = "NewStartPort"; + DeletePortMappingArgs[0].val = extPortStart; + DeletePortMappingArgs[1].elt = "NewEndPort"; + DeletePortMappingArgs[1].val = extPortEnd; + DeletePortMappingArgs[2].elt = "NewProtocol"; + DeletePortMappingArgs[2].val = proto; + DeletePortMappingArgs[3].elt = "NewManage"; + DeletePortMappingArgs[3].val = manage; + + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePortMappingRange", + DeletePortMappingArgs, &bufsize); + free(DeletePortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_GetGenericPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * index, + char * extPort, + char * intClient, + char * intPort, + char * protocol, + char * desc, + char * enabled, + char * rHost, + char * duration) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPortMappingArgs; + char * buffer; + int bufsize; + char * p; + int r = UPNPCOMMAND_UNKNOWN_ERROR; + if(!index) + return UPNPCOMMAND_INVALID_ARGS; + intClient[0] = '\0'; + intPort[0] = '\0'; + GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); + if(GetPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + GetPortMappingArgs[0].elt = "NewPortMappingIndex"; + GetPortMappingArgs[0].val = index; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetGenericPortMappingEntry", + GetPortMappingArgs, &bufsize); + free(GetPortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); + if(p && rHost) + { + strncpy(rHost, p, 64); + rHost[63] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewExternalPort"); + if(p && extPort) + { + strncpy(extPort, p, 6); + extPort[5] = '\0'; + r = UPNPCOMMAND_SUCCESS; + } + p = GetValueFromNameValueList(&pdata, "NewProtocol"); + if(p && protocol) + { + strncpy(protocol, p, 4); + protocol[3] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewInternalClient"); + if(p) + { + strncpy(intClient, p, 16); + intClient[15] = '\0'; + r = 0; + } + p = GetValueFromNameValueList(&pdata, "NewInternalPort"); + if(p) + { + strncpy(intPort, p, 6); + intPort[5] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewEnabled"); + if(p && enabled) + { + strncpy(enabled, p, 4); + enabled[3] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); + if(p && desc) + { + strncpy(desc, p, 80); + desc[79] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); + if(p && duration) + { + strncpy(duration, p, 16); + duration[15] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + r = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &r); + } + ClearNameValueList(&pdata); + return r; +} + +MINIUPNP_LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char * controlURL, + const char * servicetype, + unsigned int * numEntries) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char* p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetPortMappingNumberOfEntries", 0, + &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } +#ifdef DEBUG + DisplayNameValueList(buffer, bufsize); +#endif + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); + if(numEntries && p) { + *numEntries = 0; + sscanf(p, "%u", numEntries); + ret = UPNPCOMMAND_SUCCESS; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping + * the result is returned in the intClient and intPort strings + * please provide 16 and 6 bytes of data */ +MINIUPNP_LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * extPort, + const char * proto, + const char * remoteHost, + char * intClient, + char * intPort, + char * desc, + char * enabled, + char * leaseDuration) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPortMappingArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!intPort || !intClient || !extPort || !proto) + return UPNPCOMMAND_INVALID_ARGS; + + GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); + if(GetPortMappingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + GetPortMappingArgs[0].elt = "NewRemoteHost"; + GetPortMappingArgs[0].val = remoteHost; + GetPortMappingArgs[1].elt = "NewExternalPort"; + GetPortMappingArgs[1].val = extPort; + GetPortMappingArgs[2].elt = "NewProtocol"; + GetPortMappingArgs[2].val = proto; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetSpecificPortMappingEntry", + GetPortMappingArgs, &bufsize); + free(GetPortMappingArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewInternalClient"); + if(p) { + strncpy(intClient, p, 16); + intClient[15] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + intClient[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "NewInternalPort"); + if(p) { + strncpy(intPort, p, 6); + intPort[5] = '\0'; + } else + intPort[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "NewEnabled"); + if(p && enabled) { + strncpy(enabled, p, 4); + enabled[3] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); + if(p && desc) { + strncpy(desc, p, 80); + desc[79] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); + if(p && leaseDuration) + { + strncpy(leaseDuration, p, 16); + leaseDuration[15] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetListOfPortMappings() + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + * consistent. + */ +MINIUPNP_LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, + const char * servicetype, + const char * startPort, + const char * endPort, + const char * protocol, + const char * numberOfPorts, + struct PortMappingParserData * data) +{ + struct NameValueParserData pdata; + struct UPNParg * GetListOfPortMappingsArgs; + const char * p; + char * buffer; + int bufsize; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!startPort || !endPort || !protocol) + return UPNPCOMMAND_INVALID_ARGS; + + GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); + if(GetListOfPortMappingsArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + GetListOfPortMappingsArgs[0].elt = "NewStartPort"; + GetListOfPortMappingsArgs[0].val = startPort; + GetListOfPortMappingsArgs[1].elt = "NewEndPort"; + GetListOfPortMappingsArgs[1].val = endPort; + GetListOfPortMappingsArgs[2].elt = "NewProtocol"; + GetListOfPortMappingsArgs[2].val = protocol; + GetListOfPortMappingsArgs[3].elt = "NewManage"; + GetListOfPortMappingsArgs[3].val = "1"; + GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; + GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; + + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetListOfPortMappings", + GetListOfPortMappingsArgs, &bufsize); + free(GetListOfPortMappingsArgs); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ + /*if(p) { + printf("NewPortListing : %s\n", p); + }*/ + /*printf("NewPortListing(%d chars) : %s\n", + pdata.portListingLength, pdata.portListing);*/ + if(pdata.portListing) + { + /*struct PortMapping * pm; + int i = 0;*/ + ParsePortListing(pdata.portListing, pdata.portListingLength, + data); + ret = UPNPCOMMAND_SUCCESS; + /* + for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) + { + printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", + i, pm->protocol, pm->externalPort, pm->internalClient, + pm->internalPort, + pm->description, pm->remoteHost); + i++; + } + */ + /*FreePortListing(&data);*/ + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + + /*printf("%.*s", bufsize, buffer);*/ + + return ret; +} + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +MINIUPNP_LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * fe, *ipa, *p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!firewallEnabled || !inboundPinholeAllowed) + return UPNPCOMMAND_INVALID_ARGS; + + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetFirewallStatus", 0, &bufsize); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); + ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); + if(ipa && fe) + ret = UPNPCOMMAND_SUCCESS; + if(fe) + *firewallEnabled = my_atoui(fe); + /*else + *firewallEnabled = 0;*/ + if(ipa) + *inboundPinholeAllowed = my_atoui(ipa); + /*else + *inboundPinholeAllowed = 0;*/ + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + int * opTimeout) +{ + struct UPNParg * GetOutboundPinholeTimeoutArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + char * p; + int ret; + + if(!intPort || !intClient || !proto || !remotePort || !remoteHost) + return UPNPCOMMAND_INVALID_ARGS; + + GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); + if(GetOutboundPinholeTimeoutArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; + GetOutboundPinholeTimeoutArgs[0].val = remoteHost; + GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; + GetOutboundPinholeTimeoutArgs[1].val = remotePort; + GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; + GetOutboundPinholeTimeoutArgs[2].val = proto; + GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; + GetOutboundPinholeTimeoutArgs[3].val = intPort; + GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; + GetOutboundPinholeTimeoutArgs[4].val = intClient; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); + free(GetOutboundPinholeTimeoutArgs); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); + if(p) + *opTimeout = my_atoui(p); + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + const char * leaseTime, + char * uniqueID) +{ + struct UPNParg * AddPinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + char * p; + int ret; + + if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) + return UPNPCOMMAND_INVALID_ARGS; + + AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); + if(AddPinholeArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + /* RemoteHost can be wilcarded */ + if(strncmp(remoteHost, "empty", 5)==0) + { + AddPinholeArgs[0].elt = "RemoteHost"; + AddPinholeArgs[0].val = ""; + } + else + { + AddPinholeArgs[0].elt = "RemoteHost"; + AddPinholeArgs[0].val = remoteHost; + } + AddPinholeArgs[1].elt = "RemotePort"; + AddPinholeArgs[1].val = remotePort; + AddPinholeArgs[2].elt = "Protocol"; + AddPinholeArgs[2].val = proto; + AddPinholeArgs[3].elt = "InternalPort"; + AddPinholeArgs[3].val = intPort; + if(strncmp(intClient, "empty", 5)==0) + { + AddPinholeArgs[4].elt = "InternalClient"; + AddPinholeArgs[4].val = ""; + } + else + { + AddPinholeArgs[4].elt = "InternalClient"; + AddPinholeArgs[4].val = intClient; + } + AddPinholeArgs[5].elt = "LeaseTime"; + AddPinholeArgs[5].val = leaseTime; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddPinhole", AddPinholeArgs, &bufsize); + free(AddPinholeArgs); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "UniqueID"); + if(p) + { + strncpy(uniqueID, p, 8); + uniqueID[7] = '\0'; + } + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + /*printf("AddPortMapping errorCode = '%s'\n", resVal);*/ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime) +{ + struct UPNParg * UpdatePinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!uniqueID || !leaseTime) + return UPNPCOMMAND_INVALID_ARGS; + + UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); + if(UpdatePinholeArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + UpdatePinholeArgs[0].elt = "UniqueID"; + UpdatePinholeArgs[0].val = uniqueID; + UpdatePinholeArgs[1].elt = "NewLeaseTime"; + UpdatePinholeArgs[1].val = leaseTime; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "UpdatePinhole", UpdatePinholeArgs, &bufsize); + free(UpdatePinholeArgs); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) +{ + /*struct NameValueParserData pdata;*/ + struct UPNParg * DeletePinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); + if(DeletePinholeArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + DeletePinholeArgs[0].elt = "UniqueID"; + DeletePinholeArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePinhole", DeletePinholeArgs, &bufsize); + free(DeletePinholeArgs); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking) +{ + struct NameValueParserData pdata; + struct UPNParg * CheckPinholeWorkingArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); + if(CheckPinholeWorkingArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + CheckPinholeWorkingArgs[0].elt = "UniqueID"; + CheckPinholeWorkingArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); + free(CheckPinholeWorkingArgs); + if(!buffer) + { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "IsWorking"); + if(p) + { + *isWorking=my_atoui(p); + ret = UPNPCOMMAND_SUCCESS; + } + else + *isWorking = 0; + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +MINIUPNP_LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPinholePacketsArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); + if(GetPinholePacketsArgs == NULL) + return UPNPCOMMAND_MEM_ALLOC_ERROR; + GetPinholePacketsArgs[0].elt = "UniqueID"; + GetPinholePacketsArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetPinholePackets", GetPinholePacketsArgs, &bufsize); + free(GetPinholePacketsArgs); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "PinholePackets"); + if(p) + { + *packets=my_atoui(p); + ret = UPNPCOMMAND_SUCCESS; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + + diff --git a/deps/miniupnpc/upnpcommands.h b/deps/miniupnpc/upnpcommands.h new file mode 100644 index 0000000000..55b7b060dc --- /dev/null +++ b/deps/miniupnpc/upnpcommands.h @@ -0,0 +1,348 @@ +/* $Id: upnpcommands.h,v 1.30 2015/07/15 12:21:28 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2015 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef UPNPCOMMANDS_H_INCLUDED +#define UPNPCOMMANDS_H_INCLUDED + +#include "upnpreplyparse.h" +#include "portlistingparse.h" +#include "miniupnpc_declspec.h" +#include "miniupnpctypes.h" + +/* MiniUPnPc return codes : */ +#define UPNPCOMMAND_SUCCESS (0) +#define UPNPCOMMAND_UNKNOWN_ERROR (-1) +#define UPNPCOMMAND_INVALID_ARGS (-2) +#define UPNPCOMMAND_HTTP_ERROR (-3) +#define UPNPCOMMAND_INVALID_RESPONSE (-4) +#define UPNPCOMMAND_MEM_ALLOC_ERROR (-5) + +#ifdef __cplusplus +extern "C" { +#endif + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype); + +MINIUPNP_LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype); + +/* UPNP_GetStatusInfo() + * status and lastconnerror are 64 byte buffers + * Return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +MINIUPNP_LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror); + +/* UPNP_GetConnectionTypeInfo() + * argument connectionType is a 64 character buffer + * Return Values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +MINIUPNP_LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType); + +/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. + * if the third arg is not null the value is copied to it. + * at least 16 bytes must be available + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * possible UPnP Errors : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. */ +MINIUPNP_LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, + const char * servicetype, + char * extIpAdd); + +/* UPNP_GetLinkLayerMaxBitRates() + * call WANCommonInterfaceConfig:1#GetCommonLinkProperties + * + * return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +MINIUPNP_LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char* controlURL, + const char* servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp); + +/* UPNP_AddPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 718 ConflictInMappingEntry - The port mapping entry specified conflicts + * with a mapping assigned previously to another client + * 724 SamePortValuesRequired - Internal and External port values + * must be the same + * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports + * permanent lease times on port mappings + * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard + * and cannot be a specific IP address or DNS name + * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and + * cannot be a specific port value + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ +MINIUPNP_LIBSPEC int +UPNP_AddPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration); + +/* UPNP_AddAnyPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization and + * the sender was not authorized. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 728 NoPortMapsAvailable - There are not enough free ports available to + * complete port mapping. + * 729 ConflictWithOtherMechanisms - Attempted port mapping is not allowed + * due to conflict with other mechanisms. + * 732 WildCardNotPermittedInIntPort - The internal port cannot be wild-carded + */ +MINIUPNP_LIBSPEC int +UPNP_AddAnyPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration, + char * reservedPort); + +/* UPNP_DeletePortMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array */ +MINIUPNP_LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost); + +/* UPNP_DeletePortRangeMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 730 PortMappingNotFound - This error message is returned if no port + * mapping is found in the specified range. + * 733 InconsistentParameters - NewStartPort and NewEndPort values are not consistent. */ +MINIUPNP_LIBSPEC int +UPNP_DeletePortMappingRange(const char * controlURL, const char * servicetype, + const char * extPortStart, const char * extPortEnd, + const char * proto, + const char * manage); + +/* UPNP_GetPortMappingNumberOfEntries() + * not supported by all routers */ +MINIUPNP_LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char* controlURL, + const char* servicetype, + unsigned int * num); + +/* UPNP_GetSpecificPortMappingEntry() + * retrieves an existing port mapping + * params : + * in extPort + * in proto + * in remoteHost + * out intClient (16 bytes) + * out intPort (6 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out leaseDuration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * List of possible UPnP errors for _GetSpecificPortMappingEntry : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 714 NoSuchEntryInArray - The specified value does not exist in the array. + */ +MINIUPNP_LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * extPort, + const char * proto, + const char * remoteHost, + char * intClient, + char * intPort, + char * desc, + char * enabled, + char * leaseDuration); + +/* UPNP_GetGenericPortMappingEntry() + * params : + * in index + * out extPort (6 bytes) + * out intClient (16 bytes) + * out intPort (6 bytes) + * out protocol (4 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out rHost (64 bytes) + * out duration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * Possible UPNP Error codes : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 606 Action not authorized - The action requested REQUIRES authorization + * and the sender was not authorized. + * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds + */ +MINIUPNP_LIBSPEC int +UPNP_GetGenericPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * index, + char * extPort, + char * intClient, + char * intPort, + char * protocol, + char * desc, + char * enabled, + char * rHost, + char * duration); + +/* UPNP_GetListOfPortMappings() Available in IGD v2 + * + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + * consistent. + */ +MINIUPNP_LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, + const char * servicetype, + const char * startPort, + const char * endPort, + const char * protocol, + const char * numberOfPorts, + struct PortMappingParserData * data); + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +MINIUPNP_LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed); + +MINIUPNP_LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + int * opTimeout); + +MINIUPNP_LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + const char * leaseTime, + char * uniqueID); + +MINIUPNP_LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime); + +MINIUPNP_LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); + +MINIUPNP_LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking); + +MINIUPNP_LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/deps/miniupnpc/upnpdev.c b/deps/miniupnpc/upnpdev.c new file mode 100644 index 0000000000..d89a9934c3 --- /dev/null +++ b/deps/miniupnpc/upnpdev.c @@ -0,0 +1,23 @@ +/* $Id: upnpdev.c,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ +/* Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2015 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#include +#include "upnpdev.h" + +/* freeUPNPDevlist() should be used to + * free the chained list returned by upnpDiscover() */ +void freeUPNPDevlist(struct UPNPDev * devlist) +{ + struct UPNPDev * next; + while(devlist) + { + next = devlist->pNext; + free(devlist); + devlist = next; + } +} + diff --git a/deps/miniupnpc/upnpdev.h b/deps/miniupnpc/upnpdev.h new file mode 100644 index 0000000000..f49fbe17ca --- /dev/null +++ b/deps/miniupnpc/upnpdev.h @@ -0,0 +1,36 @@ +/* $Id: upnpdev.h,v 1.1 2015/08/28 12:14:19 nanard Exp $ */ +/* Project : miniupnp + * Web : http://miniupnp.free.fr/ + * Author : Thomas BERNARD + * copyright (c) 2005-2015 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#ifndef UPNPDEV_H_INCLUDED +#define UPNPDEV_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct UPNPDev { + struct UPNPDev * pNext; + char * descURL; + char * st; + unsigned int scope_id; + char * usn; + char buffer[3]; +}; + +/* freeUPNPDevlist() + * free list returned by upnpDiscover() */ +MINIUPNP_LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); + + +#ifdef __cplusplus +} +#endif + + +#endif /* UPNPDEV_H_INCLUDED */ diff --git a/deps/miniupnpc/upnperrors.c b/deps/miniupnpc/upnperrors.c new file mode 100644 index 0000000000..40a2e7857f --- /dev/null +++ b/deps/miniupnpc/upnperrors.c @@ -0,0 +1,107 @@ +/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2007 Thomas Bernard + * All Right reserved. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#include +#include "upnperrors.h" +#include "upnpcommands.h" +#include "miniupnpc.h" + +const char * strupnperror(int err) +{ + const char * s = NULL; + switch(err) { + case UPNPCOMMAND_SUCCESS: + s = "Success"; + break; + case UPNPCOMMAND_UNKNOWN_ERROR: + s = "Miniupnpc Unknown Error"; + break; + case UPNPCOMMAND_INVALID_ARGS: + s = "Miniupnpc Invalid Arguments"; + break; + case UPNPCOMMAND_INVALID_RESPONSE: + s = "Miniupnpc Invalid response"; + break; + case UPNPDISCOVER_SOCKET_ERROR: + s = "Miniupnpc Socket error"; + break; + case UPNPDISCOVER_MEMORY_ERROR: + s = "Miniupnpc Memory allocation error"; + break; + case 401: + s = "Invalid Action"; + break; + case 402: + s = "Invalid Args"; + break; + case 501: + s = "Action Failed"; + break; + case 606: + s = "Action not authorized"; + break; + case 701: + s = "PinholeSpaceExhausted"; + break; + case 702: + s = "FirewallDisabled"; + break; + case 703: + s = "InboundPinholeNotAllowed"; + break; + case 704: + s = "NoSuchEntry"; + break; + case 705: + s = "ProtocolNotSupported"; + break; + case 706: + s = "InternalPortWildcardingNotAllowed"; + break; + case 707: + s = "ProtocolWildcardingNotAllowed"; + break; + case 708: + s = "WildcardNotPermittedInSrcIP"; + break; + case 709: + s = "NoPacketSent"; + break; + case 713: + s = "SpecifiedArrayIndexInvalid"; + break; + case 714: + s = "NoSuchEntryInArray"; + break; + case 715: + s = "WildCardNotPermittedInSrcIP"; + break; + case 716: + s = "WildCardNotPermittedInExtPort"; + break; + case 718: + s = "ConflictInMappingEntry"; + break; + case 724: + s = "SamePortValuesRequired"; + break; + case 725: + s = "OnlyPermanentLeasesSupported"; + break; + case 726: + s = "RemoteHostOnlySupportsWildcard"; + break; + case 727: + s = "ExternalPortOnlySupportsWildcard"; + break; + default: + s = "UnknownError"; + break; + } + return s; +} diff --git a/deps/miniupnpc/upnperrors.h b/deps/miniupnpc/upnperrors.h new file mode 100644 index 0000000000..8499d9a1c9 --- /dev/null +++ b/deps/miniupnpc/upnperrors.h @@ -0,0 +1,26 @@ +/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */ +/* (c) 2007-2015 Thomas Bernard + * All rights reserved. + * MiniUPnP Project. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef UPNPERRORS_H_INCLUDED +#define UPNPERRORS_H_INCLUDED + +#include "miniupnpc_declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* strupnperror() + * Return a string description of the UPnP error code + * or NULL for undefinded errors */ +MINIUPNP_LIBSPEC const char * strupnperror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/miniupnpc/upnpreplyparse.c b/deps/miniupnpc/upnpreplyparse.c new file mode 100644 index 0000000000..5de5796a39 --- /dev/null +++ b/deps/miniupnpc/upnpreplyparse.c @@ -0,0 +1,197 @@ +/* $Id: upnpreplyparse.c,v 1.19 2015/07/15 10:29:11 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2015 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include +#include +#include + +#include "upnpreplyparse.h" +#include "minixml.h" + +static void +NameValueParserStartElt(void * d, const char * name, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + data->topelt = 1; + if(l>63) + l = 63; + memcpy(data->curelt, name, l); + data->curelt[l] = '\0'; + data->cdata = NULL; + data->cdatalen = 0; +} + +static void +NameValueParserEndElt(void * d, const char * name, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + struct NameValue * nv; + (void)name; + (void)l; + if(!data->topelt) + return; + if(strcmp(data->curelt, "NewPortListing") != 0) + { + int l; + /* standard case. Limited to n chars strings */ + l = data->cdatalen; + nv = malloc(sizeof(struct NameValue)); + if(nv == NULL) + { + /* malloc error */ +#ifdef DEBUG + fprintf(stderr, "%s: error allocating memory", + "NameValueParserEndElt"); +#endif /* DEBUG */ + return; + } + if(l>=(int)sizeof(nv->value)) + l = sizeof(nv->value) - 1; + strncpy(nv->name, data->curelt, 64); + nv->name[63] = '\0'; + if(data->cdata != NULL) + { + memcpy(nv->value, data->cdata, l); + nv->value[l] = '\0'; + } + else + { + nv->value[0] = '\0'; + } + nv->l_next = data->l_head; /* insert in list */ + data->l_head = nv; + } + data->cdata = NULL; + data->cdatalen = 0; + data->topelt = 0; +} + +static void +NameValueParserGetData(void * d, const char * datas, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + if(strcmp(data->curelt, "NewPortListing") == 0) + { + /* specific case for NewPortListing which is a XML Document */ + data->portListing = malloc(l + 1); + if(!data->portListing) + { + /* malloc error */ +#ifdef DEBUG + fprintf(stderr, "%s: error allocating memory", + "NameValueParserGetData"); +#endif /* DEBUG */ + return; + } + memcpy(data->portListing, datas, l); + data->portListing[l] = '\0'; + data->portListingLength = l; + } + else + { + /* standard case. */ + data->cdata = datas; + data->cdatalen = l; + } +} + +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data) +{ + struct xmlparser parser; + data->l_head = NULL; + data->portListing = NULL; + data->portListingLength = 0; + /* init xmlparser object */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = data; + parser.starteltfunc = NameValueParserStartElt; + parser.endeltfunc = NameValueParserEndElt; + parser.datafunc = NameValueParserGetData; + parser.attfunc = 0; + parsexml(&parser); +} + +void +ClearNameValueList(struct NameValueParserData * pdata) +{ + struct NameValue * nv; + if(pdata->portListing) + { + free(pdata->portListing); + pdata->portListing = NULL; + pdata->portListingLength = 0; + } + while((nv = pdata->l_head) != NULL) + { + pdata->l_head = nv->l_next; + free(nv); + } +} + +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name) +{ + struct NameValue * nv; + char * p = NULL; + for(nv = pdata->l_head; + (nv != NULL) && (p == NULL); + nv = nv->l_next) + { + if(strcmp(nv->name, Name) == 0) + p = nv->value; + } + return p; +} + +#if 0 +/* useless now that minixml ignores namespaces by itself */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name) +{ + struct NameValue * nv; + char * p = NULL; + char * pname; + for(nv = pdata->head.lh_first; + (nv != NULL) && (p == NULL); + nv = nv->entries.le_next) + { + pname = strrchr(nv->name, ':'); + if(pname) + pname++; + else + pname = nv->name; + if(strcmp(pname, Name)==0) + p = nv->value; + } + return p; +} +#endif + +/* debug all-in-one function + * do parsing then display to stdout */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize) +{ + struct NameValueParserData pdata; + struct NameValue * nv; + ParseNameValue(buffer, bufsize, &pdata); + for(nv = pdata.l_head; + nv != NULL; + nv = nv->l_next) + { + printf("%s = %s\n", nv->name, nv->value); + } + ClearNameValueList(&pdata); +} +#endif /* DEBUG */ + diff --git a/deps/miniupnpc/upnpreplyparse.h b/deps/miniupnpc/upnpreplyparse.h new file mode 100644 index 0000000000..6badd15b26 --- /dev/null +++ b/deps/miniupnpc/upnpreplyparse.h @@ -0,0 +1,63 @@ +/* $Id: upnpreplyparse.h,v 1.19 2014/10/27 16:33:19 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2013 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef UPNPREPLYPARSE_H_INCLUDED +#define UPNPREPLYPARSE_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +struct NameValue { + struct NameValue * l_next; + char name[64]; + char value[128]; +}; + +struct NameValueParserData { + struct NameValue * l_head; + char curelt[64]; + char * portListing; + int portListingLength; + int topelt; + const char * cdata; + int cdatalen; +}; + +/* ParseNameValue() */ +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data); + +/* ClearNameValueList() */ +void +ClearNameValueList(struct NameValueParserData * pdata); + +/* GetValueFromNameValueList() */ +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name); + +#if 0 +/* GetValueFromNameValueListIgnoreNS() */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name); +#endif + +/* DisplayNameValueList() */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/dynamic.c b/dynamic.c index 4d18ad1380..0159bd7327 100644 --- a/dynamic.c +++ b/dynamic.c @@ -33,7 +33,7 @@ #endif #ifdef HAVE_CHEEVOS -#include "cheevos.h" +#include "cheevos/cheevos.h" #endif #ifdef HAVE_NETWORKING diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index f8db6ed7b4..5774a208ee 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1800,7 +1800,7 @@ static bool vulkan_create_display_surface(gfx_ctx_vulkan_data_t *vk, VkDisplayModePropertiesKHR *modes = NULL; unsigned dpy, i, j; uint32_t best_plane = UINT32_MAX; - VkDisplayPlaneAlphaFlagsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; + VkDisplayPlaneAlphaFlagBitsKHR alpha_mode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR; VkDisplaySurfaceCreateInfoKHR create_info = { VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR }; VkDisplayModeKHR best_mode = VK_NULL_HANDLE; @@ -1937,9 +1937,7 @@ out: create_info.planeStackIndex = planes[best_plane].currentStackIndex; create_info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; create_info.globalAlpha = 1.0f; - /* TODO/FIXME - why is this cast needed for CXX_BUILD? Why is - * alpha_mode not just VkDisplayPlaneAlphaFlagBitsKHR to begin with? */ - create_info.alphaMode = (VkDisplayPlaneAlphaFlagBitsKHR)alpha_mode; + create_info.alphaMode = alpha_mode; create_info.imageExtent.width = *width; create_info.imageExtent.height = *height; @@ -2271,6 +2269,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; VkPresentModeKHR swapchain_present_mode = VK_PRESENT_MODE_FIFO_KHR; settings_t *settings = config_get_ptr(); + VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; vkDeviceWaitIdle(vk->context.device); @@ -2371,6 +2370,15 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, else pre_transform = surface_properties.currentTransform; + if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) + composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) + composite = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) + composite = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + else if (surface_properties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) + composite = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR; + old_swapchain = vk->swapchain; info.surface = vk->vk_surface; @@ -2382,7 +2390,7 @@ bool vulkan_create_swapchain(gfx_ctx_vulkan_data_t *vk, info.imageArrayLayers = 1; info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; info.preTransform = pre_transform; - info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + info.compositeAlpha = composite; info.presentMode = swapchain_present_mode; info.clipped = true; info.oldSwapchain = old_swapchain; diff --git a/gfx/drivers/dispmanx_gfx.c b/gfx/drivers/dispmanx_gfx.c index 96abb92971..090a76ad1b 100644 --- a/gfx/drivers/dispmanx_gfx.c +++ b/gfx/drivers/dispmanx_gfx.c @@ -16,8 +16,6 @@ #include -#include - #ifdef HAVE_CONFIG_H #include "../../config.h" #endif @@ -36,10 +34,6 @@ struct dispmanx_page /* Each page contains it's own resource handler * instead of pointing to in by page number */ DISPMANX_RESOURCE_HANDLE_T resource; - bool used; - /* Each page has it's own mutex for - * isolating it's used flag access. */ - slock_t *page_used_mutex; /* This field will allow us to access the * main _dispvars struct from the vsync CB function */ @@ -57,10 +51,7 @@ struct dispmanx_surface struct dispmanx_page *pages; /* the page that's currently on screen */ struct dispmanx_page *current_page; - /*The page to wich we will dump the render. We need to know this - * already when we enter the surface update function. No time to wait - * for free pages before blitting and showing the just rendered frame! */ - struct dispmanx_page *next_page; + bool flip_page; unsigned int bpp; VC_RECT_T src_rect; @@ -102,12 +93,6 @@ struct dispmanx_video unsigned int dispmanx_width; unsigned int dispmanx_height; - /* For threading */ - scond_t *vsync_condition; - slock_t *vsync_cond_mutex; - slock_t *pending_mutex; - unsigned int pageflip_pending; - /* Menu */ bool menu_active; @@ -129,94 +114,15 @@ struct dispmanx_video float aspect_ratio; }; -/* If no free page is available when called, wait for a page flip. */ -static struct dispmanx_page *dispmanx_get_free_page(void *data, struct dispmanx_surface *surface) -{ - unsigned i; - struct dispmanx_video *_dispvars = data; - struct dispmanx_page *page = NULL; - - while (!page) - { - /* Try to find a free page */ - for (i = 0; i < surface->numpages; ++i) - { - if (!surface->pages[i].used) - { - page = (surface->pages) + i; - break; - } - } - - /* If no page is free at the moment, - * wait until a free page is freed by vsync CB. */ - if (!page) - { - slock_lock(_dispvars->vsync_cond_mutex); - scond_wait(_dispvars->vsync_condition, _dispvars->vsync_cond_mutex); - slock_unlock(_dispvars->vsync_cond_mutex); - } - } - - /* We mark the choosen page as used */ - slock_lock(page->page_used_mutex); - page->used = true; - slock_unlock(page->page_used_mutex); - - return page; -} - -static void dispmanx_vsync_callback(DISPMANX_UPDATE_HANDLE_T u, void *data) -{ - struct dispmanx_page *page = data; - struct dispmanx_surface *surface = page->surface; - - /* Marking the page as free must be done before the signaling - * so when update_main continues (it won't continue until we signal) - * we can chose this page as free */ - if (surface->current_page) - { - slock_lock(surface->current_page->page_used_mutex); - - /* We mark as free the page that was visible until now */ - surface->current_page->used = false; - slock_unlock(surface->current_page->page_used_mutex); - } - - /* The page on which we issued the flip that - * caused this callback becomes the visible one */ - surface->current_page = page; - - /* These two things must be isolated "atomically" to avoid getting - * a false positive in the pending_mutex test in update_main. */ - slock_lock(page->dispvars->pending_mutex); - - page->dispvars->pageflip_pending--; - scond_signal(page->dispvars->vsync_condition); - - slock_unlock(page->dispvars->pending_mutex); -} - static void dispmanx_surface_free(void *data, struct dispmanx_surface **sp) { int i; struct dispmanx_video *_dispvars = data; struct dispmanx_surface *surface = *sp; - /* What if we run into the vsync cb code after freeing the surface? - * We could be trying to get non-existant lock, signal non-existant condition.. - * So we wait for any pending flips to complete before freeing any surface. */ - slock_lock(_dispvars->pending_mutex); - if (_dispvars->pageflip_pending > 0) - scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex); - - slock_unlock(_dispvars->pending_mutex); - for (i = 0; i < surface->numpages; i++) { vc_dispmanx_resource_delete(surface->pages[i].resource); - surface->pages[i].used = false; - slock_free(surface->pages[i].page_used_mutex); } free(surface->pages); @@ -260,16 +166,12 @@ static void dispmanx_surface_setup(void *data, int src_width, int src_height, for (i = 0; i < surface->numpages; i++) { - surface->pages[i].used = false; surface->pages[i].surface = surface; surface->pages[i].dispvars = _dispvars; - surface->pages[i].page_used_mutex = slock_new(); } - /* No need to mutex this access to the "used" member because - * the flipping/callbacks are not still running */ - surface->next_page = &(surface->pages[0]); - surface->next_page->used = true; + /* We blit to page 0 first */ + surface->flip_page = 0; /* The "visible" width obtained from the core pitch. We blit based on * the "visible" width, for cores with things between scanlines. */ @@ -325,40 +227,24 @@ static void dispmanx_surface_update_async(void *data, const void *frame, static void dispmanx_surface_update(void *data, const void *frame, struct dispmanx_surface *surface) { - /* Updating is very delicate: we REALLY want to show the just rendered frame ASAP, - * so we dump and issue flip, and then we can wait for free pages, but we don't - * want to wait for free pages at the beggining of the update or we will be - * adding lag! */ - struct dispmanx_video *_dispvars = data; - + struct dispmanx_page *page = NULL; + + page = &surface->pages[surface->flip_page]; + /* Frame blitting */ - vc_dispmanx_resource_write_data(surface->next_page->resource, surface->pixformat, + vc_dispmanx_resource_write_data(page->resource, surface->pixformat, surface->pitch, (void*)frame, &(surface->bmp_rect)); - /* Dispmanx doesn't support more than one pending pageflip. Doing so would overwrite - * the page in the callback function, so we would be always freeing the same page. */ - slock_lock(_dispvars->pending_mutex); - if (_dispvars->pageflip_pending > 0) - scond_wait(_dispvars->vsync_condition, _dispvars->pending_mutex); - slock_unlock(_dispvars->pending_mutex); - /* Issue a page flip that will be done at the next vsync. */ _dispvars->update = vc_dispmanx_update_start(0); vc_dispmanx_element_change_source(_dispvars->update, surface->element, - surface->next_page->resource); + page->resource); - vc_dispmanx_update_submit(_dispvars->update, - dispmanx_vsync_callback, (void*)(surface->next_page)); + vc_dispmanx_update_submit_sync(_dispvars->update); - slock_lock(_dispvars->pending_mutex); - _dispvars->pageflip_pending++; - slock_unlock(_dispvars->pending_mutex); - - /* Get the next page ready for our next surface_update re-entry. - * It's OK to wait now that we've issued the flip to the last produced frame! */ - surface->next_page = dispmanx_get_free_page(_dispvars, surface); + surface->flip_page = !surface->flip_page; } /* Enable/disable bilinear filtering. */ @@ -414,7 +300,6 @@ static void *dispmanx_gfx_init(const video_info_t *video, /* Setup surface parameters */ _dispvars->vc_image_ptr = 0; - _dispvars->pageflip_pending = 0; _dispvars->menu_active = false; _dispvars->rgb32 = video->rgb32; @@ -424,10 +309,7 @@ static void *dispmanx_gfx_init(const video_info_t *video, * before we get to gfx_frame(). */ _dispvars->aspect_ratio = video_driver_get_aspect_ratio(); - /* Initialize the rest of the mutexes and conditions. */ - _dispvars->vsync_condition = scond_new(); - _dispvars->vsync_cond_mutex = slock_new(); - _dispvars->pending_mutex = slock_new(); + /* Initialize the rest of video variables. */ _dispvars->core_width = 0; _dispvars->core_height = 0; _dispvars->menu_width = 0; @@ -695,11 +577,6 @@ static void dispmanx_gfx_free(void *data) vc_dispmanx_display_close(_dispvars->display); bcm_host_deinit(); - /* Destroy mutexes and conditions. */ - slock_free(_dispvars->pending_mutex); - slock_free(_dispvars->vsync_cond_mutex); - scond_free(_dispvars->vsync_condition); - free(_dispvars); } diff --git a/gfx/drivers/sdl2_gfx.c b/gfx/drivers/sdl2_gfx.c index de65f8ffff..f8275ffd49 100644 --- a/gfx/drivers/sdl2_gfx.c +++ b/gfx/drivers/sdl2_gfx.c @@ -505,6 +505,7 @@ static bool sdl2_gfx_frame(void *data, const void *frame, unsigned width, { static struct retro_perf_counter sdl_copy_frame = {0}; + SDL_RenderClear(vid->renderer); sdl_refresh_input_size(vid, false, vid->video.rgb32, width, height, pitch); performance_counter_init(sdl_copy_frame, "sdl_copy_frame"); diff --git a/gfx/drivers/vga_gfx.c b/gfx/drivers/vga_gfx.c index 481cba965f..5f8a89c31c 100644 --- a/gfx/drivers/vga_gfx.c +++ b/gfx/drivers/vga_gfx.c @@ -222,14 +222,14 @@ static bool vga_gfx_frame(void *data, const void *frame, for (x = 0; x < VGA_WIDTH; x++) { /* scale incoming frame to fit the screen */ - unsigned scaled_x = (width / (float)VGA_WIDTH) * x; - unsigned scaled_y = (height / (float)VGA_HEIGHT) * y; + unsigned scaled_x = (width * x) / VGA_WIDTH; + unsigned scaled_y = (height * y) / VGA_HEIGHT; unsigned short pixel = ((unsigned short*)frame_to_copy)[width * scaled_y + scaled_x]; /* convert RGB565 to BGR332 */ - unsigned r = (7.0f / 31.0f) * ((pixel & 0xF800) >> 11); - unsigned g = (7.0f / 63.0f) * ((pixel & 0x07E0) >> 5); - unsigned b = (3.0f / 31.0f) * ((pixel & 0x001F) >> 0); + unsigned r = ((pixel & 0xF800) >> 13); + unsigned g = ((pixel & 0x07E0) >> 8); + unsigned b = ((pixel & 0x001F) >> 3); vga_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r; } @@ -368,10 +368,13 @@ static void vga_set_texture_frame(void *data, { for(x = 0; x < VGA_WIDTH; x++) { - unsigned short pixel = video_frame[width * y + x]; - unsigned r = (7.0f / 15.0f) * ((pixel & 0xF000) >> 12); - unsigned g = (7.0f / 15.0f) * ((pixel & 0xF00) >> 8); - unsigned b = (3.0f / 15.0f) * ((pixel & 0xF0) >> 4); + /* scale incoming frame to fit the screen */ + unsigned scaled_x = (width * x) / VGA_WIDTH; + unsigned scaled_y = (height * y) / VGA_HEIGHT; + unsigned short pixel = video_frame[width * scaled_y + scaled_x]; + unsigned r = ((pixel & 0xF000) >> 13); + unsigned g = ((pixel & 0xF00) >> 9); + unsigned b = ((pixel & 0xF0) >> 6); vga_menu_frame[VGA_WIDTH * y + x] = (b << 6) | (g << 3) | r; } } diff --git a/gfx/drivers_tracker/video_state_python.c b/gfx/drivers_tracker/video_state_python.c index dc86caa010..8c62bb7bdd 100644 --- a/gfx/drivers_tracker/video_state_python.c +++ b/gfx/drivers_tracker/video_state_python.c @@ -27,6 +27,8 @@ #include #include "video_state_python.h" + +#include "../../configuration.h" #include "../../dynamic.h" #include "../../core.h" #include "../../verbosity.h" @@ -106,9 +108,10 @@ static PyObject* py_read_vram(PyObject *self, PyObject *args) static PyObject *py_read_input(PyObject *self, PyObject *args) { unsigned user, key, i; + rarch_joypad_info_t joypad_info; const struct retro_keybind *py_binds[MAX_USERS]; - int16_t res = 0; - settings_t *settings = config_get_ptr(); + int16_t res = 0; + settings_t *settings = config_get_ptr(); for (i = 0; i < MAX_USERS; i++) py_binds[i] = settings->input.binds[i]; @@ -121,8 +124,12 @@ static PyObject *py_read_input(PyObject *self, PyObject *args) if (user > MAX_USERS || user < 1 || key >= RARCH_FIRST_META_KEY) return NULL; + joypad_info.joy_idx = settings->input.joypad_map[user - 1]; + joypad_info.auto_binds = settings->input.autoconf_binds[joypad_info.joy_idx]; + if (!input_driver_is_libretro_input_blocked()) - res = current_input->input_state(current_input_data, py_binds, + res = current_input->input_state(current_input_data, joypad_info, + py_binds, user - 1, RETRO_DEVICE_JOYPAD, 0, key); return PyBool_FromLong(res); } @@ -130,9 +137,10 @@ static PyObject *py_read_input(PyObject *self, PyObject *args) static PyObject *py_read_analog(PyObject *self, PyObject *args) { unsigned user, index, id, i; - int16_t res = 0; - settings_t *settings = config_get_ptr(); + rarch_joypad_info_t joypad_info; const struct retro_keybind *py_binds[MAX_USERS]; + int16_t res = 0; + settings_t *settings = config_get_ptr(); for (i = 0; i < MAX_USERS; i++) py_binds[i] = settings->input.binds[i]; @@ -145,8 +153,12 @@ static PyObject *py_read_analog(PyObject *self, PyObject *args) if (user > MAX_USERS || user < 1 || index > 1 || id > 1) return NULL; - res = current_input->input_state(current_input_data, py_binds, - user - 1, RETRO_DEVICE_ANALOG, index, id) + joypad_info.joy_idx = settings->input.joypad_map[user - 1]; + joypad_info.auto_binds = settings->input.autoconf_binds[joypad_info.joy_idx]; + + res = current_input->input_state(current_input_data, + joypad_info, py_binds, + user - 1, RETRO_DEVICE_ANALOG, index, id); return PyFloat_FromDouble((double)res / 0x7fff); } diff --git a/gfx/video_shader_driver.h b/gfx/video_shader_driver.h index ab344056b5..91060b6f06 100644 --- a/gfx/video_shader_driver.h +++ b/gfx/video_shader_driver.h @@ -27,7 +27,7 @@ #include "../config.h" #endif -#if defined(HAVE_CG) || defined(HAVE_HLSL) || defined(HAVE_GLSL) +#if defined(HAVE_CG) || defined(HAVE_HLSL) || defined(HAVE_GLSL) || defined(HAVE_SLANG) #ifndef HAVE_SHADER_MANAGER #define HAVE_SHADER_MANAGER #endif diff --git a/griffin/griffin.c b/griffin/griffin.c index dc0f2784ef..7c8dc2e1e2 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -133,7 +133,7 @@ ACHIEVEMENTS #include "../libretro-common/formats/json/jsonsax.c" #include "../network/net_http_special.c" -#include "../cheevos.c" +#include "../cheevos/cheevos.c" #endif /*============================================================ @@ -1128,6 +1128,22 @@ XML #include "../database_info.c" #endif +#if defined(HAVE_BUILTINMINIUPNPC) +#include "../deps/miniupnpc/igd_desc_parse.c" +#include "../deps/miniupnpc/upnpreplyparse.c" +#include "../deps/miniupnpc/upnpcommands.c" +#include "../deps/miniupnpc/upnperrors.c" +#include "../deps/miniupnpc/connecthostport.c" +#include "../deps/miniupnpc/portlistingparse.c" +#include "../deps/miniupnpc/receivedata.c" +#include "../deps/miniupnpc/upnpdev.c" +#include "../deps/miniupnpc/minissdpc.c" +#include "../deps/miniupnpc/miniwget.c" +#include "../deps/miniupnpc/miniupnpc.c" +#include "../deps/miniupnpc/minixml.c" +#include "../deps/miniupnpc/minisoap.c" +#endif + /*============================================================ HTTP SERVER ============================================================ */ diff --git a/input/drivers/android_input.c b/input/drivers/android_input.c index d93e53daf4..54e763c4bc 100644 --- a/input/drivers/android_input.c +++ b/input/drivers/android_input.c @@ -47,6 +47,26 @@ #define MAX_TOUCH 16 #define MAX_NUM_KEYBOARDS 3 +// If using an SDK lower than 14 then add missing mouse button codes +#if __ANDROID_API__ < 14 +enum { + AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, + AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1, + AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, + AMOTION_EVENT_BUTTON_BACK = 1 << 3, + AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, +}; +#endif + +// If using an SDK lower than 24 then add missing relative axis codes +#if __ANDROID_API__ < 24 +#define AMOTION_EVENT_AXIS_RELATIVE_X 27 +#define AMOTION_EVENT_AXIS_RELATIVE_Y 28 +#endif + +// Use this to enable/disable using the touch screen as mouse +#define ENABLE_TOUCH_SCREEN_MOUSE 1 + typedef struct { float x; @@ -96,6 +116,10 @@ typedef struct android_input_data sensor_t accelerometer_state; struct input_pointer pointer[MAX_TOUCH]; unsigned pointer_count; + int mouse_x_delta, mouse_y_delta; + int mouse_x_prev, mouse_y_prev; + int mouse_l, mouse_r; + int64_t quick_tap_time; } android_input_data_t; typedef struct android_input @@ -123,6 +147,12 @@ static typeof(AMotionEvent_getAxisValue) *p_AMotionEvent_getAxisValue; #define AMotionEvent_getAxisValue (*p_AMotionEvent_getAxisValue) +extern int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); + +static typeof(AMotionEvent_getButtonState) *p_AMotionEvent_getButtonState; + +#define AMotionEvent_getButtonState (*p_AMotionEvent_getButtonState) + static void *libandroid_handle; static bool android_input_lookup_name_prekitkat(char *buf, @@ -452,6 +482,9 @@ static bool android_input_init_handle(void) RARCH_LOG("Set engine_handle_dpad to 'Get Axis Value' (for reading extra analog sticks)"); engine_handle_dpad = engine_handle_dpad_getaxisvalue; } + + p_AMotionEvent_getButtonState = dlsym(RTLD_DEFAULT,"AMotionEvent_getButtonState"); + pad_id1 = -1; pad_id2 = -1; @@ -470,6 +503,8 @@ static void *android_input_init(const char *joypad_driver) android->thread.pads_connected = 0; android->copy.pads_connected = 0; + android->thread.quick_tap_time = 0; + android->copy.quick_tap_time = 0; android->joypad = input_joypad_init_driver(joypad_driver, android); input_keymaps_init_keyboard_lut(rarch_key_map_android); @@ -495,6 +530,59 @@ static void *android_input_init(const char *joypad_driver) return android; } +static int16_t android_mouse_state(android_input_data_t *android_data, unsigned id) +{ + switch (id) + { + case RETRO_DEVICE_ID_MOUSE_LEFT: + return android_data->mouse_l; + case RETRO_DEVICE_ID_MOUSE_RIGHT: + return android_data->mouse_r; + case RETRO_DEVICE_ID_MOUSE_X: + return android_data->mouse_x_delta; + case RETRO_DEVICE_ID_MOUSE_Y: + return android_data->mouse_y_delta; + } + + return 0; +} + +static INLINE void android_mouse_calculate_deltas(android_input_data_t *android_data, AInputEvent *event,size_t motion_ptr) +{ + // Adjust mouse speed based on ratio between core resolution and system resolution + float x_scale = 1; + float y_scale = 1; + video_viewport_t *custom_vp = video_viewport_get_custom(); + struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); + if(custom_vp && av_info) + { + const struct retro_game_geometry *geom = (const struct retro_game_geometry*)&av_info->geometry; + x_scale = 2 * (float)geom->base_width / (float)custom_vp->width; + y_scale = 2 * (float)geom->base_height / (float)custom_vp->height; + } + + // This axis is only available on Android Nougat and on Android devices with NVIDIA extensions + float x = AMotionEvent_getAxisValue(event,AMOTION_EVENT_AXIS_RELATIVE_X, motion_ptr); + float y = AMotionEvent_getAxisValue(event,AMOTION_EVENT_AXIS_RELATIVE_Y, motion_ptr); + + // Use AXIS_RELATIVE values if they were available + if (x != 0 || y != 0) + { + android_data->mouse_x_delta = ceil(x * x_scale); + android_data->mouse_y_delta = ceil(y * y_scale); + } + // If not then calculate deltas based on AXIS_X and AXIS_Y. This has limitations compared to AXIS_RELATIVE + // because once the Android mouse cursor hits the edge of the screen it is not possible to move the in-game + // mouse any further in that direction. + else + { + android_data->mouse_x_delta = ceil((AMotionEvent_getX(event, motion_ptr) - android_data->mouse_x_prev) * x_scale); + android_data->mouse_y_delta = ceil((AMotionEvent_getY(event, motion_ptr) - android_data->mouse_y_prev) * y_scale); + android_data->mouse_x_prev = AMotionEvent_getX(event, motion_ptr); + android_data->mouse_y_prev = AMotionEvent_getY(event, motion_ptr); + } +} + static INLINE int android_input_poll_event_type_motion( android_input_data_t *android_data, AInputEvent *event, int port, int source) @@ -502,6 +590,7 @@ static INLINE int android_input_poll_event_type_motion( int getaction, action; size_t motion_ptr; bool keyup; + int btn; // Only handle events from a touchscreen or mouse if (!(source & (AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_MOUSE))) @@ -517,8 +606,38 @@ static INLINE int android_input_poll_event_type_motion( (source == AINPUT_SOURCE_MOUSE && action != AMOTION_EVENT_ACTION_DOWN); + // If source is mouse then calculate button state and mouse deltas and don't process as touchscreen event + if (source == AINPUT_SOURCE_MOUSE) + { + // getButtonState requires API level 14 + if (p_AMotionEvent_getButtonState) + { + btn = (int)AMotionEvent_getButtonState(event); + android_data->mouse_l = (btn & AMOTION_EVENT_BUTTON_PRIMARY); + android_data->mouse_r = (btn & AMOTION_EVENT_BUTTON_SECONDARY); + } + else + { + // If getButtonState is not available then treat all MotionEvent.ACTION_DOWN as left button presses + if (action == AMOTION_EVENT_ACTION_DOWN) + android_data->mouse_l = 1; + if (action == AMOTION_EVENT_ACTION_UP) + android_data->mouse_l = 0; + } + android_mouse_calculate_deltas(android_data,event,motion_ptr); + return 0; + } + if (keyup && motion_ptr < MAX_TOUCH) { + if(action == AMOTION_EVENT_ACTION_UP && ENABLE_TOUCH_SCREEN_MOUSE) + { + // If touchscreen was pressed for less than 200ms then register time stamp of a quick tap + if((AMotionEvent_getEventTime(event)-AMotionEvent_getDownTime(event))/1000000 < 200) + android_data->quick_tap_time = AMotionEvent_getEventTime(event); + android_data->mouse_l = 0; + } + memmove(android_data->pointer + motion_ptr, android_data->pointer + motion_ptr + 1, (MAX_TOUCH - motion_ptr - 1) * sizeof(struct input_pointer)); @@ -529,6 +648,25 @@ static INLINE int android_input_poll_event_type_motion( { int pointer_max = MIN(AMotionEvent_getPointerCount(event), MAX_TOUCH); + if(action == AMOTION_EVENT_ACTION_DOWN && ENABLE_TOUCH_SCREEN_MOUSE) + { + // When touch screen is pressed, set mouse previous position to current position + // before starting to calculate mouse movement deltas. + android_data->mouse_x_prev = AMotionEvent_getX(event, motion_ptr); + android_data->mouse_y_prev = AMotionEvent_getY(event, motion_ptr); + + // If another touch happened within 200ms after a quick tap then cancel the quick tap + // and register left mouse button as being held down + if((AMotionEvent_getEventTime(event) - android_data->quick_tap_time)/1000000 < 200) + { + android_data->quick_tap_time = 0; + android_data->mouse_l = 1; + } + } + + if(action == AMOTION_EVENT_ACTION_MOVE && ENABLE_TOUCH_SCREEN_MOUSE) + android_mouse_calculate_deltas(android_data,event,motion_ptr); + for (motion_ptr = 0; motion_ptr < pointer_max; motion_ptr++) { struct video_viewport vp = {0}; @@ -549,6 +687,10 @@ static INLINE int android_input_poll_event_type_motion( } } + // If more than one pointer detected then count it as a mouse right click + if (ENABLE_TOUCH_SCREEN_MOUSE) + android_data->mouse_r = (android_data->pointer_count == 2); + return 0; } @@ -1007,6 +1149,20 @@ static void android_input_poll_memcpy(void *data) memcpy(&android->copy, &android->thread, sizeof(android->copy)); + // If a quick tap timer is active then check if more than 200ms have passed without it being + // reset by a new motionevent. If so then queue a single left mouse click. This really should + // by done in one of the polling functions, but since android_input_state() uses a copy of + // the inputstate being created here, it has to be done here. Same goes for the deltas resets. + retro_time_t now = cpu_features_get_time_usec(); + if(android->thread.quick_tap_time && (now/1000 - android->thread.quick_tap_time/1000000) >= 200) + { + android->thread.quick_tap_time = 0; + android->copy.mouse_l = 1; + } + + android->thread.mouse_x_delta = 0; + android->thread.mouse_y_delta = 0; + for (i = 0; i < MAX_PADS; i++) { for (j = 0; j < 2; j++) @@ -1128,6 +1284,8 @@ static int16_t android_input_state(void *data, return input_joypad_analog(android->joypad, joypad_info, port, idx, id, binds[port]); break; + case RETRO_DEVICE_MOUSE: + return android_mouse_state(android_data, id); case RETRO_DEVICE_POINTER: switch (id) { diff --git a/input/drivers/dos_input.c b/input/drivers/dos_input.c index e9b65ad98d..b73f0f73ab 100644 --- a/input/drivers/dos_input.c +++ b/input/drivers/dos_input.c @@ -14,16 +14,17 @@ * If not, see . */ +#include #include #include "../input_driver.h" +#include "../input_keymaps.h" #include "../input_joypad_driver.h" +#include "../drivers_keyboard/keyboard_event_dos.h" typedef struct dos_input { const input_device_driver_t *joypad; - unsigned char normal_keys[256]; - unsigned char extended_keys[256]; } dos_input_t; static void dos_input_poll(void *data) @@ -48,7 +49,10 @@ static int16_t dos_input_state(void *data, switch (device) { case RETRO_DEVICE_JOYPAD: - return input_joypad_pressed(dos->joypad, joypad_info, port, binds[port], id); + return input_joypad_pressed(dos->joypad, joypad_info, port, binds[port], id) || + dos_keyboard_port_input_pressed(binds[port], id); + case RETRO_DEVICE_KEYBOARD: + return dos_keyboard_port_input_pressed(binds[port], id); } return 0; @@ -61,6 +65,8 @@ static void dos_input_free_input(void *data) if (dos && dos->joypad) dos->joypad->destroy(); + dos_keyboard_free(); + if (data) free(data); } @@ -72,8 +78,12 @@ static void* dos_input_init(const char *joypad_driver) if (!dos) return NULL; + dos_keyboard_free(); + dos->joypad = input_joypad_init_driver(joypad_driver, dos); + input_keymaps_init_keyboard_lut(rarch_key_map_dos); + return dos; } @@ -87,7 +97,6 @@ static uint64_t dos_input_get_capabilities(void *data) uint64_t caps = 0; caps |= UINT64_C(1) << RETRO_DEVICE_JOYPAD; - caps |= UINT64_C(1) << RETRO_DEVICE_KEYBOARD; return caps; } diff --git a/input/drivers/wiiu_input.c b/input/drivers/wiiu_input.c index 56bbf8bbaf..2425640b83 100644 --- a/input/drivers/wiiu_input.c +++ b/input/drivers/wiiu_input.c @@ -28,11 +28,63 @@ #include "../input_config.h" #include "../input_driver.h" #include "../input_joypad_driver.h" +#include "../input_keyboard.h" +#include "../input_keymaps.h" +#include #include "wiiu_dbg.h" #define MAX_PADS 5 +static unsigned char keyboardChannel = 0x00; +static KBDModifier keyboardModifier = 0x00; +static unsigned char keyboardCode = 0x00; +static KEYState keyboardState[256] = { KBD_WIIU_NULL }; + +void kb_connection_callback(KBDKeyEvent *key) { + keyboardChannel = keyboardChannel + (key->channel + 0x01); +} + +void kb_disconnection_callback(KBDKeyEvent *key) { + keyboardChannel = keyboardChannel - (key->channel + 0x01); +} + +void kb_key_callback(KBDKeyEvent *key) { + keyboardModifier = key->modifier; + keyboardCode = key->scancode; + + bool pressed = false; + + if (key->state > 0) + { + pressed = true; + } + uint16_t mod = 0; + unsigned code = input_keymaps_translate_keysym_to_rk(key->scancode); + keyboardState[code] = key->state; + + if (key->modifier & KBD_WIIU_SHIFT) + mod |= RETROKMOD_SHIFT; + + if (key->modifier & KBD_WIIU_CTRL) + mod |= RETROKMOD_CTRL; + + if (key->modifier & KBD_WIIU_ALT) + mod |= RETROKMOD_ALT; + + if (key->modifier & KBD_WIIU_NUM_LOCK) + mod |= RETROKMOD_NUMLOCK; + + if (key->modifier & KBD_WIIU_CAPS_LOCK) + mod |= RETROKMOD_CAPSLOCK; + + if (key->modifier & KBD_WIIU_SCROLL_LOCK) + mod |= RETROKMOD_SCROLLOCK; + + input_keyboard_event(pressed, code, (char)key->UTF16, mod, + RETRO_DEVICE_KEYBOARD); +} + typedef struct wiiu_input { bool blocked; @@ -46,7 +98,20 @@ static void wiiu_input_poll(void *data) wiiu_input_t *wiiu = (wiiu_input_t*)data; if (wiiu->joypad) - wiiu->joypad->poll(); + wiiu->joypad->poll(); +} + +static bool wiiu_key_pressed(int key) +{ + bool ret = false; + + if (key >= RETROK_LAST) + return false; + + if ((keyboardState[key] > 0) && (keyboardChannel > 0)) + ret = true; + + return ret; } static int16_t wiiu_input_state(void *data, @@ -59,11 +124,13 @@ static int16_t wiiu_input_state(void *data, if(!wiiu || !(port < MAX_PADS) || !binds || !binds[port]) return 0; - + switch (device) { case RETRO_DEVICE_JOYPAD: return input_joypad_pressed(wiiu->joypad, joypad_info, port, binds[port], id); + case RETRO_DEVICE_KEYBOARD: + return wiiu_key_pressed(id); case RETRO_DEVICE_ANALOG: if (binds[port]) return input_joypad_analog(wiiu->joypad, joypad_info, port, idx, id, binds[port]); @@ -79,6 +146,8 @@ static void wiiu_input_free_input(void *data) if (wiiu && wiiu->joypad) wiiu->joypad->destroy(); + + KBDTeardown(); free(data); } @@ -91,6 +160,10 @@ static void* wiiu_input_init(const char *joypad_driver) DEBUG_STR(joypad_driver); wiiu->joypad = input_joypad_init_driver(joypad_driver, wiiu); + + KBDSetup(&kb_connection_callback,&kb_disconnection_callback,&kb_key_callback); + + input_keymaps_init_keyboard_lut(rarch_key_map_wiiu); return wiiu; } @@ -107,7 +180,7 @@ static uint64_t wiiu_input_get_capabilities(void *data) { (void)data; - return (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG); + return (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG) | (1 << RETRO_DEVICE_KEYBOARD); } static const input_device_driver_t *wiiu_input_get_joypad_driver(void *data) diff --git a/input/drivers_joypad/dos_joypad.c b/input/drivers_joypad/dos_joypad.c index 05f07b766d..686db8238e 100644 --- a/input/drivers_joypad/dos_joypad.c +++ b/input/drivers_joypad/dos_joypad.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include @@ -30,19 +29,17 @@ #include "../input_joypad_driver.h" #include "../input_driver.h" #include "../input_config.h" +#include "../input_keyboard.h" +#include "../input_keymaps.h" #include "../../tasks/tasks_internal.h" - -#define MAX_PADS 1 +#include "../drivers_keyboard/keyboard_event_dos.h" #define END_FUNC(x) static void x##_End() { } #define LOCK_VAR(x) LockData((void*)&x, sizeof(x)) #define LOCK_FUNC(x) LockCode(x, (int)x##_End - (int)x) -static uint64_t dos_key_state[MAX_PADS]; - -static unsigned char normal_keys[256]; -static unsigned char extended_keys[256]; +static uint16_t normal_keys[LAST_KEYCODE + 1]; static _go32_dpmi_seginfo old_kbd_int; static _go32_dpmi_seginfo kbd_int; @@ -85,7 +82,7 @@ int LockCode(void *a, int size) static void keyb_int(void) { - static unsigned char buffer; + static unsigned char buffer = 0; unsigned char rawcode; unsigned char make_break; int scancode; @@ -99,14 +96,14 @@ static void keyb_int(void) /* second byte of an extended key */ if (scancode < 0x60) { - extended_keys[scancode] = make_break; + normal_keys[scancode | (1 << 8)] = make_break; } buffer = 0; } else if (buffer >= 0xE1 && buffer <= 0xE2) { - buffer = 0; /* ingore these extended keys */ + buffer = 0; /* ignore these extended keys */ } else if (rawcode >= 0xE0 && rawcode <= 0xE2) { @@ -126,10 +123,10 @@ static void hook_keyb_int(void) _go32_dpmi_get_protected_mode_interrupt_vector(9, &old_kbd_int); memset(&kbd_int, 0, sizeof(kbd_int)); + memset(normal_keys, 0, sizeof(normal_keys)); LOCK_FUNC(keyb_int); LOCK_VAR(normal_keys); - LOCK_VAR(extended_keys); kbd_int.pm_selector = _go32_my_cs(); kbd_int.pm_offset = (uint32_t)&keyb_int; @@ -170,8 +167,6 @@ static void dos_joypad_autodetect_add(unsigned autoconf_pad) static bool dos_joypad_init(void *data) { - memset(dos_key_state, 0, sizeof(dos_key_state)); - hook_keyb_int(); dos_joypad_autodetect_add(0); @@ -183,44 +178,64 @@ static bool dos_joypad_init(void *data) static bool dos_joypad_button(unsigned port_num, uint16_t key) { + uint16_t *buf = dos_keyboard_state_get(port_num); + if (port_num >= MAX_PADS) return false; - return (dos_key_state[port_num] & (UINT64_C(1) << key)); -} + switch (key) + { + case RETRO_DEVICE_ID_JOYPAD_A: + return buf[DOSKEY_x]; + case RETRO_DEVICE_ID_JOYPAD_B: + return buf[DOSKEY_z]; + case RETRO_DEVICE_ID_JOYPAD_X: + return buf[DOSKEY_s]; + case RETRO_DEVICE_ID_JOYPAD_Y: + return buf[DOSKEY_a]; + case RETRO_DEVICE_ID_JOYPAD_SELECT: + return buf[DOSKEY_RSHIFT]; + case RETRO_DEVICE_ID_JOYPAD_START: + return buf[DOSKEY_RETURN]; + case RETRO_DEVICE_ID_JOYPAD_UP: + return buf[DOSKEY_UP]; + case RETRO_DEVICE_ID_JOYPAD_DOWN: + return buf[DOSKEY_DOWN]; + case RETRO_DEVICE_ID_JOYPAD_LEFT: + return buf[DOSKEY_LEFT]; + case RETRO_DEVICE_ID_JOYPAD_RIGHT: + return buf[DOSKEY_RIGHT]; + } -static uint64_t dos_joypad_get_buttons(unsigned port_num) -{ - if (port_num >= MAX_PADS) - return 0; - return dos_key_state[port_num]; + return false; } static void dos_joypad_poll(void) { uint32_t i; - for (i = 0; i < MAX_PADS; i++) + for (i = 0; i <= MAX_PADS; i++) { - uint64_t *cur_state = &dos_key_state[i]; + uint16_t *cur_state = dos_keyboard_state_get(i); + uint32_t key; - *cur_state = 0; - *cur_state |= extended_keys[75] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_LEFT : 0; - *cur_state |= extended_keys[77] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_RIGHT : 0; - *cur_state |= extended_keys[72] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_UP : 0; - *cur_state |= extended_keys[80] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_DOWN : 0; - *cur_state |= normal_keys[28] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_START : 0; /* ENTER */ - *cur_state |= normal_keys[54] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_SELECT : 0; /* RSHIFT */ - *cur_state |= normal_keys[44] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_B : 0; /* Z */ - *cur_state |= normal_keys[45] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_A : 0; /* X */ - *cur_state |= normal_keys[30] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_Y : 0; /* A */ - *cur_state |= normal_keys[31] ? UINT64_C(1) << RETRO_DEVICE_ID_JOYPAD_X : 0; /* S */ + for (key = 0; key < LAST_KEYCODE; key++) + { + if (cur_state[key] != normal_keys[key]) + { + unsigned code = input_keymaps_translate_keysym_to_rk(key); + + input_keyboard_event(normal_keys[key], code, code, 0, RETRO_DEVICE_KEYBOARD); + } + } + + memcpy(cur_state, normal_keys, sizeof(normal_keys)); } } static bool dos_joypad_query_pad(unsigned pad) { - return pad < MAX_USERS && dos_key_state[pad]; + return (pad < MAX_USERS); } static int16_t dos_joypad_axis(unsigned port_num, uint32_t joyaxis) @@ -238,7 +253,7 @@ input_device_driver_t dos_joypad = { dos_joypad_query_pad, dos_joypad_destroy, dos_joypad_button, - dos_joypad_get_buttons, + NULL, dos_joypad_axis, dos_joypad_poll, NULL, diff --git a/input/drivers_keyboard/keyboard_event_dos.c b/input/drivers_keyboard/keyboard_event_dos.c new file mode 100644 index 0000000000..f7f8f373ef --- /dev/null +++ b/input/drivers_keyboard/keyboard_event_dos.c @@ -0,0 +1,56 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * 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- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include + +#include "keyboard_event_dos.h" +#include "../input_keymaps.h" + +#define MAX_KEYS LAST_KEYCODE + 1 + +// First ports are used to keeping track of gamepad states. Last port is used for keyboard state +static uint16_t dos_key_state[MAX_PADS+1][MAX_KEYS]; + +bool dos_keyboard_port_input_pressed(const struct retro_keybind *binds, unsigned id) +{ + if (id < RARCH_BIND_LIST_END) + { + const struct retro_keybind *bind = &binds[id]; + unsigned key = input_keymaps_translate_rk_to_keysym(bind->key); + return dos_key_state[DOS_KEYBOARD_PORT][key]; + } + return false; +} + +bool dos_keyboard_input_pressed(unsigned key) +{ + unsigned keysym = input_keymaps_translate_rk_to_keysym(key); + return dos_key_state[DOS_KEYBOARD_PORT][keysym]; +} + +uint16_t *dos_keyboard_state_get(unsigned port) +{ + return dos_key_state[port]; +} + +void dos_keyboard_free(void) +{ + unsigned i, j; + + for (i = 0; i < MAX_PADS; i++) + for (j = 0; j < MAX_KEYS; j++) + dos_key_state[i][j] = 0; +} diff --git a/input/drivers_keyboard/keyboard_event_dos.h b/input/drivers_keyboard/keyboard_event_dos.h new file mode 100644 index 0000000000..0cecb85576 --- /dev/null +++ b/input/drivers_keyboard/keyboard_event_dos.h @@ -0,0 +1,137 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2016-2017 - Brad Parker + * + * 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- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef _KEYBOARD_EVENT_DOS_H +#define _KEYBOARD_EVENT_DOS_H + +#include "../input_driver.h" + +/* + * Key codes. + */ +enum { + DOSKEY_ESCAPE = 0x1, + DOSKEY_F1 = 0x3b, + DOSKEY_F2 = 0x3c, + DOSKEY_F3 = 0x3d, + DOSKEY_F4 = 0x3e, + DOSKEY_F5 = 0x3f, + DOSKEY_F6 = 0x40, + DOSKEY_F7 = 0x41, + DOSKEY_F8 = 0x42, + DOSKEY_F9 = 0x43, + DOSKEY_F10 = 0x44, + + DOSKEY_BACKQUOTE = 0x29, + DOSKEY_1 = 0x2, + DOSKEY_2 = 0x3, + DOSKEY_3 = 0x4, + DOSKEY_4 = 0x5, + DOSKEY_5 = 0x6, + DOSKEY_6 = 0x7, + DOSKEY_7 = 0x8, + DOSKEY_8 = 0x9, + DOSKEY_9 = 0xa, + DOSKEY_0 = 0xb, + DOSKEY_MINUS = 0xc, + DOSKEY_EQUAL = 0xd, + DOSKEY_BACKSPACE = 0xe, + + DOSKEY_TAB = 0xf, + DOSKEY_q = 0x10, + DOSKEY_w = 0x11, + DOSKEY_e = 0x12, + DOSKEY_r = 0x13, + DOSKEY_t = 0x14, + DOSKEY_y = 0x15, + DOSKEY_u = 0x16, + DOSKEY_i = 0x17, + DOSKEY_o = 0x18, + DOSKEY_p = 0x19, + DOSKEY_LBRACKET = 0x1a, + DOSKEY_RBRACKET = 0x1b, + DOSKEY_BACKSLASH = 0x2b, + + DOSKEY_CAPSLOCK = 0x3a, + DOSKEY_a = 0x1e, + DOSKEY_s = 0x1f, + DOSKEY_d = 0x20, + DOSKEY_f = 0x21, + DOSKEY_g = 0x22, + DOSKEY_h = 0x23, + DOSKEY_j = 0x24, + DOSKEY_k = 0x25, + DOSKEY_l = 0x26, + DOSKEY_SEMICOLON = 0x27, + DOSKEY_QUOTE = 0x28, + DOSKEY_RETURN = 0x1c, + + DOSKEY_LSHIFT = 0x2a, + DOSKEY_z = 0x2c, + DOSKEY_x = 0x2d, + DOSKEY_c = 0x2e, + DOSKEY_v = 0x2f, + DOSKEY_b = 0x30, + DOSKEY_n = 0x31, + DOSKEY_m = 0x32, + DOSKEY_COMMA = 0x33, + DOSKEY_PERIOD = 0x34, + DOSKEY_SLASH = 0x35, + DOSKEY_RSHIFT = 0x36, + + DOSKEY_LCTRL = 0x1d, + DOSKEY_LSUPER = 0x15b, + DOSKEY_LALT = 0x38, + DOSKEY_SPACE = 0x39, + DOSKEY_RALT = 0x138, + DOSKEY_RSUPER = 0x15c, + DOSKEY_MENU = 0x15d, + DOSKEY_RCTRL = 0x11d, + + DOSKEY_UP = 0x148, + DOSKEY_DOWN = 0x150, + DOSKEY_LEFT = 0x14b, + DOSKEY_RIGHT = 0x14d, + + DOSKEY_HOME = 0x147, + DOSKEY_END = 0x14f, + DOSKEY_PGUP = 0x149, + DOSKEY_PGDN = 0x151, +}; + +#include + +#include + +#define LAST_KEYCODE 0x1ff + +#ifndef MAX_PADS +#define MAX_PADS 1 +#endif + +#define DOS_KEYBOARD_PORT MAX_PADS + +bool dos_keyboard_port_input_pressed(const struct retro_keybind *binds, unsigned id); + +bool dos_keyboard_input_pressed(unsigned key); + +uint16_t *dos_keyboard_state_get(unsigned port); + +void dos_keyboard_init(void); + +void dos_keyboard_free(void); + +#endif diff --git a/input/input_driver.c b/input/input_driver.c index 485a49d19a..470986d2d9 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -606,6 +606,7 @@ static INLINE bool input_menu_keys_pressed_internal( return false; } +#ifdef HAVE_MENU static bool input_driver_toggle_button_combo( unsigned mode, uint64_t *trigger_input) { @@ -650,6 +651,7 @@ static bool input_driver_toggle_button_combo( return true; } +#endif /** * input_menu_keys_pressed: @@ -723,6 +725,7 @@ uint64_t input_menu_keys_pressed( input_driver_block_hotkey = true; } +#ifdef HAVE_MENU if ( ((settings->input.menu_toggle_gamepad_combo != INPUT_TOGGLE_NONE) && input_driver_toggle_button_combo( settings->input.menu_toggle_gamepad_combo, &old_input)) @@ -731,6 +734,7 @@ uint64_t input_menu_keys_pressed( settings->input.binds[0][RARCH_MENU_TOGGLE].valid, settings->input.all_users_control_menu)) ret |= (UINT64_C(1) << RARCH_MENU_TOGGLE); +#endif for (i = 0; i < RARCH_BIND_LIST_END; i++) { @@ -944,11 +948,13 @@ uint64_t input_keys_pressed( input_driver_block_hotkey = false; } +#ifdef HAVE_MENU if ( ((settings->input.menu_toggle_gamepad_combo != INPUT_TOGGLE_NONE) && input_driver_toggle_button_combo(settings->input.menu_toggle_gamepad_combo, &old_input)) || input_keys_pressed_internal(settings, joypad_info, RARCH_MENU_TOGGLE, binds)) ret |= (UINT64_C(1) << RARCH_MENU_TOGGLE); +#endif for (i = 0; i < RARCH_BIND_LIST_END; i++) { diff --git a/input/input_keymaps.c b/input/input_keymaps.c index a6317b254f..9bc933bf55 100644 --- a/input/input_keymaps.c +++ b/input/input_keymaps.c @@ -32,6 +32,10 @@ #include "drivers_keyboard/keyboard_event_android.h" #endif +#ifdef DJGPP +#include "drivers_keyboard/keyboard_event_dos.h" +#endif + #ifdef __QNX__ #include #endif @@ -680,6 +684,112 @@ const struct rarch_key_map rarch_key_map_rwebinput[] = { }; #endif +#ifdef WIIU +const struct rarch_key_map rarch_key_map_wiiu[] = { + { 4, RETROK_a }, + { 5, RETROK_b }, + { 6, RETROK_c }, + { 7, RETROK_d }, + { 8, RETROK_e }, + { 9, RETROK_f }, + { 10, RETROK_g }, + { 11, RETROK_h }, + { 12, RETROK_i }, + { 13, RETROK_j }, + { 14, RETROK_k }, + { 15, RETROK_l }, + { 16, RETROK_m }, + { 17, RETROK_n }, + { 18, RETROK_o }, + { 19, RETROK_p }, + { 20, RETROK_q }, + { 21, RETROK_r }, + { 22, RETROK_s }, + { 23, RETROK_t }, + { 24, RETROK_u }, + { 25, RETROK_v }, + { 26, RETROK_w }, + { 27, RETROK_x }, + { 28, RETROK_y }, + { 29, RETROK_z }, + { 30, RETROK_1 }, + { 31, RETROK_2 }, + { 32, RETROK_3 }, + { 33, RETROK_4 }, + { 34, RETROK_5 }, + { 35, RETROK_6 }, + { 36, RETROK_7 }, + { 37, RETROK_8 }, + { 38, RETROK_9 }, + { 39, RETROK_0 }, + { 40, RETROK_RETURN }, + { 41, RETROK_ESCAPE }, + { 42, RETROK_BACKSPACE }, + { 43, RETROK_TAB }, + { 44, RETROK_SPACE }, + { 45, RETROK_MINUS }, + { 46, RETROK_EQUALS }, + { 47, RETROK_LEFTBRACKET }, + { 48, RETROK_RIGHTBRACKET }, + { 49, RETROK_BACKSLASH }, + { 51, RETROK_SEMICOLON }, + { 52, RETROK_QUOTE }, + { 53, RETROK_BACKQUOTE }, + { 54, RETROK_COMMA }, + { 55, RETROK_PERIOD }, + { 56, RETROK_SLASH }, + { 57, RETROK_CAPSLOCK }, + { 58, RETROK_F1 }, + { 59, RETROK_F2 }, + { 60, RETROK_F3 }, + { 61, RETROK_F4 }, + { 62, RETROK_F5 }, + { 63, RETROK_F6 }, + { 64, RETROK_F7 }, + { 65, RETROK_F8 }, + { 66, RETROK_F9 }, + { 67, RETROK_F10 }, + { 68, RETROK_F11 }, + { 69, RETROK_F12 }, + { 71, RETROK_SCROLLOCK }, + { 72, RETROK_PAUSE }, + { 73, RETROK_INSERT }, + { 74, RETROK_HOME }, + { 75, RETROK_PAGEUP }, + { 76, RETROK_DELETE }, + { 77, RETROK_END }, + { 78, RETROK_PAGEDOWN }, + { 79, RETROK_RIGHT }, + { 80, RETROK_LEFT }, + { 81, RETROK_DOWN }, + { 82, RETROK_UP }, + { 83, RETROK_NUMLOCK }, + { 84, RETROK_KP_DIVIDE }, + { 85, RETROK_KP_MULTIPLY }, + { 86, RETROK_KP_MINUS }, + { 87, RETROK_KP_PLUS }, + { 88, RETROK_KP_ENTER }, + { 89, RETROK_KP1 }, + { 90, RETROK_KP2 }, + { 91, RETROK_KP3 }, + { 92, RETROK_KP4 }, + { 93, RETROK_KP5 }, + { 94, RETROK_KP6 }, + { 95, RETROK_KP7 }, + { 96, RETROK_KP8 }, + { 97, RETROK_KP9 }, + { 98, RETROK_KP0 }, + { 99, RETROK_KP_PERIOD }, + { 224, RETROK_LCTRL }, + { 225, RETROK_LSHIFT }, + { 226, RETROK_LALT }, + { 228, RETROK_RCTRL }, + { 229, RETROK_RSHIFT }, + { 230, RETROK_RALT }, + { 0, RETROK_UNKNOWN }, +}; +#endif + #ifdef HAVE_X11 #ifndef XF68XK_Calculator @@ -1311,6 +1421,100 @@ const struct rarch_key_map rarch_key_map_apple_hid[] = { }; #endif +#ifdef DJGPP +const struct rarch_key_map rarch_key_map_dos[] = { + { DOSKEY_ESCAPE, RETROK_ESCAPE }, + { DOSKEY_F1, RETROK_F1 }, + { DOSKEY_F2, RETROK_F2 }, + { DOSKEY_F3, RETROK_F3 }, + { DOSKEY_F4, RETROK_F4 }, + { DOSKEY_F5, RETROK_F5 }, + { DOSKEY_F6, RETROK_F6 }, + { DOSKEY_F7, RETROK_F7 }, + { DOSKEY_F8, RETROK_F8 }, + { DOSKEY_F9, RETROK_F9 }, + { DOSKEY_F10, RETROK_F10 }, + + { DOSKEY_BACKQUOTE, RETROK_BACKQUOTE }, + { DOSKEY_1, RETROK_1 }, + { DOSKEY_2, RETROK_2 }, + { DOSKEY_3, RETROK_3 }, + { DOSKEY_4, RETROK_4 }, + { DOSKEY_5, RETROK_5 }, + { DOSKEY_6, RETROK_6 }, + { DOSKEY_7, RETROK_7 }, + { DOSKEY_8, RETROK_8 }, + { DOSKEY_9, RETROK_9 }, + { DOSKEY_0, RETROK_0 }, + { DOSKEY_MINUS, RETROK_MINUS }, + { DOSKEY_EQUAL, RETROK_EQUALS }, + { DOSKEY_BACKSPACE, RETROK_BACKSPACE }, + + { DOSKEY_TAB, RETROK_TAB }, + { DOSKEY_q, RETROK_q }, + { DOSKEY_w, RETROK_w }, + { DOSKEY_e, RETROK_e }, + { DOSKEY_r, RETROK_r }, + { DOSKEY_t, RETROK_t }, + { DOSKEY_y, RETROK_y }, + { DOSKEY_u, RETROK_u }, + { DOSKEY_i, RETROK_i }, + { DOSKEY_o, RETROK_o }, + { DOSKEY_p, RETROK_p }, + { DOSKEY_LBRACKET, RETROK_LEFTBRACKET }, + { DOSKEY_RBRACKET, RETROK_RIGHTBRACKET }, + { DOSKEY_BACKSLASH, RETROK_BACKSLASH }, + + { DOSKEY_CAPSLOCK, RETROK_CAPSLOCK }, + { DOSKEY_a, RETROK_a }, + { DOSKEY_s, RETROK_s }, + { DOSKEY_d, RETROK_d }, + { DOSKEY_f, RETROK_f }, + { DOSKEY_g, RETROK_g }, + { DOSKEY_h, RETROK_h }, + { DOSKEY_j, RETROK_j }, + { DOSKEY_k, RETROK_k }, + { DOSKEY_l, RETROK_l }, + { DOSKEY_SEMICOLON, RETROK_SEMICOLON }, + { DOSKEY_QUOTE, RETROK_QUOTE }, + { DOSKEY_RETURN, RETROK_RETURN }, + + { DOSKEY_LSHIFT, RETROK_LSHIFT }, + { DOSKEY_z, RETROK_z }, + { DOSKEY_x, RETROK_x }, + { DOSKEY_c, RETROK_c }, + { DOSKEY_v, RETROK_v }, + { DOSKEY_b, RETROK_b }, + { DOSKEY_n, RETROK_n }, + { DOSKEY_m, RETROK_m }, + { DOSKEY_COMMA, RETROK_COMMA }, + { DOSKEY_PERIOD, RETROK_PERIOD }, + { DOSKEY_SLASH, RETROK_SLASH }, + { DOSKEY_RSHIFT, RETROK_RSHIFT }, + + { DOSKEY_LCTRL, RETROK_LCTRL }, + { DOSKEY_LSUPER, RETROK_LSUPER }, + { DOSKEY_LALT, RETROK_LALT }, + { DOSKEY_SPACE, RETROK_SPACE }, + { DOSKEY_RALT, RETROK_RALT }, + { DOSKEY_RSUPER, RETROK_RSUPER }, + { DOSKEY_MENU, RETROK_MENU }, + { DOSKEY_RCTRL, RETROK_RCTRL }, + + { DOSKEY_UP, RETROK_UP }, + { DOSKEY_DOWN, RETROK_DOWN }, + { DOSKEY_LEFT, RETROK_LEFT }, + { DOSKEY_RIGHT, RETROK_RIGHT }, + + { DOSKEY_HOME, RETROK_HOME }, + { DOSKEY_END, RETROK_END }, + { DOSKEY_PGUP, RETROK_PAGEUP }, + { DOSKEY_PGDN, RETROK_PAGEDOWN }, + + { 0, RETROK_UNKNOWN } +}; +#endif + static enum retro_key rarch_keysym_lut[RETROK_LAST]; /** diff --git a/input/input_keymaps.h b/input/input_keymaps.h index 4e7b5dab32..df3cb48790 100644 --- a/input/input_keymaps.h +++ b/input/input_keymaps.h @@ -57,6 +57,8 @@ extern const struct rarch_key_map rarch_key_map_linux[]; extern const struct rarch_key_map rarch_key_map_apple_hid[]; extern const struct rarch_key_map rarch_key_map_android[]; extern const struct rarch_key_map rarch_key_map_qnx[]; +extern const struct rarch_key_map rarch_key_map_dos[]; +extern const struct rarch_key_map rarch_key_map_wiiu[]; /** * input_keymaps_init_keyboard_lut: diff --git a/input/input_overlay.c b/input/input_overlay.c index 3a04b2738c..a252ebbb3d 100644 --- a/input/input_overlay.c +++ b/input/input_overlay.c @@ -30,6 +30,7 @@ #endif #include "../verbosity.h" +#include "../gfx/video_driver.h" #include "input_overlay.h" #include "input_keyboard.h" diff --git a/intl/msg_hash_chs.h b/intl/msg_hash_chs.h index 6f955cc773..2247b51f46 100644 --- a/intl/msg_hash_chs.h +++ b/intl/msg_hash_chs.h @@ -1,42 +1,42 @@ MSG_HASH( MSG_COMPILER, - "Compiler" + "编译器" ) MSG_HASH( MSG_UNKNOWN_COMPILER, - "Unknown compiler" + "未知的编译器" ) MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT, - "Device disconnected from port" + "设备已从端口上断开" ) MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, - "Unknown netplay command received" + "接收到未知的联机游戏指令" ) MSG_HASH( MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, - "文件已存在. Saving to backup buffer" + "文件已存在。保存到备份缓冲区" ) MSG_HASH( MSG_GOT_CONNECTION_FROM, - "Got connection from: \"%s\"" + "连接来自: \"%s\"" ) MSG_HASH( MSG_GOT_CONNECTION_FROM_NAME, - "Got connection from: \"%s (%s)\"" + "连接来自: \"%s (%s)\"" ) MSG_HASH( MSG_PUBLIC_ADDRESS, - "Public address" + "公开地址" ) MSG_HASH( MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, - "No arguments supplied and no menu builtin, displaying help..." + "未提供参数也没有内建菜单,显示帮助..." ) MSG_HASH( MSG_NETPLAY_USERS_HAS_FLIPPED, - "Netplay users has flipped" + "联机游戏用户已被踢出" ) MSG_HASH( MSG_SETTING_DISK_IN_TRAY, @@ -44,19 +44,19 @@ MSG_HASH( ) MSG_HASH( MSG_WAITING_FOR_CLIENT, - "Waiting for client ..." + "等待客户端 ..." ) MSG_HASH( MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, - "You have left the game" + "你已离开游戏" ) MSG_HASH( MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, - "You have joined as player %d" + "你已作为玩家 %d 加入" ) MSG_HASH( MSG_NETPLAY_IMPLEMENTATIONS_DIFFER, - "Implementations differ. Make sure you're using the exact same versions of RetroArch and the core." + "实现有差异。确保正在使用的RetroArch和核心是同版本的。" ) MSG_HASH( MSG_NETPLAY_ENDIAN_DEPENDENT, @@ -68,43 +68,43 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_ENTER_PASSWORD, - "Enter netplay server password:" + "输入联机游戏服务器的密码:" ) MSG_HASH( MSG_NETPLAY_INCORRECT_PASSWORD, - "Incorrect password" + "密码错误" ) MSG_HASH( MSG_NETPLAY_SERVER_NAMED_HANGUP, - "\"%s\" has disconnected" + "\"%s\" 已断开连接" ) MSG_HASH( MSG_NETPLAY_SERVER_HANGUP, - "A netplay client has disconnected" + "一个联机游戏客户端已断开" ) MSG_HASH( MSG_NETPLAY_CLIENT_HANGUP, - "Netplay disconnected" + "联机游戏已断开" ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, - "You do not have permission to play" + "你没有游戏权限" ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, - "There are no free player slots" + "已无空闲插槽" /*FIXME:"There are no free player slots"*/ ) MSG_HASH( MSG_NETPLAY_CANNOT_PLAY, - "Cannot switch to play mode" + "无法切换到游戏模式" ) MSG_HASH( MSG_NETPLAY_PEER_PAUSED, - "Netplay peer \"%s\" paused" + "联机游戏对方 \"%s\" 暂停" ) MSG_HASH( MSG_NETPLAY_CHANGED_NICK, - "Your nickname changed to \"%s\"" + "你的昵称已修改为 \"%s\"" ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, @@ -133,27 +133,27 @@ MSG_HASH( ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-loading savestate from" + "自动加载存档从" ) MSG_HASH( MSG_CAPABILITIES, - "Capabilities" + "容量" ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "Connecting to netplay host" + "连接到联机游戏主机" ) MSG_HASH( MSG_CONNECTING_TO_PORT, - "Connecting to port" + "连接到端口" ) MSG_HASH( MSG_CONNECTION_SLOT, - "Connection slot" + "连接到插槽" ) MSG_HASH( MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, - "Sorry, unimplemented: cores that don't demand content cannot participate in netplay." + "对不起,未实现:核心未请求内容,无法加入联机游戏。" ) MSG_HASH( MSG_FAILED_TO_SET_DISK, @@ -164,7 +164,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, - "Accounts Cheevos" + "Cheevos账户" /*FIXME:"Accounts Cheevos"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, @@ -189,7 +189,7 @@ MSG_HASH( MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Achievement List (Hardcore)" + "成就列表(硬核)" /*FIXME:"Achievement List (Hardcore)"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, @@ -205,7 +205,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "Netplay Rooms" + "联机游戏房间" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ARCHIVE_MODE, @@ -221,7 +221,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, - "Block Frames" + "块帧" /*FIXME:"Block Frames"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, @@ -245,7 +245,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, - "Turbo/Deadzone" + "涡轮/盲区" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, @@ -417,7 +417,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, - "Cheat Passes" + "金手指通过" /*FIXME: "Cheat Passes"*/ ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, @@ -598,9 +598,9 @@ 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' */ - "Load Dummy on Core Shutdown") + "核心关闭时加载虚拟程序") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, - "Check for Missing Firmware Before Loading") + "加载前检查丢失的固件") /*FIXME: "Check for Missing Firmware Before Loading"*/ MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, "动态壁纸") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, @@ -691,7 +691,7 @@ 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, - "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, @@ -747,7 +747,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, "Y键(左侧)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, - "(Key: %s)") + "(键: %s)") /*FIXME:"(Key: %s)"*/ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, "键盘控制器映射类型") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, @@ -789,9 +789,9 @@ 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, - "Netplay flip users") + "联机游戏踢出用户") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "Netplay toggle play/spectate mode") + "联机游戏切换 游戏/围观 模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, "切换屏幕键盘") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, @@ -999,19 +999,19 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "用户名") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, - "Server Password") + "服务器密码") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, "在线游戏设置") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, - "Netplay Stateless Mode") + "联机无状态模式") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, - "Server Spectate-Only Password") + "服务器围观的密码") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, "启用在线游戏旁观者") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, "在线游戏TCP/UDP端口") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "Netplay NAT Traversal") + "联机NAT遍历") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, "网络命令") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, @@ -1135,11 +1135,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, "开发者") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, - "Edge Magazine Issue") + "Edge杂志发行") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, - "Edge Magazine Rating") + "Edge杂志评分") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, - "Edge Magazine Review") + "Edge杂志评论") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, "ELSPA 分级") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, @@ -1147,7 +1147,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, "ESRB 分级") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, - "Famitsu Magazine Rating") + "次世代(Famitsu)杂志评分") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, "经销商") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, @@ -1175,7 +1175,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, "启动游戏内容") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, - "TGDB Rating") + "TGDB 评分") MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, "重启") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, @@ -1213,9 +1213,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME, MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "继续") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, - "RetroKeyboard") + "Retro键盘") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD, - "RetroPad") + "Retro触摸板") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, "RetroPad w/ Analog") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, @@ -1631,7 +1631,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_TAB, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, "多线程渲染") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, - "Deflicker") + "降低闪烁") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, "自定义视口高度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, @@ -1641,7 +1641,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, "自定义视口Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "Set VI Screen Width") + "设置 VI 屏幕宽度") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, "垂直同步") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, @@ -1705,7 +1705,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_HISTORY, "显示历史页") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_ADD, - "Display Import content Tab") + "显示导入内容页") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_IMAGES, "显示图像页") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_MUSIC, @@ -1721,11 +1721,11 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, "Shader预设") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Enable or disable achievements. For more information, visit http://retroachievements.org") + "打开或关闭成就。更多内容请访问 http://retroachievements.org") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, - "Enable or disable unofficial achievements and/or beta features for testing purposes.") + "为测试目的而打开或关闭非官方成就和/或测试版特性。") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Enable or disable savestates, cheats, rewind, fast-forward, pause, and slow-motion for all games.") + "为所有游戏打开或关闭存档、金手指、回退、快进、暂停和慢动作。") MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, "修改驱动设置。") MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, @@ -1733,7 +1733,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, "修改核心设置。") MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Change settings for the recording.") + "修改录制的设置。") MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, "修改显示覆盖、键盘覆盖和屏幕通知的设置。") MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, @@ -1804,9 +1804,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, "在帧与帧之间插入黑色的中间帧,通常用于消除在\n" "120Hz刷新率的显示器上运行60Hz的游戏内容带来\n" "的鬼影。") - MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, - "以增加画面卡顿的风险换取低延时,在垂直同步后增加\n" - "时延(毫秒)。") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "以增加画面卡顿的风险换取低延时,在垂直同步后增加\n" + "时延(毫秒)。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, "设置当开启“强制GPU同步”时CPU可以预先GPU多少帧。") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, @@ -1832,35 +1832,35 @@ MSG_HASH(MSG_AUDIO_MUTED, MSG_HASH(MSG_AUDIO_UNMUTED, "取消静音。") MSG_HASH(MSG_AUTOCONFIG_FILE_ERROR_SAVING, - "Error saving autoconf file.") + "保存 autoconf 文件错误。") MSG_HASH(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, - "Autoconfig file saved successfully.") + "自动配置文件保存成功。") MSG_HASH(MSG_AUTOSAVE_FAILED, - "Could not initialize autosave.") + "无法初始化自动保存。") MSG_HASH(MSG_AUTO_SAVE_STATE_TO, "自动保存状态至") MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, - "Blocking SRAM Overwrite") + "阻止 SRAM 覆盖") MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, "Bringing up command interface on port") MSG_HASH(MSG_BYTES, - "bytes") + "字节") MSG_HASH(MSG_CANNOT_INFER_NEW_CONFIG_PATH, - "Cannot infer new config path. Use current time.") + "无法推断新的配置路径,使用当前时间。") MSG_HASH(MSG_CHEEVOS_HARDCORE_MODE_ENABLE, "硬核模式开启:及时存档和回放被禁用.") MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, - "Comparing with known magic numbers...") + "与已知的magic numbers比较...") MSG_HASH(MSG_COMPILED_AGAINST_API, "Compiled against API") MSG_HASH(MSG_CONFIG_DIRECTORY_NOT_SET, - "Config directory not set. Cannot save new config.") + "未设置配置目录,无法保存新的配置。") MSG_HASH(MSG_CONNECTED_TO, "连接至") MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, - "Content CRC32s differ. Cannot use different games.") + "内容的CRC32s不同。无法使用不同的游戏。") 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, "核心不支持保存状态。") MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, @@ -2066,25 +2066,25 @@ MSG_HASH(MSG_LOADING_STATE, MSG_HASH(MSG_MEMORY, "内存") MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, - "Movie file is not a valid BSV1 file.") + "视频不是有效的BSV1文件。") MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, - "Movie format seems to have a different serializer version. Will most likely fail.") + "视频格式看起来使用了不同的序列化版本。很有可能失败。") MSG_HASH(MSG_MOVIE_PLAYBACK_ENDED, "视频回放结束.") MSG_HASH(MSG_MOVIE_RECORD_STOPPED, - "Stopping movie record.") + "停止视频录制。") MSG_HASH(MSG_NETPLAY_FAILED, - "Failed to initialize netplay.") + "初始化联机游戏失败。") MSG_HASH(MSG_NO_CONTENT_STARTING_DUMMY_CORE, - "No content, starting dummy core.") + "没有内容,启动虚拟核心。") MSG_HASH(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, - "No save state has been overwritten yet.") + "未覆盖任何存档。") MSG_HASH(MSG_NO_STATE_HAS_BEEN_LOADED_YET, - "No state has been loaded yet.") + "没有加载任何存档。") MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, - "Error saving overrides.") + "保存覆盖错误。") MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, - "Overrides saved successfully.") + "覆盖保存成功。") MSG_HASH(MSG_PAUSED, "暂停。") MSG_HASH(MSG_PROGRAM, @@ -2094,9 +2094,9 @@ MSG_HASH(MSG_READING_FIRST_DATA_TRACK, MSG_HASH(MSG_RECEIVED, "接收完毕") MSG_HASH(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, - "Recording terminated due to resize.") + "录制因改变大小而停止。") MSG_HASH(MSG_RECORDING_TO, - "Recording to") + "录制到") MSG_HASH(MSG_REDIRECTING_CHEATFILE_TO, "重定向金手指文件至") MSG_HASH(MSG_REDIRECTING_SAVEFILE_TO, @@ -2112,9 +2112,9 @@ MSG_HASH(MSG_REMOVING_TEMPORARY_CONTENT_FILE, MSG_HASH(MSG_RESET, "重置") MSG_HASH(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, - "Restarting recording due to driver reinit.") + "重启录制由于驱动器重新初始化。") MSG_HASH(MSG_RESTORED_OLD_SAVE_STATE, - "Restored old save state.") + "重载旧的存档。") MSG_HASH(MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, "Shaders: restoring default shader preset to") MSG_HASH(MSG_REVERTING_SAVEFILE_DIRECTORY_TO, @@ -2140,15 +2140,15 @@ MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, "成功保存至") MSG_HASH(MSG_SAVING_RAM_TYPE, - "Saving RAM type") + "保存 RAM 类型") MSG_HASH(MSG_SAVING_STATE, - "Saving state") + "存档中") MSG_HASH(MSG_SCANNING, "扫描中") MSG_HASH(MSG_SCANNING_OF_DIRECTORY_FINISHED, "已完成对文件夹的扫描") MSG_HASH(MSG_SENDING_COMMAND, - "Sending command") + "发送指令") MSG_HASH(MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, "Several patches are explicitly defined, ignoring all...") MSG_HASH(MSG_SHADER, @@ -2156,7 +2156,7 @@ MSG_HASH(MSG_SHADER, MSG_HASH(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, "Shader preset saved successfully.") MSG_HASH(MSG_SKIPPING_SRAM_LOAD, - "Skipping SRAM load.") + "跳过 SRAM 加载。") MSG_HASH(MSG_SLOW_MOTION, "慢动作。") MSG_HASH(MSG_SLOW_MOTION_REWIND, @@ -2172,9 +2172,9 @@ MSG_HASH(MSG_STATE_SIZE, MSG_HASH(MSG_STATE_SLOT, "状态存档槽") MSG_HASH(MSG_TAKING_SCREENSHOT, - "Taking screenshot.") + "截屏。") MSG_HASH(MSG_TO, - "to") + "到") MSG_HASH(MSG_UNDID_LOAD_STATE, "已撤销加载状态。") MSG_HASH(MSG_UNDOING_SAVE_STATE, @@ -2184,15 +2184,15 @@ MSG_HASH(MSG_UNKNOWN, 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.") MSG_HASH(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, - "Using libretro dummy core. Skipping recording.") + "使用libretro虚拟核心。跳过录制。") MSG_HASH(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, "Connect device from a valid port.") MSG_HASH(MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, - "Disconnecting device from port") + "从端口断开设备") MSG_HASH(MSG_VALUE_REBOOTING, "正在重启……") MSG_HASH(MSG_VALUE_SHUTTING_DOWN, @@ -2206,7 +2206,7 @@ MSG_HASH(MSG_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.") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Mute/unmute 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." @@ -2237,7 +2237,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "Synchronize audio. Recommended." + "同步音频。推荐。" ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, @@ -2295,6 +2295,10 @@ 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, "数据库 Cursor List" @@ -2363,38 +2367,38 @@ 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, - "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, - "Show onscreen messages.") + "显示屏幕消息。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, - "User %d Remote Enable") + "用户 %d 远程允许") MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, - "Display battery level") + "显示电池电量") MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FILE, - "Select File") + "选择文件") MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, - "Select From Collection") + "从收藏中选择") MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, - "Filter") + "过滤器") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, - "Scale") + "刻度") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "Netplay will start when content is loaded.") + "联机游戏将在内容加载后开始。") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, - "Couldn't find a suitable core or content file, load manually.") + "无法找到合适的核心或内容文件,手动加载。") MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, - "Browse URL" + "浏览URL" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL, - "URL Path" + "URL路径" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_START, - "Start" + "开始" ) MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, "Bokeh") diff --git a/intl/msg_hash_de.c b/intl/msg_hash_de.c index 81e039f3ee..94d0bc03d6 100644 --- a/intl/msg_hash_de.c +++ b/intl/msg_hash_de.c @@ -1,5 +1,6 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2017 - Lothar Serra Mari * * 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- @@ -14,40 +15,686 @@ */ #include -#include +#include #include #include #include "../msg_hash.h" #include "../configuration.h" - -#ifdef __clang__ -#pragma clang diagnostic ignored "-Winvalid-source-encoding" -#endif +#include "../verbosity.h" int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) { - uint32_t driver_hash = 0; - settings_t *settings = config_get_ptr(); + uint32_t driver_hash = 0; + settings_t *settings = config_get_ptr(); + + if (msg <= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_END && + msg >= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN) { + unsigned idx = msg - MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN; + + switch (idx) { + case RARCH_FAST_FORWARD_KEY: + snprintf(s, len, + "Schaltet zwischen schnellem Vorlauf und \n" + "normaler Spielgeschwindigkeit um." + ); + break; + case RARCH_FAST_FORWARD_HOLD_KEY: + snprintf(s, len, + "Halte die Taste gedrückt, um vorzuspulen.\n" + " \n" + "Beim Loslassen wird der schnelle Vorlauf beendet." + ); + break; + case RARCH_PAUSE_TOGGLE: + snprintf(s, len, + "Inhalt pausieren und wieder fortsetzen."); + break; + case RARCH_FRAMEADVANCE: + snprintf(s, len, + "Einzelbildvorlauf, wenn der Inhalt pausiert ist."); + break; + case RARCH_SHADER_NEXT: + snprintf(s, len, + "Wendet den nächsten Shader im Verzeichnis an."); + break; + case RARCH_SHADER_PREV: + snprintf(s, len, + "Wendet den vorherigen Shader im Verzeichnis an."); + break; + case RARCH_CHEAT_INDEX_PLUS: + case RARCH_CHEAT_INDEX_MINUS: + case RARCH_CHEAT_TOGGLE: + snprintf(s, len, + "Cheats."); + break; + case RARCH_RESET: + snprintf(s, len, + "Setzt den Inhalt zurück."); + break; + case RARCH_SCREENSHOT: + snprintf(s, len, + "Bildschirmfoto anfertigen."); + break; + case RARCH_MUTE: + snprintf(s, len, + "Tonwiedergabe stummschalten bzw. Stummschaltung aufheben."); + break; + case RARCH_OSK: + snprintf(s, len, + "Bildschirmtastatur ein-/ausschalten."); + break; + case RARCH_NETPLAY_FLIP: + snprintf(s, len, + "Netplay-Spieler tauschen."); + break; + case RARCH_NETPLAY_GAME_WATCH: + snprintf(s, len, + "Im Netplay zwischen Spiel- und Beobachter-Modus wechseln."); + break; + case RARCH_SLOWMOTION: + snprintf(s, len, + "Halte die Taste gedrückt, um die Zeitlupe einzuschalten."); + break; + case RARCH_ENABLE_HOTKEY: + snprintf(s, len, + "Andere Hotkeys aktivieren. \n" + " \n" + "Wenn dieser Hotkey entweder einer\n" + "Tastatur, einer Joypad-Taste oder \n" + "Joypad-Achse zugeordnet ist, werden alle \n" + "anderen Hotkeys nur aktiviert, wenn dieser \n" + "Hotkey zur gleichen Zeit gehalten wird. \n" + " \n" + "Dies ist hilfreich für Implementierungen, die auf \n" + "RETRO_KEYBOARD ausgelegt sind und eine große \n" + "Fläche auf der Tastatur benötigen, wo es nicht \n" + "gewünscht ist, dass es zu Kollisionen mit Hotkeys kommt. \n" + " \n" + "Alternativ können auch alle Tastatur-Hotkeys durch \n" + "den Benutzer deaktiviert werden."); + break; + case RARCH_VOLUME_UP: + snprintf(s, len, + "Erhöht die Lautstärke."); + break; + case RARCH_VOLUME_DOWN: + snprintf(s, len, + "Verringert die Lautstärke."); + break; + case RARCH_OVERLAY_NEXT: + snprintf(s, len, + "Wechselt zum nächsten Overlay."); + break; + case RARCH_DISK_EJECT_TOGGLE: + snprintf(s, len, + "Datenträger einbinden/auswerfen. \n" + " \n" + "Wird für Inhalt verwendet, der auf mehreren Datenträgern ausgeliefert wird. "); + break; + case RARCH_DISK_NEXT: + case RARCH_DISK_PREV: + snprintf(s, len, + "Wechselt durch Datenträger-Abbilder. Nach dem Auswerfen verwenden. \n" + " \n" + "Zum Abschließen, Datenträger erneut einbinden."); + break; + case RARCH_GRAB_MOUSE_TOGGLE: + snprintf(s, len, + "Maus einfangen/freilassen. \n" + " \n" + "Wenn die Maus eingefangen ist, versteckt RetroArch \n" + "die Maus und hält den Mauszeiger im RetroArch-Fenster, \n" + "um die Eingabe der Maus zu verbessern."); + break; + case RARCH_GAME_FOCUS_TOGGLE: + snprintf(s, len, + "Spiel-Fokus umschalten.\n" + " \n" + "Wenn ein Spiel fokussiert ist, wird RetroArch die Hotkeys\n" + "deaktivieren und den Mauszeiger im RetroArch-Fenster halten."); + break; + case RARCH_MENU_TOGGLE: + snprintf(s, len, "Menü aufrufen."); + break; + case RARCH_LOAD_STATE_KEY: + snprintf(s, len, + "Spielstand laden."); + break; + case RARCH_FULLSCREEN_TOGGLE_KEY: + snprintf(s, len, + "Vollbildmodus umschalten"); + break; + case RARCH_QUIT_KEY: + snprintf(s, len, + "Taste zum Beenden von RetroArch. \n" + " \n" + "Wenn Du RetroArch unsanft beendest (SIGKILL, etc.) wird \n" + "RetroArch beendet, ohne Arbeitsspeicher oder ähnliches zu speichern." +#ifdef __unix__ + "\nAuf unixoiden Systemen erlaubt SIGINT/SIGTERM ein sauberes \n" + "Beenden von RetroArch." +#endif + ""); + break; + case RARCH_STATE_SLOT_PLUS: + case RARCH_STATE_SLOT_MINUS: + snprintf(s, len, + "Speicherplätze. \n" + " \n" + "Wenn der Speicherplatz 0 ausgewählt wird, ist der Name des Spielstands \n" + "*.state (oder was entsprechend auf der Kommandozeile definiert wurde). \n" + " \n" + "Wenn ein anderer Speicherplatz als 0 gewählt wird, wird das Verzeichnis \n" + "verwendet, wobei die Nummer des Speicherplatzes ist."); + break; + case RARCH_SAVE_STATE_KEY: + snprintf(s, len, + "Spielstand abspeichern."); + break; + case RARCH_REWIND: + snprintf(s, len, + "Halte die Taste zum Zurückspulen gedrückt. \n" + " \n" + "Die Zurückspulfunktion muss eingeschaltet sein."); + break; + case RARCH_MOVIE_RECORD_TOGGLE: + snprintf(s, len, + "Aufnahme starten/beenden"); + break; + default: + if (string_is_empty(s)) + strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); + break; + } + + return 0; + } switch (msg) { + case MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS: + snprintf(s, len, "Anmelde-Daten für dein \n" + "Retro Achievements-Konto. \n" + " \n" + "Besuche retroachievements.org und eröffne \n" + "ein kostenloses Konto. \n" + " \n" + "Nach der Registrierung musst Du deinen \n" + "Benutzernamen und dein Passwort in RetroArch \n" + "angeben."); + break; + case MENU_ENUM_LABEL_CHEEVOS_USERNAME: + snprintf(s, len, "Benutzernahme für dein Retro Achievements-Konto."); + break; + case MENU_ENUM_LABEL_CHEEVOS_PASSWORD: + snprintf(s, len, "Passwort für dein Retro Achievements-Konto."); + break; + case MENU_ENUM_LABEL_USER_LANGUAGE: + snprintf(s, len, "Übersetzt das Menü und alle Bildschirm-Meldungen \n" + "in die Sprache, die Du hier ausgewählt hast. \n" + " \n" + "Ein Neustart wird benötigt, um die geänderten \n" + "Einstellungen zu aktivieren. \n" + " \n" + "Hinweis: möglicherweise sind nicht alle Sprachen \n" + "implementiert. \n" + " \n" + "Wenn die gewählte Sprache nicht implementiert ist, \n" + "wird Englisch als Sprache ausgewählt."); + break; + case MENU_ENUM_LABEL_VIDEO_FONT_PATH: + snprintf(s, len, "Wählt die Schriftart, \n" + "die für Bildschirm-Meldungen verwendet wird."); + break; + case MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS: + snprintf(s, len, "Inhaltsspezifische Core-Einstellungen automatisch laden."); + break; + case MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE: + snprintf(s, len, "Überschreibende Konfigurationen automatisch laden."); + break; + case MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE: + snprintf(s, len, "Eingabebelegungsdateien automatisch laden."); + break; + case MENU_ENUM_LABEL_SORT_SAVESTATES_ENABLE: + snprintf(s, len, "Speichert Spielstand-Dateien in Ordnern, \n" + "die nach dem verwendeten libretro-Core benannt sind."); + break; + case MENU_ENUM_LABEL_SORT_SAVEFILES_ENABLE: + snprintf(s, len, "Speichert Speicherdaten in Ordnern, \n" + "die nach dem verwendeten libretro-Core benannt sind."); + break; + case MENU_ENUM_LABEL_RESUME_CONTENT: + snprintf(s, len, "Verlässt das Menü und kehrt \n" + "zum Inhalt zurück."); + break; + case MENU_ENUM_LABEL_RESTART_CONTENT: + snprintf(s, len, "Startet den Inhalt vom Beginn an neu."); + break; + case MENU_ENUM_LABEL_CLOSE_CONTENT: + snprintf(s, len, "Schließt den Inhalt und entlädt ihn aus dem \n" + "Speicher."); + break; + case MENU_ENUM_LABEL_UNDO_LOAD_STATE: + snprintf(s, len, "Wenn ein Spielstand geladen war, wird der Inhalt \n" + "zum Status vor dem Laden des Spielstands zurückkehren."); + break; + case MENU_ENUM_LABEL_UNDO_SAVE_STATE: + snprintf(s, len, "Wenn ein Spielstand überschrieben wurde, wird \n" + "der Inhalt zum vorherigen Spielstand zurückkehren."); + break; + case MENU_ENUM_LABEL_TAKE_SCREENSHOT: + snprintf(s, len, "Fertigt ein Bildschirmfoto an. \n" + " \n" + "Das Bildschirmfoto wird im Bildschirmfoto-Verzeichnis \n" + "gespeichert."); + break; + case MENU_ENUM_LABEL_RUN: + snprintf(s, len, "Startet den Inhalt."); + break; + case MENU_ENUM_LABEL_INFORMATION: + snprintf(s, len, "Zeige zusätzliche Metadaten \n" + "über den Inhalt an."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_CONFIG: + snprintf(s, len, "Konfigurationsdatei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_COMPRESSED_ARCHIVE: + snprintf(s, len, "Komprimierte Archivdatei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_RECORD_CONFIG: + snprintf(s, len, "Aufzeichnungs-Konfigurationsdatei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_CURSOR: + snprintf(s, len, "Vorherige Datenbank-Suchanfragen."); /*Maybe a FIXME*/ + break; + case MENU_ENUM_LABEL_FILE_CONFIG: + snprintf(s, len, "Konfigurationsdatei."); + break; + case MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY: + snprintf(s, len, + "Auswählen, um das gewählte Verzeichnis nach Inhalten \n" + "zu durchsuchen."); + break; + case MENU_ENUM_LABEL_USE_THIS_DIRECTORY: + snprintf(s, len, + "Dieses Verzeichnis auswählen."); + break; + case MENU_ENUM_LABEL_CONTENT_DATABASE_DIRECTORY: + snprintf(s, len, + "Verzeichnis für Inhaltsdatenbanken. \n" + " \n" + "Verzeichnis, in welchem die Inhaltsdatenbanken \n" + "gespeichert werden."); + break; + case MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY: + snprintf(s, len, + "Verzeichnis für Vorschaubilder. \n" + " \n" + "Verzeichnis, in welchem die Vorschaubilder \n" + "gespeichert werden."); + break; + case MENU_ENUM_LABEL_LIBRETRO_INFO_PATH: + snprintf(s, len, + "Verzeichnis für Core-Informationsdateien. \n" + " \n" + "Ein Verzeichnis, in dem nach \n" + "libretro-Core-Informationen gesucht wird."); + break; + case MENU_ENUM_LABEL_PLAYLIST_DIRECTORY: + snprintf(s, len, + "Wiedergabelisten-Verzeichnis. \n" + " \n" + "Speichere alle Wiedergabelisten in diesem \n" + "Verzeichnis."); + break; + case MENU_ENUM_LABEL_DUMMY_ON_CORE_SHUTDOWN: + snprintf(s, len, + "Einige Cores haben eine \n" + "Abschalt-Funktion. \n" + " \n" + "Wenn diese Option deaktiviert bleibt, \n" + "wird RetroArch beendet, wenn die Abschalt-Funktion \n" + "ausgelöst wird. \n" + " \n" + "Wenn diese Option aktiviert ist, wird stattdessen \n" + "ein 'leerer' Core geladen, sodass wir im Menü bleiben \n" + "und RetroArch nicht beendet wird."); + break; + case MENU_ENUM_LABEL_CHECK_FOR_MISSING_FIRMWARE: + snprintf(s, len, + "Einige Cores benötigen spezielle \n" + "Firmware- oder BIOS-Dateien. \n" + " \n" + "Wenn diese Option deaktiviert ist, \n" + "wird versucht, den Core auch zu laden, \n" + "wenn die Firmware fehlt. \n"); + break; + case MENU_ENUM_LABEL_PARENT_DIRECTORY: + snprintf(s, len, + "Kehre zum übergeordneten Verzeichnis zurück."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_SHADER_PRESET: + snprintf(s, len, + "Datei mit Shader-Voreinstellungen."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_SHADER: + snprintf(s, len, + "Shader-Datei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_REMAP: + snprintf(s, len, + "Eingabebelegungsdatei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_CHEAT: + snprintf(s, len, + "Cheat-Datei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_OVERLAY: + snprintf(s, len, + "Overlay-Datei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_RDB: + snprintf(s, len, + "Datenbankdatei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_FONT: + snprintf(s, len, + "TrueType-Schriftartendatei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_PLAIN_FILE: + snprintf(s, len, + "Einfache Datei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_MOVIE_OPEN: + snprintf(s, len, + "Video. \n" + " \n" + "Auswählen, um diese Datei mit dem \n" + "Video-Player abzuspielen."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_MUSIC_OPEN: + snprintf(s, len, + "Musik. \n" + " \n" + "Auswählen, um diese Datei mit dem \n" + "Musik-Player abzuspielen."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_IMAGE: + snprintf(s, len, + "Bild-Datei."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_IMAGE_OPEN_WITH_VIEWER: + snprintf(s, len, + "Bild. \n" + " \n" + "Auswählen, um diese Datei mit dem \n" + "Bildbetrachter zu öffnen."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION: + snprintf(s, len, + "libretro-Core. \n" + " \n" + "Auswählen, um diesen Core dem Spiel zuzuordnen."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_CORE: + snprintf(s, len, + "libretro-Core. \n" + " \n" + "Auswählen, um diesen Core in RetroArch zu laden."); + break; + case MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY: + snprintf(s, len, + "Verzeichnis. \n" + " \n" + "Auswählen, um dieses Verzeichnis zu öffnen."); + break; + case MENU_ENUM_LABEL_CACHE_DIRECTORY: + snprintf(s, len, + "Zwischenspeicher-Verzeichnis. \n" + " \n" + "Von RetroArch entpackter Inhalt wird \n" + "temporär in diesem Verzeichnis gespeichert."); + break; + case MENU_ENUM_LABEL_HISTORY_LIST_ENABLE: + snprintf(s, len, + "Wenn aktiviert, wird jeder Inhalt, der in RetroArch \n" + "geöffnet wird, automatisch in \n" + "die Verlaufsliste aufgenommen."); + break; + case MENU_ENUM_LABEL_RGUI_BROWSER_DIRECTORY: + snprintf(s, len, + "Dateibrowser-Verzeichnis. \n" + " \n" + "Legt das Verzeichnis fest, in dem der Dateibrowser startet."); + break; + case MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR: + snprintf(s, len, + "Beeinflusst, wie die Eingabe-Abfrage in \n" + "RetroArch gehandhabt wird. \n" + " \n" + "Früh - Eingabe wird abgefragt, bevor \n" + "das aktuelle Frame verarbeitet wird. \n" + "Normal - Eingabe wird abgefragt, wenn \n" + "eine Abfrage angefordert wird. \n" + "Spät - Eingabe wird abgefragt, wenn \n" + "die erste Eingabe-Abfrage im Frame angefordert wird.\n" + " \n" + "Diese Option auf 'Früh' oder 'Spät' zu setzen kann \n" + "eine verringerte Latenz bewirken, \n" + "abhängig von deiner Konfiguration.\n\n" + "Wenn Netplay aktiviert ist, wird das Standard-Abfrageverhalten \n" + "(Normal) verwendet. Dieser Wert wird dann nicht berücksichtigt." + ); + break; + case MENU_ENUM_LABEL_INPUT_DESCRIPTOR_HIDE_UNBOUND: + snprintf(s, len, + "Verstecke Eingabe-Beschreibungen, die nicht vom \n" + "Core festgelegt werden."); + break; + case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE: + snprintf(s, len, + "Bildwiederholrate deines Bildschirms. \n" + "Wird verwendet, um eine geeignete Audio-Eingaberate zu finden."); + break; + case MENU_ENUM_LABEL_VIDEO_FORCE_SRGB_DISABLE: + snprintf(s, len, + "Unterstützung für sRGB FBO zwangsweise deaktivieren. Einige Intel \n" + "OpenGL-Treiber unter Windows haben Bildprobleme bei aktivierter \n" + "sRGB FBO-Unterstützung."); + break; + case MENU_ENUM_LABEL_AUDIO_ENABLE: + snprintf(s, len, + "Tonausgabe aktivieren."); + break; + case MENU_ENUM_LABEL_AUDIO_SYNC: + snprintf(s, len, + "Ton synchronisieren (empfohlen)."); + break; + case MENU_ENUM_LABEL_AUDIO_LATENCY: + snprintf(s, len, + "Gewünschte Ton-Latenz in Millisekunden. \n" + "Wird evtl. nicht berücksichtigt, wenn der Audiotreiber \n" + "die Latenz nicht zurückmelden kann."); + break; + case MENU_ENUM_LABEL_VIDEO_ALLOW_ROTATE: + snprintf(s, len, + "Erlaube Core, die Drehung festzulegen. Wenn deaktiviert, \n" + "werden Dreh-Anfragen angenommen, aber ignoriert. \n\n" + "Wird in Setups verwendet, in denen der Benutzer den \n" + "Monitor manuell dreht."); + break; + case MENU_ENUM_LABEL_INPUT_DESCRIPTOR_LABEL_SHOW: + snprintf(s, len, + "Zeige vom Core festgelegte Eingabe-Beschreibungen anstelle \n" + "der standardmäßigen an."); + break; + case MENU_ENUM_LABEL_CONTENT_HISTORY_SIZE: + snprintf(s, len, + "Anzahl der Elemente, die in der \n" + "Verlaufsliste gespeichert werden."); + break; + case MENU_ENUM_LABEL_VIDEO_WINDOWED_FULLSCREEN: + snprintf(s, len, + "Legt fest, ob der Fenstermodus verwendet wird oder nicht, \n" + "wenn das Bild in Vollbild angezeigt werden soll."); + break; + case MENU_ENUM_LABEL_VIDEO_FONT_SIZE: + snprintf(s, len, + "Schriftgröße für Bildschirm-Meldungen."); + break; + case MENU_ENUM_LABEL_SAVESTATE_AUTO_INDEX: + snprintf(s, len, + "Erhöht den Speicherplatz-Index bei jedem Speichervorgang, \n" + "sodass mehrere Spielstand-Dateien erzeugt werden. \n" + "Wenn der Inhalt geladen ist, wird der Speicherplatz-Index \n" + "auf den höchsten existierenden Wert gesetzt (neuester Spielstand)."); + break; + case MENU_ENUM_LABEL_FPS_SHOW: + snprintf(s, len, + "Aktiviert die Anzeige der aktuellen Bilder \n" + "pro Sekunde."); + break; + case MENU_ENUM_LABEL_VIDEO_FONT_ENABLE: + snprintf(s, len, + "Zeige und/oder verstecke Bildschirm-Meldungen."); + break; + case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_X: + case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_Y: + snprintf(s, len, + "Legt den Versatz für die Anzeige von Bildschirm-Meldungen \n" + "fest. Gültige Werte liegen im Bereich [0.0 bis 1.0]."); + break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_ENABLE: + snprintf(s, len, + "Aktiviert oder deaktiviert das aktuelle Overlay."); + break; + case MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU: + snprintf(s, len, + "Verhindert, dass das aktuelle Overlay im \n" + "Menü angezeigt wird."); + break; + case MENU_ENUM_LABEL_OVERLAY_PRESET: + snprintf(s, len, + "Pfad zum Eingabe-Overlay."); + break; + case MENU_ENUM_LABEL_OVERLAY_OPACITY: + snprintf(s, len, + "Overlay-Deckkraft"); + break; + case MENU_ENUM_LABEL_INPUT_BIND_TIMEOUT: + snprintf(s, len, + "Zeitlimit für Eingabe-Belegungen (in Sekunden). \n" + "Anzahl der Sekunden, die gewartet werden soll, \n" + "bis zur nächsten Belegung gewechselt wird."); + break; + case MENU_ENUM_LABEL_OVERLAY_SCALE: + snprintf(s, len, + "Overlay-Skalierung."); + break; + case MENU_ENUM_LABEL_AUDIO_OUTPUT_RATE: + snprintf(s, len, + "Audio-Abtastrate."); + break; + case MENU_ENUM_LABEL_VIDEO_SHARED_CONTEXT: + snprintf(s, len, + "Aktivieren, wenn Hardware-beschleunigte Cores \n" + "ihren eigenen privaten Kontext bekommen sollen. \n" + "Dies verhindert, dass Änderungen des Geräte-Status \n" + "zwischen den Einzelbildern geschätzt werden müssen." + ); + break; case MENU_ENUM_LABEL_CORE_LIST: snprintf(s, len, "Lade Core. \n" " \n" - "Suche nach einer Libretro-Core- \n" - "Implementierung. In welchem Verzeichnis der \n" - "Browser startet, hängt vom deinem Core-Verzeichnis \n" - "ab. Falls du es nicht eingestellt hast, wird er \n" - "im Root-Verzeichnis starten. \n" + "Suche nach einer libretro-Core-Implementierung. \n" + "In welchem Verzeichnis der Browser beginnt, \n" + "hängt von deinem Core-Verzeichnispfad \n" + "ab. Ist dieser nicht eingestellt, wird im Wurzelverzeichnis begonnen. \n" " \n" - "Ist das Core-Verzeichnis ein Ordner, wird das \n" - "Menü diesen als Startverzeichnis nutzen. Ist \n" - "das Core-Verzeichnis ein Pfad zu einer Datei, \n" - "wird es in dem Verzeichnis starten, in dem \n" - "sich die Datei befindet."); + "Ist als Core-Verzeichnis ein Ordner ausgewählt, wird \n" + "das Menü diesen als Startverzeichnis nutzen. \n" + "Ist das Core-Verzeichnis ein vollständiger Pfad, wird \n" + "es in dem Ordner beginnen, in welchem sich die Datei befindet."); + break; + case MENU_ENUM_LABEL_VALUE_MENU_ENUM_CONTROLS_PROLOG: + snprintf(s, len, + "Du kannst folgende Steuerelemente mit\n" + "deinem Controller oder deiner Tastatur verwenden\n" + "um durch das Menü zu navigieren: \n" + " \n" + ); + break; + case MENU_ENUM_LABEL_WELCOME_TO_RETROARCH: + snprintf(s, len, + "Willkommen bei RetroArch\n" + ); + break; + case MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC: + { + /* Work around C89 limitations */ + char u[501]; + const char * t = + "RetroArch verwendet eine einzigartige Form der\n" + "Audio/Video-Synchronisierung. Diese muss\n" + "an die Bildwiederholrate deines Bildschirms angepasst werden,\n" + "um die bestmögliche Leistung zu erhalten.\n" + " \n" + "Treten Probleme wie eine knackende Ton-Wiedergabe oder\n" + "eine unregelmäßige Bildwiedergabe auf, bedeutet dies in der Regel,\n" + "dass Du die Einstellungen kalibrieren musst. Du hast folgende Möglichkeiten:\n" + " \n"; + snprintf(u, sizeof(u), /* can't inline this due to the printf arguments */ + "a) Gehe zu '%s' -> '%s', und aktiviere\n" + "'Threaded Video'. Die Bildwiederholrate wird in diesem\n" + "Modus nicht berücksichtigt. Die Bildwiederholrate wird höher,\n" + "aber die Video-Darstellung wird eventuell weniger flüssig.\n" + "b) Gehe zu '%s' -> '%s', und schaue nach\n" + "'%s'. Lass' es für \n" + "2048 Frames laufen, dann drücke auf 'OK'.", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO)); + strlcpy(s, t, len); + strlcat(s, u, len); + } + break; + case MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC: + snprintf(s, len, + "Um nach Inhalten zu suchen, gehe zu '%s' und\n" + "wähle '%s' oder %s'.\n" + " \n" + "Die Dateien werden werden mit einer Datenbank abgeglichen.\n" + "Bei einem Treffer wird die Datei zu einer Sammlung\n" + "hinzugefügt.\n" + " \n" + "Du kannst diese Inhalte einfach aufrufen, indem Du\n" + "zu'%s' ->\n" + "'%s'\n gehst," + "anstatt jedes Mal den Dateibrowser\n" + "verwenden zu müssen.\n" + " \n" + "HINWEIS: Inhalte für einige Cores können möglicherweise\n" + "noch nicht durchsucht werden." + , + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_FILE), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST) + ); + break; + case MENU_ENUM_LABEL_VALUE_EXTRACTING_PLEASE_WAIT: + snprintf(s, len, + "Willkommen bei RetroArch \n" + "\n" + "Extrahiere Assets, bitte warten.\n" + "Dies kann eine Weile dauern...\n" + ); break; case MENU_ENUM_LABEL_INPUT_DRIVER: if (settings) @@ -56,31 +703,26 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) switch (driver_hash) { case MENU_LABEL_INPUT_DRIVER_UDEV: - { - /* Work around C89 limitations */ - const char * t = - "udev-Eingabetreiber. \n" - " \n" - "Dieser Treiber kann ohne X ausgeführt werden. \n" - " \n" - "Er verwende die neue evdev-Joypad-API \n" - "für die Joystick-Unterstützung und unterstützt \n" - "auch Hotplugging und Force-Feedback (wenn das \n" - "Gerät dies unterstützt). \n" - " \n"; - const char * u = - "Der Treiber liest evdev-Ereignisse für die Tastatur- \n" - "Unterstützung und kann auch mit Tastatur-Callbacks, \n" - "Mäusen und Touchpads umgehen. \n" - " \n" - "Standardmäßig sind die /dev/input-Dateien in den \n" - "meisten Linux-Distribution nur vom Root- \n" - "Benutzer lesbar (mode 600). Du kannst eine udev- \n" - "Regel erstellen, die auch den Zugriff für andere \n" - "Benutzer erlaubt."; - strlcpy(s, t, len); - strlcat(s, u, len); - } + snprintf(s, len, + "udev-Eingabetreiber. \n" + " \n" + "Dieser Treiber kann ohne X ausgeführt werden. \n" + " \n" + "Er verwende die neue evdev-Joypad-API \n" + "für die Joystick-Unterstützung und unterstützt \n" + "auch Hotplugging und Force-Feedback (wenn das \n" + "Gerät dies unterstützt). \n" + " \n" + "Der Treiber liest evdev-Ereignisse für die Tastatur- \n" + "Unterstützung und kann auch mit Tastatur-Callbacks, \n" + "Mäusen und Touchpads umgehen. \n" + " \n" + "Standardmäßig sind die /dev/input-Dateien in den \n" + "meisten Linux-Distribution nur vom Root- \n" + "Benutzer lesbar (mode 600). Sie können eine udev- \n" + "Regel erstellen, die auch den Zugriff für andere \n" + "Benutzer erlaubt." + ); break; case MENU_LABEL_INPUT_DRIVER_LINUXRAW: snprintf(s, len, @@ -89,7 +731,7 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "Dieser Treiber erfordert eine aktive TTY-Schnittstelle. \n" "Tastatur-Ereignisse werden direkt von der TTY gelesen, \n" "was es einfacher, aber weniger flexibel als udev macht. \n" - "Mäuse, etc, werden nicht unterstützt. \n" + "Mäuse und ähnliche Geräte werden nicht unterstützt. \n" " \n" "Dieser Treiber verwendet die alte Joystick-API \n" "(/dev/input/js*)."); @@ -103,11 +745,29 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) break; } break; + case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: + snprintf(s, len, + "Lade Inhalt. \n" + "Suche nach Inhalten. \n" + " \n" + "Um Inhalte zu laden benötigst Du den passenden \n" + "libretro-Core und die Inhalts-Datei. \n" + " \n" + "Um einzustellen, welcher Ordner standardmäßig \n" + "geöffnet wird, um nach Inhalten zu suchen, solltest \n" + "Du das Inhalts-Verzeichnis setzen. Wenn es nicht \n" + "gesetzt ist, wird es im Hauptverzeichen starten. \n" + " \n" + "Der Browser wird nur Dateierweiterungen des \n" + "zuletzt geladenen Cores zeigen und diesen Core \n" + "nutzen, wenn Inhalt geladen wird." + ); + break; case MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY: snprintf(s, len, - "Lade Content aus dem Verlauf. \n" + "Lade Inhalt aus dem Verlauf. \n" " \n" - "Wenn Content geladen wird, wird der Content \n" + "Wenn Inhalt geladen wird, wird der Inhalt \n" "sowie der dazugehörige Core im Verlauf gespeichert. \n" " \n" "Der Verlauf wird im selben Verzeichnis wie die \n" @@ -117,31 +777,9 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "im Hauptmenü angezeigt." ); break; - case MENU_ENUM_LABEL_LOAD_CONTENT_LIST: - snprintf(s, len, - "Lade Inhalt. \n" - "Suche nach Inhalt. \n" - " \n" - "Um Inhalte zu laden brauchst du\n" - "einen 'Core'. \n" - " \n" - "Um einzustellen wo das Verzeichnis beginnt, \n" - "setze das \n" - "'%s'. \n" - "Falls diese nicht gesetzt ist, startet \n" - "die Suche beim obersten Verzeichnis.\n" - " \n" - "Beim Durchsuchen werden Inhalte gefiltert. \n" - "Nur Inhalte mit der Dateiendung, welche \n" - "mit den ausgewählten Core funktionieren \n" - "werden angezeigt. \n" - "Dieser Core wird dann auch für den Inhalt verwendet.", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY) - ); - break; case MENU_ENUM_LABEL_VIDEO_DRIVER: snprintf(s, len, - "Momentaner Grafiktreiber."); + "Aktueller Grafiktreiber"); if (string_is_equal(settings->video.driver, "gl")) { @@ -149,11 +787,11 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "OpenGL-Grafiktreiber. \n" " \n" "Dieser Treiber erlaubt es, neben software- \n" - "gerenderten Cores auch Libretro-GL-Cores zu \n" + "gerenderten Cores auch libretro-GL-Cores zu \n" "verwenden. \n" " \n" "Die Leistung, sowohl bei software-gerenderten, \n" - "als auch bei Libretro-GL-Cores, hängt von dem \n" + "als auch bei libretro-GL-Cores, hängt von dem \n" "GL-Treiber deiner Grafikkarte ab."); } else if (string_is_equal(settings->video.driver, "sdl2")) @@ -175,13 +813,13 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "Dies ist ein SDL1.2-Grafiktreiber \n" "mit Software-Rendering." " \n" - "Die Leistung ist suboptimal und du \n" - "solltest ihn nur als letzte \n" + "Die Leistung ist suboptimal und Du \n" + "solltest diesen Treiber nur als letzte \n" "Möglichkeit verwenden."); } else if (string_is_equal(settings->video.driver, "d3d")) { - snprintf(s, len, + snprintf(s, len, "Direct3D-Grafiktreiber. \n" " \n" "Die Leistung bei software-gerenderten \n" @@ -194,12 +832,21 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "Exynos-G2D-Grafiktreiber. \n" " \n" "Dies ist ein Low-Level-Exynos-Grafiktreiber. \n" - "Er verwendet den G2D-Block in Samsung-Exynos-SoCs. \n" + "Er verwendet den G2D-Block in Samsung-Exynos-SoCs \n" "für Blitting-Operationen. \n" " \n" "Die Leistung bei software-gerendeten Cores sollte \n" "optimal sein."); } + else if (string_is_equal(settings->video.driver, "drm")) + { + snprintf(s, len, + "DRM-Grafiktreiber \n" + " \n" + "Dies ist ein Low-Level DRM-Grafiktreiber.\n" + "Er verwendet libdrm für Hardware-Skalierung und \n" + "GPU-Overlays."); + } else if (string_is_equal(settings->video.driver, "sunxi")) { snprintf(s, len, @@ -230,36 +877,23 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "Convoluted-Kosinus-Implementierung."); break; + default: + if (string_is_empty(s)) + strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); + break; } break; case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET: snprintf(s, len, "Lade Shader-Voreinstellung. \n" " \n" - " Lade eine " -#ifdef HAVE_CG - "Cg" -#endif -#ifdef HAVE_GLSL -#ifdef HAVE_CG - "/" -#endif - "GLSL" -#endif -#ifdef HAVE_HLSL -#if defined(HAVE_CG) || defined(HAVE_HLSL) - "/" -#endif - "HLSL" -#endif - "-Voreinstellung. \n" - "Das Menüshader-Menü wird entsprechend \n" - "aktualisiert." + " Lade eine Shader-Voreinstellung direkt. \n" + "Das Shader-Menü wird entsprechend angepasst. \n" " \n" - "Wenn der CGP komplexe Methoden verwendet, \n" - "(also andere als Quellskalierung mit dem \n" - "selben Faktor für X/Y) kann der im Menü \n" - "angezeigte Skalierungsfaktor inkorrekt sein." + "Wenn der CGP Skalierungsmethoden verwendet, die nicht \n" + "einfach sind, (z.B. Quellen-Skalierung, gleicher \n" + "Skalierungsfaktor für X/Y), ist der angezeigte Skalierungsfaktor \n" + "im Menü möglicherweise nicht korrekt." ); break; case MENU_ENUM_LABEL_VIDEO_SHADER_SCALE_PASS: @@ -276,8 +910,8 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "mit dem als 'Standardfilter' eingestellten \n" "Filter auf die Bildschirmgröße gestreckt. \n" " \n" - "Wenn 'Mir egal' eingestellt ist, wird \n" - "entweder einfache Skalierung or Vollbild- \n" + "Wenn 'Ignorieren' eingestellt ist, wird \n" + "entweder einfache Skalierung oder Vollbild- \n" "Streckung verwendet - abhängig davon, ob \n" "es der letzte Durchgang ist oder nicht." ); @@ -286,13 +920,13 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "Shader-Durchgänge. \n" " \n" - "RetroArch erlaubt es dir, verschiedene Shader \n" + "RetroArch erlaubt es, verschiedene Shader \n" "in verschiedenen Durchgängen miteinander zu \n" "kombinieren. \n" " \n" "Diese Option legt die Anzahl der Shader- \n" - "Durchgänge fest. Wenn du die Anzahl auf 0 setzt, \n" - "verwendest du einen 'leeren' Shader." + "Durchgänge fest. Wenn Du die Anzahl auf 0 setzt, \n" + "verwendest Du einen 'leeren' Shader." " \n" "Die 'Standardfilter'-Option beeinflusst den \n" "Streckungsfilter"); @@ -306,106 +940,939 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) break; case MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_PARAMETERS: snprintf(s, len, - "Shader-Voreinstellung-Parameter. \n" + "Parameter der Shader-Voreinstellung. \n" " \n" "Verändert die Shader-Voreinstellung, die aktuell \n" "im Menü aktiv ist." ); break; - /* - * FIXME: Some stuff still missing here. - */ + case MENU_ENUM_LABEL_VIDEO_SHADER_PASS: + snprintf(s, len, + "Pfad zum Shader. \n" + " \n" + "Alle Shader mmüssen vom selben Typ sein \n" + "(z.B. CG, GLSL oder HLSL). \n" + " \n" + "Durch das Setzen des Shader-Verzeichnisses \n" + "legst Du fest, in welchem Verzeichnis der Browser \n" + "nach Shadern sucht." + ); + break; + case MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT: + snprintf(s, len, + "Speichert die Konfiguration beim Beenden. \n" + "Hilfreich für das Menü, da Einstellungen geändert \n" + "werden können. Überschreibt die Konfiguration. \n" + " \n" + "#include-Einträge und Kommentare bleiben nicht erhalten. \n" + " \n" + "Die Konfigurationsdatei sollte als 'unantastbar' \n" + "angesehen werden, da es wahrscheinlich ist, \n" + "dass der Benutzer Änderungen vornimmt \n" + "und diese nicht ohne Wissen des \n" + "Benutzers überschrieben werden sollten." +#if defined(RARCH_CONSOLE) || defined(RARCH_MOBILE) + "\nDies gilt nicht für \n" + "Konsolen, bei denen eine manuelle \n" + "Konfiguration keine sinnvolle Option ist. \n" +#endif + ); + break; + case MENU_ENUM_LABEL_CONFIRM_ON_EXIT: + snprintf(s, len, "Bist Du sicher, dass Du RetroArch verlassen möchtest?"); + break; + case MENU_ENUM_LABEL_SHOW_HIDDEN_FILES: + snprintf(s, len, "Zeige versteckte Dateien \n" + "und Ordner."); + break; + case MENU_ENUM_LABEL_VIDEO_SHADER_FILTER_PASS: + snprintf(s, len, + "Hardware-Filter für diesen Durchgang. \n" + " \n" + "Wenn 'Ignorieren' gewählt ist, wird der \n" + "Standard-Filter verwendet." + ); + break; + case MENU_ENUM_LABEL_AUTOSAVE_INTERVAL: + snprintf(s, len, + "Speichert den nichtflüchtigen SRAM-Speicher \n" + "in regelmäßigen Abständen.\n" + " \n" + "Sofern nicht anders festgelegt, ist das automatische \n" + "Speichern standardmäßig deaktiviert. Das Intervall wird \n" + "in Sekunden angegeben. \n" + " \n" + "Ein Wert von 0 deaktiviert das automatische Speichern."); + break; + case MENU_ENUM_LABEL_INPUT_BIND_DEVICE_TYPE: + snprintf(s, len, + "Typ des Eingabe-Gerätes. \n" + " \n" + "Wählt aus, welcher Eingabe-Gerätetyp verwendet wird. \n" + "Dies ist für den libretro-Core selbst relevat." + ); + break; + case MENU_ENUM_LABEL_LIBRETRO_LOG_LEVEL: + snprintf(s, len, + "Legt das Log-Level für das \n" + "(GET_LOG_INTERFACE) der Cores fest. \n" + " \n" + " Wenn ein libretro-Core ein Log-Level unterhalb \n" + " des eingestellten Log-Levels ausgibt, wird \n" + " dies ignoriert.\n" + " \n" + " DEBUG-Logs werden immer ignoriert, außer der \n" + " ausführliche Ausgabemodus (--verbose) ist aktiviert.\n" + " \n" + " DEBUG = 0\n" + " INFO = 1\n" + " WARN = 2\n" + " ERROR = 3" + ); + break; + case MENU_ENUM_LABEL_STATE_SLOT_INCREASE: + case MENU_ENUM_LABEL_STATE_SLOT_DECREASE: + snprintf(s, len, + "Speicherplätze. \n" + " \n" + "Wenn der Speicherplatz auf 0 gesetzt wird, ist der Name des Spielstands \n" + "*.state (oder was auf der Kommandozeile definiert wurde). \n" + " \n" + "Wenn der Speicherplatz nicht auf 0 gesetzt wird, wird das Verzeichnis , \n" + "gewählt, wobei die Nummer des Speicherplatzes ist."); + break; + case MENU_ENUM_LABEL_SHADER_APPLY_CHANGES: + snprintf(s, len, + "Shader-Einstellungen übernehmen. \n" + " \n" + "Verwende diese Option, um Änderungen an den \n" + "Shader-Einstellungen zu übernehmen. \n" + " \n" + "Da das Ändern der Shader-Optionen \n" + "einiges an Rechenleistung erfordert, \n" + "musst Du die Option manuell auslösen. \n" + " \n" + "Wenn Du Shader anwendest, werden die Menüeinstellungen \n" + "in einer temporären Datei gespeichert (entweder \n" + "menu.cgp oder menu.glslp) und geladen. Die Datei \n" + "bleibt nach dem Beenden von RetroArch bestehen. Die Datei \n" + "wird im Shader-Verzeichnis gespeichert." + ); + break; + case MENU_ENUM_LABEL_MENU_TOGGLE: + snprintf(s, len, + "Menü aufrufen."); + break; + case MENU_ENUM_LABEL_GRAB_MOUSE_TOGGLE: + snprintf(s, len, + "Maus einfangen/freilassen. \n" + " \n" + "Wenn die Maus eingefangen ist, versteckt RetroArch \n" + "die Maus und hält den Mauszeiger im RetroArch-Fenster, \n" + "um die Eingabe der Maus zu verbessern."); + break; + case MENU_ENUM_LABEL_GAME_FOCUS_TOGGLE: + snprintf(s, len, + "Spiel-Fokus umschalten.\n" + " \n" + "Wenn ein Spiel fokussiert ist, wird RetroArch die Hotkeys\n" + "deaktivieren and und den Mauszeiger im RetroArch-Fenster halten."); + break; + case MENU_ENUM_LABEL_DISK_NEXT: + snprintf(s, len, + "Wechselt durch Datenträger-Abbilder. Nach dem Auswerfen verwenden. \n" + " \n" + "Zum Abschließen, Datenträger erneut einbinden."); + break; + case MENU_ENUM_LABEL_VIDEO_FILTER: +#ifdef HAVE_FILTERS_BUILTIN + snprintf(s, len, + "CPU-basierte Grafikfilter."); +#else + snprintf(s, len, + "CPU-basierte Grafikfilter.\n" + " \n" + "Pfad zu einer dynamischen Bibliothek."); +#endif + break; + case MENU_ENUM_LABEL_AUDIO_DEVICE: + snprintf(s, len, + "Überschreibt das Standard-Audiogerät, welches \n" + "der Audiotreiber verwendet.\n" + "Dies ist treiberabhängig. z.B.\n" +#ifdef HAVE_ALSA + " \n" + "benötigt ALSA ein PCM-Gerät." +#endif +#ifdef HAVE_OSS + " \n" + "benötigt OSS einen Pfad (z.B. /dev/dsp)." +#endif +#ifdef HAVE_JACK + " \n" + "benötigt JACK Portnamen (z.B. system:playback1\n" + ",system:playback_2)." +#endif +#ifdef HAVE_RSOUND + " \n" + "benötigt RSound eine IP-Adresse zu einem RSound-Server \n" + " \n" +#endif + ); + break; + case MENU_ENUM_LABEL_DISK_EJECT_TOGGLE: + snprintf(s, len, + "Datenträger einbinden/auswerfen. \n" + " \n" + "Verwendet für Inhalt, der auf mehreren Datenträgern ausgeliefert wird. "); + break; + case MENU_ENUM_LABEL_ENABLE_HOTKEY: + snprintf(s, len, + "Andere Hotkeys aktivieren. \n" + " \n" + "Wenn dieser Hotkey entweder einer\n" + "Tastatur, einem Joypad-Taste oder \n" + "Joypad-Achse zugeordnet ist, werden alle \n" + "anderen Hotkeys nur aktiviert, wenn dieser \n" + "Hotkey zur gleichen Zeit gehalten wird. \n" + " \n" + "Dies ist hilfreich für Implementierungen, die auf \n" + "RETRO_KEYBOARD ausgelegt sind und eine große \n" + "Fläche auf der Tastatur benötigen, wo es nicht \n" + "gewünscht ist, dass es zu Kollisionen mit Hotkeys kommt \n." + " \n" + "Alternativ können auch alle Tastatur-Hotkeys durch \n" + "den Benutzer deaktiviert werden."); + break; + case MENU_ENUM_LABEL_REWIND_ENABLE: + snprintf(s, len, + "Zurückspulen aktivieren.\n" + " \n" + "Dies wird die Leistung negativ beeinflussen, \n" + "weshalb es standardmäßig deaktiviert ist."); + break; + case MENU_ENUM_LABEL_LIBRETRO_DIR_PATH: + snprintf(s, len, + "Core-Verzeichnis. \n" + " \n" + "Ein Verzeichnis, in welchem nach \n" + "libretro-Core-Implementierungen gesucht wird."); + break; + case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE_AUTO: + snprintf(s, len, + "Bildwiederholrate.\n" + " \n" + "Die genaue Bildwiederholrate Deines Bildschirms (Hz).\n" + "Diese wird verwendet, um die Audio-Eingaberate mithilfe \n" + "der folgenden Formel zu berechnen: \n" + " \n" + "audio_input_rate = Spiel-Eingaberate * Bildschirm- \n" + "Wiederholrate / Spiel-Wiederholrate\n" + " \n" + "Wenn die Implementierung keinen Wert liefert, \n" + "werden aus Kompatiblitätsgründen die Werte für NTSC \n" + "angenommen.\n" + " \n" + "Dieser Wert sollte nahe 60Hz liegen, um Tonsprünge zu vermeiden. \n" + "Wenn Dein Bildschirm nicht auf 60Hz oder einem ähnlichen Wert läuft, \n" + "deaktiviere VSync und lasse diese Einstellung unverändert. \n"); + break; + case MENU_ENUM_LABEL_VIDEO_ROTATION: + snprintf(s, len, + "Erzwinge eine bestimmte \n" + "Bildschirm-Rotation.\n" + " \n" + "Diese Drehung wird zu den Drehungen hinzugefügt, \n" + "die durch den libretro-Core festgelegt werden. (siehe 'Erlaube \n" + "Bild-Drehung')."); + break; + case MENU_ENUM_LABEL_VIDEO_SCALE: + snprintf(s, len, + "Vollbild-Auflösung.\n" + " \n" + "Auflösung von 0 verwendet die \n" + "Auflösung der Umgebung. \n"); + break; + case MENU_ENUM_LABEL_FASTFORWARD_RATIO: + snprintf(s, len, + "Vorspul-Verhältnis." + " \n" + "Die maximale Geschwindigkeit, mit der Inhalt \n" + "wiedergegeben wird, wenn der schnelle Vorlauf aktiviert ist.\n" + " \n" + " (z.B. 5.0 für Inhalt mit 60 FPS => auf 300 FPS \n" + "begrenzt).\n" + " \n" + "RetroArch wird pausieren, um sicherzustellen, \n" + "dass die maximale Geschwindigkeit nicht überschritten wird.\n" + "Verlasse dich nicht darauf, dass diese Begrenzung \n" + "vollkommen zuverlässig ist."); + break; + case MENU_ENUM_LABEL_VIDEO_MONITOR_INDEX: + snprintf(s, len, + "Legt fest, welcher Bildschirm bevorzugt wird.\n" + " \n" + "0 (Standard) bedeutet, dass kein bestimmter Bildschirm \n" + "bevorzugt wird, 1 und größer (1 stellt den ersten \n" + "Bildschirm dar), bewirkt, dass RetroArch diesen \n" + "bestimmten Bildschirm verwenden."); + break; + case MENU_ENUM_LABEL_VIDEO_CROP_OVERSCAN: + snprintf(s, len, + "Erzwingt das Beschneiden von übertasteten \n" + "Frames.\n" + " \n" + "Das exakte Verhalten dieser Option ist von der \n" + "Core-Implementierung abhängig."); + break; + case MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER: + snprintf(s, len, + "Skaliere die Bildwiedergabe nur in ganzzahligen \n" + "Schritten.\n" + " \n" + "Die Basis-Größe hängt von der vom System gemeldeten \n" + "Geometrie und Seitenverhältnis ab.\n" + " \n" + "Wenn 'Seitenverhältnis erzwingen' nicht aktiv ist, wird X/Y \n" + "unabhängig voneinander ganzzahlig skaliert."); + break; + case MENU_ENUM_LABEL_AUDIO_VOLUME: + snprintf(s, len, + "Audio-Lautstärke, ausgedrückt in dB.\n" + " \n" + " 0 dB ist die normale Lautstärke. Keine Verstärkung wird angewendet.\n" + "Die Verstärkung kann zur Laufzeit mit 'Lautstärke erhöhen' \n" + "und 'Lautstärke verringern' angepasst werden."); + break; + case MENU_ENUM_LABEL_AUDIO_RATE_CONTROL_DELTA: + snprintf(s, len, + "Audioratenkontrolle.\n" + " \n" + "Ist dieser Wert 0, wird Ratenkontrolle deaktiviert.\n" + "Jeder andere Wert steuert die Änderung der \n" + "Audiorate.\n" + " \n" + "Beschreibt, wie weit die Audiorate dynamisch \n" + "verändert werden kann.\n" + " \n" + " Eingaberate ist definiert als: \n" + " Eingaberate * (1.0 +/- (Ratenkontroll-Wert))"); + break; + case MENU_ENUM_LABEL_AUDIO_MAX_TIMING_SKEW: + snprintf(s, len, + "Maximaler Audioversatz.\n" + " \n" + "Definiert die maximale Änderung der Eingaberate.\n" + "Aktivieren Sie diese Option, wenn Sie \n" + "umfangreiche Änderungen im Timing wünschen, zum Beispiel\n" + "um PAL-Cores auf NTSC-Bildschirmen zu spielen.\n" + "Die Tonhöhe ist dann nicht korrekt.\n" + " \n" + " Eingaberate ist definiert als: \n" + " Eingaberate * (1.0 +/- (Max. Audioversatz))"); + break; + case MENU_ENUM_LABEL_OVERLAY_NEXT: + snprintf(s, len, + "Wechselt zum nächsten Overlay.\n" + " \n" + // Translation unclear, disabled for now. Some context would be really helpful. + // "Wraps around." + ); + break; + case MENU_ENUM_LABEL_LOG_VERBOSITY: + snprintf(s, len, + "Aktiviert oder deaktiviert ausführliche Ausgabe \n" + "des Frontends."); + break; + case MENU_ENUM_LABEL_VOLUME_UP: + snprintf(s, len, + "Erhöht die Lautstärke."); + break; + case MENU_ENUM_LABEL_VOLUME_DOWN: + snprintf(s, len, + "Verringert die Lautstärke."); + break; + case MENU_ENUM_LABEL_VIDEO_DISABLE_COMPOSITION: + snprintf(s, len, + "Abschaltung der Desktop-Gestaltung erzwingen.\n" + "Nur gültig für Windows Vista/7."); + break; + case MENU_ENUM_LABEL_PERFCNT_ENABLE: + snprintf(s, len, + "Leistungs-Zähler im Frontend aktivieren \n" + "und deaktivieren."); + break; + case MENU_ENUM_LABEL_SYSTEM_DIRECTORY: + snprintf(s, len, + "Systemverzeichnis. \n" + " \n" + "Bestimmt das 'system'-Verzeichnis. \n" + "Cores können dieses Verzeichnis verwenden, \n" + "um BIOS-Dateien, systemspezifische \n" + "Konfigurationen etc. zu laden. "); + break; + case MENU_ENUM_LABEL_SAVESTATE_AUTO_SAVE: + case MENU_ENUM_LABEL_SAVESTATE_AUTO_LOAD: + snprintf(s, len, + "Erstellt einen Spielstand automatisch, \n" + "wenn RetroArch beendet wird .\n" + " \n" + "RetroArch wird Spielstände in diesem Pfad automatisch \n" + "nach dem Starten laden, wenn 'Spielstand automatisch laden' \n" + "aktiviert ist."); + break; + case MENU_ENUM_LABEL_VIDEO_THREADED: + snprintf(s, len, + "Video-Treiber in separatem Thread ausführen.\n" + " \n" + "Diese Option kann die Leistung verbessern, \n" + "verursacht jedoch möglicherweise eine erhöhte Latenz \n" + "und eine weniger flüssige Video-Ausgabe."); + break; + case MENU_ENUM_LABEL_VIDEO_VSYNC: + snprintf(s, len, + "Vertikale Synchronisation (VSync).\n"); + break; + case MENU_ENUM_LABEL_VIDEO_HARD_SYNC: + snprintf(s, len, + "Versucht, die CPU und GPU \n" + "'hart' zu synchronisieren.\n" + " \n" + "Dies kann die Latenz verringern, \n" + "reduziert jedoch möglicherweise die Leistung."); + break; + case MENU_ENUM_LABEL_REWIND_GRANULARITY: + snprintf(s, len, + "Rückspul-Genauigkeit.\n" + " \n" + "Wenn eine festgelegte Anzahl von Frames zurückgespult \n" + "wird, kannst Du mehrere Frames auf einmal \n" + "zurückspulen, was die Rückspul-Geschwindigkeit \n" + "erhöht."); + break; + case MENU_ENUM_LABEL_SCREENSHOT: + snprintf(s, len, + "Bildschirmfoto anfertigen."); + break; + case MENU_ENUM_LABEL_VIDEO_FRAME_DELAY: + snprintf(s, len, + "Legt fest, wie viele Millisekunden nach \n" + "VSync gewartet wird, bevor der Core gestartet wird.\n" + "\n" + "Dies kann die Latenz verringern, birgt jedoch\n" + "ein erhöhtes Risiko für stotternde Videoausgabe.\n" + " \n" + "Maximum ist 15."); + break; + case MENU_ENUM_LABEL_VIDEO_HARD_SYNC_FRAMES: + snprintf(s, len, + "Legt fest, wie viele Frames die CPU \n" + "vor der GPU bearbeitet, wenn 'GPU-Hardsync' \n" + "aktiviert ist.\n" + " \n" + "Maximum ist 3.\n" + " \n" + " 0: Synchronisiert direkt mit der GPU.\n" + " 1: Synchronisiert zum vorherigen Frame.\n" + " 2: Etc ..."); + break; + case MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION: + snprintf(s, len, + "Fügt ein schwarzes Bild zwischen den einzelnen \n" + "Frames ein.\n" + " \n" + "Hilfreich für 120 Hz-Monitore, wenn \n" + "60 Hz-Material ohne Ghosting dargestellt \n" + "werden soll.\n" + " \n" + "Die Bildwiederholrate sollte so eingestellt \n" + "werden, dass sie einem 60 Hz-Monitor entspricht. \n" + "(Bildwiederholrate durch 2 teilen)."); + break; + case MENU_ENUM_LABEL_RGUI_SHOW_START_SCREEN: + snprintf(s, len, + "Startbildschirm im Menü anzeigen.\n" + "Wird automatisch deaktiviert, wenn er zum\n" + "ersten Mal dargestellt wurde.\n" + " \n" + "Dies wird nur in die Konfiguration übernommen, wenn\n" + "'Konfiguration beim Beenden speichern' aktiviert ist.\n"); + break; + case MENU_ENUM_LABEL_VIDEO_FULLSCREEN: + snprintf(s, len, "Vollbildmodus umschalten"); + break; + case MENU_ENUM_LABEL_BLOCK_SRAM_OVERWRITE: + snprintf(s, len, + "Verhindert, dass SRAM überschrieben wird, \n" + "wenn Spielstände geladen werden.\n" + " \n" + "Kann zu fehlerhaften Spielen führen."); + break; + case MENU_ENUM_LABEL_PAUSE_NONACTIVE: + snprintf(s, len, + "Spiel pausieren, wenn Fenster-Fokus \n" + "verloren ist."); + break; + case MENU_ENUM_LABEL_VIDEO_GPU_SCREENSHOT: + snprintf(s, len, + "Sofern verfügbar, werden Screenshots \n" + "aus Bildmaterial nach Shader-Durchgängen erzeugt."); + break; + case MENU_ENUM_LABEL_SCREENSHOT_DIRECTORY: + snprintf(s, len, + "Bildschirmfoto-Verzeichnis. \n" + " \n" + "Verzeichnis, in welchem Bildschirmfotos abgelegt werden." + ); + break; + case MENU_ENUM_LABEL_VIDEO_SWAP_INTERVAL: + snprintf(s, len, + "Benutzerdefiniertes VSync-Intervall.\n" + " \n" + "Verwendet ein benutzerdefiniertes Intervall für VSync. \n" + "Aktiviert halbiert diese Einstellung die Bildwiederholrate."); + break; + case MENU_ENUM_LABEL_SAVEFILE_DIRECTORY: + snprintf(s, len, + "Verzeichnis für Speicherdaten. \n" + " \n" + "Speichert alle Speicherdaten (*.srm) in diesem \n" + "Verzeichnis. Dies beinhaltet verwandte Dateitypen wie \n" + ".bsv, .rt, .psrm, etc...\n" + " \n" + "Explizite Optionen über die Kommandozeile überschreiben \n" + "diese Einstellung."); + break; + case MENU_ENUM_LABEL_SAVESTATE_DIRECTORY: + snprintf(s, len, + "Verzeichnis für Spielstände. \n" + " \n" + "Speichert alle Spielstände (*.state) in diesem \n" + "Verzeichnis.\n" + " \n" + "Explizite Optionen über die Kommandozeile überschreiben \n" + "diese Einstellung."); + break; + case MENU_ENUM_LABEL_ASSETS_DIRECTORY: + snprintf(s, len, + "Assets-Verzeichnis. \n" + " \n" + "Dieses Verzeichnis wird standardmäßig vom Menü \n" + "verwendet, um dort nach ladbaren Inhalten wie Assets \n" + "etc. zu suchen."); + break; + case MENU_ENUM_LABEL_DYNAMIC_WALLPAPERS_DIRECTORY: + snprintf(s, len, + "Verzeichnis für dynamische Hintergrundbilder. \n" + " \n" + "In diesem Verzeichnis werden Hintergrundbilder \n" + "abgelegt, die vom Menü dynamisch abhängig vom \n" + "Kontext geladen werden."); + break; + case MENU_ENUM_LABEL_SLOWMOTION_RATIO: + snprintf(s, len, + "Verhältnis für Zeitlupe. \n" + " \n" + "Ist die Zeitlupe eingeschaltet, wird das Spiel \n" + "um diesen Faktor verlangsamt."); + break; + case MENU_ENUM_LABEL_INPUT_AXIS_THRESHOLD: + snprintf(s, len, + "Definiert Achsen-Grenzwert.\n" + " \n" + "Wie weit eine Achse bewegt werden muss, um einen \n" + "Tastendruck auszulösen .\n" + "Mögliche Werte liegen im Bereich [0.0, 1.0]."); + break; + case MENU_ENUM_LABEL_INPUT_TURBO_PERIOD: + snprintf(s, len, + "Turbo-Frequenz.\n" + " \n" + "Beschreibt, wie oft Tasten, für die der Turbo \n" + "aktiviert ist, ausgelöst werden.\n" + " \n" + "Dieser Wert wird in der Anzahl der Einzelbilder angegeben." + ); + break; + case MENU_ENUM_LABEL_INPUT_DUTY_CYCLE: + snprintf(s, len, + "Turbo-Dauer.\n" + " \n" + "Beschreibt, wie lange Tasten, für die der Turbo \n" + "aktiviert ist, gehalten werden sollen.\n" + " \n" + "Dieser Wert wird in der Anzahl der Einzelbilder angegeben." + ); + break; + case MENU_ENUM_LABEL_INPUT_TOUCH_ENABLE: + snprintf(s, len, "Touch-Unterstützung aktivieren."); + break; + case MENU_ENUM_LABEL_INPUT_PREFER_FRONT_TOUCH: + snprintf(s, len, "Touch-Eingabe auf der Vorderseite bevorzugen."); + break; + case MENU_ENUM_LABEL_MOUSE_ENABLE: + snprintf(s, len, "Maussteuerung im Menü aktivieren."); + break; + case MENU_ENUM_LABEL_POINTER_ENABLE: + snprintf(s, len, "Touch-Steuerung im Menü aktivieren."); + break; + case MENU_ENUM_LABEL_MENU_WALLPAPER: + snprintf(s, len, "Pfad zu einem Bild, welches als Hintergrundbild verwendet werden soll."); + break; + case MENU_ENUM_LABEL_NAVIGATION_WRAPAROUND: + snprintf(s, len, + "Am Anfang und/oder dem Ende einer Liste umbrechen, \n" + "wenn die Grenzen der Liste horizontal und/oder \n" + "vertikal erreicht werden."); + break; + case MENU_ENUM_LABEL_PAUSE_LIBRETRO: + snprintf(s, len, + "Wenn deaktiviert wird der libretro-Core im \n" + "Hintergrund weiter laufen, wenn wir uns \n" + "im Menü befinden."); + break; + case MENU_ENUM_LABEL_SUSPEND_SCREENSAVER_ENABLE: + snprintf(s, len, + "Deaktiviert den Bildschirmschoner. Diese Einstellung \n" + "wird möglicherweise vom Video-Treiber nicht \n" + "berücksichtigt."); + break; + case MENU_ENUM_LABEL_NETPLAY_MODE: + snprintf(s, len, + "Netplay-Client-Modus für den aktuellen Benutzer. \n" + "Wird zu 'Server'-Modus, wenn deaktiviert."); + break; + case MENU_ENUM_LABEL_NETPLAY_DELAY_FRAMES: + snprintf(s, len, + "Anzahl der Verzögerungs-Frames für Netplay. \n" + " \n" + "Wird dieser Wert erhöht, verbessert sich \n" + "die Leistung, die Latenz erhöht sich jedoch."); + case MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE: /* Maybe FIXME*/ + snprintf(s, len, + "Legt fest, ob Netplay in einem Modus laufen soll, der keine\n" + "Savestates benötigt. \n" + " \n" + "Wenn diese Option eingeschaltet wird, wird ein sehr \n" + "schnelles Netzwerk benötigt. Da kein Rücklauf benötigt wird, \n" + "tritt keine Netplay-Verzögerung auf.\n"); + break; + break; + case MENU_ENUM_LABEL_NETPLAY_CHECK_FRAMES: + snprintf(s, len, + "Die Frequenz in Einzelbildern, mit der Netplay \n" + "sicherstellen wird, dass Host und Clients \n" + "synchronisiert sind. \n" + " \n" + "Bei den meisten Cores wird diese Einstellungen \n" + "keine sichtbaren Auswirkungen haben und kann ignoriert werden. \n" + "Bei nichtdeterministischen Cores legt dieser Wert fest, \n" + "wie oft die Netplay-Mitglieder miteinander synchronisiert \n" + "werden. Bei fehlerhaften Cores wird ein \n" + "anderer Wert als 0 für diese Einstellung erhebliche \n" + "Leistungsprobleme verursachen. Auf 0 setzen, um keine \n" + "Überprüfungen durchzuführen. Diese Einstellung wird nur \n" + "auf dem Netplay-Host verwendet. \n"); + break; + case MENU_ENUM_LABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN: + snprintf(s, len, + "Legt die Eingabeverzögerung in Einzelbildern fest, \n" + "die Netplay verwendet, um die Netzwerklatenz zu verstecken. \n" + " \n" + "In einem Multiplayer-Spiel verzögert diese Option die lokale \n" + "Eingabe, sodass das aktuelle Einzelbild \n" + "näher an dem Einzelbild liegt, welches vom Netzwerk \n" + "empfangen wird. Dies verbessert die Netplay-Performance \n" + "und benötigt weniger CPU-Leistung, verursacht \n" + "jedoch eine spürbare Eingabe-Verzögerung. \n"); + break; + case MENU_ENUM_LABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE: + snprintf(s, len, + "Legt den Bereich in Einzelbildern fest, die von \n" + "Netplay für die Eingabeverzögerung verwendet werden, \n" + "um die Netzwerklatenz zu verstecken. \n" + "\n" + "Wenn aktiviert, wird Netplay die Eingabeverzögerung \n" + "in Einzelbildern dynamisch anpassen, um \n" + "die CPU-Zeit, Eingabeverzögerung und \n" + "Netzwerklatenz auszubalancieren. Dies verbessert \n" + "die Netplay-Performance und benötigt weniger CPU-Leistung, \n" + "verursacht jedoch eine Eingabe-Verzögerung, die nicht vorhergesagt werden kann. \n"); + break; + case MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL: + snprintf(s, len, + "Versuche, beim Hosten eines Spiels auf eingehende \n" + "Verbindungen aus dem öffentlichen Internet zu hören. \n" + "Dabei werden UPnP oder ähnliche Techniken verwendet, \n" + "um das eigene LAN zu verlassen. \n"); + break; + case MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES: + snprintf(s, len, + "Maximale Zahl von Zwischenbildern. Diese Einstellung \n" + "kann dem Video-Treiber vorschreiben, einen bestimmten \n" + "Videopuffer-Modus zu verwenden. \n" + " \n" + "Einfache Pufferung - 1\n" + "Doppelte Pufferung - 2\n" + "Dreifache Pufferung - 3\n" + " \n" + "Den richtigen Puffer-Modus auzuwählen \n" + "kann einen großen Einfluss auf die Leistung nehmen."); + break; + case MENU_ENUM_LABEL_VIDEO_SMOOTH: + snprintf(s, len, + "Bild mit bilinearer Filterung glätten. \n" + "Sollte deaktiviert werden, wenn Shader verwendet werden."); + break; + case MENU_ENUM_LABEL_TIMEDATE_ENABLE: + snprintf(s, len, + "Zeigt das aktuelle Datum/die aktuelle Zeit im Menü an."); + break; + case MENU_ENUM_LABEL_BATTERY_LEVEL_ENABLE: + snprintf(s, len, + "Zeigt den aktuellen Ladezustand des Akkus im Menü an."); + break; + case MENU_ENUM_LABEL_CORE_ENABLE: + snprintf(s, len, + "Zeigt den aktuellen Core im Menü an."); + break; + case MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST: + snprintf(s, len, + "Aktiviert Netplay im Host-(Server)-Modus."); + break; + case MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT: + snprintf(s, len, + "Aktiviert Netplay im Client-Modus."); + break; + case MENU_ENUM_LABEL_NETPLAY_DISCONNECT: + snprintf(s, len, + "Bestehende Netplay-Verbindung beenden."); + break; + case MENU_ENUM_LABEL_NETPLAY_LAN_SCAN_SETTINGS: + snprintf(s, len, + "Suche nach einem Netplay-Host im lokalen Netzwerk und stelle eine Verbindung zu diesem her."); + break; + case MENU_ENUM_LABEL_NETPLAY_SETTINGS: + snprintf(s, len, + "Netplay-bezogene Einstellungen."); + break; + case MENU_ENUM_LABEL_DYNAMIC_WALLPAPER: + snprintf(s, len, + "Lade ein neues Hintergrundbild dynamisch, \n" + "abhängig vom aktuellen Kontext."); + break; + case MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL: + snprintf(s, len, + "URL zum Core-Verzeichnis auf dem \n" + "libretro-Server."); + break; + case MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL: + snprintf(s, len, + "URL zum Assets-Verzeichnis auf dem \n" + "libretro-Server."); + break; + case MENU_ENUM_LABEL_INPUT_REMAP_BINDS_ENABLE: + snprintf(s, len, + "Wenn aktiviert, werden die aktuellen Tastenbelegungen \n" + "mit den neu zugewiesenen Belegungen für den \n" + "aktuellen Core überschrieben."); + break; + case MENU_ENUM_LABEL_OVERLAY_DIRECTORY: + snprintf(s, len, + "Overlay-Verzeichnis. \n" + " \n" + "Definiert ein Verzeichnis, in dem alle Overlays \n" + "aufbewahrt werden."); + break; + case MENU_ENUM_LABEL_INPUT_MAX_USERS: + snprintf(s, len, + "Maximale Anzahl von Benutzern, die in \n" + "RetroArch unterstützt werden."); + break; + case MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE: + snprintf(s, len, + "Entpacke Archive, die heruntergeladenen Inhalt \n" + "enthalten, nach dem Herunterladen \n" + "automatisch."); + break; + case MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE: + snprintf(s, len, + "Filtere die angezeigten Dateien nach \n" + "unterstützten Dateierweiterungen."); + break; + case MENU_ENUM_LABEL_NETPLAY_NICKNAME: + snprintf(s, len, + "Der Benutzername der Person, die RetroArch verwendet. \n" + "Wird in Online-Spielen verwendet."); + break; + case MENU_ENUM_LABEL_NETPLAY_CLIENT_SWAP_INPUT: + snprintf(s, len, + "Verwende Tastenbelegung für Spieler 1, \n" + "wenn Du Teilnehmer an einem Netplay-Spiel bist."); + break; + case MENU_ENUM_LABEL_NETPLAY_TCP_UDP_PORT: + snprintf(s, len, + "Der Port der Host-IP-Adresse. \n" + "Kann entweder ein TCP- oder ein UDP-Port sein."); + break; + case MENU_ENUM_LABEL_NETPLAY_SPECTATOR_MODE_ENABLE: + snprintf(s, len, + "Aktiviere oder deaktiviere Beobachter-Modus\n" + "für den Benutzer im Netplay-Spiel."); + break; + case MENU_ENUM_LABEL_NETPLAY_IP_ADDRESS: + snprintf(s, len, + "Die Addresse des Hosts, zu dem verbunden werden soll."); + break; + case MENU_ENUM_LABEL_NETPLAY_PASSWORD: + snprintf(s, len, + "Das Passwort, welches für die Verbindung mit dem Netplay-Host \n" + "verwendet wird. Wird nur im Host-Modus verwendet."); + break; + case MENU_ENUM_LABEL_NETPLAY_SPECTATE_PASSWORD: + snprintf(s, len, + "Das Passwort, welches für die Verbindung mit dem Netplay-Host \n" + "und ausschließlich mit Beobachter-Privilegien verwendet wird. \n" + "Wird nur im Host-Modus verwendet."); + break; + case MENU_ENUM_LABEL_STDIN_CMD_ENABLE: + snprintf(s, len, + "Aktiviere stdin-Kommandozeile."); + break; + case MENU_ENUM_LABEL_UI_COMPANION_START_ON_BOOT: + snprintf(s, len, + "Starte begleitenden Treiber für Benutzeroberfläche \n" + "während des Bootens (wenn verfügbar)."); + break; + case MENU_ENUM_LABEL_MENU_DRIVER: + snprintf(s, len, "Menü-Treiber, der verwendet werden soll."); + break; + case MENU_ENUM_LABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO: + snprintf(s, len, + "Gamepad-Tastenkombination, um Menü aufzurufen. \n" + " \n" + "0 - Keine \n" + "1 - Drücke L + R + Y + D-Pad nach unten \n" + "gleichzeitig. \n" + "2 - Drücke L3 + R3 gleichzeitig. \n" + "3 - Drücke Start + Select gleichzeitig."); + break; + case MENU_ENUM_LABEL_INPUT_ALL_USERS_CONTROL_MENU: + snprintf(s, len, "Erlaubt jedem Benutzer, das Menü zu steuern. \n" + " \n" + "Wenn deaktiviert, kann nur Benutzer 1 das Menü steuern."); + break; + case MENU_ENUM_LABEL_INPUT_AUTODETECT_ENABLE: + snprintf(s, len, + "Aktiviere automatische Eingabe-Erkennung.\n" + " \n" + "Wird versuchen, Joypads automatisch zu konfigurieren. \n" + "(Plug-and-Play)."); + break; + case MENU_ENUM_LABEL_CAMERA_ALLOW: + snprintf(s, len, + "Erlaubt oder verbietet den Cores Zugriff auf \n" + "die Kamera."); + break; + case MENU_ENUM_LABEL_LOCATION_ALLOW: + snprintf(s, len, + "Erlaubt oder verbietet den Cores Zugriff \n" + "auf Ortungsdienste."); + break; + case MENU_ENUM_LABEL_TURBO: + snprintf(s, len, + "Aktiviert den Turbo.\n" + " \n" + "Wird die Turbo-Taste gedrückt, während eine andere Taste \n" + "gedrückt wird, wird für diese Taste der Turbo-Modus aktiviert. \n" + "Im Turbo-Modus wird die Taste innerhalb der Emulation \n" + "automatisch wiederholt gedrückt und wieder losgelassen. \n" + " \n" + "Der Turbo-Modus wird beendet, wenn die Taste \n" + "selbst (nicht die Turbo-Taste) losgelassen wird."); + break; case MENU_ENUM_LABEL_OSK_ENABLE: snprintf(s, len, - "(De-)Aktiviere die Bildschirmtastatur."); + "Bildschirmtastatur ein/ausschalten."); break; case MENU_ENUM_LABEL_AUDIO_MUTE: snprintf(s, len, - "Audio stummschalten."); + "Ton stumm/lautschalten."); break; case MENU_ENUM_LABEL_REWIND: snprintf(s, len, - "Halte die Taste zum Zurückspulen gedrückt.\n" + "Taste zum Zurückspulen gedrückt halten.\n" " \n" - "Die Zurückspulfunktion muss eingeschaltet \n" - "sein."); + "Die Rücklauf-Funktion muss aktiviert sein."); break; - case MENU_ENUM_LABEL_RGUI_BROWSER_DIRECTORY: - snprintf(s, len, - "%s. \n" - " \n" - "Setzt das Startverzeichnis des Dateibrowsers.", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY) - ); - break; case MENU_ENUM_LABEL_EXIT_EMULATOR: snprintf(s, len, - "Taste zum Beenden von RetroArch." + "Taste zum sauberen Beenden von RetroArch." #if !defined(RARCH_MOBILE) && !defined(RARCH_CONSOLE) - "\nWenn du es stattdessen mittels SIGKILL \n" - "beendest, wird RetroArch nicht den RAM \n" - "sichern. Bei unixoiden Betriebssystemen \n" - "erlaubt SIGINT/SIGTERM ein sauberes \n" + "\nWenn Du RetroArch 'unsanft' beendest (SIGKILL, \n" + "etc), werden RAM-Speicher etc. nicht gespeichert.\n" + "Auf Unix-ähnlichen Systemen erlaubt\n" + "SIGINT/SIGTERM ein sauberes\n" "Beenden." #endif ); break; case MENU_ENUM_LABEL_LOAD_STATE: snprintf(s, len, - "Lädt einen Savestate."); + "Lädt Save-State."); break; case MENU_ENUM_LABEL_SAVE_STATE: snprintf(s, len, - "Speichert einen Savestate."); + "Speichert Save-State."); break; case MENU_ENUM_LABEL_NETPLAY_FLIP_PLAYERS: snprintf(s, len, - "Netplay-Spieler tauschen."); + "Netplay-Benutzer vertauschen."); break; case MENU_ENUM_LABEL_CHEAT_INDEX_PLUS: snprintf(s, len, - "Erhöht den Cheat-Index.\n"); + "Cheat-Index erhöhen.\n"); break; case MENU_ENUM_LABEL_CHEAT_INDEX_MINUS: snprintf(s, len, - "Verringert den Cheat-Index.\n"); + "Cheat-Index verringern.\n"); break; case MENU_ENUM_LABEL_SHADER_PREV: snprintf(s, len, - "Wendet vorherigen Shader im Verzeichnis an."); + "Wendet den vorherigen Shader im Verzeichnis an."); break; case MENU_ENUM_LABEL_SHADER_NEXT: snprintf(s, len, - "Wendet nächsten Shader im Verzeichnis an."); + "Wendet den nächsten Shader im Verzeichnis an."); break; case MENU_ENUM_LABEL_RESET: snprintf(s, len, - "Setzt den Content zurück.\n"); + "Inhalt zurücksetzen.\n"); break; case MENU_ENUM_LABEL_PAUSE_TOGGLE: snprintf(s, len, - "Pausiert den Content und setzt ihn wieder fort."); + "Inhalt pausieren und wieder fortsetzen."); break; case MENU_ENUM_LABEL_CHEAT_TOGGLE: snprintf(s, len, - "Schaltet den Cheat-Index ein und aus.\n"); + "Cheat-Index ein-/ausschalten.\n"); break; case MENU_ENUM_LABEL_HOLD_FAST_FORWARD: snprintf(s, len, - "Halte den Knopf gedrückt, um vorzuspulen. Beim Loslassen \n" - "wird das Vorspulen beendet."); + "Zum Vorspulen gedrückt halten. Wird die Taste \n" + "losgelassen, wird der schnelle Vorlauf beendet."); break; case MENU_ENUM_LABEL_SLOWMOTION: snprintf(s, len, - "Halte den Knopf gedrückt, um die Zeitlupe einzuschalten."); + "Gedrückt halten für Zeitlupe."); break; case MENU_ENUM_LABEL_FRAME_ADVANCE: snprintf(s, len, - "Frame-Advance, wenn der Content pausiert ist."); + "Einzelbild-Vorlauf, wenn Inhalt pausiert ist."); break; case MENU_ENUM_LABEL_MOVIE_RECORD_TOGGLE: snprintf(s, len, - "Aufnahme ein- und ausschalten."); + "Aufnahme starten/beenden."); break; case MENU_ENUM_LABEL_L_X_PLUS: case MENU_ENUM_LABEL_L_X_MINUS: @@ -425,145 +1892,54 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) "Positive X-Achse ist rechts. \n" "Positive Y-Achse ist unten."); break; - case MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST: - snprintf(s, len, "Erfolgsliste"); - break; - case MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE: - snprintf(s, len, "Erfolgsliste (Hardcore)"); - break; - case MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC: - { - /* Work around C89 limitations */ - char u[501]; - const char * t = - "RetroArch verwendet eine einzigartige\n" - "Art der Synchronisation von Audio/Video.\n" - "Diese wird durch die Bildwiederholrate\n" - "des Monitors kalibriert.\n" - "\n" - "Falls du irgenwelches Knistern oder Risse\n" - "feststellst, kannst du folgende Möglichkeiten:\n" - "\n"; - snprintf(u, sizeof(u), - "a) Gehe zu '%s' -> '%s' und aktiviere\n" - "'%s'. Die Bildwiederholungsrate spielt\n" - "in diesem Modus keine Rolle. \n" - "Die Bildwiederholungsrate wird höher sein,\n" - "allerdings läuft das Video weniger flüssig.\n" - "b) Gehe zu '%s' -> '%s' und beachte\n" - "'%s'. Lass es bis 2048 Frames laufen und\n" - "bestätige mit 'OK'.\n", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO) - ); - strlcpy(s, t, len); - strlcat(s, u, len); - } - break; - case MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD_DESC: - snprintf(s, len, - "Du kannst das virtuelle Gamepad-Overlay\n" - "unter '%s' -> '%s' ändern." - " \n" - "Darin kannst du die Grösse, die Transparenz\n" - "und vieles mehr anpassen.\n" - " \n" - "WICHTIG: Standartmässig, ist das virtuelle\n" - "Gamepad-Overlay im Menü nicht ersichtlich.\n" - "Wenn du dies ändern möchtest,\n" - "kannst du '%s' auf Nein stellen.", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU) - ); - break; - case MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC: - snprintf(s, len, - "Um Inhalte zu suchen, gehe zu '%s' und\n" - "wähle entweder '%s' oder '%s'.\n" - " \n" - "Die Dateien werden mit Einträgen in der\n" - "Datenbank verglichen.\n" - "Wenn es einen Treffer gibt, wird der Inhalt\n" - "zur Sammlung hinzugefügt.\n" - " \n" - "Danach kannst du einfach den Inhalt unter\n" - "'%s' -> '%s' laden,\n" - "anstatt jedesmal die Datei neu zu suchen.\n" - " \n" - "WICHTIG: Inhalte für einige Cores sind zum\n" - "Teil noch nicht scannbar.", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_FILE), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST) - ); - break; - case MENU_ENUM_LABEL_VALUE_MENU_ENUM_CONTROLS_PROLOG: - snprintf(s, len, - "Du kannst folgende Steuerelemente mit\n" - "deinem Controller oder deiner Tastatur verwenden\n" - "um durch das Menü zu navigieren: \n" - " \n" - ); - break; - case MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY: - snprintf(s, len, "Übergeordnetes Verzeichnis"); - break; - case MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE: - snprintf(s, len, "SAMBA aktivieren"); - break; - case MENU_ENUM_LABEL_VALUE_SHUTDOWN: - snprintf(s, len, "Herunterfahren"); - break; - case MENU_ENUM_LABEL_VALUE_SSH_ENABLE: - snprintf(s, len, "SSH aktivieren"); - break; - case MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST: - snprintf(s, len, "Vorschaubilder aktualisieren"); - break; - case MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA: - snprintf(s, len, "Lakka aktualisieren"); - break; case MENU_ENUM_LABEL_VALUE_WHAT_IS_A_CORE_DESC: - snprintf(s, len, - "RetroArch alleine macht nichts. \n" - " \n" - "Damit es etwas tut, musst du \n" - "ein Programm darin laden. \n" - "\n" - "Wir nennen so ein Programm 'Libretro core', \n" - "oder 'core' als Abkürzung. \n" - " \n" - "Um einen Core zu laden, wählen Sie einen \n" - "unter '%s' aus.\n" - " \n" + snprintf(s, len, + "RetroArch selbst tut nichts. \n" + " \n" + "Damit RetroArch etwas tut, musst \n" + "Du ein Programm hineinladen. \n" + "\n" + "Wir nennen diese Programme 'libretro-Core', \n" + "oder einfach nur 'Core'. \n" + " \n" + "Um einen Core zu laden, verwende \n" + "'Core laden'.\n" + " \n" #ifdef HAVE_NETWORKING - "Du erhälst Cores durch verschiedene Wege: \n" - "* Herunterladen unter\n" - "'%s' -> '%s'.\n" - "* Manuelles hinzufügen nach\n" - "'%s'.", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST), - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH) + "Du kannst die Cores auf mehreren Wegen beziehen: \n" + "* Herunterladen, indem Du\n" + "'%s' -> '%s' verwendest. \n" + "* Manuell ins Verzeichnis \n" + "'%s' kopieren.", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH) #else - "Du erhälst Cores wenn du diese \n" - "manuell hinzufügst unter\n" - "'%s'.", - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH) + "Du kannst die Cores beziehen, indem\n" + "du sie manuell ins Verzeichnis \n" + "'%s' kopierst.", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH) #endif - ); - break; - case MSG_UNKNOWN: + ); + break; + case MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD_DESC: + snprintf(s, len, + "Du kannst das virtuelle Gamepad-Overlay ändern, indem Du \n" + "zu '%s' -> '%s' gehst." + " \n" + "Hier kannst du das Overlay ändern,\n" + "die Größe und Transparenz der Tasten verändern, etc.\n" + " \n" + "HINWEIS: Standardmäßig werden virtuelle Gamepad-Overlays \n" + "versteckt, wenn Du dich im Menü befindest.\n" + "Wenn Du dieses Verhalten ändern möchtest,\n" + "kannst Du '%s' auf 'aus' setzen.", + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU) + ); + break; default: - /* TODO/FIXME - translate */ if (string_is_empty(s)) strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE), len); return -1; @@ -572,12 +1948,51 @@ int menu_hash_get_help_de_enum(enum msg_hash_enums msg, char *s, size_t len) return 0; } -const char *msg_hash_to_str_de(enum msg_hash_enums msg) +#ifdef HAVE_MENU +static const char *menu_hash_to_str_de_label_enum(enum msg_hash_enums msg) { + if (msg <= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_END && + msg >= MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN) + { + static char hotkey_lbl[128] = {0}; + unsigned idx = msg - MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN; + snprintf(hotkey_lbl, sizeof(hotkey_lbl), "input_hotkey_binds_%d", idx); + return hotkey_lbl; + } + switch (msg) { - #include "msg_hash_de.h" + #include "msg_hash_lbl.h" default: +#if 0 + RARCH_LOG("Unimplemented: [%d]\n", msg); +#endif + break; + } + + return "null"; +} +#endif + +const char *msg_hash_to_str_de(enum msg_hash_enums msg) +{ +#ifdef HAVE_MENU + const char *ret = menu_hash_to_str_de_label_enum(msg); + + if (ret && !string_is_equal(ret, "null")) + return ret; +#endif + + switch (msg) + { + #include "msg_hash_de.h" + default: +#if 0 + RARCH_LOG("Unimplemented: [%d]\n", msg); + { + RARCH_LOG("[%d] : %s\n", msg - 1, msg_hash_to_str(((enum msg_hash_enums)(msg - 1)))); + } +#endif break; } diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 2de7f39702..27a3715b2a 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -1,113 +1,500 @@ -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, - "Passwort") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, - "Benutzername") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, - "Konten") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Errungenschaften") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Errungenschaften (Hardcore)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ADD_TAB, - "Hinzufügen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ARCHIVE_MODE, - "Verknüpfte Aktion bei Archivdateien") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, - "Nachfragen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, - "Assets-Verzeichnis") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, - "Warte auf Audio-Frames") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, - "Soundkarte") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, - "Audiotreiber") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, - "Audio-DSP-Plugin") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, - "Aktiviere Audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, - "Audiofilterverzeichnis") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, - "Audiolatenz (ms)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, - "Maximaler Audioversatz") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, - "Stumm") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, - "Audiofrequenzrate (kHz)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, - "Audio Rate Control Delta") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, - "Audio-Resampler-Treiber") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, - "Audioeinstellungen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, - "Synchronisiere Audio") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "Lautstärke (dB)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "Automatischespeicherungsintervall") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, - "Override-Dateien automatisch laden") -MSG_HASH(MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, - "Remap-Dateien automatisch laden") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, - "Blockiere SRAM-Überschreibung") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, - "Buildbot-Assets-URL") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, /* FIXME/UPDATE */ - "Entpackverzeichnis") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, - "Erlaube Kamera-Zugriff") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, - "Kameratreiber") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT, - "Cheat") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, - "Änderungen übernehmen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, - "Cheat-Dateiverzeichnis") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Cheat-Datei laden") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "Speichere Cheat-Datei unter...") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, - "Cheat-Durchgänge") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, - "Überprüfe Firmware vor dem Laden.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Aktiviere Errungenschaften") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, - "Hardcore-Modus") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, - "Teste unoffizielle Errungenschaften") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, - "Schließen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "Konfigurationsdatei laden") /* FIXME/UPDATE */ -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, - "Konfigurationseinstellungen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, - "Konfigurationen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, - "Speichere Konfiguration beim Beenden") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, - "Inhalt laden") /* FIXME/TODO - rewrite */ -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, - "Inhaltsdatenbankverzeichnis") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, +MSG_HASH( + MSG_COMPILER, + "Compiler" + ) +MSG_HASH( + MSG_UNKNOWN_COMPILER, + "Unbekannter Compiler" + ) +MSG_HASH( + MSG_DEVICE_DISCONNECTED_FROM_PORT, + "Gerät von Anschluss getrennt" + ) +MSG_HASH( + MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, + "Unbekannter Netplay-Befehl wurde empfangen" + ) +MSG_HASH( + MSG_FILE_ALREADY_EXISTS_SAVING_TO_BACKUP_BUFFER, + "Datei existiert bereits. Speichere im Backup-Puffer" + ) +MSG_HASH( + MSG_GOT_CONNECTION_FROM, + "Verbindung mit \"%s\" hergestellt" + ) +MSG_HASH( + MSG_GOT_CONNECTION_FROM_NAME, + "Verbindung mit \"%s (%s)\" hergestellt" + ) +MSG_HASH( + MSG_PUBLIC_ADDRESS, + "Öffentliche Addresse" + ) +MSG_HASH( + MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, + "Es wurden keine Argumente übergeben, außerdem ist kein Menü vorhanden - zeige Hilfe an..." + ) +MSG_HASH( + MSG_NETPLAY_USERS_HAS_FLIPPED, + "Netplay-Benutzer wurden vertauscht" + ) +MSG_HASH( + MSG_SETTING_DISK_IN_TRAY, + "Lege Datenträger in Laufwerksschublade ein" + ) +MSG_HASH( + MSG_WAITING_FOR_CLIENT, + "Warte auf Client ..." + ) +MSG_HASH( + MSG_NETPLAY_YOU_HAVE_LEFT_THE_GAME, + "Du hast das Spiel verlassen" + ) +MSG_HASH( + MSG_NETPLAY_YOU_HAVE_JOINED_AS_PLAYER_N, + "Du bist als Spieler %d beigetreten" + ) +MSG_HASH( + MSG_NETPLAY_IMPLEMENTATIONS_DIFFER, + "Unterschiedliche Implementierungen. Stelle sicher, dass Du die gleiche Version von RetroArch und dem Core verwendest." + ) +MSG_HASH( + MSG_NETPLAY_ENDIAN_DEPENDENT, + "Dieser Core unterstützt kein Netplay zwischen diesen Systemen" + ) +MSG_HASH( + MSG_NETPLAY_PLATFORM_DEPENDENT, + "Dieser Core unterstützt kein Netplay zwischen verschiedenen Systemen" + ) +MSG_HASH( + MSG_NETPLAY_ENTER_PASSWORD, + "Gib das Server-Passwort ein:" + ) +MSG_HASH( + MSG_NETPLAY_INCORRECT_PASSWORD, + "Falsches Passwort" + ) +MSG_HASH( + MSG_NETPLAY_SERVER_NAMED_HANGUP, + "\"%s\" wurde getrennt" + ) +MSG_HASH( + MSG_NETPLAY_SERVER_HANGUP, + "Die Verbindung mit einem Netplay-Client wurde getrennt" + ) +MSG_HASH( + MSG_NETPLAY_CLIENT_HANGUP, + "Verbindung mit Netplay getrennt" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_UNPRIVILEGED, + "Du hast nicht die Berechtigung, an diesem Spiel teilzunehmen" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY_NO_SLOTS, + "Es gibt keine freien Spieler-Plätze mehr" + ) +MSG_HASH( + MSG_NETPLAY_CANNOT_PLAY, + "Konnte nicht zum Spieler-Modus wechseln" + ) +MSG_HASH( + MSG_NETPLAY_PEER_PAUSED, + "Netplay-Teilnehmer \"%s\" pausiert" + ) +MSG_HASH( + MSG_NETPLAY_CHANGED_NICK, + "Dein Nickname wurde zu \"%s\" geändert" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, + "Gibt Hardware-gerenderten Cores einen eigenen privaten Kontext. Vermeidet, dass der Hardware-Status zwischen den Frames geschätzt werden muss." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_SETTINGS, + "Legt die Einstellungen für das Aussehen des Menübildschirms fest." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, + "'Harte' Synchronisation der CPU und der GPU. Reduziert Latenz, braucht aber mehr Leistung." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_THREADED, + "Verbessert die Leistung, führt aber zu größerer Latenz und kann Videoprobleme verursachen. Verwende dies nur, wenn Du sonst die gewünschte Leistung nicht erreichst." + ) +MSG_HASH( + MSG_AUDIO_VOLUME, + "Audio-Lautstärke" + ) +MSG_HASH( + MSG_AUTODETECT, + "Automatisch erkennen" + ) +MSG_HASH( + MSG_AUTOLOADING_SAVESTATE_FROM, + "Lade Spielstände automatisch von" + ) +MSG_HASH( + MSG_CAPABILITIES, + "Fähigkeiten" + ) +MSG_HASH( + MSG_CONNECTING_TO_NETPLAY_HOST, + "Verbinde zu Netplay-Host" + ) +MSG_HASH( + MSG_CONNECTING_TO_PORT, + "Verbinde zu Port" + ) +MSG_HASH( + MSG_CONNECTION_SLOT, + "Verbindungs-Slot" + ) +MSG_HASH( + MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, + "Entschuldigung, nicht implementiert: Cores, die keinen Inhalt verlangen, können nicht an Netplay teilnehmen." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, + "Passwort" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, + "Cheevos-Benutzerkonten" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, + "Benutzername" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, + "Benutzerkonten" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST_END, + "Endpunkt der Benutzerkonten-Liste" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Retro-Errungenschaften" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, + "Errungenschaften" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, + "Errungenschaften (Hardcore)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, + "Inhalt durchsuchen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS_LIST, + "Konfigurationen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ADD_TAB, + "Inhalt importieren" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, + "Netplay-Räume" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ARCHIVE_MODE, + "Verknüpfte Aktion für Archivdateien" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE, + "Nachfragen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY, + "Assets" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES, + "Warte auf Audio-Frames" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE, + "Soundkarte" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER, + "Audiotreiber" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN, + "Audio-DSP-Plugin" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE, + "Aktiviere Audio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR, + "Audiofilter" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TURBO_DEADZONE_LIST, + "Turbo/Deadzone" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY, + "Audiolatenz (ms)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW, + "Maximaler Audioversatz" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_MUTE, + "Stumm" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE, + "Audiofrequenzrate (KHz)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA, + "Dynamische Audio-Ratenkontrolle" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER, + "Audio-Resampling-Treiber" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, + "Audio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_SYNC, + "Synchronisiere Audio" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, + "Lautstärke (dB)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, + "Intervall für automatisches Speichern des SaveRAM" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, + "Override-Dateien automatisch laden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE, + "Remap-Dateien automatisch laden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, + "Shader-Voreinstellungen automatisch laden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, + "Zurück" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, + "Bestätigen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, + "Info" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, + "Beenden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, + "Nach unten scrollen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, + "Nach oben scrollen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, + "Start" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, + "Tastatur ein-/ausschalten" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, + "Menü ein-/ausschalten" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, + "Grundlegende Menüsteuerung" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, + "Bestätigen/OK" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, + "Info" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, + "Beenden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, + "Nach oben scrollen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, + "Standardwerte" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, + "Tastatur ein-/ausschalten" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, + "Menü ein-/ausschalten" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, + "Überschreibe SaveRAM nicht, wenn ein Savestate geladen wird" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, + "Bluetooth aktivieren" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, + "Buildbot-Assets-URL" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY, + "Temporäre Dateien" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW, + "Erlaube Kamera-Zugriff" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER, + "Kameratreiber" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT, + "Cheat" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES, + "Änderungen übernehmen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH, + "Cheat-Datei" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE, + "Cheat-Date" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, + "Cheat-Datei laden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, + "Speichere Cheat-Datei unter ..." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, + "Cheat-Durchläufe" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_DESCRIPTION, + "Beschreibung" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, + "Hardcore-Modus" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, + "Gesperrte Errungenschaften:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, + "Gesperrt" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, + "Retro-Errungenschaften" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, + "Teste inoffizielle Errungenschaften" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, + "Entsperrte Errungenschaften:" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, + "Entsperrt" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, + "Schließen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIG, + "Konfiguration" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, + "Konfgurationsdatei laden" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, + "Konfigurationen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, + "Einstellungen beim Beenden speichern" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST, + "Sammlungen" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, + "Inhaltsdatenbank" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_DIR, + "Inhalt" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, "Länge der Verlaufsliste") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, + "Erlaube, Einträge zu entfernen") MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, - "Inhaltseinstellungen") /* FIXME */ + "Spielmenü") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, + "Core-Assets") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, - "Core-Assets-Verzeichnis") /* FIXME/UPDATE */ + "Downloads") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Cheats") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, "Core-Zähler") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, - "Zeige Core-Namen") + "Core-Namen anzeigen") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, "Core-Informationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, @@ -115,7 +502,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES, "Kategorien") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL, - "Core-Beschriftung") + "Core-Bezeichnung") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME, "Core-Name") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, @@ -125,101 +512,117 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS, "Berechtigungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, - "Unterstütze Erweiterungen") + "Unterstützte Erweiterungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER, "System-Hersteller") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, "System-Name") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, /* UPDATE/FIXME */ - "Core-Input-Optionen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, + "Steuerung") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_LIST, "Core laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS, "Optionen") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS, - "Core-Einstellungen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, /* TODO/FIXME */ - "Cores nicht automatisch starten") + "Cores") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE, + "Cores automatisch starten") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, "Heruntergeladene Archive automatisch entpacken") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL, - "Buildbot-Cores-URL") + "Buildbot-Core-URL") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST, - "Aktualisiere Core") + "Cores aktualisieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS, - "Core-Aktualisierungseinstellungen") /* UPDATE/FIXME */ + "Aktualisierungen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE, + "CPU-Architektur:") MSG_HASH(MENU_ENUM_LABEL_VALUE_CPU_CORES, - "Prozessorkerne:") + "CPU-Kerne:") MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY, - "Cursor-Verzeichnis") + "Suchanfragen") MSG_HASH(MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER, - "Zeiger-Manager") + "Suchanfragen verwalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, "Benutzerdefiniertes Verhältnis") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, - "Datenbank-Manager") + "Datenbanken verwalten") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, + "Datenbank-Auswahl") MSG_HASH(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, - "Von der Wiedergabeliste löschen") + "Von der Liste löschen") MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES, - "Lesezeichen") + "Startverzeichnis") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, "") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT, - "") + "") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE, "") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, - "Ordner nicht gefunden.") + "Verzeichnis nicht gefunden.") MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS, - "Verzeichniseinstellungen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISABLED, - "Deaktiviert") + "Verzeichnisse") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS, - "Datenträgerstatus") + "Datentägerstatus") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND, "Füge Datenträgerabbild hinzu") MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_INDEX, "Datenträger-Nummer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, /* UPDATE/FIXME */ +MSG_HASH(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS, "Datenträger-Optionen") MSG_HASH(MENU_ENUM_LABEL_VALUE_DONT_CARE, - "Mir egal") + "Ignorieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST, + "Downloads") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, "Core herunterladen...") MSG_HASH(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT, - "Inhalt Downloader") + "Inhalt herunterladen") MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE, - "Aktiviere DPI-Override") + "Aktiviere DPI-Überschreibung") MSG_HASH(MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE, - "DPI-Override") + "DPI-Überschreibung") MSG_HASH(MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS, - "Treibereinstellungen") + "Treiber") MSG_HASH(MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN, - "Dummy bei Core-Abschaltung") + "Dummy laden, wenn Core beendet wird") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CHECK_FOR_MISSING_FIRMWARE, + "Vor dem Laden nach fehlender Firmware suchen") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, - "Dynamischer Hintergrund") + "Dynamisches Hintergrundbild") MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, - "Dynamischehintergrundbilderverzeichnis") + "Dynamische Hintergrundbilder") +MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, + "Aktiviere Errungenschaften") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, - "Hover-Farbe für Menü-Einträge") + "Farbe für gewählte Menü-Einträge") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, - "Normale Farbe für Menü-Einträge") + "Farbe für nicht gewählte Menü-Einträge") MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, - "False") + "Aus") MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, - "Maximale Ausführungsgeschwindigkeit") + "Maximale Ausführgeschwindigkeit") MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, "Zeige Bildwiederholrate") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, - "Begrenze maximale Ausführungsgeschwindigkeit") + "Begrenze maximale Ausführgeschwindigkeit") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, + "Bildgeschwindigkeit") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, - "Frontendzähler") + "Frontend-Zähler") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, + "Lade inhaltsspezifische Core-Einstellungen automatisch") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, + "Erstelle Datei für Spieloptionen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, + "Spieloptionen") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, "Hilfe") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "Audio/Video Fehlerbehebung") + "Audio/Video-Fehlerbehebung") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, - "Ändere das Virtual Gamepad Overlay") + "Ändere virtuelles Gamepad-Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, "Grundlegende Menüsteuerung") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST, @@ -231,45 +634,61 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT, MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_WHAT_IS_A_CORE, "Was ist ein Core?") MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE, - "Aktiviere Verlaufsliste") + "Verlaufliste aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_HISTORY_TAB, "Verlauf") -MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, /* Don't change. Breaks everything. (Would be, "Horizontales Menu") */ - "Horizontal Menu") +MSG_HASH(MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU, + "Horizontales Menü") MSG_HASH(MENU_ENUM_LABEL_VALUE_IMAGES_TAB, "Bilder") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION, + "Informationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INFORMATION_LIST, "Informationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, "Analog-zu-Digital-Typ") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ALL_USERS_CONTROL_MENU, - "Jeder Nutzer kann das Menü steuern") + "Alle Benutzer können das Menü steuern") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X, "Linker Analogstick X") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_MINUS, "Linker Analogstick X- (links)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_X_PLUS, - "Linker Analogstick X+ (Rechts)") + "Linker Analogstick X+ (rechts)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y, "Linker Analogstick Y") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_MINUS, - "Linker Analogstick Y- (hoch)") + "Linker Analogstick Y- (nach oben)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_LEFT_Y_PLUS, - "Linker Analogstick Y+ (runter)") + "Linker Analogstick Y+ (nach unten)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X, + "Rechter Analogstick X") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_MINUS, + "Rechter Analogstick X- (links)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_X_PLUS, + "Rechter Analogstick X+ (rechts)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y, + "Rechter Analogstick Y") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_MINUS, + "Rechter Analogstick Y- (nach oben)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_RIGHT_Y_PLUS, + "Rechter Analogstick Y+ (nach unten)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE, "Automatische Konfiguration aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD, - "Schwellwert der Eingabe-Achsen") + "Schwellenwert der Analogsticks") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, + "Vertausche OK- und Zurück-Tasten im Menü") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_ALL, - "Binde alle") + "Alle zuordnen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_DEFAULT_ALL, - "Binde alle Standard") /* @TODO: What is this */ + "Standard-Belegung wiederherstellen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_BIND_TIMEOUT, - "Bindeunterbrechung") + "Zeitlimit für Belegung") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND, - "Verstecke nicht zugewiesene Core-Eingabe-Beschriftungen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, /* TODO/FIXME */ - "Zeige Core-Eingabe-Beschriftungen") + "Verstecke nicht zugewiesene Eingabe-Beschriftungen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW, + "Zeige Eingabe-Beschriftungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, "Geräteindex") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, @@ -277,87 +696,95 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_TYPE, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DRIVER, "Eingabetreiber") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE, - "Auslastungsgrad") + "Turbo-Haltedauer") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS, + "Hotkeys belegen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_ICADE_ENABLE, + "Gamepad-Eingabe auf Tastatur legen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_A, "A-Knopf (rechts)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_B, - "B-Knopf (unten)") + "B-Knopf (nach unten)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_DOWN, - "Steuerkreuz unten") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, - "L-Knopf (Schultertaste)") + "Steuerkreuz nach unten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L2, "L2-Knopf (Abzug)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L3, "L3-Knopf (Daumen)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_L, + "L-Knopf (Schultertaste)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_LEFT, - "Steuerkreuz links") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, - "R-Knopf (Schultertaste)") + "Steuerkreuz nach links") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R2, "R2-Knopf (Abzug)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R3, "R3-Knopf (Daumen)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_R, + "R-Knopf (Schultertaste)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_RIGHT, - "Steuerkreuz rechts") + "Steuerkreuz nach rechts") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_SELECT, "Select-Knopf") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_START, - "Startknopf") + "Start-Knopf") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_UP, - "Steuerkreuz oben") + "Steuerkreuz nach oben") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_X, "X-Knopf (oben)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_JOYPAD_Y, "Y-Knopf (links)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEY, + "(Taste: %s)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, + "Typ der Keyboard-Gamepad-Abbildung") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS, "Maximale Benutzeranzahl") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Gamepad-Menükombination") + "Gamepad-Tastenkombination für Menü") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_MINUS, "Cheat-Index -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_INDEX_PLUS, "Cheat-Index +") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_CHEAT_TOGGLE, - "Cheat ein/aus") + "Cheat ein-/ausschalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE, - "Disk ein-/auswerfen") + "Datenträger einlegen/auswerfen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT, - "Nächste Disk") + "Nächster Datenträger") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV, - "Vorherige Disk") + "Vorheriger Datenträger") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_ENABLE_HOTKEY, - "Hotkeys ein/aus") + "Hotkeys aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_HOLD_KEY, - "Zeitraffer") + "Zeitraffer (halten)") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FAST_FORWARD_KEY, - "Zeitraffer ein/aus") + "Zeitraffer ein-/ausschalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FRAMEADVANCE, - "Bildervorlauf") /* @TODO: I don't know what this is */ + "Einzelbildvorlauf") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY, - "Vollbild ein/aus") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, - "Spielfokus ein/aus") + "Vollbildmodus ein-/ausschalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE, - "Maus greiffen ein/aus") + "Mauszeiger einfangen/loslassen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_GAME_FOCUS_TOGGLE, + "Spielfokus ein-/ausschalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_LOAD_STATE_KEY, - "Lade Speicherstand") + "Spielstand laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE, - "Menü ein/aus") + "Menü aufrufen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MOVIE_RECORD_TOGGLE, - "Videoaufzeichnung ein/aus") + "Videoaufzeichnung starten/beenden") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE, - "Stumm ein/aus") + "Audio stumm-/lautschalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_FLIP, - "Netplay wechsle Benutzer") /* @TODO What does flip mean in this context? */ + "Netplay-Benutzer vertauschen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_NETPLAY_GAME_WATCH, - "Netplay Zuschauermodus ein/aus") + "Zwischen Spieler- und Beobachter-Modus wechseln") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OSK, - "Bildschirmtastatus ein/aus") + "Bildschirmtastatur ein-/ausschalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_OVERLAY_NEXT, "Nächstes Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE, - "Pause ein/aus") + "Pause/weiter") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY, "RetroArch beenden") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, @@ -365,63 +792,69 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_RESET, MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_REWIND, "Zurückspulen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SAVE_STATE_KEY, - "Erstelle Speicherstand") + "Erstelle Spielstand") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT, "Erstelle Bildschirmfoto") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_NEXT, "Nächster Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SHADER_PREV, - "Verheriger Shader") + "Vorheriger Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_SLOWMOTION, "Zeitlupe") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_MINUS, - "Speicherstandplatz -") + "Spielstand-Speicherplatz -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_STATE_SLOT_PLUS, - "Speicherstandplatz +") + "Spielstand-Speicherplatz +") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_DOWN, "Lautstärke -") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_META_VOLUME_UP, "Lautstärke +") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OSK_OVERLAY_ENABLE, - "Zeige Tastatur-Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE, "Aktiviere Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_HIDE_IN_MENU, "Overlay im Menü nicht anzeigen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR, - "Eingabeabfrageverhalten") + "Abfrageverhalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_EARLY, "Früh") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_LATE, "Spät") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_POLL_TYPE_BEHAVIOR_NORMAL, "Normal") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, /* UPDATE/FIXME */ - "Eingabebelegungsverzeichnis") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_PREFER_FRONT_TOUCH, + "Touch-Eingabe auf der Vorderseite bevorzugen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY, + "Tastenbelegungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE, - "Bind-Remapping aktivieren") + "Tasten-Umbelegung aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SAVE_AUTOCONFIG, - "Speichere Autokonfigurationen") + "Speichere Autokonfiguration") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS, - "Eingabeeinstellungen") + "Eingabe") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_SMALL_KEYBOARD_ENABLE, + "Kleine Tastatur aktivieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TOUCH_ENABLE, + "Touch-Eingabe aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_ENABLE, "Turbo aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD, - "Turbo-Dauer") -MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, - "Einheitliche Menüsteuerung") + "Turbo-Häufigkeit") MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS, - "Spieler %u Tastenbelegung") + "Belegungen für Benutzer %u") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INTERNAL_STORAGE_STATUS, + "Status des internen Speichers") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR, - "Eingabegerät-Autoconfig-Verzeichnis") + "Automatische Eingabekonfigurationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER, "Joypad-Treiber") +MSG_HASH(MENU_ENUM_LABEL_VALUE_LAKKA_SERVICES, + "Services") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED, - "Chinesisch (Vereinfacht)") + "Chinesisch (vereinfacht)") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL, - "Chinesisch (Traditionell)") + "Chinesisch (traditionell)") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_DUTCH, - "Niederländisch") + "Niederlöndisch") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ENGLISH, "Englisch") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO, @@ -436,132 +869,152 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_JAPANESE, "Japanisch") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_KOREAN, "Koreanisch") +MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_POLISH, + "Polnisch") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE, "Portugiesisch") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN, "Russisch") MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_SPANISH, "Spanisch") +MSG_HASH(MENU_ENUM_LABEL_VALUE_LANG_VIETNAMESE, + "Vietnamesisch") MSG_HASH(MENU_ENUM_LABEL_VALUE_LEFT_ANALOG, "Linker Analogstick") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH, - "Core-Verzeichnis") + "Core") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH, - "Core-Info-Verzeichnis") + "Core-Informationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL, - "Core-Logging-Stufe") + "Core-Loglevel") MSG_HASH(MENU_ENUM_LABEL_VALUE_LINEAR, "Linear") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE, "Archiv laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY, - "Inhalt laden (Verlauf)") /* FIXME/UPDATE */ + "Inhalt aus Verlauf laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST, "Inhalt laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOAD_STATE, "Spielstand laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW, - "Erlaube Standort-Lokalisierung") + "Standortbestimmung erlauben") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER, - "Standorttreiber") + "Standort-Treiber") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS, - "Logging-Einstellungen") + "Logging") MSG_HASH(MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY, - "Log-Ausführlichkeit") + "Logs auf Kommandozeile ausgeben") MSG_HASH(MENU_ENUM_LABEL_VALUE_MAIN_MENU, "Hauptmenü") MSG_HASH(MENU_ENUM_LABEL_VALUE_MANAGEMENT, - "Datenbankeinstellungen") + "Datenbanken") MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME, - "Menüfarbschema") + "Menü-Farbschema") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE, + "Blau") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_BLUE_GREY, + "Blau/Grau") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_DARK_BLUE, + "Dunkelblau") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_GREEN, + "Grün") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_NVIDIA_SHIELD, + "Shield") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_RED, + "Rot") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_COLOR_THEME_YELLOW, + "Gelb") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_FOOTER_OPACITY, + "Footer-Transparenz") +MSG_HASH(MENU_ENUM_LABEL_VALUE_MATERIALUI_MENU_HEADER_OPACITY, + "Header-Transparenz") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_DRIVER, "Menütreiber") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_ENUM_THROTTLE_FRAMERATE, - "Drossle Menübildwiederholrate") + "Bildwiederholrate im Menü begrenzen") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS, "Einstellungen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL, - "Wechsle Ok & Zurück Tasten im Menü") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_LINEAR_FILTER, - "Linearer Filter") + "Linearer Filter für Menü") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_SETTINGS, - "Menüeinstellungen") + "Menü") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER, - "Menühintergrund") + "Menü-Hintergrundbild") MSG_HASH(MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER_OPACITY, - "Hintergrundtransparenz") + "Hintergrundbild-Transparenz") MSG_HASH(MENU_ENUM_LABEL_VALUE_MISSING, "Fehlt") MSG_HASH(MENU_ENUM_LABEL_VALUE_MORE, "...") MSG_HASH(MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE, - "Mausunterstützung") + "Maus-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS, - "Multimediaeinstellungen") + "Multimedia") MSG_HASH(MENU_ENUM_LABEL_VALUE_MUSIC_TAB, "Musik") MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, - "Bekannte Dateiendungen filtern") /* TODO/FIXME - rewrite */ + "Unbekannte Dateierweiterungen filtern") MSG_HASH(MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND, "Navigation umbrechen") MSG_HASH(MENU_ENUM_LABEL_VALUE_NEAREST, "Nächster") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY, "Netplay") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, /* TODO: What actually does this? The translation might be odd. */ - "Netplay Bildübetragungsrate prüfen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CLIENT_SWAP_INPUT, /* TODO, Original string changed */ - "Tausche Netplay-Eingabe") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CHECK_FRAMES, + "Netplay-Synchronisation prüfen") /* TODO: What does this setting do? Need more context. */ +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Eingabeverzögerung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Erlaubte Eingabeverzögerung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_CLIENT_SWAP_INPUT, + "Netplay-Spieler 2 verwendet Client 1") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES, - "Verzögere Netplay-Frames") + "Netplay-Verzögerung") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT, "Verbindung trennen") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE, "Aktiviere Netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT, - "Verbinde zu einem Netplay Host") + "Verbinde zu einem Netplay-Host") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST, - "Starte Host") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, /* TODO, Original string changed */ - "IP-Addresse für Netplay") + "Starte Hosting") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS, + "Server-Adresse") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LAN_SCAN_SETTINGS, - "Durchsuche lokales Netzwerk") + "Lokales Netzwerk durchsuchen") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_MODE, - "Aktiviere Netplay-Client") + "Netplay-Client aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "Benutzername") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, - "Server Passwort") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, - "Aktualisiere Lobby-Liste") + "Server-Passwort") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + "Netplay öffentlich ankündigen") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, - "Netplay settings") + "Netplay-Einstellungen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, + "Netplay ohne Savestates") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATE_PASSWORD, - "Server Passwort für Zuschauer") + "Server-Passwort für Beobachter-Modus") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE, - "Aktiviere Netplay-Zuschauermodus") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, - "Netplay wird gestartet sobald ein Inhalt geladen wurde.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, /* TODO: What is this actually? */ - "Zustandsloser Netplay-Modus") -MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TAB, - "Netplay Lobbies") + "Beobachtermodus aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT, - "TCP/UDP-Port für Netplay") + "Netplay TCP/UDP-Port") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NAT_TRAVERSAL, - "Netplay NAT Traversal") + "Netplay NAT-Traversal") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE, - "Netzwerkbefehle") + "Netzwerk-Befehle") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT, - "Port für Netzwerkbefehle") + "Port für Netzwerk-Befehle") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION, - "Netzwerkinformationen") + "Netzwerk-Informationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_ENABLE, - "Network Gamepad") + "Netzwerk-Gamepad aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_PORT, - "Network Remote Base Port") + "Netzwerk-Remote-Port") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS, - "Netzwerkeinstellungen") + "Netzwerk") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO, "Nein") MSG_HASH(MENU_ENUM_LABEL_VALUE_NONE, @@ -579,47 +1032,51 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE, "Keine Core-Optionen verfügbar.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY, - "No entries to display.") + "Keine Einträge.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE, - "No history available.") + "Kein Verlauf verfügbar.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE, "Keine Informationen verfügbar.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_ITEMS, "Keine Einträge.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_HOSTS_FOUND, - "Kein Netplay Host gefunden.") + "Keine Netplay-Hosts gefunden.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND, - "No networks found.") + "Kein Netzwerk gefunden.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS, "Keine Leistungszähler.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS, "Keine Wiedergabelisten.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE, - "Keine Einträge verfügbar.") + "Keine Wiedergabelisten-Einträge verfügbar.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND, "Keine Einstellungen gefunden.") MSG_HASH(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS, - "Keine Shaderparameter") + "Keine Shader-Parameter.") MSG_HASH(MENU_ENUM_LABEL_VALUE_OFF, - "AN") -MSG_HASH(MENU_ENUM_LABEL_VALUE_ON, "AUS") +MSG_HASH(MENU_ENUM_LABEL_VALUE_ON, + "EIN") +MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE, + "Online") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER, - "Online-Aktualisierung") + "Online-Aktualisierungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS, - "OSD-Einstellungen") + "Bildschirm-Meldungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS, "Bildschirm-Overlay") +MSG_HASH(MENU_ENUM_LABEL_VALUE_ONSCREEN_NOTIFICATIONS_SETTINGS, + "Bildschirm-Benachrichtigungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE, - "Öffne Archiv") /* TODO/FIXME */ + "Öffne Archiv als Ordner") MSG_HASH(MENU_ENUM_LABEL_VALUE_OPTIONAL, "Optional") -MSG_HASH(MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_DIRECTORY, - "OSK-Overlay-Verzeichnis") +MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY, + "Overlay") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED, - "Automatisch bevorzuges Overlay laden") + "Bevorzugtes Overlay automatisch laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY, - "Overlay-Verzeichnis") + "Overlays") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY, "Overlay-Transparenz") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, @@ -627,23 +1084,23 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET, MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE, "Overlay-Skalierung") MSG_HASH(MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS, - "Overlay-Einstellungen") + "Overlays") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAL60_ENABLE, "Verwende PAL60-Modus") MSG_HASH(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, "Übergeordnetes Verzeichnis") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO, - "Pausiere wenn das Menü aktiv ist") + "Pausiere, wenn das Menü aktiv ist") MSG_HASH(MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE, - "Nicht im Hintergrund laufen") + "Nicht im Hintergrund ausführen") MSG_HASH(MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE, "Leistungsindikatoren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB, + "Wiedergabelisten") MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY, - "Wiedergabelistenverzeichnis") -MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_ENTRY_REMOVE, - "Löschen von Einträgen erlauben") + "Wiedergabelisten") MSG_HASH(MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS, - "Wiedergabelisteneinstellungen") + "Wiedergabelisten") MSG_HASH(MENU_ENUM_LABEL_VALUE_POINTER_ENABLE, "Touch-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_PORT, @@ -651,51 +1108,85 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_PORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_PRESENT, "Vorhanden") MSG_HASH(MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS, - "Privatsphäreeinstellungen") + "Privatsphäre") MSG_HASH(MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH, "RetroArch beenden") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG, + "Analog unterstützt") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING, + "BBFC-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING, + "CERO-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP, + "Co-op unterstützt") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32, "CRC32") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION, "Beschreibung") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER, "Entwickler") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE, + "Edge Magazine-Ausgabe") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING, + "Edge Magazine-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW, + "Edge Magazine-Testbericht") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING, + "ELSPA-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW, + "Hardware-Erweiterungen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING, + "ESRB-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING, + "Famitsu Magazine-Bewertung") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE, "Franchise") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE, + "Genre") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5, "MD5") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME, "Name") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN, "Herkunft") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING, + "PEGI-Bewertung") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER, "Publisher") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH, "Veröffentlichungsmonat") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR, "Veröffentlichungsjahr") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE, + "Rumble unterstützt") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL, + "Seriennummer") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1, "SHA1") MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT, "Starte Inhalt") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING, + "TGDB-Bewertung") MSG_HASH(MENU_ENUM_LABEL_VALUE_REBOOT, "Neustart") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY, - "Aufnahme-Konfigurationsverzeichnis") + "Aufnahme-Konfigurationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY, - "Aufnahme-Ausgabeverzeichnis") + "Aufnahmen") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS, - "Aufnahmeeinstellungen") + "Aufnahme") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_CONFIG, - "Aufnahme-Konfiguration") + "Lade Aufnahme-Konfiguration...") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_DRIVER, "Aufnahmetreiber") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_ENABLE, "Aktiviere Aufnahmefunktion") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, /* FIXME/UPDATE */ - "Aufnahmepfad") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_PATH, + "Speichere Aufnahme als...") MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, - "Verwende Aufnahme-Ausgabeverzeichnis") + "Speichere Aufname im Ausgabeverzeichnis") +MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE, + "Remap-Datei") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, "Remap-Datei laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, @@ -705,107 +1196,131 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, "Notwendig") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, - "Neustarten") + "Neu starten") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH, "RetroArch neustarten") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME, "Fortsetzen") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT, "Fortsetzen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, - "Errungenschaften") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROKEYBOARD, "RetroKeyboard") MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD, "RetroPad") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG, + "RetroPad mit Analogsticks") +MSG_HASH(MENU_ENUM_LABEL_VALUE_RETRO_ACHIEVEMENTS_SETTINGS, + "Errungenschaften") MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_ENABLE, "Zurückspulen (Rewind) aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY, "Genauigkeit des Zurückspulens (Rewind)") MSG_HASH(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS, - "Zurückspuleinstellungen") + "Zurückspulen") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY, - "Dateibrowserverzeichnis") + "Dateibrowser") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY, - "Konfigurationsverzeichnis") + "Konfigurationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN, "Zeige Startbildschirm") MSG_HASH(MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, "Rechter Analogstick") MSG_HASH(MENU_ENUM_LABEL_VALUE_RUN, "Starten") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SAMBA_ENABLE, + "SAMBA aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY, - "Spielstandverzeichnis") + "Speicherdaten") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX, "Automatische Indexierung von Spielständen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD, - "Automatisches Laden von Spielständen") + "Spielstand automatisch laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE, - "Automatisch Spielstände speichern") + "Spielstand automatisch speichern") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY, - "Spielstandverzeichnis") + "Spielstände") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVESTATE_THUMBNAIL_ENABLE, - "Spielstandminiaturansichten") + "Spielstand-Miniaturansichten") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG, - "Aktuelle Konfigurationen speichern") + "Speichere aktuelle Konfiguration") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, "Speichere Core-Überschreibungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, - "Speichere Spieleüberschreibungen") + "Speichere Spiel-Überschreibungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG, - "Neue Konfigurationen speichern") + "Speichere neue Konfiguration") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVE_STATE, "Spielstand speichern") MSG_HASH(MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS, - "Spielstandeinstellungen") + "Speichern") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY, - "Verzeichnis Durchsuchen") + "Verzeichnis durchsuchen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_FILE, - "Datei Durchsuchen") + "Datei durchsuchen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY, - "<- Durchsuchen ->") + "") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY, - "Bildschirmfotoverzeichnis") + "Bildschirmfotos") MSG_HASH(MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION, - "Bildschirmauflösung") + "Bildschirm-Auflösung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SEARCH, + "Suchen:") MSG_HASH(MENU_ENUM_LABEL_VALUE_SECONDS, "Sekunden") MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS, "Einstellungen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SETTINGS_TAB, + "Einstellungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER, "Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES, "Änderungen übernehmen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS, - "Shaders") + "Shader") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON, + "Band") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_RIBBON_SIMPLIFIED, + "Band (vereinfacht)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SIMPLE_SNOW, + "Schnee (vereinfacht)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_SNOW, + "Schnee") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS, - "Zeige erweitere Einstellungen") + "Zeige erweiterte Einstellungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, - "Zeige versteckte Ordner und Dateien") + "Zeige versteckte Dateien und Ordner") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SHUTDOWN, + "Beenden") MSG_HASH(MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO, "Zeitlupen-Verhältnis") MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE, - "Sortiere Speicherdateien per Ordner") + "Sortiere Speicherdaten in Ordnern") MSG_HASH(MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE, - "Sortiere Spielstände per Ordner") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATE_SLOT, - "Spielstand Feld") -MSG_HASH(MENU_ENUM_LABEL_VALUE_STATUS, - "Status") + "Sortiere Spielstände in Ordnern") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SSH_ENABLE, + "SSH aktivieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_START_CORE, + "Core starten") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD, "Starte Remote-RetroPad") MSG_HASH(MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR, "Starte Videoprozessor") +MSG_HASH(MENU_ENUM_LABEL_VALUE_STATE_SLOT, + "Spielstand-Speicherplatz") +MSG_HASH(MENU_ENUM_LABEL_VALUE_STATUS, + "Status") MSG_HASH(MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE, "stdin-Befehle") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SUPPORTED_CORES, + "Unterstützte Cores") MSG_HASH(MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE, "Bildschirmschoner ausschalten") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE, "Aktiviere System-BGM") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY, - "System/BIOS-Verzeichnis") + "System/BIOS") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION, - "Systeminformationen") + "System-Informationen") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT, "7zip-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT, @@ -831,7 +1346,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT, "DirectSound-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT, - "Dynamic-Library-Unterstützung") + "Unterstützung für dynamische Bibliotheken") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYNAMIC_SUPPORT, + "Dymanisches Laden der libretro-Bilbiothek zur Laufzeit") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT, "EGL-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT, @@ -866,6 +1383,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT, "Netplay-Unterstützung (Peer-to-Peer)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT, "Netzwerk-Befehlsinterface-Unterstützung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_REMOTE_SUPPORT, + "Unterstützung für Netzwerk-Gamepads") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT, "OpenAL-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT, @@ -889,25 +1408,33 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING, "Entlädt") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE, - "Keine Quelle") + "Keine Stromquelle") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT, "PulseAudio-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT, "Python-Unterstützung (Script-Unterstützung in Shadern)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RBMP_SUPPORT, + "BMP-Unterstützung (RBMP)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL, "RetroRating-Stufe") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RJPEG_SUPPORT, + "JPEG-Unterstützung (RJPEG)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT, "RoarAudio-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT, "PNG-Unterstützung (RPNG)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT, "RSound-Unterstützung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RTGA_SUPPORT, + "TGA-Unterstützung (RTGA)") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT, "SDL2-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT, "SDL-Image-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT, "SDL1.2-Unterstützung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SLANG_SUPPORT, + "Slang-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT, "Threading-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, @@ -915,7 +1442,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT, "Video4Linux2-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER, - "Video-Context-Treiber") + "Video-Kontext-Treiber") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VULKAN_SUPPORT, + "Vulkan-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT, "Wayland-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT, @@ -927,27 +1456,29 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT, MSG_HASH(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT, "Zlib-Unterstützung") MSG_HASH(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT, - "Bildschirmfoto") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, /* TODO/FIXME - update */ - "Threaded Datenschlaufe") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, - "Boxart") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, - "Bildschirmfoto") -MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, - "Titelbildschrim") + "Bildschirmfoto anfertigen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE, + "Multithreading") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS, "Miniaturansichten") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_DIRECTORY, - "Miniaturansichtenverzeichnis") + "Miniaturansichten") MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAILS_UPDATER_LIST, - "Aktualisiere Miniaturansichten") + "Miniaturansichten aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS, + "Boxarts") +MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS, + "Bildschirmfoto") +MSG_HASH(MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS, + "Titelbildschirm") MSG_HASH(MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, - "Zeige Uhrzeit / Datum") + "Uhrzeit / Datum anzeigen") MSG_HASH(MENU_ENUM_LABEL_VALUE_TITLE_COLOR, - "Menü-Titel-Farbe") + "Menü-Titelfarbe") MSG_HASH(MENU_ENUM_LABEL_VALUE_TRUE, - "True") + "An") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_ENABLE, + "UI-Companion aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT, "UI-Companion beim Hochfahren starten") MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, @@ -955,69 +1486,73 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE, MSG_HASH(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE, "Komprimiertes Archiv kann nicht gelesen werden.") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE, - "Spielstand laden rückgängig machen") + "Laden des Spielstandes rückgängig machen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, + "Speichern des Spielstandes rückgängig machen") MSG_HASH(MENU_ENUM_LABEL_VALUE_UNKNOWN, "Unbekannt") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE, - "Spielstand speichern rückgängig machen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, - "Aktualisiere Assets") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, - "Aktualisiere Autoconfig-Profile") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, - "Aktualisiere CG-Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, - "Aktualisiere Cheats") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, - "Aktualisiere Core Info Dateien") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, - "Aktualisiere Datenbanken") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, - "Aktualisiere GLSL-Shader") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, - "Aktualisiere Lakka") -MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, - "Aktualisiere Overlays") MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATER_SETTINGS, - "Aktualisierungen") + "Online-Aktualisierungen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS, + "Assets aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES, + "Profile f. automatische Konfiguration aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS, + "CG-Shader aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS, + "Cheats aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES, + "Core-Infodateien aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES, + "Datenbanken aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS, + "GLSL-Shader aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA, + "Lakka aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS, + "Overlays aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS, + "Slang-Shader aktualisieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER, "Benutzer") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS, - "Benutzeroberflächeneinstellungen") + "Benutzeroberfläche") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_LANGUAGE, "Sprache") MSG_HASH(MENU_ENUM_LABEL_VALUE_USER_SETTINGS, - "Benutzereinstellungen") + "Benutzer") +MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER, + "Verwende eingebauten Bildbetrachter") MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER, - "Verwende integrierten Player") /* FIXME/UPDATE */ + "Verwende eingebauten Medienplayer") MSG_HASH(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY, - "") + "") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE, "Erlaube Bildrotation") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO, "Automatisches Bildseitenverhältnis") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, - "Video-Seitenverhältnis") + "Bildseitenverhältnis") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION, - "Setze schwarzes Bild zwischen Frames ein") + "Schwarzes Bild zwischen Einzelbildern einfügen") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN, "Bildränder (Overscan) zuschneiden (Neustart erforderlich)") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, - "Deaktiviere Desktop-Komposition") + "Deaktiviere Desktop-Gestaltung") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER, - "Grafiktreiber") + "Videotreiber") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER, - "Videofilter") + "Grafikfilter") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR, - "Grafikfilter-Verzeichnis") + "Grafikfilter") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER, - "Aktiviere Flacker-Filter") + "Flacker-Filter aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE, - "Zeige OSD-Nachrichten") + "Bildschirm-Benachrichtigungen aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH, - "Schriftart der OSD-Nachrichten") + "Schriftart für Bildschirm-Benachrichtigungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE, - "Schriftgröße der OSD-Nachrichten") + "Schritftgröße der Bildschirm-Benachrichtigungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT, "Erzwinge Bildseitenverhältnis") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE, @@ -1029,23 +1564,23 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA, "Gamma") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD, - "Aktiviere GPU-Aufnahmefunktion") + "Verwende GPU für Aufnahme") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT, - "Aktiviere GPU-Bildschirmfotos") + "Verwende GPU für Bildschirmfotos") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC, "Synchronisiere GPU und CPU") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES, - "Synchronisiere Frames fest mit GPU") + "Anzahl der Frames für GPU-CPU-Sync") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Maximale Anzahl der Wechselkettenbilder") + "Maximale Anzahl von Zwischenbildern") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X, - "X-Position der OSD-Nachrichten") + "X-Position der Bildschirm-Benachrichtigungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y, - "Y-Position der OSD-Nachrichten") + "Y-Position der Bildschirm-Benachrichtigungen") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX, - "Monitorindex") + "Monitor-Index") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD, - "Aktiviere Aufnahme von Post-Filtern") + "Wende Filter auf Aufnahme an") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE, "Bildwiederholrate") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, @@ -1053,267 +1588,805 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO, MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION, "Rotation") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE, - "Fenterskalierung") + "Skalierung im Fenstermodus") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER, "Ganzzahlige Bildskalierung") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, - "Videoeinstellungen") + "Video") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR, - "Grafikshader-Verzeichnis") + "Video-Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES, - "Shader-Durchgänge") /* FIXME */ + "Shader-Durchläufe") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS, - "Momentane Shaderparameter") /* FIXME/UPDATE */ + "Vorschau der Shader-Parameter") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET, "Shader-Voreinstellung laden") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_PARAMETERS, - "Menü Shaderparameter (Menü)") + "Shader-Parameter anpassen") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS, - "Speichere Shader-Voreinstellung unter...") + "Shader-Voreinstellung speichern unter...") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE, + "Core-Voreinstellung speichern") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME, + "Spiel-Voreinstellung speichern") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT, - "HW-Shared-Context aktivieren") + "Gemeinsamen Hardware-Kontext aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH, - "Bilineare Filterung (HW)") + "Bilineare Filterung") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER, - "Aktiviere Soft-Filter") + "Soft-Filter aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL, "VSync-Intervall") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_TAB, - "Videos") + "Video") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_THREADED, - "Threaded Video") + "Video in separatem Thread") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER, - "Bild entflackern") + "Entflackern") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, - "Bildchirmauflösung Höhe") + "Bildhöhe") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, - "Bildchirmauflösung Breite") + "Bildbreite") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_X, - "Bildchirmauflösung X") + "X-Position des Bildes") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_Y, - "Bildchirmauflösung Y") + "Y-Position des Bildes") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH, - "Kalibriere VI-Bildbreite") + "VI-Bildgröße") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC, - "Vertikale Synchronisation (VSync)") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, - "Fensterhöhe") + "Vertikale Synchronisation (Vsync)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, + "Unechter Vollbildmodus (Windowed Fullscreen)") MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_WIDTH, "Fensterbreite") -MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN, - "Unechter Vollbild-Modus (Windowed Fullscreen)") +MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_WINDOW_HEIGHT, + "Fensterhöhe") MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_DRIVER, "WLAN-Treiber") MSG_HASH(MENU_ENUM_LABEL_VALUE_WIFI_SETTINGS, "WLAN") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ALPHA_FACTOR, - "Menüalphafaktor") + "Menü-Transparenz") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_FONT, - "Menüschriftart") + "Menü-Schriftart") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_CUSTOM, + "Benutzerdefiniert") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_FLATUI, + "FlatUI") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_MONOCHROME, + "Monochrome") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_SYSTEMATIC, + "Systematic") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_NEOACTIVE, + "NeoActive") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_PIXEL, + "Pixel") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_RETROACTIVE, + "RetroActive") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_ICON_THEME_DOTART, + "Dot-Art") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME, + "Menü-Farbschema") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_APPLE_GREEN, + "Apple Green") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK, + "Dark") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_DARK_PURPLE, + "Dark Purple") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_ELECTRIC_BLUE, + "Electric Blue") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_GOLDEN, + "Golden") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_LEGACY_RED, + "Legacy Red") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_MIDNIGHT_BLUE, + "Midnight Blue") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_PLAIN, + "Plain") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_UNDERSEA, + "Undersea") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_MENU_COLOR_THEME_VOLCANIC_RED, + "Volcanic Red") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_RIBBON_ENABLE, - "Menü-Shaderpipeline") + "Menü-Shader") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SCALE_FACTOR, - "Menüskalierungsfaktor") + "Menü-Skalierungsfaktor") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHADOWS_ENABLE, - "Bild Schatten") -MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_ADD, - "Zeige Inhalte importieren Tab") + "Icon-Schatten aktivieren") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_HISTORY, - "Zeige Verlauf Tab") + "Zeige Tab 'Verlauf'") +MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_ADD, + "Zeige Tab 'Inhalte importieren'") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_IMAGES, - "Zeige Bilder Tab") + "Zeige Tab 'Bilder'") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_MUSIC, - "Zeige Musik Tab") + "Zeige Tab 'Musik'") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_SETTINGS, - "Zeige Einstellungen Tab") + "Zeige Tab 'Einstellungen'") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_SHOW_VIDEO, - "Zeige Videos Tab") + "Zeige Tab 'Video'") MSG_HASH(MENU_ENUM_LABEL_VALUE_XMB_THEME, - "Menüdesign") + "Menü-Design") MSG_HASH(MENU_ENUM_LABEL_VALUE_YES, "Ja") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_ENABLE, - "Aktiviert den Audioausgang.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_LATENCY, - "Gewünschte Audiolatenz in Millisekunden. Je nach Audiotreiber kann die gewünschte Latenz nicht erzielt werden.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, - "Die maximale Änderung der Audioeingangsleistung. " - "Wenn du PAL Cores auf NTSC Monitoren spielen willst, kannst du diesen Wert erhöhen um bessere Timings zu erreichen, " - "als Nebeneffekt kann es zu unechten Tonhöhen kommen.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, - "Audio Stummschalten.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, - "Hilft Fehler bei der Audio- und Videosynchronisierung auszubügeln. " - "Wenn deaktiviert, ist eine brauchbare Synchronisation nahezu unmöglich.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "Einstellungen zur Audioausgabe.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SYNC, - "Synchronisiert Audio. Empfohlen.") -MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Lautstärkeverstärkung in dB.") -MSG_HASH(MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, - "Überprüfe benötigte Firmware bevor versucht wird einen Core zu laden.") +MSG_HASH(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_TWO, + "Shader-Voreinstellungen") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_ENABLE, - "Aktiviert Errungenschaften. " - "Für weitere Informationen, besuche http://retroachievements.org") -MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, - "Deaktiviert Spielstände, Cheats, Zurückspulen, Zeitraffer, Pause, und Zeitlupe für alle Spiele.") + "Aktiviere Errungenschaften. Für weitere Informationen, besuche http://retroachievements.org") MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, - "Aktiviere unoffizielle Errungenschaften und/oder Beta-Features zu Testzwecken.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "Speichert Änderungen in die Konfigurationsdatei beim Beenden.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, - "Ändere die Standardeinstellungen für Konfigurationsdateien.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, - "Verwalte und erstelle Konfigurationsdateien.") -MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, - "Limitiert die Anzahl der Einträge in der Verlaufsliste.") + "Aktiviere inoffizielle Errungenschaften und/oder Beta-Funktionen zu Testzwecken.") +MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, + "Deaktiviert Spielstände, Cheats, Zurückspulen, Zeitraffer, Pause und Zeitlupe für alle Spiele.") +MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, + "Ändere die Treiber, die von diesem System verwendet werden.") +MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, + "Ändere die Einstellungen für Errungenschaften.") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, "Ändere die Einstellungen der Cores.") -MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, - "Ändere das Standardverzeichis für dieses System.") -MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "Ändere Treiber für dieses System.") -MSG_HASH(MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, - "Einige Cores haben ein Herunterfahren-Feature. " - "Wenn aktive, wird der Core davon abgehalten RetroArch herunterzufahren. " - "Stattdessen lädt es einen Dummy-Core.") +MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, + "Ändere die Einstellungen für die Aufnahme-Funktion.") +MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, + "Ändere die Einstellungen für Bildschirm-Overlays, Bildschirmtastatur und Bildschirmbenachrichtigung.") MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "Ändere die Einstellungen für Rückspulen, Zeitraffer, und Zeitlupe.") /* This does not sound like a correct sentence. Suggestions are appreciated. */ + "Ändere die Einstellungen für Zurückspulen, Zeitraffer und Zeitlupe.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, + "Ändere die Einstellungen der Speicherfunktion.") +MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, + "Ändere die Log-Einstellungen.") +MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, + "Ändere die Einstellungen für die Benutzeroberläche.") +MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, + "Konten, Benutzername, Sprache.") +MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, + "Ändere deine Privatsphären-Einstellungen.") +MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, + "Ändere die Standard-Verzeichnisse für dieses System") +MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, + "Ändere die Einstellungen für die Wiedergabelisten.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, + "Ändere die Einstellungen für das Netzwerk.") +MSG_HASH(MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, + "Sucht nach Inhalten und fügt diese zur Datenbank hinzu.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, + "Ändere die Einstellungen der Audio-Ausgabe.") +MSG_HASH(MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, + "Aktiviere oder deaktiviere Bluetooth.") +MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, + "Speichere Änderungen an der Konfigurationsdatei beim Beenden.") +MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, + "Ändere die Standard-Einstellungen für Konfigurationsdateien.") +MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, + "Verwalte und erstelle Konfigurationsdateien.") +MSG_HASH(MENU_ENUM_SUBLABEL_CPU_CORES, + "Anzahl der verfügbaren CPU-Kerne.") MSG_HASH(MENU_ENUM_SUBLABEL_FPS_SHOW, "Zeigt die aktuelle Bildwiederholrate auf dem Bildschirm an.") -MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, - "Erfahre mehr derüber wie Retroarch funktioniert.") -MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, - "Aktiviere Wiedergabeliste für kürzlich geöffnete Medien.") -MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Zeigt Informationen über Core, Netzwerk, und des Systems an. Anzeigen-Manager für Datenbank und Zeiger.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, - "Ermöglicht jedem Spieler das Menü zu benutzen. Wenn deaktiviert, kann nur Spieler 1 das Menü benutzen.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, - "Wie weit ein Analog-Stick bewegt werden muss bis er reagiert.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, - "Anzahl Sekunden bis der nächste Bind abgehandelt wird.") /* @TODO: What is a Bind? */ -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, - "Anzahl Bilder wie lange ein Durchlauf während dem Turbomodus dauert.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, - "Einstellungen der Hotkeys.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, - "Maximale Anzahl Benutzer welche von RetroArch unterstützt werden.") + "Konfiguriere Hotkey-Einstellungen.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, - "Gamepad-Tastenkombination um ins Menü zu gelangen.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, - "Hat Einwirkungen auf die Art wie Eingabeabfragen in RetroArch abgehandelt werden. " - "Werte 'Früh' und 'Spät' kann die Latenz verringern, je nach Konfiguration.") + "Gamepad-Tastenkombination, mit der das Menü aufgerufen wird.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, "Einstellungen für Joypads, Tastaturen und Mäuse.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Anzahl Bilder wie lange der Turbomodus anhält.") -MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, - "Verwende die selbe Steuerung für Menü und Spiele. Betrifft nur Tastatur.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, - "Bedienungseinstellungen dieses Spielers.") + "Steuerung für diesen Benutzer konfigurieren.") MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, "Aktiviere Logging im Terminal.") -MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "Ändere die Logging-Einstellungen.") -MSG_HASH(MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "Stellt die Einstellungen für das Aussehen des Menübildschirms ein.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, - "Hoste eine Netplay Session oder trete einer bei.") + "Hoste eine Netplay-Sitzung oder trete einer bei.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, - "Suche und verbinde mit Netplay Hosts in deinem lokalen Netzwerk.") -MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, - "Ändere die Netzwerkeinstellungen.") + "Suche und verbinde mit Netplay-Hosts in deinem lokalen Netzwerk.") +MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, + "Zeige Informationen über Core, Netzwerk und das System an.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Lade Add-Ons, Komponenten und Inhalte für RetroArch herunter.") -MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "Ändere die Einstellungen des Display-Overlays, Bildschirmtastatur und Bildschirmbenachrichtigung.") /* There is no Translation for display overlay. */ -MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, - "Spiel pausieren wenn das Fenster den Fokus verliert.") -MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "Ändere die Einstellungen der Wiedergabelisten.") -MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, - "Ändere deine Privatsphäreneinstellungen.") -MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Ändere die Einstellungen der Errungenschaften.") -MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "Ändere die Einstellungen der Spielstände.") + "Lade Erweiterungen, Komponenten und Inhalte für RetroArch herunter.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, + "Aktiviere die Netzwerkfreigabe deiner Ordner.") +MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, + "Verwalte Service-Einstellungen deines Betriebssystems.") MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_HIDDEN_FILES, - "Zeigt versteckte Dateien und Ordner im Dateimanager an.") + "Zeige versteckte Dateien und Ordner im Dateimanager an.") +MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, + "Aktiviere Fernzugriff auf die Kommandozeile.") MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, - "Haltet dein System davon ab den Bildschirmschoner zu aktivieren.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "Ändere die Einstellungen der Benutzeroberfläche.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, - "Ändere die Sprache der Oberfläche.") -MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, - "Ändere das Konto, Benutzername, und die Sprache.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, - "Erlaubt Cores die Rotation zu setzen. Wenn deaktiviert, Rotationsanfragen werden ignoriert. Nützlich für Geräte bei denen man die Rotation manuell wählt.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, - "Zeigt ein schwarzes Bild zwischen Frames an. Nützlich für 120 Hz Monitore welche 60 Hz mit weniger 'ghosting' möchten.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, - "Deaktiviere Desktop-Komposition. (Nur bei Windows)") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, - "Zeige Bildschirmbenachrichtigungen an.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, - "Reduziert Latenz, kann aber zu Anzeigefehlern führen. Fügt einen Unterbruch bei V-Sync hinzu (in ms).") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, - "Hartsynchronisierung des CPU und der GPU. Reduziert Latenz, braucht aber mehr Leistung.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, - "Anzahl Bilder welche die CPU der GPU voraus sein darf wenn die 'Hartsynchronisierung' verwendet wird.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, - "Zwingt den Videotreiber explizit einen bestimmten Puffer zu verwenden.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, - "Wählt den Monitor aus welcher RetroArch anzeigen soll.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, - "Vertikale Bildwiederholrate des Monitors. " - "Wird verwendet um die passende Audioinputrate zu berechnen. " - "WICHTIG: Diese Option wird ignoriert wenn du 'Threaded Video' aktiviert hast.") /* TODO: Any way to inject the reference in the .h file? */ -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, - "Die genau geschätzte Bildwiederholrate des Monitors in Hz.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "Einstellungen zur Videoausgabe.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, - "Gibt hardware-gerendered Cores einen eigenen privaten Kontext. Vermeided den Hardware-State anzunehmen zwischen den Frames.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_THREADED, - "Verbessert die Leistung, führt aber zu grösserer Latenz und Videoproblemen. " - "Verwende dies nur wenn du sonst die gewünschte Leistung erbringst.") -MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VSYNC, - "Synchronisiert den Video-Output der Grafikkarte zu der Bildwiederholrate des Monitors. Empfohlen.") + "Hält dein System davon ab, den Bildschirmschoner zu aktivieren.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_SCALE, - "Setzt die Fenstergrösse relativ zu der Core-Fenstergrösse. " - "Alternativ kannst du die Fenstergrösse weiter unten setzten für eine konstante Grösse.") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, - "Zurück") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, - "Bestätigen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "Info") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, - "Runter Scrollen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, - "Hoch Scrollen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, - "Starten") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, - "Tastatur ein/aus") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "Menü ein/aus") -MSG_HASH(MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, - "Beenden") + "Legt die Fenstergröße relativ zu der Core-Bildgröße fest. Alternativ kannst Du weiter unten die Höhe und Breite des Bildes selbst anpassen.") +MSG_HASH(MENU_ENUM_SUBLABEL_USER_LANGUAGE, + "Legt die Sprache der Benutzeroberfläche fest.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_BLACK_FRAME_INSERTION, + "Fügt ein schwarzes Bild zwischen Einzelbildern ein. Nützlich für Benutzer von 120Hz-Monitoren, die 60Hz mit weniger 'ghosting' wünschen.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, + "Reduziert Latenz, kann aber zu Anzeigefehlern führen. Fügt eine Verzögerung bei V-Sync hinzu (in ms).") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC_FRAMES, + "Anzahl der Bilder, der die CPU der GPU voraus sein darf, wenn die CPU/GPU-Synchronisation aktiviert ist.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, + "Zwingt den Videotreiber dazu, einen bestimmten Framebuffer zu verwenden.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, + "Wält den Bildschirm aus, der für RetroArch verwendet wird.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, + "Die geschätzte Bildwiederholrate des Bildschirms in Hz.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, + "Einstellungen für die Videoausgabe anpassen.") +MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, + "Sucht nach drahtlosen Netzwerken und stellt eine Verbindung her.") +MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, + "Erfahre mehr darüber, wie Retroarch funktioniert.") +MSG_HASH(MSG_APPENDED_DISK, + "Datenträger hinzufügen") +MSG_HASH(MSG_APPLICATION_DIR, + "Anwendungen") +MSG_HASH(MSG_APPLYING_CHEAT, + "Änderungen übernehmen.") +MSG_HASH(MSG_APPLYING_SHADER, + "Shader anwenden") +MSG_HASH(MSG_AUDIO_MUTED, + "Audio stummgeschaltet.") +MSG_HASH(MSG_AUDIO_UNMUTED, + "Audio laut.") +MSG_HASH(MSG_AUTOCONFIG_FILE_ERROR_SAVING, + "Speichern der Autokonfigurations-Datei fehlgeschlagen.") +MSG_HASH(MSG_AUTOCONFIG_FILE_SAVED_SUCCESSFULLY, + "Autokonfigurations-Datei erfolgreich gespeichert.") +MSG_HASH(MSG_AUTOSAVE_FAILED, + "Initialisierung der Autospeichern-Funktion fehlgeschlagen.") +MSG_HASH(MSG_AUTO_SAVE_STATE_TO, + "Spielstand automatisch speichern in") +MSG_HASH(MSG_BLOCKING_SRAM_OVERWRITE, + "Überschreiben des SRAM blockieren") +MSG_HASH(MSG_BRINGING_UP_COMMAND_INTERFACE_ON_PORT, + "Starte Befehlsinterface auf Port") +MSG_HASH(MSG_BYTES, + "Bytes") +MSG_HASH(MSG_CANNOT_INFER_NEW_CONFIG_PATH, + "Kann neuen Konfigurationspfad nicht ableiten. Verwende aktuelle Zeit.") /* huh?*/ +MSG_HASH(MSG_CHEEVOS_HARDCORE_MODE_ENABLE, + "Hardcore-Modus aktiviert. Spielstände & die Rückspul-Funktion wurden ausgeschaltet.") +MSG_HASH(MSG_COMPARING_WITH_KNOWN_MAGIC_NUMBERS, + "Vergleiche mit bekannten Magic Numbers...") +MSG_HASH(MSG_COMPILED_AGAINST_API, + "Kompiliert gegen API") +MSG_HASH(MSG_CONFIG_DIRECTORY_NOT_SET, + "Konfigurations-Verzeichnis nicht definiert. Kann neue Konfiguration nicht speichern.") +MSG_HASH(MSG_CONNECTED_TO, + "Verbunden mit") +MSG_HASH(MSG_CONTENT_CRC32S_DIFFER, + "CRC32-Prüfsummen des Inhalts weichen ab. Andere Spiele können nicht verwendet werden.") +MSG_HASH(MSG_CONTENT_LOADING_SKIPPED_IMPLEMENTATION_WILL_DO_IT, + "Laden des Inhalts übersprungen. Die Implementierung wird ihn selbst laden.") +MSG_HASH(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES, + "Core unterstützt keine Spielstände.") +MSG_HASH(MSG_CORE_OPTIONS_FILE_CREATED_SUCCESSFULLY, + "Core-Optionsdatei wurde erfolgreich erstellt.") +MSG_HASH(MSG_COULD_NOT_FIND_ANY_NEXT_DRIVER, + "Konnte keinen nächsten Treiber finden") +MSG_HASH(MSG_COULD_NOT_FIND_COMPATIBLE_SYSTEM, + "Konnte kein kompatibles System finden") +MSG_HASH(MSG_COULD_NOT_FIND_VALID_DATA_TRACK, + "Konnte keinen gültigen Daten-Track finden") +MSG_HASH(MSG_COULD_NOT_OPEN_DATA_TRACK, + "Konnte Daten-Track nicht öffnen") +MSG_HASH(MSG_COULD_NOT_READ_CONTENT_FILE, + "Konnte Inhalts-Datei nicht lesen") +MSG_HASH(MSG_COULD_NOT_READ_MOVIE_HEADER, + "Konnte Film-Header nicht lesen.") +MSG_HASH(MSG_COULD_NOT_READ_STATE_FROM_MOVIE, + "Konnte Status der Filmdatei nicht lesen.") +MSG_HASH(MSG_CRC32_CHECKSUM_MISMATCH, + "CRC32-Prüfsumme des Inhalts und die gespeicherte Prüfsumme der Replay-Datei stimmen nicht überein. Wird die Aufzeichnung wiedergegeben, wird sie sehr wahrscheinlich asynchron.") +MSG_HASH(MSG_CUSTOM_TIMING_GIVEN, + "Benutzerdefiniertes Timing gefunden") +MSG_HASH(MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, + "Dekompression läuft bereits.") +MSG_HASH(MSG_DECOMPRESSION_FAILED, + "Dekompression fehlgeschlagen.") +MSG_HASH(MSG_DETECTED_VIEWPORT_OF, + "Erkannte Bildbereich von") +MSG_HASH(MSG_DID_NOT_FIND_A_VALID_CONTENT_PATCH, + "Kein gültiger Patch für diesen Inhalt gefunden.") +MSG_HASH(MSG_DISCONNECT_DEVICE_FROM_A_VALID_PORT, + "Gerät von einem gültigen Anschluss trennen.") +MSG_HASH(MSG_DISK_CLOSED, + "Geschlossen") +MSG_HASH(MSG_DISK_EJECTED, + "Ausgeworfen") +MSG_HASH(MSG_DOWNLOADING, + "Herunterladen von") +MSG_HASH(MSG_DOWNLOAD_FAILED, + "Herunterladen fehlgeschlagen") +MSG_HASH(MSG_ERROR, + "Fehler") +MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_CONTENT, + "Libretro-Core benötigt Inhalt, es wurde jedoch keiner bereitgestellt.") +MSG_HASH(MSG_ERROR_LIBRETRO_CORE_REQUIRES_SPECIAL_CONTENT, + "Libretro-Core benötigt speziellen Inhalt, es wurde jedoch keiner bereitgestellt.") +MSG_HASH(MSG_ERROR_PARSING_ARGUMENTS, + "Fehler beim Verarbeiten der Argumente.") +MSG_HASH(MSG_ERROR_SAVING_CORE_OPTIONS_FILE, + "Fehler beim Speichern der Core-Optionen") +MSG_HASH(MSG_ERROR_SAVING_REMAP_FILE, + "Fehler beim Speichern der Tasten-Umbelegung.") +MSG_HASH(MSG_ERROR_SAVING_SHADER_PRESET, + "Fehler beim Speichern der Shader-Voreinstellungen.") +MSG_HASH(MSG_EXTERNAL_APPLICATION_DIR, + "Externe Anwendungen") +MSG_HASH(MSG_EXTRACTING, + "Entpacke") +MSG_HASH(MSG_EXTRACTING_FILE, + "Entpacke Datei") +MSG_HASH(MSG_FAILED_SAVING_CONFIG_TO, + "Fehler beim Speichern der Konfiguration in") +MSG_HASH(MSG_FAILED_TO, + "Fehler beim") +MSG_HASH(MSG_FAILED_TO_ACCEPT_INCOMING_SPECTATOR, + "Ankommender Beobachter konnte nicht akzeptiert werden.") +MSG_HASH(MSG_FAILED_TO_ALLOCATE_MEMORY_FOR_PATCHED_CONTENT, + "Fehler beim zuweisen des Arbeitsspeichers für den gepatchten Inhalt...") +MSG_HASH(MSG_FAILED_TO_APPLY_SHADER, + "Fehler beim Anwenden des Shaders.") +MSG_HASH(MSG_FAILED_TO_BIND_SOCKET, + "Fehler beim binden des Sockets.") +MSG_HASH(MSG_FAILED_TO_CREATE_THE_DIRECTORY, + "Fehler beim Erstellen des Verzeichnisses.") +MSG_HASH(MSG_FAILED_TO_EXTRACT_CONTENT_FROM_COMPRESSED_FILE, + "Fehler beim Entpacken des Inhalts aus dem Archiv") +MSG_HASH(MSG_FAILED_TO_GET_NICKNAME_FROM_CLIENT, + "Benutzername konnte vom Client nicht gelesen werden.") +MSG_HASH(MSG_FAILED_TO_LOAD, + "Laden fehlgeschlagen") +MSG_HASH(MSG_FAILED_TO_LOAD_CONTENT, + "Laden des Inhalts fehlgeschlagen") +MSG_HASH(MSG_FAILED_TO_LOAD_MOVIE_FILE, + "Laden der Filmdatei fehlgeschlagen") +MSG_HASH(MSG_FAILED_TO_LOAD_OVERLAY, + "Laden des Overlays fehlgeschlagen.") +MSG_HASH(MSG_FAILED_TO_LOAD_STATE, + "Fehler beim Laden des Spielstands von") +MSG_HASH(MSG_FAILED_TO_OPEN_LIBRETRO_CORE, + "Öffnen des Libretro-Cores fehlgeschlagen") +MSG_HASH(MSG_FAILED_TO_PATCH, + "Patch fehlgeschlagen") +MSG_HASH(MSG_FAILED_TO_RECEIVE_HEADER_FROM_CLIENT, + "Header konnte nicht vom Client empfangen werden.") +MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME, + "Empfangen des Nickname fehlgeschlagen.") +MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_FROM_HOST, + "Empfangen des Nickname vom Host fehlgeschlagen.") +MSG_HASH(MSG_FAILED_TO_RECEIVE_NICKNAME_SIZE_FROM_HOST, + "Länge des Nickname wurde vom Host nicht empfangen.") +MSG_HASH(MSG_FAILED_TO_RECEIVE_SRAM_DATA_FROM_HOST, + "SRAM-Daten wurden vom Host nicht empfangen.") +MSG_HASH(MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY, + "Auswerfen des Datenträgers fehlgeschlagen.") +MSG_HASH(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE, + "Fehler beim entfernen der temporären Datei") +MSG_HASH(MSG_FAILED_TO_SAVE_SRAM, + "Fehler beim Speichern des SRAM") +MSG_HASH(MSG_FAILED_TO_SAVE_STATE_TO, + "Fehler beim Speichern des Spielstands in") +MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME, + "Fehler beim Senden des Nickname.") +MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_SIZE, + "Fehler beim Senden der Nickname-Länge.") +MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_CLIENT, + "Fehler beim Senden des Nickname zum Client.") +MSG_HASH(MSG_FAILED_TO_SEND_NICKNAME_TO_HOST, + "Fehler beim Senden des Nickname zum Host.") +MSG_HASH(MSG_FAILED_TO_SEND_SRAM_DATA_TO_CLIENT, + "Fehler beim Senden der SRAM-Daten zum Client.") +MSG_HASH(MSG_FAILED_TO_START_AUDIO_DRIVER, + "Audiotreiber konnte nicht gestartet werden. Fahre ohne Audio fort.") +MSG_HASH(MSG_FAILED_TO_START_MOVIE_RECORD, + "Konnte Film-Aufzeichnung nicht starten.") +MSG_HASH(MSG_FAILED_TO_START_RECORDING, + "Konnte Aufzeichnung nicht starten.") +MSG_HASH(MSG_FAILED_TO_TAKE_SCREENSHOT, + "Konnte Bildschirmfoto nicht erstellen.") +MSG_HASH(MSG_FAILED_TO_UNDO_LOAD_STATE, + "Laden des Spielstands konnte nicht rückgängig gemacht werden.") +MSG_HASH(MSG_FAILED_TO_UNDO_SAVE_STATE, + "Speichern des Spielstands konnte nicht rückgängig gemacht werden.") +MSG_HASH(MSG_FAILED_TO_UNMUTE_AUDIO, + "Audio konnte nicht lautgeschaltet werden.") +MSG_HASH(MSG_FATAL_ERROR_RECEIVED_IN, + "Fataler Fehler in") +MSG_HASH(MSG_FILE_NOT_FOUND, + "Datei nicht gefunden") +MSG_HASH(MSG_FOUND_AUTO_SAVESTATE_IN, + "Spielstand gefunden in") +MSG_HASH(MSG_FOUND_DISK_LABEL, + "Datenträger-Label gefunden") +MSG_HASH(MSG_FOUND_FIRST_DATA_TRACK_ON_FILE, + "Ersten Daten-Track in der Datei gefunden") +MSG_HASH(MSG_FOUND_LAST_STATE_SLOT, + "Letzten Speicherplatz gefunden") +MSG_HASH(MSG_FOUND_SHADER, + "Shader gefunden") +MSG_HASH(MSG_FRAMES, + "Bilder") +MSG_HASH(MSG_GAME_SPECIFIC_CORE_OPTIONS_FOUND_AT, + "Spieloptionen: Spielspezifische Core-Optionen gefunden in") +MSG_HASH(MSG_GOT_INVALID_DISK_INDEX, + "Ungültiger Datenträger-Index.") +MSG_HASH(MSG_GRAB_MOUSE_STATE, + "Maus-Status") +MSG_HASH(MSG_GAME_FOCUS_ON, + "Spielfokus ein") +MSG_HASH(MSG_GAME_FOCUS_OFF, + "Spielfokus aus") +MSG_HASH(MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING, + "Der Libretro-Core ist Hardware-gerendert. GPU-Aufzeichnung muss ebenfalls aktiviert werden.") +MSG_HASH(MSG_INFLATED_CHECKSUM_DID_NOT_MATCH_CRC32, + "Prüfsumme entspricht nicht CRC32.") +MSG_HASH(MSG_INPUT_CHEAT, + "Cheat eingeben") +MSG_HASH(MSG_INPUT_CHEAT_FILENAME, + "Cheat-Dateiname") +MSG_HASH(MSG_INPUT_PRESET_FILENAME, + "Vorlagen-Dateiname") +MSG_HASH(MSG_INTERFACE, + "Netzwerk-Karte") +MSG_HASH(MSG_INTERNAL_STORAGE, + "Interner Speicher") +MSG_HASH(MSG_REMOVABLE_STORAGE, + "Wechseldatenträger") +MSG_HASH(MSG_INVALID_NICKNAME_SIZE, + "Ungültige Nickname-Länge.") +MSG_HASH(MSG_IN_BYTES, + "in Bytes") +MSG_HASH(MSG_IN_GIGABYTES, + "in Gigabyte") +MSG_HASH(MSG_IN_MEGABYTES, + "in Megabyte") +MSG_HASH(MSG_LIBRETRO_ABI_BREAK, + "ist gegen eine andere libretro-Version als diese kompiliert.") +MSG_HASH(MSG_LIBRETRO_FRONTEND, + "Frontend für libretro") +MSG_HASH(MSG_LOADED_STATE_FROM_SLOT, + "Spielstand aus Speicherplatz #%d geladen.") +MSG_HASH(MSG_LOADED_STATE_FROM_SLOT_AUTO, + "Spielstand aus Speicherplatz #-1 (auto) geladen.") +MSG_HASH(MSG_LOADING, + "Laden...") +MSG_HASH(MSG_FIRMWARE, + "Eine oder mehrere Firmware-Dateien fehlen") +MSG_HASH(MSG_LOADING_CONTENT_FILE, + "Lade Inhalts-Datei") +MSG_HASH(MSG_LOADING_HISTORY_FILE, + "Lade Verlaufs-Datei") +MSG_HASH(MSG_LOADING_STATE, + "Lade Spielstand") +MSG_HASH(MSG_MEMORY, + "Speicher") +MSG_HASH(MSG_MOVIE_FILE_IS_NOT_A_VALID_BSV1_FILE, + "Filmdatei ist keine gültige BSV1-Datei.") +MSG_HASH(MSG_MOVIE_FORMAT_DIFFERENT_SERIALIZER_VERSION, + "Filmdatei besitzt offenbar eine andere Serializer-Version. Wird höchstwahrscheinlich fehlschlagen.") +MSG_HASH(MSG_MOVIE_PLAYBACK_ENDED, + "Film-Wiedergabe beendet.") +MSG_HASH(MSG_MOVIE_RECORD_STOPPED, + "Beende Film-Aufzeichnung.") +MSG_HASH(MSG_NETPLAY_FAILED, + "Netplay-Initialisierung fehlgeschlagen.") +MSG_HASH(MSG_NO_CONTENT_STARTING_DUMMY_CORE, + "Kein Inhalt, starte Dummy-Core.") +MSG_HASH(MSG_NO_SAVE_STATE_HAS_BEEN_OVERWRITTEN_YET, + "Kein Spielstand wurde bis jetzt überschrieben.") +MSG_HASH(MSG_NO_STATE_HAS_BEEN_LOADED_YET, + "Kein Spielstand wurde bis jetzt geladen.") +MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, + "Fehler beim Speichern der Überschreibungen.") +MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, + "Überschreibungen erfolgreich gespeichert.") +MSG_HASH(MSG_PAUSED, + "Pausiert.") +MSG_HASH(MSG_PROGRAM, + "RetroArch") +MSG_HASH(MSG_READING_FIRST_DATA_TRACK, + "Lese ersten Daten-Track...") +MSG_HASH(MSG_RECEIVED, + "empfangen") +MSG_HASH(MSG_RECORDING_TERMINATED_DUE_TO_RESIZE, + "Aufzeichnung wurde wegen Größenänderung beendet.") +MSG_HASH(MSG_RECORDING_TO, + "Aufzeichen in") +MSG_HASH(MSG_REDIRECTING_CHEATFILE_TO, + "Cheat-Datei umleiten in") +MSG_HASH(MSG_REDIRECTING_SAVEFILE_TO, + "Speicherdaten umleiten in") +MSG_HASH(MSG_REDIRECTING_SAVESTATE_TO, + "Spielstand umleiten in") +MSG_HASH(MSG_REMAP_FILE_SAVED_SUCCESSFULLY, + "Remap-Datei wurde erfolgreich gespeichert.") +MSG_HASH(MSG_REMOVED_DISK_FROM_TRAY, + "Datenträger aus Laufwerk entfernt.") +MSG_HASH(MSG_REMOVING_TEMPORARY_CONTENT_FILE, + "Entferne temporäre Inhalts-Datei") +MSG_HASH(MSG_RESET, + "Zurücksetzen") +MSG_HASH(MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT, + "Starte Aufzeichnung neu, da Treiber reinitialisiert wurde.") +MSG_HASH(MSG_RESTORED_OLD_SAVE_STATE, + "Alter Spielstand wiederhergestellt") +MSG_HASH(MSG_RESTORING_DEFAULT_SHADER_PRESET_TO, + "Shader: Standard-Shader-Voreinstellung wiederhergestellt zu") +MSG_HASH(MSG_REVERTING_SAVEFILE_DIRECTORY_TO, + "Setze Speicherdaten-Verzeichnis zurück auf") +MSG_HASH(MSG_REVERTING_SAVESTATE_DIRECTORY_TO, + "Setze Spielstand-Verzeichnis zurück auf") +MSG_HASH(MSG_REWINDING, + "Zurückspulen.") +MSG_HASH(MSG_REWIND_INIT, + "Initialisiere Rückspul-Puffer mit Größe") +MSG_HASH(MSG_REWIND_INIT_FAILED, + "Fehler beim Initialisieren des Rückspul-Puffers. Zurückspulen wird deaktiviert.") +MSG_HASH(MSG_REWIND_INIT_FAILED_THREADED_AUDIO, + "Implementierung verwendet separaten Audio-Thread. Zurückspulen kann nicht verwendet werden.") +MSG_HASH(MSG_REWIND_REACHED_END, + "Ende des Rückspul-Puffers erreicht.") +MSG_HASH(MSG_SAVED_NEW_CONFIG_TO, + "Neue Konfiguration gespeichert in") +MSG_HASH(MSG_SAVED_STATE_TO_SLOT, + "Spielstand in Speicherplatz #%d gespeichert.") +MSG_HASH(MSG_SAVED_STATE_TO_SLOT_AUTO, + "Spielstand in Speicherplatz #-1 (auto) gespeichert.") +MSG_HASH(MSG_SAVED_SUCCESSFULLY_TO, + "Erfolgreich gespeichert in") +MSG_HASH(MSG_SAVING_RAM_TYPE, + "Speichere RAM-Typ") +MSG_HASH(MSG_SAVING_STATE, + "Speichere Spielstand") /* more context needed */ +MSG_HASH(MSG_SCANNING, + "Durchsuchen") +MSG_HASH(MSG_SCANNING_OF_DIRECTORY_FINISHED, + "Durchsuchen des Verzeichnisses beendet") +MSG_HASH(MSG_SENDING_COMMAND, + "Sende Befehl") +MSG_HASH(MSG_SEVERAL_PATCHES_ARE_EXPLICITLY_DEFINED, + "Mehrere Patches wurden explizit definiert, ignoriere alle...") +MSG_HASH(MSG_SHADER, + "Shader") +MSG_HASH(MSG_SHADER_PRESET_SAVED_SUCCESSFULLY, + "Shader-Voreinstellung erfolgreich gespeichert.") +MSG_HASH(MSG_SKIPPING_SRAM_LOAD, + "Überspringe Laden des SRAM.") +MSG_HASH(MSG_SLOW_MOTION, + "Zeitlupe.") +MSG_HASH(MSG_SLOW_MOTION_REWIND, + "In Zeitlupe zurückspulen.") +MSG_HASH(MSG_SRAM_WILL_NOT_BE_SAVED, + "SRAM wird nicht gespeichert.") +MSG_HASH(MSG_STARTING_MOVIE_PLAYBACK, + "Starte Film-Wiedergabe.") +MSG_HASH(MSG_STARTING_MOVIE_RECORD_TO, + "Starte Film-Aufzeichnung in") +MSG_HASH(MSG_STATE_SIZE, + "Spielstand-Größe") +MSG_HASH(MSG_STATE_SLOT, + "Spielstand-Speicherplatz") +MSG_HASH(MSG_TAKING_SCREENSHOT, + "Erstelle Bildschirmfoto.") +MSG_HASH(MSG_TO, + "nach") +MSG_HASH(MSG_UNDID_LOAD_STATE, + "Laden des Spielstands wurde rückgängig gemacht.") +MSG_HASH(MSG_UNDOING_SAVE_STATE, + "Speichern des Spielstands wurde rückgängig gemacht.") +MSG_HASH(MSG_UNKNOWN, + "Unbekannt") +MSG_HASH(MSG_UNPAUSED, + "Nicht pausiert.") +MSG_HASH(MSG_UNRECOGNIZED_COMMAND, + "Unbekannter Befehl") +MSG_HASH(MSG_USING_CORE_NAME_FOR_NEW_CONFIG, + "Verwende Core-Namen für neue Konfiguration.") +MSG_HASH(MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED, + "Verwende libretro-Dumy-Core. Überspringe Aufzeichnung.") +MSG_HASH(MSG_VALUE_CONNECT_DEVICE_FROM_A_VALID_PORT, + "Verbinde Gerät mit einem gültigen Anschluss.") /* sounds odd, maybe improper translation*/ +MSG_HASH(MSG_VALUE_DISCONNECTING_DEVICE_FROM_PORT, + "Trenne Gerät von Anschluss") +MSG_HASH(MSG_VALUE_REBOOTING, + "Neustart...") +MSG_HASH(MSG_VALUE_SHUTTING_DOWN, + "Beenden...") +MSG_HASH(MSG_VERSION_OF_LIBRETRO_API, + "Version der libretro-API") +MSG_HASH(MSG_VIEWPORT_SIZE_CALCULATION_FAILED, + "Berechnung der Bildgröße fehlgeschlagen! Wird unter Verwendung von Rohdaten fortfahren. Dies wird wahrscheinlich nicht richtig funktionieren ...") +MSG_HASH(MSG_VIRTUAL_DISK_TRAY, + "Virtuelle Laufwerksschublade.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_LATENCY, + "Gewünschte Audiolatenz in Millisekunden. Je nach Audiotreiber kann die gewünschte Latenz nicht erzielt werden; diese Einstellung wird dann ignoriert.") +MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, + "Audio stumm-/lautschalten.") +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RATE_CONTROL_DELTA, + "Hilft Fehler bei der Audio- und Videosynchronisierung auszubügeln. Wenn deaktiviert, ist eine brauchbare Synchronisation nahezu unmöglich." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CAMERA_ALLOW, + "Erlaube oder verbiete den Cores Zugriff auf die Kamera." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOCATION_ALLOW, + "Erlaube oder verbiete den Cores Zugriff auf Ortsdienste." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_MAX_USERS, + "Maximale Anzahl von Benutzern, die von RetroArch unterstützt werden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_POLL_TYPE_BEHAVIOR, + "Beeinflusst, wie die Eingabe in RetroArch abgefragt wird. Wird dieser Wert auf 'Früh' oder 'Spät' gesetzt, kann sich je nach Konfiguration die Latenz verringern." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_ALL_USERS_CONTROL_MENU, + "Ermöglicht jedem Benutzer das Menü zu benutzen. Wenn deaktiviert, kann nur Benutzer 1 das Menü benutzen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_VOLUME, + "Lautstärkeverstärkung in dB. 0 dB ist die normale Lautstärke, es erfolgt eine Verstärkung." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_SYNC, + "Synchronisiere Audio. Empfohlen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_AXIS_THRESHOLD, + "Wie weit ein Analog-Stick bewegt werden muss, bis er reagiert." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_BIND_TIMEOUT, + "Zeitdauer in Sekunden, nach der die nächste Tastenbelegung abgefragt wird." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, + "Beschreibt, nach wie vielen Einzelbildern eine Taste mit aktiviertem Turbo-Modus erneut gedrückt wird." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, + "Beschreibt, wie lange eine Taste mit aktivierem Turbo-Modus 'gedrückt' wird. Dieser Wert wird in der Anzahl der Einzelbilder angegeben." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_VSYNC, + "Synchronisiert die Video-Ausgabe der Grafikkarte mit der Bildwiederholrate des Bildschirms. Empfohlen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ALLOW_ROTATE, + "Erlaubt Cores, die Bildrotation zu setzen. Wenn deaktiviert, werden Anfragen nach der Bildrotation deaktiviert. Nützlich für Bildschirme, die manuell gedreht werden sollen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DUMMY_ON_CORE_SHUTDOWN, + "Einige Cores haben eine eigene Abschalt-Funktion. Wenn aktiviert, wird der Core daran gehindert, RetroArch zu beenden. Stattdessen wird ein Dummy-Core geladen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHECK_FOR_MISSING_FIRMWARE, + "Überprüft, ob eventuell benötigte Firmware vorhanden ist, bevor versucht wird, Inhalte zu laden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE, + "Vertikale Bildwiederholrate des Bildschirms. Wird verwendet, um eine geeignete Audio-Eingangsrate zu berechnen. Hinweis: Wird ignoriert, wenn 'Video in separatem Thread' aktiviert ist." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_ENABLE, + "Aktiviere Audio-Ausgabe." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, + "Maximale Änderung der Audio-Eingangsrate. Dieser Wert kann erhöht werden, wenn sehr große Änderungen im Timing aktiviert werden sollen, (beispielsweise um einen PAL-Core auf einem NTSC-Bildschirm darzustellen), verursacht jedoch fehlerhafte Tonhöhen." + ) +MSG_HASH( + MSG_FAILED, + "fehlgeschlagen" + ) +MSG_HASH( + MSG_SUCCEEDED, + "erfolgreich" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED, + "nicht konfiguriert" + ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "nicht konfiguriert, verwende Rückfalloption" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, + "Datenbank-Suchanfragen" /* might be inaccurate */ + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DEVELOPER, + "Datenbank - Filter : Entwickler" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PUBLISHER, + "Datenbank - Filter : Publisher" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DISABLED, + "Deaktiviert" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_ENABLED, + "Aktiviert" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_PATH, + "Pfad zur Verlaufsliste" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ORIGIN, + "Datenbank - Filter : Herkunft") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_FRANCHISE, + "Datenbank - Filter : Franchise") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ESRB_RATING, + "Datenbank - Filter : ESRB-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_ELSPA_RATING, + "Datenbank - Filter : ELSPA-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_PEGI_RATING, + "Datenbank - Filter : PEGI-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_CERO_RATING, + "Datenbank - Filter : CERO-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_BBFC_RATING, + "Datenbank - Filter : BBFC-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_MAX_USERS, + "Datenbank - Filter : Max. Spieler") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_MONTH, + "Datenbank - Filter : Veröffentlichungsdatum nach Monat") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_RELEASEDATE_BY_YEAR, + "Datenbank - Filter : Veröffentlichungsdatum nach Jahr") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_ISSUE, + "Datenbank - Filter : Edge Magazine-Ausgabe") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_EDGE_MAGAZINE_RATING, + "Datenbank - Filter : Edge Magazine-Bewertung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST_ENTRY_DATABASE_INFO, + "Datenbank-Informationen") +MSG_HASH(MSG_WIFI_SCAN_COMPLETE, + "Suche nach WLAN-Netzwerken abgeschlossen.") +MSG_HASH(MSG_SCANNING_WIRELESS_NETWORKS, + "Suche nach WLAN-Netzwerken...") +MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, + "Netplay-Suche abgeschlossen.") +MSG_HASH(MSG_NETPLAY_LAN_SCANNING, + "Suche nach Netplay-Hosts...") +MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, + "Pausiere das Spiel, wenn RetroArch nicht das aktive Fenster ist.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, + "Aktiviere oder deaktiviere Desktop-Gestaltung (nur Windows).") +MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, + "Aktiviere Wiedergabeliste für kürzlich geöffnete Inhalte.") +MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_HISTORY_SIZE, + "Begrenzt die Anzahl der Einträge in der Verlaufsliste.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_INPUT_UNIFIED_MENU_CONTROLS, + "Einheitliche Menüsteuerung") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_UNIFIED_MENU_CONTROLS, + "Verwende die selbe Steuerung für das Menü und die Spiele. Betrifft nur Tastatur.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_ENABLE, + "Zeige Bildschirmbenachrichtungen an.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETWORK_USER_REMOTE_ENABLE, + "Aktiviere Fernsteuerung für Benutzer %d") MSG_HASH(MENU_ENUM_LABEL_VALUE_BATTERY_LEVEL_ENABLE, - "Batteriestand anzeigen") -MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "Lade inhaltsspezifische Core-Optionen automatisch") + "Akkustand anzeigen") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FILE, + "Wähle Datei") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SELECT_FROM_COLLECTION, + "Wähle aus Sammlung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_FILTER, + "Filter") +MSG_HASH(MENU_ENUM_LABEL_VALUE_SCALE, + "Skalierung") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_START_WHEN_LOADED, + "Netplay wird gestartet, sobald ein Inhalt geladen wurde.") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_LOAD_CONTENT_MANUALLY, + "Konnte keinen geeigneten Core oder Inhalt finden, lade manuell.") MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL_LIST, - "Browse URL" + "Besuche URL" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_URL, - "URL Path" + "URL-Pfad" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BROWSE_START, @@ -1321,21 +2394,557 @@ MSG_HASH( ) MSG_HASH(MENU_ENUM_LABEL_VALUE_SHADER_PIPELINE_BOKEH, "Bokeh") -MSG_HASH(MSG_DOWNLOADING, - "Herunterladen") -MSG_HASH(MSG_DOWNLOAD_FAILED, - "Herunterladen fehlgeschlagen") -MSG_HASH(MSG_ERROR, - "Fehler") -MSG_HASH(MSG_EXTRACTING, - "Extrahiere") -MSG_HASH(MSG_EXTRACTING_FILE, - "Extrahiere Datei") -MSG_HASH(MSG_OVERRIDES_ERROR_SAVING, - "Fehler beim Speichern der Überschreibungen.") -MSG_HASH(MSG_OVERRIDES_SAVED_SUCCESSFULLY, - "Überschreibungen wurden erfolgreich gespeichert.") -MSG_HASH(MSG_SCANNING, - "Durchsuche") /* Used for displaying progress */ -MSG_HASH(MSG_SCANNING_OF_DIRECTORY_FINISHED, - "Durchsuchen des Verzeichnisses wurde beendet.") \ No newline at end of file +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS, + "Aktualisieren") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, + "Nickname: %s") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_COMPAT_CONTENT_FOUND, + "Kompatibler Inhalt gefunden") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_CROP_OVERSCAN, + "Schneidet ein paar Pixel an den Bildrändern ab, die üblicherweise von Entwicklern leer gelassen werden und manchmal auch fehlerhafte Pixel enthalten.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SMOOTH, + "Wendet einen leichten Weichzeichner auf das Bild an, um die Pixelkanten etwas abzurunden. Diese Option hat einen sehr geringen Einfluss auf die Leistung.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FILTER, + "Wendet einen CPU-Videofilter an. HINWEIS: Kann hohe Leistungseinbußen verursachen. Manche Videofilter funktionieren nur mit Cores, die eine Farbtiefe von 32 Bit oder 16 Bit verwenden.") +MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, + "Gib den Benutzernamen deines Errungenschaften-Kontos ein.") +MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, + "Gib das Passwort deines Errungenschaften-Kontos ein.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, + "Gib deinen Benutzernamen hier ein. Dieser wird unter anderem für Netplay-Sitzungen verwendet.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, + "Zeichnet das Bild auf, nachdem Filter (aber keine Shader) angewendet wurden. Dein Video wird genauso gut aussehen, wie das, was Du auf dem Bildschirm siehst.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_LIST, + "Wähle, welcher Core verwendet werden soll.") +MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, + "Wähle, welcher Inhalt gestartet werden soll.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, + "Zeige Netzwerk-Karten und zugewiesene IP-Adressen.") +MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, + "Zeige Informationen über dieses Gerät an.") +MSG_HASH(MENU_ENUM_SUBLABEL_QUIT_RETROARCH, + "Verlasse das Programm.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_WIDTH, + "Wähle die Fensterbreite. Wird dieser Wert auf 0 belassen, wird versucht, das Fenster so groß wie möglich zu skalieren.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_WINDOW_HEIGHT, + "Wähle die Fensterhöhe. Wird dieser Wert auf 0 belassen, wird versucht, das Fenster so groß wie möglich zu skalieren.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_X, + "Wähle eine eigene X-Achsenposition für Bildschirmmeldungen.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, + "Wähle eine eigene Y-Achsenposition für Bildschirmmeldungen.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_SIZE, + "Wähle die Schriftgröße in Punkten.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_OVERLAY_HIDE_IN_MENU, + "Verberge das Overlay im Menü und zeige es wieder an, wenn das Menü verlassen wird.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, + "Durchsuchter Inhalt wird hier erscheinen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, + "Skaliere das Bild in ganzzahligen Schritten. Die Basisgröße hängt von der vom System gemeldeten Geometrie und dem Seitenverhältnis ab. Wenn 'Seitenverhältnis erzwingen' nicht gewählt ist, werden Höhe u. Breite unabhängig skaliert." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT, + "Verwende Bildmaterial nach Shaderdurchläufen für Bildschirmfotos, sofern verfügbar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_ROTATION, + "Erzwinge eine bestimmte Bildrotation. Diese Rotation wird Rotationen hinzugefügt, die vom Core vorgegeben werden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FORCE_SRGB_DISABLE, + "Erzwinge die Deaktivierung der Unterstützung für sRGB FBO. Einige Intel OpenGL-Treiber können unter Windows Probleme verursachen, wenn sRGB FBO aktiviert ist. Diese Einstellung kann dies beheben." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN, + "Starte im Vollbildmodus. Kann zur Laufzeit geändert werden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN, + "Bevorzuge einen Fenster-Vollbildmodus für den Vollbildmodus." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_GPU_RECORD, + "Verwende Bildmaterial nach Shaderdurchläufen für Aufnahmen, sofern verfügbar." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, + "Wenn ein Spielstand erstellt wird, wird der Spielstand-Index automatisch erhöht, bevor der Spielstand gespeichert wird. Wenn Inhalt geladen wird, wird automatisch der höchste existierende Spielstand-Index gewählt." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, + "Verhindere, dass das Save-RAM überschrieben wird, wenn ein Spielstand geladen wird. Kann zu fehlerhaften Spielen führen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, + "Die maximale Geschwindigkeit, mit der Inhalt im Vorlauf-Modus dargestellt wird (z.B. 5x für 60 Inhalt mit 60 Bildern/sek => Begrenzung auf 300 Bilder/sek). Wenn 0x gewählt ist, ist die Vorlauf-Geschwindigkeit unbegrenzt." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, + "Im Zeitlupen-Modus wird der Inhalt um diesen Faktor verlangsamt." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_ENABLE, + "Aktiviere Zurückspulen. Kann Leistungseinbußen im Spiel verursachen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, + "Wenn eine bestimmte Anzahl von Einzelbildern zurückgespult wird, kannst Du mehrere Einzelbilder auf einmal zurückspulen und damit die Zurückspul-Geschwindigkeit erhöhen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, + "Setzt den Log-Level für Cores. Wenn der Log-Level, der von einem Core zurückgemeldet wird, unter diesem Wert liegt, wird er ignoriert." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PERFCNT_ENABLE, + "Aktiviere Leistungszähler für RetroArch (und Cores)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, + "Speichere einen Spielstand automatisch, wenn RetroArch beendet wird. RetroArch wird diesen Spielstand automatisch laden, wenn 'Spielstand automatisch laden' aktiviert ist." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, + "Lade einen Spielstand beim Start automatisch." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_SAVESTATE_THUMBNAIL_ENABLE, + "Zeige Miniaturansichten von Spielständen im Menü an." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTOSAVE_INTERVAL, + "Speichere den Inhalt des nicht-flüchtigen Save-RAM in regelmäßigen Abständen. Diese Einstellung ist standardmäßig deaktiviert. Das Speicherintervall wird in Sekunden angegeben. Ein Wert von 0 deaktiviert das automatische Speichern." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_REMAP_BINDS_ENABLE, + "Wenn aktiviert, wird die Eingabebelegung mit den wiederzugewiesenen Belegungen, die für diesen Core gewählt wurden, überschrieben." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_AUTODETECT_ENABLE, + "Aktiviere automatische Erkennung von Eingabegeräten. Wird versuchen, Gamepads automatisch zu erkennen (Plug-and-Play)." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_INPUT_SWAP_OK_CANCEL, + "Vertausche die Tasten für 'OK' und 'Abbrechen'. Wenn deaktiviert, wird die japanische Tastenbelegung verwendet; wenn aktiviert, wird die westliche Tastenbelegung verwendet." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, + "Wenn deaktiviert, wird der Inhalt im Hintergrund weiterlaufen, wenn das RetroArch-Menü aufgerufen wird." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_DRIVER, + "Zu verwendender Videotreiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DRIVER, + "Zu verwendender Audiotreiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_DRIVER, + "Zu verwendender Eingabetreiber. Abhängig vom Videotreiber kann dieser einen anderen Eingabetreiber erzwingen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_JOYPAD_DRIVER, + "Zu verwendender Joypad-Treiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_RESAMPLER_DRIVER, + "Zu verwendender Audio-Resampling-Treiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CAMERA_DRIVER, + "Zu verwendender Kameratreiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_LOCATION_DRIVER, + "Zu verwendender Treiber für Ortsdienste." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_DRIVER, + "Zu verwendender Menütreiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_RECORD_DRIVER, + "Zu verwendender Aufnahmetreiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_WIFI_DRIVER, + "Zu verwendender WLAN-Treiber." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, + "Zeige nur Dateien mit unterstützten Dateierweiterungen im Dateibrowser an." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MENU_WALLPAPER, + "Wähle ein Bild aus, das als Menü-Hintergrundbild verwendet werden soll." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPER, + "Lade ein neues Hintergrundbild dynamisch, abhängig vom Inhalt." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DEVICE, + "Überschreibe das standardmäßig ausgewählte Audiogerät, welches vom Audiotreiber verwendet wird. Dies ist treiberabhängig." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_DSP_PLUGIN, + "Audio-DSP-Plugin, welches die Audiodaten verarbeitet, bevor sie zum Treiber gesendet werden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, + "Sampling-Rate der Audio-Ausgabe." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, + "Transparenz aller Bedienelemente des Overlays." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_SCALE, + "Skalierung aller Bedienelemente des Overlays." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE, + "Aktiviere das Overlay." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_OVERLAY_PRESET, + "Wähle ein Overlay mit dem Dateibrowser aus." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS, + "Die Adresse des Hosts, mit dem eine Verbindung hergestellt werden soll." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT, + "Der Port der Host-IP-Adresse. Kann entweder ein TCP- oder ein UDP-Port sein." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, + "Das Passwort, das für die Verbindung zum Netplay-Host verwendet werden soll. Wird nur im Host-Modus verwendet." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, + "Lege fest, ob Netplay-Spiele öffentlich angekündigt werden sollen. Wenn deaktiviert, müssen sich Clients manuell verbinden und können die öffentliche Lobby nicht verwenden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, + "Das Passwort, das für die Verbindung zum Netplay-Host mit Beobachter-Privilegien verwendet wird. Wird nur im Host-Modus verwendet." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_STATELESS_MODE, + "Lege fest, ob Netplay in einem Modus ohne Savestates läuft. Wenn aktiviert, ist ein sehr schnelles Netwerk nötig. Da kein Rücklauf erfolgt, läuft das Spiel flüssiger." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_CHECK_FRAMES, + "Die Häufigkeit in Einzelbildern, mit der Netplay überprüfen wird wird, ob der Host und der Client miteinander synchronisiert sind." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_NAT_TRAVERSAL, + "Versuche, auf eingehende Verbindungen aus dem öffentlichen Internet zu hören. Dabei wird UPnP oder eine ähnliche Technologie benötigt, um das eigene LAN zu verlassen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_STDIN_CMD_ENABLE, + "Aktiviere stdin-Befehlsschnittstelle." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_MOUSE_ENABLE, + "Aktiviere Maussteuerung im Menü." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_POINTER_ENABLE, + "Aktiviere Touch-Steuerung im Menü." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_THUMBNAILS, + "Art der Miniaturansichten, die verwendet werden soll." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEDATE_ENABLE, + "Zeige das aktuelle Datum und/oder die Zeit im Menü an." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_BATTERY_LEVEL_ENABLE, + "Zeige den aktuellen Akkustand im Menü an." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NAVIGATION_WRAPAROUND, + "Springe zum Anfang und/oder Ende, wenn die Grenzen einer Liste horizontal oder vertikal erreicht werden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_HOST, + "Aktiviere Netplay im Host-Modus (Server)." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_ENABLE_CLIENT, + "Aktiviere Netplay im Client-Modus.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_DISCONNECT, + "Beendet eine aktive Netplay-Verbindung.") +MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_DIRECTORY, + "Durchsuche ein Verzeichnis nach kompatiblen Dateien und füge diese zur Sammlung hinzu.") +MSG_HASH(MENU_ENUM_SUBLABEL_SCAN_FILE, + "Untersuche eine kompatible Datei und fügt diese zur Sammlung hinzu.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SWAP_INTERVAL, + "Verwende ein eigenes Intervall für Vsync. Aktivieren, um die Bildschirm-Wiederholrate zu halbieren." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVEFILES_ENABLE, + "Speichere Speicherdaten in Ordnern ab, die nach dem verwendeten Core benannt sind." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_SORT_SAVESTATES_ENABLE, + "Speichere Spielstände in Ordnern ab, die nach dem verwendeten Core benannt sind." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_CLIENT_SWAP_INPUT, + "Verwende die Tastenbelegung für Spieler 1, wenn Du ein Client im Netplay bist.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, + "URL zum Core-Verzeichnis auf dem libretro-Buildbot.") +MSG_HASH(MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, + "URL zum Assets-Verzeichnis auf dem libretro-Buildbot.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, + "Entpacke Dateien, die sich in heruntergeladenen Archiven befinden, nach dem Download automatisch." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, + "Suche nach neuen Räumen.") +MSG_HASH(MENU_ENUM_SUBLABEL_DELETE_ENTRY, + "Entferne diesen Eintrag aus der Sammlung.") +MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION, + "Zeige weiterführende Informationen über diesen Inhalt an.") +MSG_HASH(MENU_ENUM_SUBLABEL_RUN, + "Starte den Inhalt.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_FILE_BROWSER_SETTINGS, + "Passe die Dateibrowser-Einstellungen an.") +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_REMAPS_ENABLE, + "Aktiviere benutzerdefinierte Tastenbelegungen beim Start automatisch." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUTO_OVERRIDES_ENABLE, + "Aktiviere benutzerdefininerte Einstellungen beim Start automatisch." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_GAME_SPECIFIC_OPTIONS, + "Aktiviere benutzerdefinierte Core-Einstellungen beim Start automatisch.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ENABLE, + "Zeige den Namen des aktuellen Cores im Menü an.") +MSG_HASH(MENU_ENUM_SUBLABEL_DATABASE_MANAGER, + "Betrachte Datenbanken.") +MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_MANAGER, + "Betrachte vorherige Suchanfragen.") /* Maybe sloppy */ +MSG_HASH(MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, + "Fertigt ein Foto des Bildschirms an.") +#ifdef HAVE_DYNAMIC +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOSE_CONTENT, + "Schließt das aktuelle Spiel und die aktuelle Anwendung. Alle nicht gespeicherten Änderungen können verloren gehen." + ) +#else +MSG_HASH( + MENU_ENUM_SUBLABEL_CLOSE_CONTENT, + "Schließt das aktuelle Spiel. Alle nicht gespeicherten Änderungen können verloren gehen." + ) +#endif +MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_STATE, + "Lade einen gespeicherten Spielstand aus dem aktuellen Speicherplatz.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_STATE, + "Speichere einen Spielstand in dem aktuellen Speicherplatz.") +MSG_HASH(MENU_ENUM_SUBLABEL_RESUME, + "Setze die aktuelle Anwendung wieder fort und verlasse das Spielmenü.") +MSG_HASH(MENU_ENUM_SUBLABEL_RESUME_CONTENT, + "Setze den aktuellen Inhalt wieder fort und verlasse das Spielmenü") +MSG_HASH(MENU_ENUM_SUBLABEL_STATE_SLOT, + "Ändert den aktuell gewählten Spielstand-Speicherplatz.") +MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, + "Wenn ein Spielstand geladen wurde, wird der Inhalt zum Zustand vor dem Laden des Spielstandes zurückkehren.") +MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_SAVE_STATE, + "Wenn ein Spielstand überschrieben wurde, wird der Inhalt des zuvor gespeicherten Spielstands wiederhergestellt.") +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, + "Retro Achievements (Errungenschaften-Dienst). Besuche http://retroachievements.org für weitere Informationen." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, + "Verwalte die aktuell konfigurierten Benutzerkonten." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_META_REWIND, + "Verwalte die Einstellungen für die Rückspul-Funktion.") +MSG_HASH(MENU_ENUM_SUBLABEL_RESTART_CONTENT, + "Starte den Inhalt vom Beginn an neu.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE, + "Speichere eine überschreibende Konfiguration, die für jeden Inhalt, der mit diesem Core geladen wird, verwendet wird. Wird gegenüber der normalen Konfiguration bevorzugt.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME, + "Speichere eine überschreibende Konfiguration, die nur für den aktuellen Inhalt verwendet wird. Wird gegenüber der normalen Konfiguration bevorzugt.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_CHEAT_OPTIONS, + "Verwende Cheat-Codes.") +MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_OPTIONS, + "Verwende Shader, um die Videodarstellung zu verbessern.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, + "Ändere die Steuerung für den aktuell laufenden Inhalt.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_OPTIONS, + "Ändere die Optionen für die aktuell laufende Anwendung") +MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, + "Zeige erweiterte Einstellungen für erfahrene Benutzer (standardmäßig ausgeblendet).") +MSG_HASH(MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, + "Führe Aufgaben im Hintergrund aus.") +MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_ENTRY_REMOVE, + "Erlaube dem Benutzer, Einträge aus der Sammlung zu entfernen.") +MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_DIRECTORY, + "Lege das Systemverzeichnis fest. Cores können dieses Verzeichnis verwenden, um ein BIOS, system-spezifische Konfigurationen usw. zu laden.") +MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_BROWSER_DIRECTORY, + "Lege das Startverzeichnis für den Dateibrowser fest.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DIR, + "Wird normalerweise von Entwickler verwendet, die libretro/RetroArch-Apps paketieren." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, + "Verzeichnis, in dem Hintergrundbilder gespeichert werden, die vom Menü je nach verwendetem Inhalt geladen.") +MSG_HASH(MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, + "Ergänzende Miniaturansichte (Boxarts, Bildschirmfotos...) werden hier gespeichert." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, + "Legt das Verzeichnis fest, in dem das Menü mit der Suche nach Konfigurationen beginnt.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, + "Eingabeverzögerung in Einzelbildern, die im Netplay verwendet wird, um die Netzwerklatenz zu verbergen. Reduziert Bildruckeln und CPU-Last, verursacht jedoch erkennbare Eingabeverzögerung.") +MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, + "Der Bereich der Eingabeverzögerung in Einzelbildern, die im Netplay verwendet werden kann, um die Netzwerklatenz zu verbergen. Reduziert Bildruckeln und CPU-Last, verursacht jedoch unvorhersehbare Eingabeverzögerungen.") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, + "Datenträger auswerfen/einlegen. Wenn der Datenträger eingelegt ist, wird er ausgeworfen. Wenn er noch nicht eingelegt wurde, wird er jetzt eingelegt. ") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_INDEX, + "Ändere den Datenträger-Index.") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_OPTIONS, + "Verwaltung von Datenträger-Abbildern.") +MSG_HASH(MENU_ENUM_SUBLABEL_DISK_IMAGE_APPEND, + "Wähle ein Datenträger-Abbild, das eingelegt werden soll.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_ENUM_THROTTLE_FRAMERATE, + "Stelle sicher, dass die Bildwiederholrate im Menü begrenzt wird.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_THEME, + "Wähle ein anderes Thema für das Menü aus. Änderungen werden übernommen, nachdem Du das Programm neu gestartet hast.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHADOWS_ENABLE, + "Aktiviere Schatten für alle Icons. Dies hat einen geringen Einfluss auf die Leistung.") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_COLOR_THEME, + "Wähle einen anderen Farbverlauf für das Hintergrundbild.") +MSG_HASH(MENU_ENUM_SUBLABEL_MENU_WALLPAPER_OPACITY, + "Ändere die Transparenz des Hintergrundbildes.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_MENU_COLOR_THEME, + "Wähle einen anderen Farbverlauf für das Hintergrundbild.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_RIBBON_ENABLE, + "Wähle einen animierten Effekt für das Hintergrundbild. Kann je nach Effekt GPU-lastig sein. Wenn die Leistung nicht ausreicht, wähle einen einfacheren Effekt oder deaktiviere diese Option.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_FONT, + "Wähle eine andere Schriftart, die im Menü verwendet werden soll.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_IMAGES, + "Zeige den Tab 'Bilder' im Hauptmenü an.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_MUSIC, + "Zeige den Tab 'Musik' im Hauptmenü an.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_VIDEO, + "Zeige den Tab 'Video' im Hauptmenü an.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_SETTINGS, + "Zeige den Tab 'Einstellungen' im Hauptmenü an") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_HISTORY, + "Zeige den Tab 'Verlauf' im Hauptmenü an.") +MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_ADD, + "Zeige den Tab 'Inhalt importieren' im Hauptmenü an") +MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, + "Zeige einen Startbildschirm im Menü an. Wird automatisch deaktiviert, nachdem das Programm zum ersten Mal gestartet wurde.") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, + "Ändere die Transparenz der Header-Grafik.") +MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, + "Ändere die Transparenz der Footer-Grafik.") +MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_ENABLE, + "Das Menü wird normalerweise automatisch skaliert. Wenn Du stattdessen eine bestimmte Skalierung wünschst, aktiviere diese Option.") +MSG_HASH(MENU_ENUM_SUBLABEL_DPI_OVERRIDE_VALUE, + "Lege hier die gewünschte Skalierung fest. HINWEIS: Du musst 'DPI-Überschreibung' aktivieren, damit diese Skalierung verwendet wird.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, + "Speichere alle heruntergeladenen Dateien in diesem Verzeichnis.") +MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, + "Speichere alle wiederzugewiesenen Tastenbelegungen in diesem Verzeichnis.") +MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, + "Verzeichnis, in dem das Programm nach Inhalten/Cores sucht.") +MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, + "Awendungs- und Core-Informationsdateien werden hier gespeichert.") +MSG_HASH(MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, + "Wenn ein Gamepad eingesteckt wird, wird es automatisch konfiguriert, sofern eine passende Konfigurationsdatei in diesem Verzeichnis vorhanden ist.") +MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_DIRECTORY, + "Speichere alle Sammlungen in diesem Verzeichnis.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CACHE_DIRECTORY, + "Wenn ein Verzeichnis gewählt wird, wird Inhalt, der temporär entpackt wird (z.B. aus Archiven) in dieses Verzeichnis entpackt." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_CURSOR_DIRECTORY, + "Gespeicherte Suchanfragen werden in diesem Verzeichnis gespeichert.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CONTENT_DATABASE_DIRECTORY, + "Datenbanken werden in diesem Verzeichnis gespeichert." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_ASSETS_DIRECTORY, + "Dieser Ort wird standardmäßig durchsucht, wenn das Menü nach ladbaren Inhalten wie Assets sucht." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_SAVEFILE_DIRECTORY, + "Speichere alle Speicherdaten in diesem Verzeichnis. Wenn kein Verzeichnis festgelegt ist, wird versucht, die Datei im Arbeitsverzeichnis des Inhalts zu speichern.") +MSG_HASH(MENU_ENUM_SUBLABEL_SAVESTATE_DIRECTORY, + "Speichere alle Spielstände in diesem Verzeichnis. Wenn kein Verzeichnis festgelegt ist, wird versucht, die Datei im Arbeitsverzeichnis des Inhalts zu speichern.") +MSG_HASH(MENU_ENUM_SUBLABEL_SCREENSHOT_DIRECTORY, + "Verzeichnis, in dem alle Bildschirmfotos abgelegt werden.") +MSG_HASH(MENU_ENUM_SUBLABEL_OVERLAY_DIRECTORY, + "Verzeichnis, in dem alle Overlays abgelegt werden.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_DATABASE_PATH, + "Verzeichnis, in dem alle Cheat-Dateien gespeichert werden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_AUDIO_FILTER_DIR, + "Verzeichnis, in dem alle Audio-DSP-Filter gespeichert werden." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_FILTER_DIR, + "Verzeichnis, in dem alle CPU-basierten Videofilter gespeichert werden." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_DIR, + "Verzeichnis, in dem alle GPU-basierten Videoshader gespeichert werden.") +MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_OUTPUT_DIRECTORY, + "Aufnahmen werden in diesem Verzeichnis abgelegt.") +MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_CONFIG_DIRECTORY, + "Aufnahme-Konfigurationen werden in diesem Verzeichnis abgelegt.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FONT_PATH, + "Wähle eine andere Schriftart für Bildschirm-Benachrichtigungen.") +MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_APPLY_CHANGES, + "Änderungen an der Shader-Konfiguration werden sofort übernommen. Verwende diese Option, wenn Du die Anzahl der Shader-Durchläufe, die Filter, die FBO-Skalierung usw. geändert hast.") +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SHADER_NUM_PASSES, + "Erhöhe oder verringere die Anzahl der Shader-Durchläufe. Du kannst für jeden Shader-Durchlauf einen eigenen Shader festlegen und dessen Skalierung und Filterung ändern." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET, + "Lade eine Shader-Voreinstellung. Die Shader-Pipeline wird automatisch konfiguriert.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_AS, + "Speichere die aktuellen Shader-Einstellungen als neue Shader-Voreinstellung ab.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, + "Speichere die aktuellen Shader-Einstellungen als Standard-Einstellung für diesen Core.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, + "Speichere die aktuellen Shader-Einstellungen als Standard-Einstellung für diesen Inhalt.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, + "Modifiziert den aktuellen Shader direkt. Änderungen werden nicht in den Shader-Voreinstellungen gespeichert.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, + "Modizifiert die Shader-Voreinstellung, die momentan im Menü geladen ist.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, + "Erhöhe oder verringere die Anzahl der Cheats." + ) +MSG_HASH(MENU_ENUM_SUBLABEL_CHEAT_APPLY_CHANGES, + "Änderungen an den Cheats werden sofort übernommen.") +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_LOAD, + "Lade eine Cheat-Datei." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_CHEAT_FILE_SAVE_AS, + "Speichere die aktuellen Cheats." /*TODO: More context*/ + ) +MSG_HASH(MENU_ENUM_SUBLABEL_CONTENT_SETTINGS, + "Greife schnell auf alle relevanten Spieleinstellungen zu.") +MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INFORMATION, + "Zeige Informationen über diese Anwendung/diesen Core an.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, + "Benutzerdefinierte Bildhöhe, die verwendet wird, wenn das Seitenverhältnis auf 'Benutzerdefiniert' eingestellt ist.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, + "Benutzerdefinierte Bildhöhe, die verwendet wird, wenn das Seitenverhältnis auf 'Benutzerdefiniert' eingestellt ist.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, + "Benutzerdefinierter Versatz, der für die Position der X-Achse des Bildes verwendet wird. Wird ignoriert, wenn 'Ganzzahlige Bildskalierung' aktiviert ist, das Bild wird dann zentriert.") +MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y, + "Benutzerdefinierter Versatz, der für die Position der Y-Achse des Bildes verwendet wird. Wird ignoriert, wenn 'Ganzzahlige Bildskalierung' aktiviert ist, das Bild wird dann zentriert.") diff --git a/intl/msg_hash_eo.h b/intl/msg_hash_eo.h index f2a4e6db47..aede2dfc0d 100644 --- a/intl/msg_hash_eo.h +++ b/intl/msg_hash_eo.h @@ -1675,7 +1675,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, "Join or host a netplay session.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display information for core, network, and system. Display manager for database and cursor.") + "Display core, network and system information.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "Download add-ons, components and contents for RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index ddc93c2ce7..14d1eb088a 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -1,14 +1,14 @@ MSG_HASH( MSG_COMPILER, - "Compiler" + "Compilateur" ) MSG_HASH( MSG_UNKNOWN_COMPILER, - "Unknown compiler" + "Compilateur inconnu" ) MSG_HASH( MSG_DEVICE_DISCONNECTED_FROM_PORT, - "Device disconnected from port" + "Périphérique déconnecté (du port si 'port X')" ) MSG_HASH( MSG_UNKNOWN_NETPLAY_COMMAND_RECEIVED, @@ -40,7 +40,7 @@ MSG_HASH( ) MSG_HASH( MSG_WAITING_FOR_CLIENT, - "Waiting for client ..." + "En attente du client..." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SHARED_CONTEXT, @@ -48,43 +48,43 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "Adjusts settings related to the appearance of the menu screen." + "Ajuste les réglages liés à l'apparence de l'écran de menu." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, - "Hard-synchronize the CPU and GPU. Reduces latency at the cost of performance." + "Synchronisation 'hard' du CPU et du GPU. Réduit la latence au prix de la performance." ) 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." + "Améliore les performances au prix d'une certaine latence et d'à-coups visuels accrus. À n'utiliser que si vous ne pouvez pas faire autrement." ) MSG_HASH( MSG_AUDIO_VOLUME, - "Audio volume" + "Volume sonore" ) MSG_HASH( MSG_AUTODETECT, - "Autodetect" + "Détection automatique" ) MSG_HASH( MSG_AUTOLOADING_SAVESTATE_FROM, - "Auto-loading savestate from" + "Chargement auto d'une savestate depuis" ) MSG_HASH( MSG_CAPABILITIES, - "Capabilities" + "Capacités" ) MSG_HASH( MSG_CONNECTING_TO_NETPLAY_HOST, - "Connecting to netplay host" + "Connexion à l'hôte" ) MSG_HASH( MSG_CONNECTING_TO_PORT, - "Connecting to port" + "Connexion au port" ) MSG_HASH( MSG_CONNECTION_SLOT, - "Connection slot" + "Slot de connexion" ) MSG_HASH( MSG_SORRY_UNIMPLEMENTED_CORES_DONT_DEMAND_CONTENT_NETPLAY, @@ -92,7 +92,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_PASSWORD, - "Password" + "Mot de passe" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_SETTINGS, @@ -100,7 +100,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_CHEEVOS_USERNAME, - "Username" + "Nom d'utilisateur" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_LIST, @@ -112,16 +112,16 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACCOUNTS_RETRO_ACHIEVEMENTS, - "Retro Achievements" + "Succès Retro" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, - "Achievement List" + "Liste des Succès" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, - "Achievement List (Hardcore)" + "Liste des Succès (hardcore)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST, @@ -209,11 +209,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME, - "Volume sonnore (dB)" + "Volume sonore (dB)" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL, - "Intervale de sauvegarde SaveRAM" + "Intervalle de sauvegarde SaveRAM" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE, @@ -225,63 +225,63 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_AUTO_SHADERS_ENABLE, - "Load Shader Presets Automatically" + "Charger les pré-réglages de shaders automatiquement" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_BACK, - "Back" + "Retour" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_CONFIRM, - "Confirm" + "Confirmer" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_INFO, - "Info" + "Information" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_QUIT, - "Quit" + "Quitter" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_DOWN, - "Scroll Down" + "Défilement vers le bas" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_SCROLL_UP, - "Scroll Up" + "Défilement vers le haut" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_START, - "Start" + "Démarrer" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_KEYBOARD, - "Toggle Keyboard" + "Basculer sur le Clavier" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_CONTROLS_TOGGLE_MENU, - "Toggle Menu" + "Basculer sur le Menu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS, - "Basic menu controls" + "Contrôles du menu basiques" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_CONFIRM, - "Confirm/OK" + "Confirmer / OK" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_INFO, - "Info" + "Information" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_QUIT, - "Quit" + "Quitter" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_SCROLL_UP, - "Scroll Up" + "Défilement vers le haut" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_START, @@ -289,11 +289,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_KEYBOARD, - "Toggle Keyboard" + "Basculer sur le Klavier" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BASIC_MENU_ENUM_CONTROLS_TOGGLE_MENU, - "Toggle Menu" + "Basculer sur le Menu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE, @@ -301,7 +301,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BLUETOOTH_ENABLE, - "Bluetooth Enable" + "Activer le Bluetooth" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL, @@ -333,15 +333,15 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE, - "Cheat File" + "Fichier de Triche" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD, - "Load Cheat File" + "Charger un fichier de Triche" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS, - "Save Cheat File As" + "Enregistrer le fichier de Triche sous" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES, @@ -353,19 +353,19 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_HARDCORE_MODE_ENABLE, - "Achievements Hardcore Mode" + "Mode Hardcore des Succès" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ACHIEVEMENTS, - "Locked Achievements:" + "Succès verrouillés:" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY, - "Locked" + "Verrouillé" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_SETTINGS, - "Retro Achievements" + "Succès Retro" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_TEST_UNOFFICIAL, @@ -373,11 +373,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ACHIEVEMENTS, - "Unlocked Achievements:" + "Succès déverrouillés:" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY, - "Unlocked" + "Déverrouillé" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, @@ -385,11 +385,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG, - "Config" + "Configuration" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATIONS, - "Load Configuration" + "Charger la configuration" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS, @@ -405,7 +405,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY, "Dossier des bases de données de contenus") MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_DIR, - "Content" + "Contenu" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE, @@ -413,13 +413,13 @@ MSG_HASH( MSG_HASH(MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS, "Menu rapide") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIR, - "Core Assets") + "Assets de Coeur") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY, "Dossier des téléchargements") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS, "Triche") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS, - "Core Counters") + "Compteurs de Cores") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_ENABLE, "Afficher le coeur actuel") MSG_HASH(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION, @@ -475,9 +475,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO, MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER, "Gestion de la base de données") MSG_HASH(MENU_ENUM_LABEL_VALUE_DATABASE_SELECTION, - "Database Selection") + "Sélection de la base de données") MSG_HASH(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY, - "Remove") + "Supprimer") MSG_HASH(MENU_ENUM_LABEL_VALUE_FAVORITES, "Via les fichiers") /* TODO/FIXME - update */ MSG_HASH(MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT, @@ -519,7 +519,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER, MSG_HASH(MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY, "Dossier des fonds d'écran dynamiques") MSG_HASH(MENU_ENUM_LABEL_VALUE_CHEEVOS_ENABLE, - "Enable Achievements") + "Activer les Succès") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR, "Couleur de l'entrée active") MSG_HASH(MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR, @@ -529,7 +529,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FALSE, MSG_HASH(MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO, "Vitesse de l'avance rapide") MSG_HASH(MENU_ENUM_LABEL_VALUE_FPS_SHOW, - "Afficher le FPS") + "Afficher les i/s") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE, "Limiter la vitesse d'exécution") MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, @@ -537,17 +537,17 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS, MSG_HASH(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS, "Compteurs du Frontend") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS, - "Options du coeur par-jeu") + "Options du coeur par jeu") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, - "Create game-options file") + "Créer un fichier d'options par jeu") MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, - "Game-options file") + "Fichier d'option par jeu") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, "Aide") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, - "Audio/Video Troubleshooting") + "Dépannage audio / vidéo") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, - "Changing Virtual Gamepad Overlay") + "Modifier l'overlay de la manette virtuelle") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CONTROLS, "Basic Menu Controls") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_LIST, @@ -1083,9 +1083,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY, MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD, "Charger un fichier de remap") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE, - "Charger un fichier remaps de coeur") + "Sauvegarder un fichier remaps de coeur") MSG_HASH(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME, - "Charger un fichier remap de contenu") + "Sauvegarder un fichier remap de contenu") MSG_HASH(MENU_ENUM_LABEL_VALUE_REQUIRED, "Requis") MSG_HASH(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT, @@ -1643,7 +1643,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, "Join or host a netplay session.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display information for core, network, and system. Display manager for database and cursor.") + "Display core, network and system information.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "Download add-ons, components and contents for RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, @@ -2148,6 +2148,10 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, "not configured" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "not configured, using fallback" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, "Database Cursor List" diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 7ecea00bdf..4d3be0310f 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -1659,7 +1659,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, "Search for and connect to netplay hosts on the local network.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display information for core, network, and system. Display manager for database and cursor.") + "Display core, network and system information.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "Download add-ons, components and contents for RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, @@ -2170,6 +2170,10 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, "not configured" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "not configured, using fallback" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, "Database Cursor List" diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index f484af982c..01bb610aec 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -2291,6 +2291,10 @@ 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, "データベースのカーソル表" diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 9df3b15d90..277d837046 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -611,6 +611,8 @@ MSG_HASH(MENU_ENUM_LABEL_NETPLAY_PASSWORD, "netplay_password") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_SETTINGS, "menu_netplay_settings") +MSG_HASH(MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE, + "netplay_public_announce") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_SPECTATE_PASSWORD, "netplay_spectate_password") MSG_HASH(MENU_ENUM_LABEL_NETPLAY_SPECTATOR_MODE_ENABLE, diff --git a/intl/msg_hash_nl.h b/intl/msg_hash_nl.h index 5c2e49bdcc..6ce92a9aa5 100644 --- a/intl/msg_hash_nl.h +++ b/intl/msg_hash_nl.h @@ -1675,7 +1675,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, "Join or host a netplay session.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display information for core, network, and system. Display manager for database and cursor.") + "Display core, network and system information.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "Download add-ons, components and contents for RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, @@ -2182,6 +2182,10 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, "not configured" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "not configured, using fallback" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, "Database Cursor List" diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 29dbfc7ebd..480252759d 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -1,4 +1,4 @@ -#if defined(_MSC_VER) && !defined(_XBOX) +#if defined(_MSC_VER) && !defined(_XBOX) /* https://support.microsoft.com/en-us/kb/980263 */ #pragma execution_character_set("utf-8") #endif @@ -1676,7 +1676,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, "Join or host a netplay session.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display information for core, network, and system. Display manager for database and cursor.") + "Display core, network and system information.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, "Download add-ons, components and contents for RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, @@ -2181,6 +2181,10 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, "not configured" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "not configured, using fallback" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, "Database Cursor List" diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 1f4f1c8339..dfd157ff38 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -1535,6 +1535,13 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) { "Increasing this value will increase \n" "performance, but introduce more latency."); break; + case MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE: + snprintf(s, len, + "Whether to announce netplay games publicly. \n" + " \n" + "If set to false, clients must manually connect \n" + "rather than using the public lobby."); + break; case MENU_ENUM_LABEL_NETPLAY_STATELESS_MODE: snprintf(s, len, "Whether to run netplay in a mode not requiring\n" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 1ae9aa0b46..d370efde10 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -36,7 +36,7 @@ MSG_HASH( ) MSG_HASH( MSG_NETPLAY_USERS_HAS_FLIPPED, - "Netplay users has flipped" + "Netplay users have flipped" ) MSG_HASH( MSG_SETTING_DISK_IN_TRAY, @@ -112,7 +112,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SETTINGS, - "Adjusts settings related to the appearance of the menu screen." + "Adjusts menu screen appearance settings." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_HARD_SYNC, @@ -182,7 +182,6 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST, "Achievement List" ) - MSG_HASH( MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST_HARDCORE, "Achievement List (Hardcore)" @@ -449,7 +448,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT, - "Close Application" + "Close Content" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CONFIG, @@ -619,7 +618,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_CREATE, MSG_HASH(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_OPTIONS_IN_USE, "Game-options file") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP, - "help") + "Help") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING, "Audio/Video Troubleshooting") MSG_HASH(MENU_ENUM_LABEL_VALUE_HELP_CHANGE_VIRTUAL_GAMEPAD, @@ -990,6 +989,8 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME, "Username") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PASSWORD, "Server Password") +MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + "Publicly Announce Netplay") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_SETTINGS, "Netplay settings") MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_STATELESS_MODE, @@ -1717,41 +1718,41 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_TEST_UNOFFICIAL, MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_HARDCORE_MODE_ENABLE, "Enable or disable savestates, cheats, rewind, fast-forward, pause, and slow-motion for all games.") MSG_HASH(MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, - "Change drivers for this system.") + "Change drivers used by the system.") MSG_HASH(MENU_ENUM_SUBLABEL_RETRO_ACHIEVEMENTS_SETTINGS, - "Change settings for the achievements.") + "Change achievement settings.") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_SETTINGS, - "Change settings for the core.") + "Change core settings.") MSG_HASH(MENU_ENUM_SUBLABEL_RECORDING_SETTINGS, - "Change settings for the recording.") + "Change recording settings.") MSG_HASH(MENU_ENUM_SUBLABEL_ONSCREEN_DISPLAY_SETTINGS, - "Change settings for display overlay, keyboard overlay and onscreen notifications.") + "Change display overlay and keyboard overlay, and onscreen notification settings.") MSG_HASH(MENU_ENUM_SUBLABEL_FRAME_THROTTLE_SETTINGS, - "Change settings for rewinding, fast-forwarding, and slow-motion.") + "Change rewind, fast-forward, and slow-motion settings.") MSG_HASH(MENU_ENUM_SUBLABEL_SAVING_SETTINGS, - "Change settings for the saving.") + "Change saving settings.") MSG_HASH(MENU_ENUM_SUBLABEL_LOGGING_SETTINGS, - "Change settings for the logging.") + "Change logging settings.") MSG_HASH(MENU_ENUM_SUBLABEL_USER_INTERFACE_SETTINGS, - "Change settings for the user interface.") + "Change user interface settings.") MSG_HASH(MENU_ENUM_SUBLABEL_USER_SETTINGS, - "Change accounts, username, and language.") + "Change account, username, and language settings.") MSG_HASH(MENU_ENUM_SUBLABEL_PRIVACY_SETTINGS, "Change your privacy settings.") MSG_HASH(MENU_ENUM_SUBLABEL_DIRECTORY_SETTINGS, - "Change default directories for this system.") + "Change default directories where files are located.") MSG_HASH(MENU_ENUM_SUBLABEL_PLAYLIST_SETTINGS, - "Change settings for the playlists.") + "Change playlist settings.") MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_SETTINGS, "Configure server and network settings.") MSG_HASH(MENU_ENUM_SUBLABEL_ADD_CONTENT_LIST, - "Scan contents and add to the database.") + "Scan content and add to the database.") MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, - "Adjusts settings for audio output.") + "Change audio output settings.") MSG_HASH(MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE, "Enable or disable bluetooth.") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIG_SAVE_ON_EXIT, - "Saves changes to configuration file on exit.") + "Saves changes to the configuration file on exit.") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATION_SETTINGS, "Change default settings for configuration files.") MSG_HASH(MENU_ENUM_SUBLABEL_CONFIGURATIONS_LIST, @@ -1765,7 +1766,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_HOTKEY_BINDS, MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO, "Gamepad button combination to toggle menu.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_SETTINGS, - "Adjusts settings for joypads, keyboard and mouse.") + "Change joypad, keyboard, and mouse settings.") MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_USER_BINDS, "Configure controls for this user.") MSG_HASH(MENU_ENUM_SUBLABEL_LOG_VERBOSITY, @@ -1775,9 +1776,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY, MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_LAN_SCAN_SETTINGS, "Search for and connect to netplay hosts on the local network.") MSG_HASH(MENU_ENUM_SUBLABEL_INFORMATION_LIST_LIST, - "Display information for core, network, and system. Display manager for database and cursor.") + "Display core, network, and system information.") MSG_HASH(MENU_ENUM_SUBLABEL_ONLINE_UPDATER, - "Download add-ons, components and contents for RetroArch.") + "Download add-ons, components, and content for RetroArch.") MSG_HASH(MENU_ENUM_SUBLABEL_SAMBA_ENABLE, "Enable or disable network sharing of your folders.") MSG_HASH(MENU_ENUM_SUBLABEL_SERVICES_SETTINGS, @@ -1789,13 +1790,13 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SSH_ENABLE, MSG_HASH(MENU_ENUM_SUBLABEL_SUSPEND_SCREENSAVER_ENABLE, "Prevents your system's screensaver from becoming active.") 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.") + "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.") 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.") + "Inserts a black frame inbetween frames. Useful for users with 120Hz screens who want to play 60Hz content to eliminate ghosting.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_FRAME_DELAY, - "Reduces latency at the cost of higher risk of video stuttering. Adds a delay after V-Sync (in ms).") + "Reduces latency at the cost of a higher risk of video stuttering. Adds a delay after 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'.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, @@ -1805,11 +1806,11 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MONITOR_INDEX, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_REFRESH_RATE_AUTO, "The accurate estimated refresh rate of the screen in Hz.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, - "Adjusts settings for video output.") + "Change video output settings.") MSG_HASH(MENU_ENUM_SUBLABEL_WIFI_SETTINGS, "Scans for wireless networks and establishes connection.") MSG_HASH(MENU_ENUM_SUBLABEL_HELP_LIST, - "Learn more about how it works.") + "Learn more about how the program works.") MSG_HASH(MSG_APPENDED_DISK, "Appended disk") MSG_HASH(MSG_APPLICATION_DIR, @@ -1871,7 +1872,7 @@ MSG_HASH(MSG_COULD_NOT_READ_MOVIE_HEADER, MSG_HASH(MSG_COULD_NOT_READ_STATE_FROM_MOVIE, "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.") + "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, "Custom timing given") MSG_HASH(MSG_DECOMPRESSION_ALREADY_IN_PROGRESS, @@ -2200,7 +2201,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_AUDIO_MUTE, "Mute/unmute 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." + "Helps smooth out imperfections in timing when synchronizing audio and video. Be aware that if disabled, proper synchronization is nearly impossible to obtain." ) MSG_HASH( MENU_ENUM_SUBLABEL_CAMERA_ALLOW, @@ -2224,7 +2225,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_VOLUME, - "Audio volume (in dB). 0 dB is normal volume, no gain applied." + "Audio volume (in dB). 0 dB is normal volume, and no gain is applied." ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SYNC, @@ -2240,7 +2241,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD, - "Describes the period of which turbo-enabled buttons toggle. Numbers are described in frames." + "Describes the period when turbo-enabled buttons are toggled. Numbers are described in frames." ) MSG_HASH( MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE, @@ -2272,7 +2273,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_MAX_TIMING_SKEW, - "The maximum change in audio input rate. You may want to increase this to enable very large changes in timing, for example running PAL cores on NTSC displays, at the cost of inaccurate audio pitch." + "The maximum change in audio input rate. Increasing this enables very large changes in timing at the cost of an inaccurate audio pitch (e.g., running PAL cores on NTSC displays)." ) MSG_HASH( MSG_FAILED, @@ -2286,6 +2287,10 @@ MSG_HASH( MSG_DEVICE_NOT_CONFIGURED, "not configured" ) +MSG_HASH( + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, + "not configured, using fallback" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_DATABASE_CURSOR_LIST, "Database Cursor List" @@ -2346,7 +2351,7 @@ MSG_HASH(MSG_NETPLAY_LAN_SCAN_COMPLETE, MSG_HASH(MSG_NETPLAY_LAN_SCANNING, "Scanning for netplay hosts...") MSG_HASH(MENU_ENUM_SUBLABEL_PAUSE_NONACTIVE, - "Pause gameplay when window focus is lost.") + "Pause gameplay when RetroArch is not the active window.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_DISABLE_COMPOSITION, "Enable or disable composition (Windows only).") MSG_HASH(MENU_ENUM_SUBLABEL_HISTORY_LIST_ENABLE, @@ -2396,9 +2401,9 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_NETPLAY_ROOM_NICKNAME, 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 that were customarily left blank by developers and sometimes contain garbage pixels.") + "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, - "Add a slight blur to the image to take the edge off of the hard pixel edges. This option has very little impact on performance.") + "Adds a slight blur to the image to take the edge off of the hard pixel edges. This option has very little impact on performance.") 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, @@ -2406,13 +2411,13 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_USERNAME, MSG_HASH(MENU_ENUM_SUBLABEL_CHEEVOS_PASSWORD, "Input the password of your Retro Achievements account.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_NICKNAME, - "Input your user name here. This will be used for netplay sessions among other things.") + "Input your user name here. This will be used for netplay sessions, among other things.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_POST_FILTER_RECORD, "Capture the image after filters (but not shaders) are applied. Your video will look as fancy as what you see on your screen.") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_LIST, - "Select which application we wish to use.") + "Select which core to use.") MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_CONTENT_LIST, - "Select the content we want to start.") + "Select which content to start.") MSG_HASH(MENU_ENUM_SUBLABEL_NETWORK_INFORMATION, "Show network interface(s) and associated IP addresses.") MSG_HASH(MENU_ENUM_SUBLABEL_SYSTEM_INFORMATION, @@ -2430,10 +2435,10 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_MESSAGE_POS_Y, 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 we are inside the menu, and show it again when exiting the menu.") + "Hide the overlay while inside the menu, and show it again when exiting the menu.") MSG_HASH( MENU_ENUM_SUBLABEL_CONTENT_COLLECTION_LIST, - "Content which has been scanned will appear here." + "Scanned content will appear here." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, @@ -2465,7 +2470,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_INDEX, - "When saving a savestate, save state index is automatically increased before it is saved. Also, when loading content, the index will be set to the highest existing index." + "When making a savestate, save state index is automatically increased before it is saved. When loading content, the index will be set to the highest existing index." ) MSG_HASH( MENU_ENUM_SUBLABEL_BLOCK_SRAM_OVERWRITE, @@ -2473,11 +2478,11 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_FASTFORWARD_RATIO, - "The maximum rate at which content will be run when using fast forward (E.g. 5x for 60 fps content => 300 fps cap). If this is set at 0x, then fastforward ratio is unlimited (no FPS cap)." + "The maximum rate at which content will be run when using fast forward (e.g., 5.0x for 60 fps content = 300 fps cap). If set to 0.0x, fastforward ratio is unlimited (no FPS cap)." ) MSG_HASH( MENU_ENUM_SUBLABEL_SLOWMOTION_RATIO, - "When slowmotion, content will slow down by a factor." + "When in slow motion, content will slow down by the factor specified/set." ) MSG_HASH( MENU_ENUM_SUBLABEL_REWIND_ENABLE, @@ -2485,7 +2490,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_REWIND_GRANULARITY, - "When rewinding defined number of frames, you can rewind several frames at a time, increasing the rewind speed." + "When rewinding a defined number of frames, you can rewind several frames at a time, increasing the rewind speed." ) MSG_HASH( MENU_ENUM_SUBLABEL_LIBRETRO_LOG_LEVEL, @@ -2497,7 +2502,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_SAVE, - "Automatically saves a savestate at the end of RetroArch's lifetime. RetroArch will automatically load this savestate if 'Savestate Auto Load' is set." + "Automatically makes a savestate at the end of RetroArch's runtime. RetroArch will automatically load this savestate if 'Auto Load State' is enabled." ) MSG_HASH( MENU_ENUM_SUBLABEL_SAVESTATE_AUTO_LOAD, @@ -2525,7 +2530,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_PAUSE_LIBRETRO, - "If disabled, the content will keep running in the background when we are in the menu." + "If disabled, the content will keep running in the background when RetroArch's menu is toggled." ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_DRIVER, @@ -2589,7 +2594,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_OUTPUT_RATE, - "Audio output samplerate." + "Audio output sample rate." ) MSG_HASH( MENU_ENUM_SUBLABEL_OVERLAY_OPACITY, @@ -2619,6 +2624,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD, "The password for connecting to the netplay host. Used only in host mode." ) +MSG_HASH( + MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE, + "Whether to announce netplay games publicly. If unset, clients must manually connect rather than using the public lobby." + ) MSG_HASH( MENU_ENUM_SUBLABEL_NETPLAY_SPECTATE_PASSWORD, "The password for connecting to the netplay host with only spectator privileges. Used only in host mode." @@ -2691,7 +2700,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_BUILDBOT_URL, MSG_HASH(MENU_ENUM_SUBLABEL_BUILDBOT_ASSETS_URL, "URL to assets updater directory on the Libretro buildbot.") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, - "After downloading, automatically extract archives that the downloads are contained inside." + "After downloading, automatically extract files contained in the downloaded archives." ) MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_REFRESH_ROOMS, "Scan for new rooms.") @@ -2723,20 +2732,16 @@ MSG_HASH(MENU_ENUM_SUBLABEL_TAKE_SCREENSHOT, "Captures an image of the screen.") MSG_HASH( MENU_ENUM_SUBLABEL_CLOSE_CONTENT, -#ifdef HAVE_DYNAMIC - "Closes the current game and application. Any unsaved changes might be lost." -#else - "Closes the current game. Any unsaved changes might be lost." -#endif + "Closes the current content. Any unsaved changes might be lost." ) MSG_HASH(MENU_ENUM_SUBLABEL_LOAD_STATE, "Load a saved state from the currently selected slot.") MSG_HASH(MENU_ENUM_SUBLABEL_SAVE_STATE, "Save a state to the currently selected slot.") MSG_HASH(MENU_ENUM_SUBLABEL_RESUME, - "Resume the currently running application and leave the Quick Menu.") + "Resume the currently running content and leave the Quick Menu.") MSG_HASH(MENU_ENUM_SUBLABEL_RESUME_CONTENT, - "Resume the currently running application and leave the Quick Menu.") + "Resume the currently running content and leave the Quick Menu.") MSG_HASH(MENU_ENUM_SUBLABEL_STATE_SLOT, "Changes the currently selected state slot.") MSG_HASH(MENU_ENUM_SUBLABEL_UNDO_LOAD_STATE, @@ -2749,7 +2754,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_SUBLABEL_ACCOUNTS_LIST, - "Manage currently configured accounts." + "Manages currently configured accounts." ) MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_META_REWIND, "Manages rewind settings.") @@ -2766,7 +2771,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_SHADER_OPTIONS, MSG_HASH(MENU_ENUM_SUBLABEL_CORE_INPUT_REMAPPING_OPTIONS, "Change the controls for the currently running content.") MSG_HASH(MENU_ENUM_SUBLABEL_CORE_OPTIONS, - "Change the options for the currently running application.") + "Change the options for the currently running content.") MSG_HASH(MENU_ENUM_SUBLABEL_SHOW_ADVANCED_SETTINGS, "Show advanced settings for power users (hidden by default).") MSG_HASH(MENU_ENUM_SUBLABEL_THREADED_DATA_RUNLOOP_ENABLE, @@ -2782,14 +2787,14 @@ MSG_HASH( "Usually set by developers who bundle libretro/RetroArch apps to point to assets." ) MSG_HASH(MENU_ENUM_SUBLABEL_DYNAMIC_WALLPAPERS_DIRECTORY, - "The place to store the wallpapers dynamically loaded by the menu depending on context.") + "Directory to store wallpapers dynamically loaded by the menu depending on context.") MSG_HASH(MENU_ENUM_SUBLABEL_THUMBNAILS_DIRECTORY, "Supplementary thumbnails (boxarts/misc. images, etc.) are stored here." ) MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_CONFIG_DIRECTORY, "Sets start directory for menu configuration browser.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, - "The number of frames of input latency for netplay to use to hide network latency. This reduces jitter and makes netplay less CPU-intensive, at the expense of noticeable input lag.") + "The number of frames of input latency for netplay to use to hide network latency. Reduces jitter and makes netplay less CPU-intensive, at the expense of noticeable input lag.") MSG_HASH(MENU_ENUM_SUBLABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, "The range of frames of input latency that may be used to hide network latency. Reduces jitter and makes netplay less CPU-intensive, at the expense of unpredictable input lag.") MSG_HASH(MENU_ENUM_SUBLABEL_DISK_CYCLE_TRAY_STATUS, @@ -2829,7 +2834,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_HISTORY, MSG_HASH(MENU_ENUM_SUBLABEL_XMB_SHOW_ADD, "Show the import content tab inside the main menu.") MSG_HASH(MENU_ENUM_SUBLABEL_RGUI_SHOW_START_SCREEN, - "Show startup screen in menu. Is automatically set to false after we have started up the program for the first time.") + "Show startup screen in menu. This is automatically set to false after the program starts for the first time.") MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_HEADER_OPACITY, "Modify the opacity of the header graphic.") MSG_HASH(MENU_ENUM_SUBLABEL_MATERIALUI_MENU_FOOTER_OPACITY, @@ -2843,7 +2848,7 @@ MSG_HASH(MENU_ENUM_SUBLABEL_CORE_ASSETS_DIRECTORY, MSG_HASH(MENU_ENUM_SUBLABEL_INPUT_REMAPPING_DIRECTORY, "Save all remapped controls to this directory.") MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_DIR_PATH, - "A directory for where to search for applications/cores.") + "Directory where the program searches for content/cores.") MSG_HASH(MENU_ENUM_SUBLABEL_LIBRETRO_INFO_PATH, "Application/core information files are stored here.") MSG_HASH(MENU_ENUM_SUBLABEL_JOYPAD_AUTOCONFIG_DIR, @@ -2907,9 +2912,9 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_CORE, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_SAVE_GAME, "Save the current shader settings as the default settings for the content.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PARAMETERS, - "Modifies current shader directly. Will not be saved to preset file.") + "Modifies the current shader directly. Changes will not be saved to the preset file.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_SHADER_PRESET_PARAMETERS, - "Modifies shader preset currently in menu.") + "Modifies the shader preset itself currently used in the menu.") MSG_HASH( MENU_ENUM_SUBLABEL_CHEAT_NUM_PASSES, "Increase or decrease the amount of cheats." @@ -2933,6 +2938,6 @@ MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, "Custom viewport width that is used if the Aspect Ratio is set to 'Custom'.") MSG_HASH(MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_X, - "Custom viewport offset used for defining the X-axis position of the viewport. These are ignored if 'Scaled Integer' is enabled, it will be automatically centered then.") + "Custom viewport offset used for defining the X-axis position of the viewport. These are ignored if 'Integer Scale' is enabled. It will be automatically centered then.") 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 'Scaled Integer' is enabled, it will be automatically centered then.") + "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.") diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index 95e32a2c5e..c381427d6c 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -41,6 +41,7 @@ #define _WIN32_WINNT 0x0500 /*_WIN32_WINNT_WIN2K */ #endif #include +#include #endif #elif defined(GEKKO) #include "gx_pthread.h" @@ -81,16 +82,49 @@ struct sthread struct slock { #ifdef USE_WIN32_THREADS - HANDLE lock; + CRITICAL_SECTION lock; #else pthread_mutex_t lock; #endif }; +#ifdef USE_WIN32_THREADS +/* The syntax we'll use is mind-bending unless we use a struct. Plus, we might want to store more info later */ +/* This will be used as a linked list immplementing a queue of waiting threads */ +struct QueueEntry +{ + struct QueueEntry *next; +}; +#endif + struct scond { #ifdef USE_WIN32_THREADS + /* With this implementation of scond, we don't have any way of waking + * (or even identifying) specific threads + * But we need to wake them in the order indicated by the queue. + * This potato token will get get passed around every waiter. + * The bearer can test whether he's next, and hold onto the potato if he is. + * When he's done he can then put it back into play to progress + * the queue further */ + HANDLE hot_potato; + + /* The primary signalled event. Hot potatoes are passed until this is set. */ HANDLE event; + + /* the head of the queue; NULL if queue is empty */ + struct QueueEntry *head; + + /* equivalent to the queue length */ + int waiters; + + /* how many waiters in the queue have been conceptually wakened by signals + * (even if we haven't managed to actually wake them yet) */ + int wakens; + + /* used to control access to this scond, in case the user fails */ + CRITICAL_SECTION cs; + #else pthread_cond_t cond; #endif @@ -167,7 +201,7 @@ error: * @thread : pointer to thread object * * Detach a thread. When a detached thread terminates, its - * resource sare automatically released back to the system + * resources are automatically released back to the system * without the need for another thread to join with the * terminated thread. * @@ -214,6 +248,9 @@ void sthread_join(sthread_t *thread) */ bool sthread_isself(sthread_t *thread) { + /* This thread can't possibly be a null thread */ + if (!thread) return false; + #ifdef USE_WIN32_THREADS return GetCurrentThread() == thread->thread; #else @@ -231,23 +268,25 @@ bool sthread_isself(sthread_t *thread) **/ slock_t *slock_new(void) { + bool mutex_created = false; slock_t *lock = (slock_t*)calloc(1, sizeof(*lock)); if (!lock) return NULL; #ifdef USE_WIN32_THREADS - lock->lock = CreateMutex(NULL, FALSE, NULL); - if (!lock->lock) - goto error; + InitializeCriticalSection(&lock->lock); + mutex_created = true; #else - if ((pthread_mutex_init(&lock->lock, NULL) < 0)) - goto error; + mutex_created = (pthread_mutex_init(&lock->lock, NULL) == 0); #endif + if (!mutex_created) + goto error; + return lock; error: - slock_free(lock); + free(lock); return NULL; } @@ -263,7 +302,7 @@ void slock_free(slock_t *lock) return; #ifdef USE_WIN32_THREADS - CloseHandle(lock->lock); + DeleteCriticalSection(&lock->lock); #else pthread_mutex_destroy(&lock->lock); #endif @@ -283,7 +322,7 @@ void slock_lock(slock_t *lock) if (!lock) return; #ifdef USE_WIN32_THREADS - WaitForSingleObject(lock->lock, INFINITE); + EnterCriticalSection(&lock->lock); #else pthread_mutex_lock(&lock->lock); #endif @@ -300,7 +339,7 @@ void slock_unlock(slock_t *lock) if (!lock) return; #ifdef USE_WIN32_THREADS - ReleaseMutex(lock->lock); + LeaveCriticalSection(&lock->lock); #else pthread_mutex_unlock(&lock->lock); #endif @@ -317,21 +356,55 @@ void slock_unlock(slock_t *lock) **/ scond_t *scond_new(void) { - bool event_created = false; scond_t *cond = (scond_t*)calloc(1, sizeof(*cond)); if (!cond) return NULL; #ifdef USE_WIN32_THREADS - cond->event = CreateEvent(NULL, FALSE, FALSE, NULL); - event_created = !!cond->event; -#else - event_created = (pthread_cond_init(&cond->cond, NULL) == 0); -#endif - if (!event_created) + /* This is very complex because recreating condition variable semantics + * with Win32 parts is not easy. + * + * The main problem is that a condition variable can't be used to + * "pre-wake" a thread (it will get wakened only after it's waited). + * + * Whereas a win32 event can pre-wake a thread (the event will be set + * in advance, so a 'waiter' won't even have to wait on it). + * + * Keep in mind a condition variable can apparently pre-wake a thread, + * insofar as spurious wakeups are always possible, + * but nobody will be expecting this and it does not need to be simulated. + * + * Moreover, we won't be doing this, because it counts as a spurious wakeup + * -- someone else with a genuine claim must get wakened, in any case. + * + * Therefore we choose to wake only one of the correct waiting threads. + * So at the very least, we need to do something clever. But there's + * bigger problems. + * We don't even have a straightforward way in win32 to satisfy + * pthread_cond_wait's atomicity requirement. The bulk of this + * algorithm is solving that. + * + * Note: We might could simplify this using vista+ condition variables, + * but we wanted an XP compatible solution. */ + cond->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!cond->event) goto error; + cond->hot_potato = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!cond->hot_potato) + { + CloseHandle(cond->event); goto error; + } + + InitializeCriticalSection(&cond->cs); + cond->waiters = cond->wakens = 0; + cond->head = NULL; + +#else + if (pthread_cond_init(&cond->cond, NULL) != 0) + goto error; +#endif return cond; @@ -353,12 +426,189 @@ void scond_free(scond_t *cond) #ifdef USE_WIN32_THREADS CloseHandle(cond->event); + CloseHandle(cond->hot_potato); + DeleteCriticalSection(&cond->cs); #else pthread_cond_destroy(&cond->cond); #endif free(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; + DWORD tsBegin; + DWORD waitResult; + DWORD dwFinalTimeout = dwMilliseconds; /* Careful! in case we begin in the head, + we don't do the hot potato stuff, + so this timeout needs presetting. */ + + /* Reminder: `lock` is held before this is called. */ + /* however, someone else may have called scond_signal without the lock. soo... */ + EnterCriticalSection(&cond->cs); + + /* since this library is meant for realtime game software + * I have no problem setting this to 1 and forgetting about it. */ + if (!beginPeriod) + { + beginPeriod = true; + timeBeginPeriod(1); + } + + /* 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) + tsBegin = timeGetTime(); + + /* add ourselves to a queue of waiting threads */ + ptr = &cond->head; + + /* walk to the end of the linked list */ + while (*ptr) + ptr = &((*ptr)->next); + + *ptr = &myentry; + myentry.next = NULL; + + cond->waiters++; + + /* now the conceptual lock release and condition block are supposed to be atomic. + * we can't do that in Windows, but we can simulate the effects by using + * the queue, by the following analysis: + * What happens if they aren't atomic? + * + * 1. a signaller can rush in and signal, expecting a waiter to get it; + * but the waiter wouldn't, because he isn't blocked yet. + * Solution: Win32 events make this easy. The event will sit there enabled + * + * 2. a signaller can rush in and signal, and then turn right around and wait. + * Solution: the signaller will get queued behind the waiter, who's + * enqueued before he releases the mutex. */ + + /* It's my turn if I'm the head of the queue. + * Check to see if it's my turn. */ + while (cond->head != &myentry) + { + /* It isn't my turn: */ + DWORD timeout = INFINITE; + + /* As long as someone is even going to be able to wake up + * when they receive the potato, keep it going round. */ + if (cond->wakens > 0) + SetEvent(cond->hot_potato); + + /* Assess the remaining timeout time */ + if (dwMilliseconds != INFINITE) + { + DWORD now = timeGetTime(); + DWORD elapsed = now - tsBegin; + + /* Try one last time with a zero timeout (keeps the code simpler) */ + if (elapsed > dwMilliseconds) + elapsed = dwMilliseconds; + + timeout = dwMilliseconds - elapsed; + } + + /* Let someone else go */ + LeaveCriticalSection(&lock->lock); + LeaveCriticalSection(&cond->cs); + + /* Wait a while to catch the hot potato.. + * someone else should get a chance to go */ + /* After all, it isn't my turn (and it must be someone else's) */ + Sleep(0); + waitResult = WaitForSingleObject(cond->hot_potato, timeout); + + /* I should come out of here with the main lock taken */ + EnterCriticalSection(&lock->lock); + EnterCriticalSection(&cond->cs); + + if (waitResult == WAIT_TIMEOUT) + { + /* Out of time! Now, let's think about this. I do have the potato now-- + * maybe it's my turn, and I have the event? + * If that's the case, I could proceed right now without aborting + * due to timeout. + * + * However.. I DID wait a real long time. The caller was willing + * to wait that long. + * + * I choose to give him one last chance with a zero timeout + * in the next step + */ + if (cond->head == &myentry) + { + dwFinalTimeout = 0; + break; + } + else + { + /* It's not our turn and we're out of time. Give up. + * Remove ourself from the queue and bail. */ + struct QueueEntry* curr = cond->head; + + while (curr->next != &myentry) + curr = curr->next; + curr->next = myentry.next; + cond->waiters--; + LeaveCriticalSection(&cond->cs); + return false; + } + } + + } + + /* It's my turn now -- and I hold the potato */ + + /* I still have the main lock, in any case */ + /* I need to release it so that someone can set the event */ + LeaveCriticalSection(&lock->lock); + LeaveCriticalSection(&cond->cs); + + /* Wait for someone to actually signal this condition */ + /* We're the only waiter waiting on the event right now -- everyone else + * is waiting on something different */ + waitResult = WaitForSingleObject(cond->event, dwFinalTimeout); + + /* Take the main lock so we can do work. Nobody else waits on this lock + * for very long, so even though it's GO TIME we won't have to wait long */ + EnterCriticalSection(&lock->lock); + EnterCriticalSection(&cond->cs); + + /* Remove ourselves from the queue */ + cond->head = myentry.next; + cond->waiters--; + + if (waitResult == WAIT_TIMEOUT) + { + /* Oops! ran out of time in the final wait. Just bail. */ + LeaveCriticalSection(&cond->cs); + return false; + } + + /* If any other wakenings are pending, go ahead and set it up */ + /* There may actually be no waiters. That's OK. The first waiter will come in, + * find it's his turn, and immediately get the signaled event */ + cond->wakens--; + if (cond->wakens > 0) + { + SetEvent(cond->event); + + /* Progress the queue: Put the hot potato back into play. It'll be + * tossed around until next in line gets it */ + SetEvent(cond->hot_potato); + } + + LeaveCriticalSection(&cond->cs); + return true; +} +#endif + /** * scond_wait: * @cond : pointer to condition variable object @@ -369,10 +619,7 @@ void scond_free(scond_t *cond) void scond_wait(scond_t *cond, slock_t *lock) { #ifdef USE_WIN32_THREADS - WaitForSingleObject(cond->event, 0); - - SignalObjectAndWait(lock->lock, cond->event, INFINITE, FALSE); - slock_lock(lock); + _scond_wait_win32(cond, lock, INFINITE); #else pthread_cond_wait(&cond->cond, &lock->lock); #endif @@ -388,9 +635,18 @@ void scond_wait(scond_t *cond, slock_t *lock) int scond_broadcast(scond_t *cond) { #ifdef USE_WIN32_THREADS - /* FIXME _- check how this function should differ - * from scond_signal implementation. */ - SetEvent(cond->event); + /* remember: we currently have mutex */ + if (cond->waiters == 0) + return 0; + + /* awaken everything which is currently queued up */ + if (cond->wakens == 0) + SetEvent(cond->event); + cond->wakens = cond->waiters; + + /* Since there is now at least one pending waken, the potato must be in play */ + SetEvent(cond->hot_potato); + return 0; #else return pthread_cond_broadcast(&cond->cond); @@ -407,7 +663,37 @@ int scond_broadcast(scond_t *cond) void scond_signal(scond_t *cond) { #ifdef USE_WIN32_THREADS - SetEvent(cond->event); + + /* Unfortunately, pthread_cond_signal does not require that the + * lock be held in advance */ + /* To avoid stomping on the condvar from other threads, we need + * to control access to it with this */ + EnterCriticalSection(&cond->cs); + + /* remember: we currently have mutex */ + if (cond->waiters == 0) + { + LeaveCriticalSection(&cond->cs); + return; + } + + /* wake up the next thing in the queue */ + if (cond->wakens == 0) + SetEvent(cond->event); + + cond->wakens++; + + /* The data structure is done being modified.. I think we can leave the CS now. + * This would prevent some other thread from receiving the hot potato and then + * immediately stalling for the critical section. + * But remember, we were trying to replicate a semantic where this entire + * scond_signal call was controlled (by the user) by a lock. + * So in case there's trouble with this, we can move it after SetEvent() */ + LeaveCriticalSection(&cond->cs); + + /* Since there is now at least one pending waken, the potato must be in play */ + SetEvent(cond->hot_potato); + #else pthread_cond_signal(&cond->cond); #endif @@ -428,14 +714,29 @@ void scond_signal(scond_t *cond) bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us) { #ifdef USE_WIN32_THREADS - DWORD ret; + /* How to convert a microsecond (us) timeout to millisecond (ms)? + * + * Someone asking for a 0 timeout clearly wants immediate timeout. + * Someone asking for a 1 timeout clearly wants an actual timeout + * of the minimum length */ - WaitForSingleObject(cond->event, 0); - ret = SignalObjectAndWait(lock->lock, cond->event, - (DWORD)(timeout_us) / 1000, FALSE); + /* Someone asking for 1000 or 1001 timeout shouldn't + * accidentally get 2ms. */ + DWORD dwMilliseconds = timeout_us/1000; - slock_lock(lock); - return ret == WAIT_OBJECT_0; + /* The implementation of a 0 timeout here with pthreads is sketchy. + * It isn't clear what happens if pthread_cond_timedwait is called with NOW. + * Moreover, it is possible that this thread gets pre-empted after the + * clock_gettime but before the pthread_cond_timedwait. + * In order to help smoke out problems caused by this strange usage, + * let's treat a 0 timeout as always timing out. + */ + if (timeout_us == 0) + return false; + else if (timeout_us < 1000) + dwMilliseconds = 1; + + return _scond_wait_win32(cond,lock,dwMilliseconds); #else int ret; int64_t seconds, remainder; diff --git a/managers/cheat_manager.c b/managers/cheat_manager.c index 5740449e00..10d4974d51 100644 --- a/managers/cheat_manager.c +++ b/managers/cheat_manager.c @@ -30,7 +30,7 @@ #endif #ifdef HAVE_CHEEVOS -#include "../cheevos.h" +#include "../cheevos/cheevos.h" #endif #include "cheat_manager.h" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 3e0f42ed7d..e57e66043e 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -19,7 +19,7 @@ #include "../menu_cbs.h" #ifdef HAVE_CHEEVOS -#include "../../cheevos.h" +#include "../../cheevos/cheevos.h" #endif #include "../../verbosity.h" @@ -184,6 +184,7 @@ default_sublabel_macro(action_bind_sublabel_overlay_opacity, MENU_ default_sublabel_macro(action_bind_sublabel_overlay_scale, MENU_ENUM_SUBLABEL_OVERLAY_SCALE) default_sublabel_macro(action_bind_sublabel_overlay_enable, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_ENABLE) default_sublabel_macro(action_bind_sublabel_overlay_preset, MENU_ENUM_SUBLABEL_OVERLAY_PRESET) +default_sublabel_macro(action_bind_sublabel_netplay_public_announce, MENU_ENUM_SUBLABEL_NETPLAY_PUBLIC_ANNOUNCE) default_sublabel_macro(action_bind_sublabel_netplay_ip_address, MENU_ENUM_SUBLABEL_NETPLAY_IP_ADDRESS) default_sublabel_macro(action_bind_sublabel_netplay_tcp_udp_port, MENU_ENUM_SUBLABEL_NETPLAY_TCP_UDP_PORT) default_sublabel_macro(action_bind_sublabel_netplay_password, MENU_ENUM_SUBLABEL_NETPLAY_PASSWORD) @@ -736,6 +737,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_STDIN_CMD_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_stdin_cmd_enable); break; + case MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_public_announce); + break; case MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_nat_traversal); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 4824c06f4c..d414a3fb8f 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -184,7 +184,7 @@ static void mui_context_reset_textures(mui_handle_t *mui) APPLICATION_SPECIAL_DIRECTORY_ASSETS_MATERIALUI_ICONS); for (i = 0; i < MUI_TEXTURE_LAST; i++) - menu_display_reset_textures_list(mui_texture_path(i), iconpath, &mui->textures.list[i]); + menu_display_reset_textures_list(mui_texture_path(i), iconpath, &mui->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR); } static void mui_draw_icon( diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 25bdee0e3f..c4c01c986b 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -3467,7 +3467,7 @@ static void xmb_context_reset_textures( unsigned i; for (i = 0; i < XMB_TEXTURE_LAST; i++) - menu_display_reset_textures_list(xmb_texture_path(i), iconpath, &xmb->textures.list[i]); + menu_display_reset_textures_list(xmb_texture_path(i), iconpath, &xmb->textures.list[i], TEXTURE_FILTER_MIPMAP_LINEAR); menu_display_allocate_white_texture(); diff --git a/menu/menu_display.c b/menu/menu_display.c index 4e6c76e593..dc65ac645a 100644 --- a/menu/menu_display.c +++ b/menu/menu_display.c @@ -500,7 +500,7 @@ void menu_display_draw_pipeline(menu_display_ctx_draw_t *draw) menu_disp->draw_pipeline(draw); } -void menu_display_draw_bg(menu_display_ctx_draw_t *draw, +void menu_display_draw_bg(menu_display_ctx_draw_t *draw, video_frame_info_t *video_info, bool add_opacity_to_wallpaper) { static struct video_coords coords; @@ -611,6 +611,281 @@ void menu_display_draw_texture( menu_display_draw(&draw); } +/* Draw the texture split into 9 sections, without scaling the corners. + * The middle sections will only scale in the X axis, and the side + * sections will only scale in the Y axis. */ +void menu_display_draw_texture_slice( + int x, int y, unsigned w, unsigned h, + unsigned new_w, unsigned new_h, + unsigned width, unsigned height, + float *color, unsigned offset, float scale_factor, uintptr_t texture) +{ + menu_display_ctx_draw_t draw; + menu_display_ctx_rotate_draw_t rotate_draw; + struct video_coords coords; + math_matrix_4x4 mymat; + unsigned i; + + /* need space for the coordinates of two triangles in a strip, so 8 vertices */ + float *tex_coord = (float*)malloc(8 * sizeof(float)); + float *vert_coord = (float*)malloc(8 * sizeof(float)); + float *colors = (float*)malloc(16 * sizeof(float)); + + /* normalized width/height of the amount to offset from the corners, + * for both the vertex and texture coordinates */ + float vert_woff = (offset * scale_factor) / (float)width; + float vert_hoff = (offset * scale_factor) / (float)height; + float tex_woff = offset / (float)w; + float tex_hoff = offset / (float)h; + + /* the width/height of the middle sections of both the scaled and original image */ + float vert_scaled_mid_width = (new_w - (offset * scale_factor * 2)) / (float)width; + float vert_scaled_mid_height = (new_h - (offset * scale_factor * 2)) / (float)height; + float tex_mid_width = (w - (offset * 2)) / (float)w; + float tex_mid_height = (h - (offset * 2)) / (float)h; + + /* normalized coordinates for the start position of the image */ + float norm_x = x / (float)width; + float norm_y = (height - y) / (float)height; + + /* the four vertices of the top-left corner of the image, + * used as a starting point for all the other sections */ + float V_BL[2] = {norm_x, norm_y}; + float V_BR[2] = {norm_x + vert_woff, norm_y}; + float V_TL[2] = {norm_x, norm_y + vert_hoff}; + float V_TR[2] = {norm_x + vert_woff, norm_y + vert_hoff}; + float T_BL[2] = {0.0f, tex_hoff}; + float T_BR[2] = {tex_woff, tex_hoff}; + float T_TL[2] = {0.0f, 0.0f}; + float T_TR[2] = {tex_woff, 0.0f}; + + for (i = 0; i < (16 * sizeof(float)) / sizeof(colors[0]); i++) + colors[i] = 1.0f; + + rotate_draw.matrix = &mymat; + rotate_draw.rotation = 0.0; + rotate_draw.scale_x = 1.0; + rotate_draw.scale_y = 1.0; + rotate_draw.scale_z = 1; + rotate_draw.scale_enable = true; + coords.vertices = 4; + coords.vertex = vert_coord; + coords.tex_coord = tex_coord; + coords.lut_tex_coord = NULL; + draw.width = width; + draw.height = height; + draw.coords = &coords; + draw.matrix_data = &mymat; + draw.prim_type = MENU_DISPLAY_PRIM_TRIANGLESTRIP; + draw.pipeline.id = 0; + coords.color = (const float*)colors; + + menu_display_rotate_z(&rotate_draw); + + draw.texture = texture; + draw.x = 0; + draw.y = 0; + + /* vertex coords are specfied bottom-up in this order: BL BR TL TR */ + /* texture coords are specfied top-down in this order: BL BR TL TR */ + + /* If someone wants to change this to not draw several times, the + * coordinates will need to be modified because of the triangle strip usage. */ + + /* top-left corner */ + vert_coord[0] = V_BL[0]; + vert_coord[1] = V_BL[1]; + vert_coord[2] = V_BR[0]; + vert_coord[3] = V_BR[1]; + vert_coord[4] = V_TL[0]; + vert_coord[5] = V_TL[1]; + vert_coord[6] = V_TR[0]; + vert_coord[7] = V_TR[1]; + + tex_coord[0] = T_BL[0]; + tex_coord[1] = T_BL[1]; + tex_coord[2] = T_BR[0]; + tex_coord[3] = T_BR[1]; + tex_coord[4] = T_TL[0]; + tex_coord[5] = T_TL[1]; + tex_coord[6] = T_TR[0]; + tex_coord[7] = T_TR[1]; + + menu_display_draw(&draw); + + /* top-middle section */ + vert_coord[0] = V_BL[0] + vert_woff; + vert_coord[1] = V_BL[1]; + vert_coord[2] = V_BR[0] + vert_scaled_mid_width; + vert_coord[3] = V_BR[1]; + vert_coord[4] = V_TL[0] + vert_woff; + vert_coord[5] = V_TL[1]; + vert_coord[6] = V_TR[0] + vert_scaled_mid_width; + vert_coord[7] = V_TR[1]; + + tex_coord[0] = T_BL[0] + tex_woff; + tex_coord[1] = T_BL[1]; + tex_coord[2] = T_BR[0] + tex_mid_width; + tex_coord[3] = T_BR[1]; + tex_coord[4] = T_TL[0] + tex_woff; + tex_coord[5] = T_TL[1]; + tex_coord[6] = T_TR[0] + tex_mid_width; + tex_coord[7] = T_TR[1]; + + menu_display_draw(&draw); + + /* top-right corner */ + vert_coord[0] = V_BL[0] + vert_woff + vert_scaled_mid_width; + vert_coord[1] = V_BL[1]; + vert_coord[2] = V_BR[0] + vert_scaled_mid_width + vert_woff; + vert_coord[3] = V_BR[1]; + vert_coord[4] = V_TL[0] + vert_woff + vert_scaled_mid_width; + vert_coord[5] = V_TL[1]; + vert_coord[6] = V_TR[0] + vert_scaled_mid_width + vert_woff; + vert_coord[7] = V_TR[1]; + + tex_coord[0] = T_BL[0] + tex_woff + tex_mid_width; + tex_coord[1] = T_BL[1]; + tex_coord[2] = T_BR[0] + tex_mid_width + tex_woff; + tex_coord[3] = T_BR[1]; + tex_coord[4] = T_TL[0] + tex_woff + tex_mid_width; + tex_coord[5] = T_TL[1]; + tex_coord[6] = T_TR[0] + tex_mid_width + tex_woff; + tex_coord[7] = T_TR[1]; + + menu_display_draw(&draw); + + /* middle-left section */ + vert_coord[0] = V_BL[0]; + vert_coord[1] = V_BL[1] - vert_scaled_mid_height; + vert_coord[2] = V_BR[0]; + vert_coord[3] = V_BR[1] - vert_scaled_mid_height; + vert_coord[4] = V_TL[0]; + vert_coord[5] = V_TL[1] - vert_hoff; + vert_coord[6] = V_TR[0]; + vert_coord[7] = V_TR[1] - vert_hoff; + + tex_coord[0] = T_BL[0]; + tex_coord[1] = T_BL[1] + tex_mid_height; + tex_coord[2] = T_BR[0]; + tex_coord[3] = T_BR[1] + tex_mid_height; + tex_coord[4] = T_TL[0]; + tex_coord[5] = T_TL[1] + tex_hoff; + tex_coord[6] = T_TR[0]; + tex_coord[7] = T_TR[1] + tex_hoff; + + menu_display_draw(&draw); + + /* center section */ + vert_coord[0] = V_BL[0] + vert_woff; + vert_coord[1] = V_BL[1] - vert_scaled_mid_height; + vert_coord[2] = V_BR[0] + vert_scaled_mid_width; + vert_coord[3] = V_BR[1] - vert_scaled_mid_height; + vert_coord[4] = V_TL[0] + vert_woff; + vert_coord[5] = V_TL[1] - vert_hoff; + vert_coord[6] = V_TR[0] + vert_scaled_mid_width; + vert_coord[7] = V_TR[1] - vert_hoff; + + tex_coord[0] = T_BL[0] + tex_woff; + tex_coord[1] = T_BL[1] + tex_mid_height; + tex_coord[2] = T_BR[0] + tex_mid_width; + tex_coord[3] = T_BR[1] + tex_mid_height; + tex_coord[4] = T_TL[0] + tex_woff; + tex_coord[5] = T_TL[1] + tex_hoff; + tex_coord[6] = T_TR[0] + tex_mid_width; + tex_coord[7] = T_TR[1] + tex_hoff; + + menu_display_draw(&draw); + + /* middle-right section */ + vert_coord[0] = V_BL[0] + vert_woff + vert_scaled_mid_width; + vert_coord[1] = V_BL[1] - vert_scaled_mid_height; + vert_coord[2] = V_BR[0] + vert_woff + vert_scaled_mid_width; + vert_coord[3] = V_BR[1] - vert_scaled_mid_height; + vert_coord[4] = V_TL[0] + vert_woff + vert_scaled_mid_width; + vert_coord[5] = V_TL[1] - vert_hoff; + vert_coord[6] = V_TR[0] + vert_woff + vert_scaled_mid_width; + vert_coord[7] = V_TR[1] - vert_hoff; + + tex_coord[0] = T_BL[0] + tex_woff + tex_mid_width; + tex_coord[1] = T_BL[1] + tex_mid_height; + tex_coord[2] = T_BR[0] + tex_woff + tex_mid_width; + tex_coord[3] = T_BR[1] + tex_mid_height; + tex_coord[4] = T_TL[0] + tex_woff + tex_mid_width; + tex_coord[5] = T_TL[1] + tex_hoff; + tex_coord[6] = T_TR[0] + tex_woff + tex_mid_width; + tex_coord[7] = T_TR[1] + tex_hoff; + + menu_display_draw(&draw); + + /* bottom-left corner */ + vert_coord[0] = V_BL[0]; + vert_coord[1] = V_BL[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[2] = V_BR[0]; + vert_coord[3] = V_BR[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[4] = V_TL[0]; + vert_coord[5] = V_TL[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[6] = V_TR[0]; + vert_coord[7] = V_TR[1] - vert_hoff - vert_scaled_mid_height; + + tex_coord[0] = T_BL[0]; + tex_coord[1] = T_BL[1] + tex_hoff + tex_mid_height; + tex_coord[2] = T_BR[0]; + tex_coord[3] = T_BR[1] + tex_hoff + tex_mid_height; + tex_coord[4] = T_TL[0]; + tex_coord[5] = T_TL[1] + tex_hoff + tex_mid_height; + tex_coord[6] = T_TR[0]; + tex_coord[7] = T_TR[1] + tex_hoff + tex_mid_height; + + menu_display_draw(&draw); + + /* bottom-middle section */ + vert_coord[0] = V_BL[0] + vert_woff; + vert_coord[1] = V_BL[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[2] = V_BR[0] + vert_scaled_mid_width; + vert_coord[3] = V_BR[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[4] = V_TL[0] + vert_woff; + vert_coord[5] = V_TL[1] - vert_scaled_mid_height; + vert_coord[6] = V_TR[0] + vert_scaled_mid_width; + vert_coord[7] = V_TR[1] - vert_scaled_mid_height; + + tex_coord[0] = T_BL[0] + tex_woff; + tex_coord[1] = T_BL[1] + tex_hoff + tex_mid_height; + tex_coord[2] = T_BR[0] + tex_mid_width; + tex_coord[3] = T_BR[1] + tex_hoff + tex_mid_height; + tex_coord[4] = T_TL[0] + tex_woff; + tex_coord[5] = T_TL[1] + tex_mid_height; + tex_coord[6] = T_TR[0] + tex_mid_width; + tex_coord[7] = T_TR[1] + tex_mid_height; + + menu_display_draw(&draw); + + /* bottom-right corner */ + vert_coord[0] = V_BL[0] + vert_woff + vert_scaled_mid_width; + vert_coord[1] = V_BL[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[2] = V_BR[0] + vert_scaled_mid_width + vert_woff; + vert_coord[3] = V_BR[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[4] = V_TL[0] + vert_woff + vert_scaled_mid_width; + vert_coord[5] = V_TL[1] - vert_hoff - vert_scaled_mid_height; + vert_coord[6] = V_TR[0] + vert_scaled_mid_width + vert_woff; + vert_coord[7] = V_TR[1] - vert_hoff - vert_scaled_mid_height; + + tex_coord[0] = T_BL[0] + tex_woff + tex_mid_width; + tex_coord[1] = T_BL[1] + tex_hoff + tex_mid_height; + tex_coord[2] = T_BR[0] + tex_woff + tex_mid_width; + tex_coord[3] = T_BR[1] + tex_hoff + tex_mid_height; + tex_coord[4] = T_TL[0] + tex_woff + tex_mid_width; + tex_coord[5] = T_TL[1] + tex_hoff + tex_mid_height; + tex_coord[6] = T_TR[0] + tex_woff + tex_mid_width; + tex_coord[7] = T_TR[1] + tex_hoff + tex_mid_height; + + menu_display_draw(&draw); + + free(colors); + free(vert_coord); + free(tex_coord); +} + void menu_display_rotate_z(menu_display_ctx_rotate_draw_t *draw) { #if !defined(VITA) @@ -907,7 +1182,7 @@ void menu_display_set_alpha(float *color, float alpha_value) } void menu_display_reset_textures_list(const char *texture_path, const char *iconpath, - uintptr_t *item) + uintptr_t *item, enum texture_filter_type filter_type) { struct texture_image ti; char path[PATH_MAX_LENGTH]; @@ -929,6 +1204,6 @@ void menu_display_reset_textures_list(const char *texture_path, const char *icon return; video_driver_texture_load(&ti, - TEXTURE_FILTER_MIPMAP_LINEAR, item); + filter_type, item); image_texture_free(&ti); } diff --git a/menu/menu_display.h b/menu/menu_display.h index 99a6834189..c3c8104dec 100644 --- a/menu/menu_display.h +++ b/menu/menu_display.h @@ -256,6 +256,9 @@ void menu_display_draw_quad(int x, int y, unsigned w, unsigned h, void menu_display_draw_texture(int x, int y, unsigned w, unsigned h, unsigned width, unsigned height, float *color, uintptr_t texture); +void menu_display_draw_texture_slice(int x, int y, unsigned w, unsigned h, + unsigned new_w, unsigned new_h, unsigned width, unsigned height, + float *color, unsigned offset, float scale_factor, uintptr_t texture); void menu_display_rotate_z(menu_display_ctx_rotate_draw_t *draw); bool menu_display_get_tex_coords(menu_display_ctx_coord_draw_t *draw); @@ -294,7 +297,7 @@ void menu_display_set_alpha(float *color, float alpha_value); font_data_t *menu_display_font(enum application_special_type type, float font_size); void menu_display_reset_textures_list(const char *texture_path, const char *iconpath, - uintptr_t *item); + uintptr_t *item, enum texture_filter_type filter_type); extern uintptr_t menu_display_white_texture; diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 6a833cd959..a1a2b319fb 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -37,7 +37,7 @@ #endif #ifdef HAVE_CHEEVOS -#include "../cheevos.h" +#include "../cheevos/cheevos.h" #endif #ifdef HAVE_NETWORKING @@ -4793,6 +4793,10 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) unsigned user; unsigned count = 0; + if (menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE, + PARSE_ONLY_BOOL, false) != -1) + count++; if (menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_NETPLAY_IP_ADDRESS, PARSE_ONLY_STRING, false) != -1) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 428c725bf7..6cba6258f5 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -2817,13 +2817,13 @@ static bool setting_append_list( bool_entries[3].name_enum_idx = MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE; bool_entries[3].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE; bool_entries[3].default_value = default_auto_overrides_enable; - bool_entries[3].flags = SD_FLAG_NONE; + bool_entries[3].flags = SD_FLAG_ADVANCED; bool_entries[4].target = &settings->auto_remaps_enable; bool_entries[4].name_enum_idx = MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE; bool_entries[4].SHORT_enum_idx = MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE; bool_entries[4].default_value = default_auto_remaps_enable; - bool_entries[4].flags = SD_FLAG_NONE; + bool_entries[4].flags = SD_FLAG_ADVANCED; bool_entries[5].target = &settings->auto_shaders_enable; bool_entries[5].name_enum_idx = MENU_ENUM_LABEL_AUTO_SHADERS_ENABLE; @@ -5590,6 +5590,21 @@ static bool setting_append_list( #if defined(HAVE_NETWORK_CMD) unsigned user; #endif + CONFIG_BOOL( + list, list_info, + &settings->netplay.public_announce, + MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE, + MENU_ENUM_LABEL_VALUE_NETPLAY_PUBLIC_ANNOUNCE, + 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_NONE); + CONFIG_STRING( list, list_info, settings->netplay.server, diff --git a/menu/widgets/menu_dialog.c b/menu/widgets/menu_dialog.c index d2a1f26fa0..00170c516e 100644 --- a/menu/widgets/menu_dialog.c +++ b/menu/widgets/menu_dialog.c @@ -22,7 +22,7 @@ #endif #ifdef HAVE_CHEEVOS -#include "../../cheevos.h" +#include "../../cheevos/cheevos.h" #endif #include "menu_dialog.h" diff --git a/msg_hash.h b/msg_hash.h index c73d676756..fba5261515 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -168,6 +168,7 @@ enum msg_hash_enums MSG_CAPABILITIES, MSG_DEVICE_CONFIGURED_IN_PORT, MSG_DEVICE_NOT_CONFIGURED, + MSG_DEVICE_NOT_CONFIGURED_FALLBACK, MSG_DEVICE_DISCONNECTED_FROM_PORT, MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, MSG_COMPILER, @@ -1017,6 +1018,7 @@ enum msg_hash_enums MENU_LABEL(BLUETOOTH_ENABLE), MENU_LABEL(NETPLAY_CLIENT_SWAP_INPUT), MENU_LABEL(NETPLAY_DELAY_FRAMES), + MENU_LABEL(NETPLAY_PUBLIC_ANNOUNCE), MENU_LABEL(NETPLAY_STATELESS_MODE), MENU_LABEL(NETPLAY_CHECK_FRAMES), MENU_LABEL(NETPLAY_INPUT_LATENCY_FRAMES_MIN), diff --git a/network/httpserver/httpserver.c b/network/httpserver/httpserver.c index 6a7ade8dc2..45958ba060 100644 --- a/network/httpserver/httpserver.c +++ b/network/httpserver/httpserver.c @@ -29,7 +29,7 @@ #include "../../core.h" #include "../../gfx/video_driver.h" #include "../../managers/core_option_manager.h" -#include "../../cheevos.h" +#include "../../cheevos/cheevos.h" #include "../../content.h" #define BASIC_INFO "info" diff --git a/network/netplay/README b/network/netplay/README index 168dd8b4e7..460dbc91cc 100644 --- a/network/netplay/README +++ b/network/netplay/README @@ -316,6 +316,14 @@ Payload: Description: Request that a client stall for the given number of frames. +Command: RESET +Payload: + { + frame: uint32 + } +Description: + Indicate that the core was reset at the beginning of the given frame. + Command: CHEATS Unused diff --git a/network/netplay/netplay.h b/network/netplay/netplay.h index e6fd5f6488..d873e62e99 100644 --- a/network/netplay/netplay.h +++ b/network/netplay/netplay.h @@ -44,6 +44,7 @@ enum rarch_netplay_ctl_state RARCH_NETPLAY_CTL_PAUSE, RARCH_NETPLAY_CTL_UNPAUSE, RARCH_NETPLAY_CTL_LOAD_SAVESTATE, + RARCH_NETPLAY_CTL_RESET, RARCH_NETPLAY_CTL_DISCONNECT }; diff --git a/network/netplay/netplay_frontend.c b/network/netplay/netplay_frontend.c index 8e40d92403..0afbbcb353 100644 --- a/network/netplay/netplay_frontend.c +++ b/network/netplay/netplay_frontend.c @@ -32,7 +32,7 @@ #include "../../tasks/tasks_internal.h" #include #include "../../file_path_special.h" -#include "paths.h" +#include "../../paths.h" /* Only used before init_netplay */ static bool netplay_enabled = false; @@ -652,11 +652,22 @@ static void netplay_frontend_paused(netplay_t *netplay, bool paused) bool netplay_pre_frame(netplay_t *netplay) { bool sync_stalled; - reannounce ++; - if (netplay->is_server && (reannounce % 3600 == 0)) - netplay_announce(); + settings_t *settings = config_get_ptr(); + retro_assert(netplay); + if (settings->netplay.public_announce) + { + reannounce ++; + if (netplay->is_server && (reannounce % 3600 == 0)) + netplay_announce(); + } + else + { + /* Make sure that if announcement is turned on mid-game, it gets announced */ + reannounce = -1; + } + /* FIXME: This is an ugly way to learn we're not paused anymore */ if (netplay->local_paused) netplay_frontend_paused(netplay, false); @@ -729,6 +740,48 @@ void netplay_post_frame(netplay_t *netplay) } } +/** + * netplay_force_future + * @netplay : pointer to netplay object + * + * Force netplay to ignore all past input, typically because we've just loaded + * a state or reset. + */ +static void netplay_force_future(netplay_t *netplay) +{ + /* Wherever we're inputting, that's where we consider our state to be loaded */ + netplay->run_ptr = netplay->self_ptr; + netplay->run_frame_count = netplay->self_frame_count; + + /* We need to ignore any intervening data from the other side, + * and never rewind past this */ + netplay_update_unread_ptr(netplay); + if (netplay->unread_frame_count < netplay->run_frame_count) + { + uint32_t player; + for (player = 0; player < MAX_USERS; player++) + { + if (!(netplay->connected_players & (1<read_frame_count[player] < netplay->run_frame_count) + { + netplay->read_ptr[player] = netplay->run_ptr; + netplay->read_frame_count[player] = netplay->run_frame_count; + } + } + if (netplay->server_frame_count < netplay->run_frame_count) + { + netplay->server_ptr = netplay->run_ptr; + netplay->server_frame_count = netplay->run_frame_count; + } + netplay_update_unread_ptr(netplay); + } + if (netplay->other_frame_count < netplay->run_frame_count) + { + netplay->other_ptr = netplay->run_ptr; + netplay->other_frame_count = netplay->run_frame_count; + } +} + /** * netplay_send_savestate * @netplay : pointer to netplay object @@ -797,10 +850,7 @@ void netplay_load_savestate(netplay_t *netplay, { retro_ctx_serialize_info_t tmp_serial_info; - /* Wherever we're inputting, that's where we consider our state to be loaded - * (FIXME: Need to be more careful about saving it?) */ - netplay->run_ptr = netplay->self_ptr; - netplay->run_frame_count = netplay->self_frame_count; + netplay_force_future(netplay); /* Record it in our own buffer */ if (save || !serial_info) @@ -833,34 +883,6 @@ void netplay_load_savestate(netplay_t *netplay, } } - /* We need to ignore any intervening data from the other side, - * and never rewind past this */ - netplay_update_unread_ptr(netplay); - if (netplay->unread_frame_count < netplay->run_frame_count) - { - uint32_t player; - for (player = 0; player < MAX_USERS; player++) - { - if (!(netplay->connected_players & (1<read_frame_count[player] < netplay->run_frame_count) - { - netplay->read_ptr[player] = netplay->run_ptr; - netplay->read_frame_count[player] = netplay->run_frame_count; - } - } - if (netplay->server_frame_count < netplay->run_frame_count) - { - netplay->server_ptr = netplay->run_ptr; - netplay->server_frame_count = netplay->run_frame_count; - } - netplay_update_unread_ptr(netplay); - } - if (netplay->other_frame_count < netplay->run_frame_count) - { - netplay->other_ptr = netplay->run_ptr; - netplay->other_frame_count = netplay->run_frame_count; - } - /* If we can't send it to the peer, loading a state was a bad idea */ if (netplay->quirks & ( NETPLAY_QUIRK_NO_SAVESTATES @@ -875,6 +897,37 @@ void netplay_load_savestate(netplay_t *netplay, &netplay->compress_zlib); } +/** + * netplay_core_reset + * @netplay : pointer to netplay object + * + * Indicate that the core has been reset to netplay peers + **/ +static void netplay_core_reset(netplay_t *netplay) +{ + uint32_t cmd[3]; + size_t i; + + /* Ignore past input */ + netplay_force_future(netplay); + + /* Request that our peers reset */ + cmd[0] = htonl(NETPLAY_CMD_RESET); + cmd[1] = htonl(sizeof(uint32_t)); + cmd[2] = htonl(netplay->self_frame_count); + + for (i = 0; i < netplay->connections_size; i++) + { + struct netplay_connection *connection = &netplay->connections[i]; + if (!connection->active || + connection->mode < NETPLAY_CONNECTION_CONNECTED) continue; + + if (!netplay_send(&connection->send_packet_buffer, connection->fd, cmd, + sizeof(cmd))) + netplay_hangup(netplay, connection); + } +} + /** * netplay_toggle_play_spectate * @@ -1027,7 +1080,8 @@ bool init_netplay(void *direct_host, const char *server, unsigned port) msg_hash_to_str(MSG_WAITING_FOR_CLIENT), 0, 180, false); - netplay_announce(); + if (settings->netplay.public_announce) + netplay_announce(); } netplay_data = (netplay_t*)netplay_new( @@ -1133,6 +1187,9 @@ bool netplay_driver_ctl(enum rarch_netplay_ctl_state state, void *data) case RARCH_NETPLAY_CTL_LOAD_SAVESTATE: netplay_load_savestate(netplay_data, (retro_ctx_serialize_info_t*)data, true); break; + case RARCH_NETPLAY_CTL_RESET: + netplay_core_reset(netplay_data); + break; case RARCH_NETPLAY_CTL_DISCONNECT: ret = netplay_disconnect(netplay_data); goto done; diff --git a/network/netplay/netplay_handshake.c b/network/netplay/netplay_handshake.c index ad58ea3cf0..4df482e0e9 100644 --- a/network/netplay/netplay_handshake.c +++ b/network/netplay/netplay_handshake.c @@ -25,13 +25,20 @@ #include "netplay_private.h" +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + #include "../../autosave.h" #include "../../configuration.h" #include "../../content.h" #include "../../retroarch.h" #include "../../runloop.h" #include "../../version.h" + +#ifdef HAVE_MENU #include "../../menu/widgets/menu_input_dialog.h" +#endif #ifndef HAVE_SOCKET_LEGACY /* Custom inet_ntop. Win32 doesn't seem to support this ... */ @@ -265,8 +272,9 @@ struct info_buf_s } \ else if (recvd < 0) -static netplay_t *handshake_password_netplay; +static netplay_t *handshake_password_netplay = NULL; +#ifdef HAVE_MENU static void handshake_password(void *ignore, const char *line) { struct password_buf_s password_buf; @@ -285,9 +293,12 @@ static void handshake_password(void *ignore, const char *line) if (netplay_send(&connection->send_packet_buffer, connection->fd, &password_buf, sizeof(password_buf))) netplay_send_flush(&connection->send_packet_buffer, connection->fd, false); +#ifdef HAVE_MENU menu_input_dialog_end(); rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); +#endif } +#endif /** * netplay_handshake_init @@ -381,15 +392,21 @@ bool netplay_handshake_init(netplay_t *netplay, /* If a password is demanded, ask for it */ if (!netplay->is_server && (connection->salt = ntohl(header[3]))) { +#ifdef HAVE_MENU menu_input_ctx_line_t line; rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); - memset(&line, 0, sizeof(line)); +#endif + handshake_password_netplay = netplay; - line.label = msg_hash_to_str(MSG_NETPLAY_ENTER_PASSWORD); + +#ifdef HAVE_MENU + memset(&line, 0, sizeof(line)); + line.label = msg_hash_to_str(MSG_NETPLAY_ENTER_PASSWORD); line.label_setting = "no_setting"; - line.cb = handshake_password; + line.cb = handshake_password; if (!menu_input_dialog_start(&line)) return false; +#endif } /* Send our nick */ diff --git a/network/netplay/netplay_io.c b/network/netplay/netplay_io.c index c8c106a491..4de8e02375 100644 --- a/network/netplay/netplay_io.c +++ b/network/netplay/netplay_io.c @@ -1022,6 +1022,7 @@ static bool netplay_get_cmd(netplay_t *netplay, break; case NETPLAY_CMD_LOAD_SAVESTATE: + case NETPLAY_CMD_RESET: { uint32_t frame; uint32_t isize; @@ -1071,7 +1072,11 @@ static bool netplay_get_cmd(netplay_t *netplay, * (strangely) force a rewind to the frame we're already on, so it * gets loaded. This is just to avoid having reloading implemented in * too many places. */ - if (cmd_size > netplay->zbuffer_size + 2*sizeof(uint32_t)) + + /* Check the payload size */ + if ((cmd == NETPLAY_CMD_LOAD_SAVESTATE && + (cmd_size < 2*sizeof(uint32_t) || cmd_size > netplay->zbuffer_size + 2*sizeof(uint32_t))) || + (cmd == NETPLAY_CMD_RESET && cmd_size != sizeof(uint32_t))) { RARCH_ERR("CMD_LOAD_SAVESTATE received an unexpected payload size.\n"); return netplay_cmd_nak(netplay, connection); @@ -1097,44 +1102,58 @@ static bool netplay_get_cmd(netplay_t *netplay, goto shrt; } - RECV(&isize, sizeof(isize)) + /* Now we switch based on whether we're loading a state or resetting */ + if (cmd == NETPLAY_CMD_LOAD_SAVESTATE) { - RARCH_ERR("CMD_LOAD_SAVESTATE failed to receive inflated size.\n"); - return netplay_cmd_nak(netplay, connection); - } - isize = ntohl(isize); + RECV(&isize, sizeof(isize)) + { + RARCH_ERR("CMD_LOAD_SAVESTATE failed to receive inflated size.\n"); + return netplay_cmd_nak(netplay, connection); + } + isize = ntohl(isize); - if (isize != netplay->state_size) - { - RARCH_ERR("CMD_LOAD_SAVESTATE received an unexpected save state size.\n"); - return netplay_cmd_nak(netplay, connection); - } + if (isize != netplay->state_size) + { + RARCH_ERR("CMD_LOAD_SAVESTATE received an unexpected save state size.\n"); + return netplay_cmd_nak(netplay, connection); + } - RECV(netplay->zbuffer, cmd_size - 2*sizeof(uint32_t)) - { - RARCH_ERR("CMD_LOAD_SAVESTATE failed to receive savestate.\n"); - return netplay_cmd_nak(netplay, connection); - } + RECV(netplay->zbuffer, cmd_size - 2*sizeof(uint32_t)) + { + RARCH_ERR("CMD_LOAD_SAVESTATE failed to receive savestate.\n"); + return netplay_cmd_nak(netplay, connection); + } + + /* And decompress it */ + switch (connection->compression_supported) + { + case NETPLAY_COMPRESSION_ZLIB: + ctrans = &netplay->compress_zlib; + break; + default: + ctrans = &netplay->compress_nil; + } + ctrans->decompression_backend->set_in(ctrans->decompression_stream, + netplay->zbuffer, cmd_size - 2*sizeof(uint32_t)); + ctrans->decompression_backend->set_out(ctrans->decompression_stream, + (uint8_t*)netplay->buffer[netplay->read_ptr[connection->player]].state, + netplay->state_size); + ctrans->decompression_backend->trans(ctrans->decompression_stream, + true, &rd, &wn, NULL); + + /* Force a rewind to the relevant frame */ + netplay->force_rewind = true; + } + else + { + /* Resetting */ + netplay->force_reset = true; - /* And decompress it */ - switch (connection->compression_supported) - { - case NETPLAY_COMPRESSION_ZLIB: - ctrans = &netplay->compress_zlib; - break; - default: - ctrans = &netplay->compress_nil; } - ctrans->decompression_backend->set_in(ctrans->decompression_stream, - netplay->zbuffer, cmd_size - 2*sizeof(uint32_t)); - ctrans->decompression_backend->set_out(ctrans->decompression_stream, - (uint8_t*)netplay->buffer[netplay->read_ptr[connection->player]].state, - netplay->state_size); - ctrans->decompression_backend->trans(ctrans->decompression_stream, - true, &rd, &wn, NULL); /* Skip ahead if it's past where we are */ - if (frame > netplay->run_frame_count) + if (frame > netplay->run_frame_count || + cmd == NETPLAY_CMD_RESET) { /* This is squirrely: We need to assure that when we advance the * frame in post_frame, THEN we're referring to the frame to @@ -1161,8 +1180,7 @@ static bool netplay_get_cmd(netplay_t *netplay, } } - /* And force rewind to it */ - netplay->force_rewind = true; + /* Make sure our states are correct */ netplay->savestate_request_outstanding = false; netplay->other_ptr = netplay->read_ptr[connection->player]; netplay->other_frame_count = frame; diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index 9d11e133b1..03b57f34d4 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -153,8 +153,11 @@ enum netplay_cmd /* Request that a client stall because it's running fast */ NETPLAY_CMD_STALL = 0x0045, + /* Request a core reset */ + NETPLAY_CMD_RESET = 0x0046, + /* Sends over cheats enabled on client (unsupported) */ - NETPLAY_CMD_CHEATS = 0x0046, + NETPLAY_CMD_CHEATS = 0x0047, /* Misc. commands */ @@ -404,6 +407,9 @@ struct netplay * events, such as player flipping or savestate loading. */ bool force_rewind; + /* Force a reset */ + bool force_reset; + /* Quirks in the savestate implementation */ uint64_t quirks; diff --git a/network/netplay/netplay_sync.c b/network/netplay/netplay_sync.c index bfc8caa2a4..02f949aa0c 100644 --- a/network/netplay/netplay_sync.c +++ b/network/netplay/netplay_sync.c @@ -396,6 +396,13 @@ void netplay_sync_post_frame(netplay_t *netplay, bool stalled) return; } + /* Reset if it was requested */ + if (netplay->force_reset) + { + core_reset(); + netplay->force_reset = false; + } + #ifndef DEBUG_NONDETERMINISTIC_CORES if (!netplay->force_rewind) { diff --git a/pkg/android/phoenix/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java b/pkg/android/phoenix/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java index 19ad1290c6..dede1ed0b8 100644 --- a/pkg/android/phoenix/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java +++ b/pkg/android/phoenix/src/com/retroarch/browser/retroactivity/RetroActivityFuture.java @@ -3,9 +3,16 @@ package com.retroarch.browser.retroactivity; import android.view.View; import android.view.WindowManager; import android.content.Intent; +import android.content.Context; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import android.hardware.input.InputManager; public final class RetroActivityFuture extends RetroActivityCamera { + // If set to true then Retroarch will completely exit when it loses focus + private boolean quitfocus = false; + @Override public void onResume() { super.onResume(); @@ -28,7 +35,7 @@ public final class RetroActivityFuture extends RetroActivityCamera { | API_SYSTEM_UI_FLAG_FULLSCREEN | API_SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - // Check for REFRESH parameter + // Check for Android UI specific parameters Intent retro = getIntent(); String refresh = retro.getStringExtra("REFRESH"); @@ -38,7 +45,40 @@ public final class RetroActivityFuture extends RetroActivityCamera { params.preferredRefreshRate = Integer.parseInt(refresh); getWindow().setAttributes(params); } + + // If QUITFOCUS parameter is provided then enable that Retroarch quits when focus is lost + quitfocus = retro.hasExtra("QUITFOCUS"); + + // If HIDEMOUSE parameters is provided then hide the mourse cursor + // This requires NVIDIA Android extensions (available on NVIDIA Shield), if they are not + // available then nothing will be done + if (retro.hasExtra("HIDEMOUSE")) hideMouseCursor(); } } + public void hideMouseCursor() { + + // Check for NVIDIA extensions and minimum SDK version + Method mInputManager_setCursorVisibility; + try { mInputManager_setCursorVisibility = + InputManager.class.getMethod("setCursorVisibility", boolean.class); + } + catch (NoSuchMethodException ex) { + return; // Extensions were not available so do nothing + } + + // Hide the mouse cursor + InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE); + try { mInputManager_setCursorVisibility.invoke(inputManager, false); } + catch (InvocationTargetException ite) { } + catch (IllegalAccessException iae) { } + } + + @Override + public void onStop() { + super.onStop(); + + // If QUITFOCUS parameter was set then completely exit Retroarch when focus is lost + if (quitfocus) System.exit(0); + } } diff --git a/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj b/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj index 159f0092a5..0098e65435 100644 --- a/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj +++ b/pkg/msvc/msvc-2005/RetroArch-msvc2005.vcproj @@ -139,7 +139,7 @@ /> min; +#endif max = setting->max; (void)wraparound; /* TODO/FIXME - handle this */ @@ -231,13 +235,17 @@ static int setting_uint_action_left_default(void *data, bool wraparound) static int setting_uint_action_right_default(void *data, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t*)data; +#ifdef HAVE_MENU double min = 0.0f; +#endif double max = 0.0f; if (!setting) return -1; +#ifdef HAVE_MENU min = setting->min; +#endif max = setting->max; (void)wraparound; /* TODO/FIXME - handle this */ @@ -419,13 +427,17 @@ static int setting_fraction_action_right_default( void *data, bool wraparound) { rarch_setting_t *setting = (rarch_setting_t*)data; +#ifdef HAVE_MENU double min = 0.0f; +#endif double max = 0.0f; if (!setting) return -1; +#ifdef HAVE_MENU min = setting->min; +#endif max = setting->max; (void)wraparound; /* TODO/FIXME - handle this */ @@ -1526,8 +1538,12 @@ bool CONFIG_BOOL( (*list)[list_info->index++] = value; if (flags != SD_FLAG_NONE) settings_data_list_current_add_flags(list, list_info, flags); + +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif + return true; } @@ -1555,8 +1571,12 @@ bool CONFIG_INT( if (value.name) value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; + +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif + return true; } @@ -1608,8 +1628,12 @@ bool CONFIG_UINT( if (value.name) value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; + +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif + return true; } @@ -1634,8 +1658,12 @@ bool CONFIG_FLOAT( if (value.name) value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; + +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif + return true; } @@ -1664,8 +1692,10 @@ bool CONFIG_PATH( value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; settings_data_list_current_add_flags(list, list_info, SD_FLAG_ALLOW_EMPTY); +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif return true; } @@ -1700,8 +1730,10 @@ bool CONFIG_DIR( list_info, SD_FLAG_ALLOW_EMPTY | SD_FLAG_PATH_DIR | SD_FLAG_BROWSER_ACTION); +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif return true; } @@ -1728,8 +1760,10 @@ bool CONFIG_STRING( if (value.name) value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif return true; } @@ -1757,8 +1791,11 @@ bool CONFIG_STRING_OPTIONS( if (value.name) value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; + +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif /* Request values to be freed later */ settings_data_list_current_add_free_flags(list, list_info, SD_FREE_FLAG_VALUES); @@ -1788,8 +1825,12 @@ bool CONFIG_HEX( if (value.name) value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; + +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif + return true; } @@ -1889,8 +1930,12 @@ bool CONFIG_ACTION( if (value.name) value.name_hash = msg_hash_calculate(value.name); (*list)[list_info->index++] = value; + +#ifdef HAVE_MENU menu_settings_list_current_add_enum_idx(list, list_info, name_enum_idx); menu_settings_list_current_add_enum_value_idx(list, list_info, SHORT_enum_idx); +#endif + return true; } diff --git a/tasks/task_autodetect.c b/tasks/task_autodetect.c index 50459adb9b..cbbb43d5b8 100644 --- a/tasks/task_autodetect.c +++ b/tasks/task_autodetect.c @@ -124,8 +124,7 @@ static int input_autoconfigure_joypad_try_from_conf(config_file_t *conf, score += 2; else { - if ( !string_is_empty(ident) - && string_is_equal(params->name, ident)) + if (strstr(params->name, ident)) score += 1; } @@ -306,14 +305,25 @@ static void input_autoconfigure_connect_handler(retro_task_t *task) char msg[255]; msg[0] = '\0'; - +#ifndef ANDROID RARCH_LOG("Autodetect: no profiles found for %s (%d/%d).\n", params->name, params->vid, params->pid); snprintf(msg, sizeof(msg), "%s (%ld/%ld) %s.", params->name, (long)params->vid, (long)params->pid, msg_hash_to_str(MSG_DEVICE_NOT_CONFIGURED)); +#else + strlcpy(params->name, "Android Gamepad", sizeof(params->name)); + if(input_autoconfigure_joypad_from_conf_internal(params, task)) + { + RARCH_LOG("Autodetect: no profiles found for %s (%d/%d). Using fallback\n", + params->name, params->vid, params->pid); + snprintf(msg, sizeof(msg), "%s (%ld/%ld) %s.", + params->name, (long)params->vid, (long)params->pid, + msg_hash_to_str(MSG_DEVICE_NOT_CONFIGURED_FALLBACK)); + } +#endif task_set_title(task, strdup(msg)); } diff --git a/tasks/task_content.c b/tasks/task_content.c index bfef13e18d..0fa393c798 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -66,7 +66,7 @@ #endif #ifdef HAVE_CHEEVOS -#include "../cheevos.h" +#include "../cheevos/cheevos.h" #endif #include "tasks_internal.h" diff --git a/tasks/task_netplay_find_content.c b/tasks/task_netplay_find_content.c index adb32837a2..2a255695e0 100644 --- a/tasks/task_netplay_find_content.c +++ b/tasks/task_netplay_find_content.c @@ -1,5 +1,6 @@ /* RetroArch - A frontend for libretro. - * Copyright (C) 2016 - Jean-André Santoni + * Copyright (C) 2017 - Jean-André Santoni + * Copyright (C) 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- @@ -57,7 +58,8 @@ static void netplay_crc_scan_callback(void *task_data, return; fflush(stdout); - if (!string_is_empty(state->core_path) && !string_is_empty(state->content_path)) + if (!string_is_empty(state->core_path) && !string_is_empty(state->content_path) && + !string_is_equal(state->content_path, "N/A")) { command_event(CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED, state->hostname); task_push_content_load_default( @@ -67,15 +69,22 @@ static void netplay_crc_scan_callback(void *task_data, CONTENT_MODE_LOAD_CONTENT_WITH_NEW_CORE_FROM_MENU, NULL, NULL); } - else if(string_is_equal(state->content_path, "N/A")) + else if (!string_is_empty(state->core_path) && !string_is_empty(state->content_path) && + string_is_equal(state->content_path, "N/A")) { - printf("Content: %s Core: %s\n", state->content_path, state->core_path); + command_event(CMD_EVENT_NETPLAY_INIT_DIRECT_DEFERRED, state->hostname); task_push_content_load_default( state->core_path, NULL, - NULL, + &content_info, CORE_TYPE_PLAIN, CONTENT_MODE_LOAD_NOTHING_WITH_NEW_CORE_FROM_MENU, NULL, NULL); + task_push_content_load_default( + state->core_path, NULL, + &content_info, + CORE_TYPE_PLAIN, + CONTENT_MODE_LOAD_NOTHING_WITH_CURRENT_CORE_FROM_MENU, + NULL, NULL); } else { @@ -263,8 +272,13 @@ bool task_push_netplay_crc_scan(uint32_t crc, char* name, if(string_is_equal(info->list[i].core_name, state->core_name)) { strlcpy(state->core_path, info->list[i].path, sizeof(state->core_path)); - strlcpy(state->core_extensions, - info->list[i].supported_extensions, sizeof(state->core_extensions)); + + if (!string_is_equal(state->content_path, "N/A") && + !string_is_empty(info->list[i].supported_extensions)) + { + strlcpy(state->core_extensions, + info->list[i].supported_extensions, sizeof(state->core_extensions)); + } break; } } diff --git a/tasks/task_netplay_lan_scan.c b/tasks/task_netplay_lan_scan.c index 38c86c3789..edf58b837e 100644 --- a/tasks/task_netplay_lan_scan.c +++ b/tasks/task_netplay_lan_scan.c @@ -13,25 +13,36 @@ * If not, see . */ +#include #include #include "tasks_internal.h" + +#ifdef HAVE_CONFIG_H +#include "../config.h" +#endif + #include "../verbosity.h" #include "../network/netplay/netplay_discovery.h" + +#ifdef HAVE_MENU #include "../menu/menu_entries.h" #include "../menu/menu_driver.h" +#endif static void netplay_lan_scan_callback(void *task_data, void *user_data, const char *error) { unsigned i; - unsigned menu_type = 0; - const char *path = NULL; - const char *label = NULL; - enum msg_hash_enums enum_idx = MSG_UNKNOWN; file_list_t *file_list = NULL; struct netplay_host_list *netplay_hosts = NULL; +#ifdef HAVE_MENU + enum msg_hash_enums enum_idx = MSG_UNKNOWN; + unsigned menu_type = 0; + const char *label = NULL; + const char *path = NULL; + menu_entries_get_last_stack(&path, &label, &menu_type, &enum_idx, NULL); /* Don't push the results if we left the LAN scan menu */ @@ -60,6 +71,7 @@ static void netplay_lan_scan_callback(void *task_data, MENU_NETPLAY_LAN_SCAN, 0, 0); } } +#endif } static void task_netplay_lan_scan_handler(retro_task_t *task) diff --git a/tasks/task_wifi.c b/tasks/task_wifi.c index 8fc081cbcb..050766d301 100644 --- a/tasks/task_wifi.c +++ b/tasks/task_wifi.c @@ -39,13 +39,15 @@ static void wifi_scan_callback(void *task_data, void *user_data, const char *error) { unsigned i; - unsigned menu_type = 0; - const char *path = NULL; - const char *label = NULL; - enum msg_hash_enums enum_idx = MSG_UNKNOWN; file_list_t *file_list = NULL; struct string_list *ssid_list = NULL; +#ifdef HAVE_MENU + const char *path = NULL; + const char *label = NULL; + unsigned menu_type = 0; + enum msg_hash_enums enum_idx = MSG_UNKNOWN; + menu_entries_get_last_stack(&path, &label, &menu_type, &enum_idx, NULL); /* Don't push the results if we left the wifi menu */ @@ -54,12 +56,14 @@ static void wifi_scan_callback(void *task_data, return; file_list = menu_entries_get_selection_buf_ptr(0); - ssid_list = string_list_new(); - menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, file_list); +#endif + + ssid_list = string_list_new(); driver_wifi_get_ssids(ssid_list); +#ifdef HAVE_MENU for (i = 0; i < ssid_list->size; i++) { const char *ssid = ssid_list->elems[i].data; @@ -69,6 +73,7 @@ static void wifi_scan_callback(void *task_data, MENU_ENUM_LABEL_CONNECT_WIFI, MENU_WIFI, 0, 0); } +#endif string_list_free(ssid_list); } diff --git a/verbosity.c b/verbosity.c index 418c526d00..de42f41202 100644 --- a/verbosity.c +++ b/verbosity.c @@ -48,14 +48,16 @@ /* If this is non-NULL. RARCH_LOG and friends * will write to this file. */ -static FILE *log_file = NULL; -static bool main_verbosity = false; +static FILE *log_file = NULL; +static bool main_verbosity = false; +static bool log_file_initialized = false; void verbosity_enable(void) { main_verbosity = true; #ifdef RARCH_INTERNAL - frontend_driver_attach_console(); + if (!log_file) + frontend_driver_attach_console(); #endif } @@ -63,7 +65,8 @@ void verbosity_disable(void) { main_verbosity = false; #ifdef RARCH_INTERNAL - frontend_driver_detach_console(); + if (!log_file) + frontend_driver_detach_console(); #endif } @@ -84,11 +87,15 @@ void *retro_main_log_file(void) void retro_main_log_file_init(const char *path) { - log_file = stderr; + if (log_file_initialized) + return; + + log_file = stderr; if (path == NULL) return; - log_file = fopen(path, "wb"); + log_file = fopen(path, "wb"); + log_file_initialized = true; } void retro_main_log_file_deinit(void) @@ -102,7 +109,7 @@ void retro_main_log_file_deinit(void) void RARCH_LOG_V(const char *tag, const char *fmt, va_list ap) { #if TARGET_OS_IPHONE - static int asl_inited = 0; + static int asl_initialized = 0; #if !TARGET_IPHONE_SIMULATOR static aslclient asl_client; #endif @@ -117,10 +124,10 @@ static aslclient asl_client; #if TARGET_IPHONE_SIMULATOR vprintf(fmt, ap); #else - if (!asl_inited) + if (!asl_initialized) { asl_client = asl_open(file_path_str(FILE_PATH_PROGRAM_NAME), "com.apple.console", ASL_OPT_STDERR | ASL_OPT_NO_DELAY); - asl_inited = 1; + asl_initialized = 1; } aslmsg msg = asl_new(ASL_TYPE_MSG); asl_set(msg, ASL_KEY_READ_UID, "-1"); diff --git a/wiiu/include/wiiu/nsyskbd.h b/wiiu/include/wiiu/nsyskbd.h new file mode 100644 index 0000000000..9fae60fe0e --- /dev/null +++ b/wiiu/include/wiiu/nsyskbd.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _KEYState +{ + KBD_WIIU_DOWN = 0x01, + KBD_WIIU_REPEAT = 0x02, + KBD_WIIU_NULL = 0x00 +} KEYState; + +typedef enum _KBDModifier +{ + KBD_WIIU_CTRL = 0x0001, + KBD_WIIU_SHIFT = 0x0002, + KBD_WIIU_ALT = 0x0004, + KBD_WIIU_NUM_LOCK = 0x0100, + KBD_WIIU_CAPS_LOCK = 0x0200, + KBD_WIIU_SCROLL_LOCK = 0x0400, +} KBDModifier; + +typedef struct _KBDKeyEvent +{ + unsigned char channel; + unsigned char scancode; // scancode + KEYState state; // when held, value is 0x03, which is KBD_DOWN & KBD_REPEAT + KBDModifier modifier; // modifier state + unsigned short UTF16; // unicode, if any +} KBDKeyEvent; + +char KBDSetup(void *connection_callback, void *disconnection_callback, void *key_callback); +char KBDTeardown(); + +#ifdef __cplusplus +} +#endif diff --git a/wiiu/system/imports.h b/wiiu/system/imports.h index a2dfe9be99..665b6611d5 100644 --- a/wiiu/system/imports.h +++ b/wiiu/system/imports.h @@ -194,3 +194,10 @@ IMPORT(KPADRead); IMPORT_END(); +/* nsyskbd */ +IMPORT_BEGIN(nsyskbd); + +IMPORT(KBDSetup); +IMPORT(KBDTeardown); + +IMPORT_END();