diff --git a/VERSION b/VERSION index 197c4d5c..005119ba 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.0 +2.4.1 diff --git a/cmake/prebuilt-armhf-toolchain.cmake b/cmake/prebuilt-armhf-toolchain.cmake index 3f7baec6..955a9f4e 100644 --- a/cmake/prebuilt-armhf-toolchain.cmake +++ b/cmake/prebuilt-armhf-toolchain.cmake @@ -56,7 +56,6 @@ if(NOT EXISTS "${sysroot_dir}") # Delete Unneeded Files file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/audit") - file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/gconv") # Strip Files file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir}/*") @@ -68,6 +67,13 @@ if(NOT EXISTS "${sysroot_dir}") file(REMOVE "${file}") endif() endforeach() + + # Setup gconv + file( + COPY "${toolchain_dir}/arm-none-linux-gnueabihf/libc/usr/lib/gconv/gconv-modules" + DESTINATION "${sysroot_dir}/usr/lib/gconv" + USE_SOURCE_PERMISSIONS + ) endif() # Install Sysroot (Skipping Empty Directories) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f31c8ba0..38acb381 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +**2.4.1** +* Allow More Characters In Usernames And Chat +* Fix Running On ARMHF Debian Buster + **2.4.0** * [Modding SDK](../example-mods/README.md) * Cache Blacklist/Whitelist diff --git a/images/start.png b/images/start.png index 8384db47..a15bc003 100644 Binary files a/images/start.png and b/images/start.png differ diff --git a/launcher/src/bootstrap.c b/launcher/src/bootstrap.c index cbdff053..718e4467 100644 --- a/launcher/src/bootstrap.c +++ b/launcher/src/bootstrap.c @@ -14,38 +14,6 @@ #include "patchelf.h" #include "crash-report.h" -// Set Environmental Variable -static void trim(char **value) { - // Remove Trailing Colon - int length = strlen(*value); - if ((*value)[length - 1] == ':') { - (*value)[length - 1] = '\0'; - } - if ((*value)[0] == ':') { - *value = &(*value)[1]; - } -} -void set_and_print_env(const char *name, char *value) { - // Set Variable With No Trailing Colon - static const char *unmodified_name_prefix = "MCPI_"; - if (!starts_with(name, unmodified_name_prefix)) { - trim(&value); - } - - // Print New Value - DEBUG("Set %s = %s", name, value); - - // Set The Value - setenv(name, value, 1); -} - -// Get Environmental Variable -static char *get_env_safe(const char *name) { - // Get Variable Or Blank String If Not Set - char *ret = getenv(name); - return ret != NULL ? ret : ""; -} - // Get All Mods In Folder static void load(char **ld_preload, char *folder) { int folder_name_length = strlen(folder); @@ -133,6 +101,10 @@ void pre_bootstrap(int argc, char *argv[]) { // Disable stdout Buffering setvbuf(stdout, NULL, _IONBF, 0); + // Set Default Native Component Environment +#define set_variable_default(name) set_and_print_env("MCPI_NATIVE_" name, getenv(name)); + for_each_special_environmental_variable(set_variable_default); + // Print Version for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) { @@ -178,8 +150,8 @@ void pre_bootstrap(int argc, char *argv[]) { safe_asprintf(&new_path, "%s/bin", binary_directory); // Add Existing PATH { - char *value = get_env_safe("PATH"); - if (strlen(value) > 0) { + char *value = getenv("PATH"); + if (value != NULL && strlen(value) > 0) { string_append(&new_path, ":%s", value); } } @@ -331,78 +303,121 @@ void bootstrap(int argc, char *argv[]) { free(resolved_path); // Configure Library Search Path - char *library_path = NULL; { // Log DEBUG("Setting Linker Search Paths..."); // Prepare - char *new_ld_path = NULL; + char *transitive_ld_path = NULL; + char *mcpi_ld_path = NULL; - // Add Native Library Directory - safe_asprintf(&new_ld_path, "%s/lib/native", binary_directory); - - // Add LD_LIBRARY_PATH + // Library Search Path For Native Components { - char *value = get_env_safe("LD_LIBRARY_PATH"); - if (strlen(value) > 0) { - string_append(&new_ld_path, ":%s", value); + // Add Native Library Directory + safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory); + + // Add Host LD_LIBRARY_PATH + { + char *value = getenv("LD_LIBRARY_PATH"); + if (value != NULL && strlen(value) > 0) { + string_append(&transitive_ld_path, ":%s", value); + } } + + // Set + set_and_print_env("MCPI_NATIVE_LD_LIBRARY_PATH", transitive_ld_path); + free(transitive_ld_path); } - // Set LD_LIBRARY_PATH (Used For Everything Except MCPI) - set_and_print_env("LD_LIBRARY_PATH", new_ld_path); + // Library Search Path For ARM Components + { + // Add ARM Library Directory + // (This Overrides LD_LIBRARY_PATH Using ld.so's --library-path Option) + safe_asprintf(&mcpi_ld_path, "%s/lib/arm", binary_directory); - // Add ARM Library Directory - // (This Overrides LD_LIBRARY_PATH Using ld.so's --library-path Option) - safe_asprintf(&library_path, "%s/lib/arm", binary_directory); - - // Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System) + // Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System) #ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN - string_append(&library_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory); + string_append(&mcpi_ld_path, ":%s/sysroot/lib:%s/sysroot/lib/arm-linux-gnueabihf:%s/sysroot/usr/lib:%s/sysroot/usr/lib/arm-linux-gnueabihf", binary_directory, binary_directory, binary_directory, binary_directory); #endif - // Add Remaining LD_LIBRARY_PATH - string_append(&library_path, ":%s", new_ld_path); + // Add Host LD_LIBRARY_PATH + { + char *value = getenv("LD_LIBRARY_PATH"); + if (value != NULL && strlen(value) > 0) { + string_append(&transitive_ld_path, ":%s", value); + } + } - // Free LD_LIBRARY_PATH - free(new_ld_path); + // Set + set_and_print_env("MCPI_ARM_LD_LIBRARY_PATH", mcpi_ld_path); + free(mcpi_ld_path); + } + + // Setup iconv + { + // Native Components + char *host_gconv_path = getenv("GCONV_PATH"); + set_and_print_env("MCPI_NATIVE_GCONV_PATH", host_gconv_path); + + // ARM Components +#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN + char *gconv_path = NULL; + safe_asprintf(&gconv_path, "%s/sysroot/usr/lib/gconv", binary_directory); + set_and_print_env("MCPI_ARM_GCONV_PATH", gconv_path); + free(gconv_path); +#else + set_and_print_env("MCPI_ARM_GCONV_PATH", host_gconv_path); +#endif + } } - // Configure MCPI's Preloaded Objects - char *preload = NULL; + // Configure Preloaded Objects { // Log DEBUG("Locating Mods..."); - // ~/.minecraft-pi/mods - { - // Get Mods Folder - char *mods_folder = NULL; - safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME")); - // Load Mods From ./mods - load(&preload, mods_folder); - // Free Mods Folder - free(mods_folder); - } + // Native Components + char *host_ld_preload = getenv("LD_PRELOAD"); + set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload); - // Built-In Mods + // ARM Components { - // Get Mods Folder - char *mods_folder = NULL; - safe_asprintf(&mods_folder, "%s/mods/", binary_directory); - // Load Mods From ./mods - load(&preload, mods_folder); - // Free Mods Folder - free(mods_folder); - } + // Prepare + char *preload = NULL; - // Add LD_PRELOAD - { - char *value = get_env_safe("LD_PRELOAD"); - if (strlen(value) > 0) { - string_append(&preload, ":%s", value); + // ~/.minecraft-pi/mods + { + // Get Mods Folder + char *mods_folder = NULL; + safe_asprintf(&mods_folder, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/mods/", getenv("HOME")); + // Load Mods From ./mods + load(&preload, mods_folder); + // Free Mods Folder + free(mods_folder); } + + // Built-In Mods + { + // Get Mods Folder + char *mods_folder = NULL; + safe_asprintf(&mods_folder, "%s/mods/", binary_directory); + // Load Mods From ./mods + load(&preload, mods_folder); + // Free Mods Folder + free(mods_folder); + } + + // Add LD_PRELOAD + { + char *value = getenv("LD_PRELOAD"); + if (value != NULL && strlen(value) > 0) { + string_append(&preload, ":%s", value); + } + } + + // Set + set_and_print_env("MCPI_ARM_LD_PRELOAD", preload); + free(preload); } } @@ -414,23 +429,17 @@ void bootstrap(int argc, char *argv[]) { // Arguments int argv_start = 1; // argv = &new_args[argv_start] - int real_argv_start = argv_start + 5; // ld.so Arguments - const char *new_args[real_argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; // + const char *new_args[argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; // // Copy Existing Arguments for (int i = 1; i < argc; i++) { - new_args[i + real_argv_start] = argv[i]; + new_args[i + argv_start] = argv[i]; } // NULL-Terminator - new_args[real_argv_start + argc] = NULL; + new_args[argv_start + argc] = NULL; // Set Executable Argument - new_args[argv_start] = patch_get_interpreter(new_mcpi_exe_path); - new_args[argv_start + 1] = "--preload"; - new_args[argv_start + 2] = preload; - new_args[argv_start + 3] = "--library-path"; - new_args[argv_start + 4] = library_path; - new_args[real_argv_start] = new_mcpi_exe_path; + new_args[argv_start] = new_mcpi_exe_path; // Non-ARM Systems Need QEMU #ifndef __ARM_ARCH @@ -438,6 +447,20 @@ void bootstrap(int argc, char *argv[]) { new_args[argv_start] = QEMU_BINARY; #endif + // Setup Environment + setup_exec_environment(1); + + // Pass LD_* Variables Through QEMU +#ifndef __ARM_ARCH + char *qemu_set_env = NULL; +#define pass_variable_through_qemu(name) string_append(&qemu_set_env, "%s%s=%s", qemu_set_env == NULL ? "" : ",", name, getenv(name)); + for_each_special_environmental_variable(pass_variable_through_qemu); + set_and_print_env("QEMU_SET_ENV", qemu_set_env); + free(qemu_set_env); + // Treat QEMU Itself As A Native Component + setup_exec_environment(0); +#endif + // Run const char **new_argv = &new_args[argv_start]; safe_execvpe(new_argv, (const char *const *) environ); diff --git a/launcher/src/bootstrap.h b/launcher/src/bootstrap.h index f530cc80..6afe6372 100644 --- a/launcher/src/bootstrap.h +++ b/launcher/src/bootstrap.h @@ -4,8 +4,6 @@ extern "C" { #endif -void set_and_print_env(const char *name, char *value); - void pre_bootstrap(int argc, char *argv[]); void bootstrap(int argc, char *argv[]); diff --git a/launcher/src/server/launcher.c b/launcher/src/server/launcher.c index 2b0579e6..58c9d0cf 100644 --- a/launcher/src/server/launcher.c +++ b/launcher/src/server/launcher.c @@ -1,6 +1,8 @@ #include #include +#include + #include "../bootstrap.h" int main(int argc, char *argv[]) { diff --git a/libreborn/include/libreborn/exec.h b/libreborn/include/libreborn/exec.h index d7a4c268..da50efb7 100644 --- a/libreborn/include/libreborn/exec.h +++ b/libreborn/include/libreborn/exec.h @@ -16,7 +16,15 @@ extern "C" { #endif +// Set Environmental Variable +void set_and_print_env(const char *name, const char *value); + // Safe execvpe() +#define for_each_special_environmental_variable(handle) \ + handle("LD_LIBRARY_PATH"); \ + handle("GCONV_PATH"); \ + handle("LD_PRELOAD"); +void setup_exec_environment(int is_arm_component); __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]); // Chop Off Last Component @@ -24,9 +32,6 @@ void chop_last_component(char **str); // Get Binary Directory (Remember To Free) char *get_binary_directory(); -// Safe execvpe() Relative To Binary -__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]); - // Run Command And Get Output char *run_command(const char *const command[], int *exit_status); #define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0) diff --git a/libreborn/include/libreborn/string.h b/libreborn/include/libreborn/string.h index 2d356a41..9754200d 100644 --- a/libreborn/include/libreborn/string.h +++ b/libreborn/include/libreborn/string.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "util.h" @@ -33,6 +35,11 @@ extern "C" { // Sanitize String void sanitize_string(char **str, int max_length, unsigned int allow_newlines); +// CP437 +void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size); +char *to_cp437(const char *input); +char *from_cp437(const char *input); + // Starts With int starts_with(const char *str, const char *prefix); diff --git a/libreborn/src/util/exec.c b/libreborn/src/util/exec.c index d8d4b336..fbd96b83 100644 --- a/libreborn/src/util/exec.c +++ b/libreborn/src/util/exec.c @@ -2,7 +2,32 @@ #include +// Set Environmental Variable +static void setenv_safe(const char *name, const char *value) { + if (value != NULL) { + setenv(name, value, 1); + } else { + unsetenv(name); + } +} +void set_and_print_env(const char *name, const char *value) { + // Print New Value + DEBUG("Set %s = %s", name, value != NULL ? value : "(unset)"); + + // Set The Value + setenv_safe(name, value); +} + // Safe execvpe() +#define handle_environmental_variable(var) \ + { \ + const char *full_var = is_arm_component ? "MCPI_ARM_" var : "MCPI_NATIVE_" var; \ + const char *var_value = getenv(full_var); \ + set_and_print_env(var, var_value); \ + } +void setup_exec_environment(int is_arm_component) { + for_each_special_environmental_variable(handle_environmental_variable); +} __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) { // Log DEBUG("Running Command:"); @@ -45,29 +70,6 @@ char *get_binary_directory() { return exe; } -// Safe execvpe() Relative To Binary -__attribute__((noreturn)) void safe_execvpe_relative_to_binary(const char *const argv[], const char *const envp[]) { - // Get Binary Directory - char *binary_directory = get_binary_directory(); - // Create Full Path - char *full_path = NULL; - safe_asprintf(&full_path, "%s/%s", binary_directory, argv[0]); - // Free Binary Directory - free(binary_directory); - - // Build New argv - int argc; - for (argc = 0; argv[argc] != NULL; argc++); - const char *new_argv[argc + 1]; - for (int i = 1; i < argc; i++) { - new_argv[i] = argv[i]; - } - new_argv[0] = full_path; - new_argv[argc] = NULL; - // Run - safe_execvpe(new_argv, envp); -} - // Run Command And Get Output char *run_command(const char *const command[], int *exit_status) { // Store Output @@ -85,6 +87,9 @@ char *run_command(const char *const command[], int *exit_status) { close(output_pipe[0]); close(output_pipe[1]); + // Setup Environment + setup_exec_environment(0); + // Run safe_execvpe(command, (const char *const *) environ); } else { diff --git a/libreborn/src/util/string.c b/libreborn/src/util/string.c index cb4ed2e5..2c375a12 100644 --- a/libreborn/src/util/string.c +++ b/libreborn/src/util/string.c @@ -1,8 +1,9 @@ +#include +#include + #include // Sanitize String -#define MINIMUM_SAFE_CHARACTER 32 -#define MAXIMUM_SAFE_CHARACTER 126 void sanitize_string(char **str, int max_length, unsigned int allow_newlines) { // Store Message Length int length = strlen(*str); @@ -12,18 +13,135 @@ void sanitize_string(char **str, int max_length, unsigned int allow_newlines) { length = max_length; } // Loop Through Message - for (int i = 0; i < length; i++) { - if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) { - continue; - } - unsigned char c = (unsigned char) (*str)[i]; - if (c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) { - // Replace Illegal Character - (*str)[i] = '?'; + if (!allow_newlines) { + for (int i = 0; i < length; i++) { + if ((*str)[i] == '\n' || (*str)[i] == '\r') { + // Replace Newline + (*str)[i] = ' '; + } } } } +// Minecraft-Flavored CP437 +void safe_iconv(iconv_t cd, char *input, size_t input_size, char *output, size_t output_size) { + iconv(cd, &input, &input_size, &output, &output_size); +} +#define CP437_CHARACTERS 256 +static const char *cp437_characters_map[CP437_CHARACTERS] = { + "\0", "☺", "☻", "♥", "♦", "♣", "♠", "•", "◘", "○", "\n", "♂", "♀", "\r", "♫", "☼", + "►", "◄", "↕", "‼", "¶", "§", "▬", "↨", "↑", "↓", "→", "←", "∟", "↔", "▲", "▼", + " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", + "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", + "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "⌂", + "Ç", "ü", "é", "â", "ä", "à", "å", "ç", "ê", "ë", "è", "ï", "î", "ì", "Ä", "Å", + "É", "æ", "Æ", "ô", "ö", "ò", "û", "ù", "ÿ", "Ö", "Ü", "¢", "£", "¥", "₧", "ƒ", + "á", "í", "ó", "ú", "ñ", "Ñ", "ª", "º", "¿", "⌐", "¬", "½", "¼", "¡", "«", "»", + "░", "▒", "▓", "│", "┤", "╡", "╢", "╖", "╕", "╣", "║", "╗", "╝", "╜", "╛", "┐", + "└", "┴", "┬", "├", "─", "┼", "╞", "╟", "╚", "╔", "╩", "╦", "╠", "═", "╬", "╧", + "╨", "╤", "╥", "╙", "╘", "╒", "╓", "╫", "╪", "┘", "┌", "█", "▄", "▌", "▐", "▀", + "α", "ß", "Γ", "π", "Σ", "σ", "µ", "τ", "Φ", "Θ", "Ω", "δ", "∞", "φ", "ε", "∩", + "≡", "±", "≥", "≤", "⌠", "⌡", "÷", "≈", "°", "∙", "·", "√", "ⁿ", "²", "■", "©" +}; +static uint32_t *get_cp437_characters_codepoint_map() { + static uint32_t map[CP437_CHARACTERS]; + static int is_setup = 0; + if (!is_setup) { + // Build Map + iconv_t cd = iconv_open("UTF-32LE", "UTF-8"); + if (cd != (iconv_t) -1) { + size_t str_size = 4; + uint32_t *str = (uint32_t *) malloc(str_size); + ALLOC_CHECK(str); + for (int i = 0; i < CP437_CHARACTERS; i++) { + // Convert to UTF-32, Then Extract Codepoint + safe_iconv(cd, (char *) cp437_characters_map[i], strlen(cp437_characters_map[i]), (char *) str, str_size); + // Extract + map[i] = str[0]; + } + // Free + free(str); + iconv_close(cd); + } else { + IMPOSSIBLE(); + } + is_setup = 1; + } + return map; +} +char *to_cp437(const char *input) { + // Convert To UTF-32 For Easier Parsing + size_t in_size = strlen(input); + size_t utf32_str_size = in_size * 4; + size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */; + uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size); + ALLOC_CHECK(utf32_str); + memset(utf32_str, 0, real_utf32_str_size); + iconv_t cd = iconv_open("UTF-32LE", "UTF-8"); + if (cd != (iconv_t) -1) { + safe_iconv(cd, (char *) input, in_size, (char *) utf32_str, utf32_str_size); + iconv_close(cd); + } else { + IMPOSSIBLE(); + } + // Allocate String + size_t cp437_str_size; + for (cp437_str_size = 0; utf32_str[cp437_str_size] != 0; cp437_str_size++); + size_t real_cp437_str_size = cp437_str_size + 1 /* NULL-terminator */; + char *cp437_str = (char *) malloc(real_cp437_str_size); + ALLOC_CHECK(cp437_str); + memset(cp437_str, 0, real_cp437_str_size); + // Handle Characters + for (size_t i = 0; utf32_str[i] != 0; i++) { + uint32_t codepoint = utf32_str[i]; + for (int j = 0; j < CP437_CHARACTERS; j++) { + uint32_t test_codepoint = get_cp437_characters_codepoint_map()[j]; + if (codepoint == test_codepoint) { + cp437_str[i] = j; + break; + } + } + if (cp437_str[i] == '\0') { + cp437_str[i] = '?'; + } + } + // Free + free(utf32_str); + // Return + return cp437_str; +} +char *from_cp437(const char *input) { + // Convert To UTF-32 For Easier Parsing + size_t in_size = strlen(input); + size_t utf32_str_size = in_size * 4; + size_t real_utf32_str_size = utf32_str_size + 4 /* NULL-terminator */; + uint32_t *utf32_str = (uint32_t *) malloc(real_utf32_str_size); + ALLOC_CHECK(utf32_str); + memset(utf32_str, 0, real_utf32_str_size); + // Handle Characters + for (size_t i = 0; input[i] != '\0'; i++) { + utf32_str[i] = get_cp437_characters_codepoint_map()[(uint32_t) input[i]]; + } + // Convert To UTF-8 + size_t out_size = utf32_str_size; + size_t real_out_size = utf32_str_size + 1 /* NULL-terminator */; + char *output = (char *) malloc(real_out_size); + ALLOC_CHECK(output); + memset(output, 0, real_out_size); + iconv_t cd = iconv_open("UTF-8", "UTF-32LE"); + if (cd != (iconv_t) -1) { + safe_iconv(cd, (char *) utf32_str, utf32_str_size, output, out_size); + iconv_close(cd); + } else { + IMPOSSIBLE(); + } + // Return + return output; +} + // Starts With int starts_with(const char *str, const char *prefix) { return strncmp(prefix, str, strlen(prefix)) == 0; diff --git a/media-layer/core/src/media.c b/media-layer/core/src/media.c index eac865d1..05633151 100644 --- a/media-layer/core/src/media.c +++ b/media-layer/core/src/media.c @@ -156,7 +156,7 @@ static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int sc event.key.keysym.sym = glfw_key_to_sdl_key(key); SDL_PushEvent(&event); if (key == GLFW_KEY_BACKSPACE && !up) { - character_event((char) '\b'); + character_event('\b'); } } } @@ -164,7 +164,25 @@ static void glfw_key(__attribute__((unused)) GLFWwindow *window, int key, int sc // Pass Text To Minecraft static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) { if (is_interactable) { - character_event((char) codepoint); + // Signs Only Accepts ASCII Characters + size_t in_size = 4; // 1 UTF-32LE Codepoint + size_t out_size = 4; // 4 ASCII Characters Max + size_t real_out_size = out_size + 1 /* NULL-terminator */; + char *output = (char *) malloc(real_out_size); + ALLOC_CHECK(output); + memset(output, 0, real_out_size); + iconv_t cd = iconv_open("ASCII//TRANSLIT", "UTF-32LE"); + if (cd != (iconv_t) -1) { + safe_iconv(cd, (char *) &codepoint, in_size, output, out_size); + iconv_close(cd); + } else { + IMPOSSIBLE(); + } + for (size_t i = 0; output[i] != '\0'; i++) { + character_event(output[i]); + } + // Free + free(output); } } diff --git a/media-layer/proxy/src/server/server.cpp b/media-layer/proxy/src/server/server.cpp index da3bc249..e9f7011b 100644 --- a/media-layer/proxy/src/server/server.cpp +++ b/media-layer/proxy/src/server/server.cpp @@ -71,6 +71,9 @@ static void start_media_layer_proxy_client(int read, int write) { safe_asprintf(&write_str, "%i", write); const char *argv[] = {"media-layer-proxy-client", read_str, write_str, NULL}; + // Setup Environment + setup_exec_environment(0); + // Run safe_execvpe(argv, (const char *const *) environ); } else { diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 16b9a636..c63d1ebe 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -108,7 +108,7 @@ add_library(test SHARED src/test/test.c) target_link_libraries(test mods-headers reborn-patch home) add_library(init SHARED src/init/init.c) -target_link_libraries(init mods-headers compat game-mode misc death options chat creative bucket home version test media-layer-core) +target_link_libraries(init mods-headers reborn-util compat game-mode misc death options chat creative bucket home version test media-layer-core) if(MCPI_SERVER_MODE) target_link_libraries(init server) else() diff --git a/mods/src/chat/ui.c b/mods/src/chat/ui.c index fc1bad54..3752a2e4 100644 --- a/mods/src/chat/ui.c +++ b/mods/src/chat/ui.c @@ -48,7 +48,9 @@ static void *chat_thread(__attribute__((unused)) void *nop) { // Don't Allow Empty Strings if (length > 0) { // Submit - _chat_queue_message(output); + char *safe_output = to_cp437(output); + _chat_queue_message(safe_output); + free(safe_output); } } // Free Output diff --git a/mods/src/game-mode/ui.cpp b/mods/src/game-mode/ui.cpp index 4f471523..3d16e12f 100644 --- a/mods/src/game-mode/ui.cpp +++ b/mods/src/game-mode/ui.cpp @@ -186,7 +186,9 @@ static void *create_world_thread(__attribute__((unused)) void *nop) { pthread_mutex_lock(&create_world_state_lock); reset_create_world_state(); create_world_state.dialog_state = DIALOG_SUCCESS; - create_world_state.name = world_name; + char *safe_name = to_cp437(world_name); + create_world_state.name = safe_name; + free(world_name); create_world_state.game_mode = game_mode; create_world_state.seed = seed; pthread_mutex_unlock(&create_world_state_lock); diff --git a/mods/src/misc/logging.cpp b/mods/src/misc/logging.cpp index df9b918b..f6d1b602 100644 --- a/mods/src/misc/logging.cpp +++ b/mods/src/misc/logging.cpp @@ -20,7 +20,9 @@ static void Gui_addMessage_injection(unsigned char *gui, std::string const& text Gui_addMessage_recursing = true; // Print Log Message - fprintf(stderr, "[CHAT]: %s\n", new_message); + char *safe_message = from_cp437(new_message); + fprintf(stderr, "[CHAT]: %s\n", safe_message); + free(safe_message); // Call Original Method (*Gui_addMessage)(gui, std::string(new_message)); diff --git a/mods/src/options/options.c b/mods/src/options/options.c index c70342a6..e5b068c1 100644 --- a/mods/src/options/options.c +++ b/mods/src/options/options.c @@ -39,6 +39,10 @@ static char *get_username() { } return username; } +static char *safe_username = NULL; +__attribute__((destructor)) static void _free_safe_username() { + free(safe_username); +} static int anaglyph; static int render_distance; @@ -102,7 +106,8 @@ void init_options() { if (strcmp(*default_username, "StevePi") != 0) { ERR("Default Username Is Invalid"); } - patch_address((void *) default_username, (void *) username); + safe_username = to_cp437(username); + patch_address((void *) default_username, (void *) safe_username); // Disable Autojump By Default if (feature_has("Disable Autojump By Default", server_disabled)) { diff --git a/mods/src/server/server.cpp b/mods/src/server/server.cpp index d8baac4e..4b7f9b4a 100644 --- a/mods/src/server/server.cpp +++ b/mods/src/server/server.cpp @@ -64,7 +64,11 @@ static ServerProperties &get_server_properties() { // Get World Name static std::string get_world_name() { - return get_server_properties().get_string("world-name", DEFAULT_WORLD_NAME); + std::string name = get_server_properties().get_string("world-name", DEFAULT_WORLD_NAME); + char *safe_name_c = to_cp437(name.c_str()); + std::string safe_name = safe_name_c; + free(safe_name_c); + return safe_name; } // Create/Start World @@ -120,8 +124,12 @@ static std::vector get_players_in_level(unsigned char *level) { return *(std::vector *) (level + Level_players_property_offset); } // Get Player's Username -static std::string *get_player_username(unsigned char *player) { - return (std::string *) (player + Player_username_property_offset); +static std::string get_player_username(unsigned char *player) { + std::string *username = (std::string *) (player + Player_username_property_offset); + char *safe_username_c = from_cp437(username->c_str()); + std::string safe_username = safe_username_c; + free(safe_username_c); + return safe_username; } // Get Level From Minecraft static unsigned char *get_level(unsigned char *minecraft) { @@ -137,7 +145,7 @@ static void find_players(unsigned char *minecraft, std::string target_username, for (std::size_t i = 0; i < players.size(); i++) { // Iterate Players unsigned char *player = players[i]; - std::string username = *get_player_username(player); + std::string username = get_player_username(player); if (all_players || username == target_username) { // Run Callback (*callback)(minecraft, username, player); @@ -326,8 +334,11 @@ static void handle_commands(unsigned char *minecraft) { } else if (data.rfind(say_command, 0) == 0) { // Format Message std::string message = "[Server] " + data.substr(say_command.length()); + char *safe_message = to_cp437(message.c_str()); // Post Message To Chat - (*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, message); + (*ServerSideNetworkHandler_displayGameMessage)(server_side_network_handler, safe_message); + // Free + free(safe_message); } else if (data == list_command) { // List Players INFO("All Players:"); @@ -584,7 +595,7 @@ static void server_init() { // Init Server void init_server() { server_init(); - setenv("MCPI_FEATURE_FLAGS", get_features(), 1); - setenv("MCPI_RENDER_DISTANCE", "Tiny", 1); - setenv("MCPI_USERNAME", get_motd().c_str(), 1); + set_and_print_env("MCPI_FEATURE_FLAGS", get_features()); + set_and_print_env("MCPI_RENDER_DISTANCE", "Tiny"); + set_and_print_env("MCPI_USERNAME", get_motd().c_str()); }