This commit is contained in:
TheBrokenRail 2022-07-20 02:58:14 -04:00
parent 96baf9627a
commit 379da809cd
19 changed files with 357 additions and 146 deletions

View File

@ -1 +1 @@
2.4.0 2.4.1

View File

@ -56,7 +56,6 @@ if(NOT EXISTS "${sysroot_dir}")
# Delete Unneeded Files # Delete Unneeded Files
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/audit") file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/audit")
file(REMOVE_RECURSE "${sysroot_dir}/usr/lib/gconv")
# Strip Files # Strip Files
file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir}/*") file(GLOB_RECURSE files LIST_DIRECTORIES FALSE "${sysroot_dir}/*")
@ -68,6 +67,13 @@ if(NOT EXISTS "${sysroot_dir}")
file(REMOVE "${file}") file(REMOVE "${file}")
endif() endif()
endforeach() 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() endif()
# Install Sysroot (Skipping Empty Directories) # Install Sysroot (Skipping Empty Directories)

View File

@ -1,5 +1,9 @@
# Changelog # Changelog
**2.4.1**
* Allow More Characters In Usernames And Chat
* Fix Running On ARMHF Debian Buster
**2.4.0** **2.4.0**
* [Modding SDK](../example-mods/README.md) * [Modding SDK](../example-mods/README.md)
* Cache Blacklist/Whitelist * Cache Blacklist/Whitelist

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -14,38 +14,6 @@
#include "patchelf.h" #include "patchelf.h"
#include "crash-report.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 // Get All Mods In Folder
static void load(char **ld_preload, char *folder) { static void load(char **ld_preload, char *folder) {
int folder_name_length = strlen(folder); int folder_name_length = strlen(folder);
@ -133,6 +101,10 @@ void pre_bootstrap(int argc, char *argv[]) {
// Disable stdout Buffering // Disable stdout Buffering
setvbuf(stdout, NULL, _IONBF, 0); 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 // Print Version
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) { 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); safe_asprintf(&new_path, "%s/bin", binary_directory);
// Add Existing PATH // Add Existing PATH
{ {
char *value = get_env_safe("PATH"); char *value = getenv("PATH");
if (strlen(value) > 0) { if (value != NULL && strlen(value) > 0) {
string_append(&new_path, ":%s", value); string_append(&new_path, ":%s", value);
} }
} }
@ -331,78 +303,121 @@ void bootstrap(int argc, char *argv[]) {
free(resolved_path); free(resolved_path);
// Configure Library Search Path // Configure Library Search Path
char *library_path = NULL;
{ {
// Log // Log
DEBUG("Setting Linker Search Paths..."); DEBUG("Setting Linker Search Paths...");
// Prepare // Prepare
char *new_ld_path = NULL; char *transitive_ld_path = NULL;
char *mcpi_ld_path = NULL;
// Add Native Library Directory // Library Search Path For Native Components
safe_asprintf(&new_ld_path, "%s/lib/native", binary_directory);
// Add LD_LIBRARY_PATH
{ {
char *value = get_env_safe("LD_LIBRARY_PATH"); // Add Native Library Directory
if (strlen(value) > 0) { safe_asprintf(&transitive_ld_path, "%s/lib/native", binary_directory);
string_append(&new_ld_path, ":%s", value);
// 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) // Library Search Path For ARM Components
set_and_print_env("LD_LIBRARY_PATH", new_ld_path); {
// 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 // Add ARM Sysroot Libraries (Ensure Priority) (Ignore On Actual ARM System)
// (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)
#ifdef MCPI_USE_PREBUILT_ARMHF_TOOLCHAIN #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 #endif
// Add Remaining LD_LIBRARY_PATH // Add Host LD_LIBRARY_PATH
string_append(&library_path, ":%s", new_ld_path); {
char *value = getenv("LD_LIBRARY_PATH");
if (value != NULL && strlen(value) > 0) {
string_append(&transitive_ld_path, ":%s", value);
}
}
// Free LD_LIBRARY_PATH // Set
free(new_ld_path); 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 // Configure Preloaded Objects
char *preload = NULL;
{ {
// Log // Log
DEBUG("Locating Mods..."); DEBUG("Locating Mods...");
// ~/.minecraft-pi/mods // Native Components
{ char *host_ld_preload = getenv("LD_PRELOAD");
// Get Mods Folder set_and_print_env("MCPI_NATIVE_LD_PRELOAD", host_ld_preload);
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 // ARM Components
{ {
// Get Mods Folder // Prepare
char *mods_folder = NULL; char *preload = 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 // ~/.minecraft-pi/mods
{ {
char *value = get_env_safe("LD_PRELOAD"); // Get Mods Folder
if (strlen(value) > 0) { char *mods_folder = NULL;
string_append(&preload, ":%s", value); 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 // Arguments
int argv_start = 1; // argv = &new_args[argv_start] int argv_start = 1; // argv = &new_args[argv_start]
int real_argv_start = argv_start + 5; // ld.so Arguments const char *new_args[argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
const char *new_args[real_argv_start /* 1 Potential Prefix Argument (QEMU) */ + argc + 1 /* NULL-Terminator */]; //
// Copy Existing Arguments // Copy Existing Arguments
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
new_args[i + real_argv_start] = argv[i]; new_args[i + argv_start] = argv[i];
} }
// NULL-Terminator // NULL-Terminator
new_args[real_argv_start + argc] = NULL; new_args[argv_start + argc] = NULL;
// Set Executable Argument // Set Executable Argument
new_args[argv_start] = patch_get_interpreter(new_mcpi_exe_path); new_args[argv_start] = 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;
// Non-ARM Systems Need QEMU // Non-ARM Systems Need QEMU
#ifndef __ARM_ARCH #ifndef __ARM_ARCH
@ -438,6 +447,20 @@ void bootstrap(int argc, char *argv[]) {
new_args[argv_start] = QEMU_BINARY; new_args[argv_start] = QEMU_BINARY;
#endif #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 // Run
const char **new_argv = &new_args[argv_start]; const char **new_argv = &new_args[argv_start];
safe_execvpe(new_argv, (const char *const *) environ); safe_execvpe(new_argv, (const char *const *) environ);

View File

@ -4,8 +4,6 @@
extern "C" { extern "C" {
#endif #endif
void set_and_print_env(const char *name, char *value);
void pre_bootstrap(int argc, char *argv[]); void pre_bootstrap(int argc, char *argv[]);
void bootstrap(int argc, char *argv[]); void bootstrap(int argc, char *argv[]);

View File

@ -1,6 +1,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <libreborn/libreborn.h>
#include "../bootstrap.h" #include "../bootstrap.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

View File

@ -16,7 +16,15 @@
extern "C" { extern "C" {
#endif #endif
// Set Environmental Variable
void set_and_print_env(const char *name, const char *value);
// Safe execvpe() // 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[]); __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]);
// Chop Off Last Component // Chop Off Last Component
@ -24,9 +32,6 @@ void chop_last_component(char **str);
// Get Binary Directory (Remember To Free) // Get Binary Directory (Remember To Free)
char *get_binary_directory(); 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 // Run Command And Get Output
char *run_command(const char *const command[], int *exit_status); char *run_command(const char *const command[], int *exit_status);
#define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0) #define is_exit_status_success(status) (WIFEXITED(status) && WEXITSTATUS(status) == 0)

View File

@ -3,6 +3,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <iconv.h>
#include <stdint.h>
#include "util.h" #include "util.h"
@ -33,6 +35,11 @@ extern "C" {
// Sanitize String // Sanitize String
void sanitize_string(char **str, int max_length, unsigned int allow_newlines); 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 // Starts With
int starts_with(const char *str, const char *prefix); int starts_with(const char *str, const char *prefix);

View File

@ -2,7 +2,32 @@
#include <libreborn/exec.h> #include <libreborn/exec.h>
// 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() // 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[]) { __attribute__((noreturn)) void safe_execvpe(const char *const argv[], const char *const envp[]) {
// Log // Log
DEBUG("Running Command:"); DEBUG("Running Command:");
@ -45,29 +70,6 @@ char *get_binary_directory() {
return exe; 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 // Run Command And Get Output
char *run_command(const char *const command[], int *exit_status) { char *run_command(const char *const command[], int *exit_status) {
// Store Output // Store Output
@ -85,6 +87,9 @@ char *run_command(const char *const command[], int *exit_status) {
close(output_pipe[0]); close(output_pipe[0]);
close(output_pipe[1]); close(output_pipe[1]);
// Setup Environment
setup_exec_environment(0);
// Run // Run
safe_execvpe(command, (const char *const *) environ); safe_execvpe(command, (const char *const *) environ);
} else { } else {

View File

@ -1,8 +1,9 @@
#include <iconv.h>
#include <stdint.h>
#include <libreborn/string.h> #include <libreborn/string.h>
// Sanitize String // Sanitize String
#define MINIMUM_SAFE_CHARACTER 32
#define MAXIMUM_SAFE_CHARACTER 126
void sanitize_string(char **str, int max_length, unsigned int allow_newlines) { void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
// Store Message Length // Store Message Length
int length = strlen(*str); int length = strlen(*str);
@ -12,18 +13,135 @@ void sanitize_string(char **str, int max_length, unsigned int allow_newlines) {
length = max_length; length = max_length;
} }
// Loop Through Message // Loop Through Message
for (int i = 0; i < length; i++) { if (!allow_newlines) {
if (allow_newlines && ((*str)[i] == '\n' || (*str)[i] == '\r')) { for (int i = 0; i < length; i++) {
continue; if ((*str)[i] == '\n' || (*str)[i] == '\r') {
} // Replace Newline
unsigned char c = (unsigned char) (*str)[i]; (*str)[i] = ' ';
if (c < MINIMUM_SAFE_CHARACTER || c > MAXIMUM_SAFE_CHARACTER) { }
// Replace Illegal Character
(*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 // Starts With
int starts_with(const char *str, const char *prefix) { int starts_with(const char *str, const char *prefix) {
return strncmp(prefix, str, strlen(prefix)) == 0; return strncmp(prefix, str, strlen(prefix)) == 0;

View File

@ -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); event.key.keysym.sym = glfw_key_to_sdl_key(key);
SDL_PushEvent(&event); SDL_PushEvent(&event);
if (key == GLFW_KEY_BACKSPACE && !up) { 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 // Pass Text To Minecraft
static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) { static void glfw_char(__attribute__((unused)) GLFWwindow *window, unsigned int codepoint) {
if (is_interactable) { 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);
} }
} }

View File

@ -71,6 +71,9 @@ static void start_media_layer_proxy_client(int read, int write) {
safe_asprintf(&write_str, "%i", write); safe_asprintf(&write_str, "%i", write);
const char *argv[] = {"media-layer-proxy-client", read_str, write_str, NULL}; const char *argv[] = {"media-layer-proxy-client", read_str, write_str, NULL};
// Setup Environment
setup_exec_environment(0);
// Run // Run
safe_execvpe(argv, (const char *const *) environ); safe_execvpe(argv, (const char *const *) environ);
} else { } else {

View File

@ -108,7 +108,7 @@ add_library(test SHARED src/test/test.c)
target_link_libraries(test mods-headers reborn-patch home) target_link_libraries(test mods-headers reborn-patch home)
add_library(init SHARED src/init/init.c) 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) if(MCPI_SERVER_MODE)
target_link_libraries(init server) target_link_libraries(init server)
else() else()

View File

@ -48,7 +48,9 @@ static void *chat_thread(__attribute__((unused)) void *nop) {
// Don't Allow Empty Strings // Don't Allow Empty Strings
if (length > 0) { if (length > 0) {
// Submit // Submit
_chat_queue_message(output); char *safe_output = to_cp437(output);
_chat_queue_message(safe_output);
free(safe_output);
} }
} }
// Free Output // Free Output

View File

@ -186,7 +186,9 @@ static void *create_world_thread(__attribute__((unused)) void *nop) {
pthread_mutex_lock(&create_world_state_lock); pthread_mutex_lock(&create_world_state_lock);
reset_create_world_state(); reset_create_world_state();
create_world_state.dialog_state = DIALOG_SUCCESS; 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.game_mode = game_mode;
create_world_state.seed = seed; create_world_state.seed = seed;
pthread_mutex_unlock(&create_world_state_lock); pthread_mutex_unlock(&create_world_state_lock);

View File

@ -20,7 +20,9 @@ static void Gui_addMessage_injection(unsigned char *gui, std::string const& text
Gui_addMessage_recursing = true; Gui_addMessage_recursing = true;
// Print Log Message // 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 // Call Original Method
(*Gui_addMessage)(gui, std::string(new_message)); (*Gui_addMessage)(gui, std::string(new_message));

View File

@ -39,6 +39,10 @@ static char *get_username() {
} }
return username; return username;
} }
static char *safe_username = NULL;
__attribute__((destructor)) static void _free_safe_username() {
free(safe_username);
}
static int anaglyph; static int anaglyph;
static int render_distance; static int render_distance;
@ -102,7 +106,8 @@ void init_options() {
if (strcmp(*default_username, "StevePi") != 0) { if (strcmp(*default_username, "StevePi") != 0) {
ERR("Default Username Is Invalid"); 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 // Disable Autojump By Default
if (feature_has("Disable Autojump By Default", server_disabled)) { if (feature_has("Disable Autojump By Default", server_disabled)) {

View File

@ -64,7 +64,11 @@ static ServerProperties &get_server_properties() {
// Get World Name // Get World Name
static std::string 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 // Create/Start World
@ -120,8 +124,12 @@ static std::vector<unsigned char *> get_players_in_level(unsigned char *level) {
return *(std::vector<unsigned char *> *) (level + Level_players_property_offset); return *(std::vector<unsigned char *> *) (level + Level_players_property_offset);
} }
// Get Player's Username // Get Player's Username
static std::string *get_player_username(unsigned char *player) { static std::string get_player_username(unsigned char *player) {
return (std::string *) (player + Player_username_property_offset); 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 // Get Level From Minecraft
static unsigned char *get_level(unsigned char *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++) { for (std::size_t i = 0; i < players.size(); i++) {
// Iterate Players // Iterate Players
unsigned char *player = players[i]; 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) { if (all_players || username == target_username) {
// Run Callback // Run Callback
(*callback)(minecraft, username, player); (*callback)(minecraft, username, player);
@ -326,8 +334,11 @@ static void handle_commands(unsigned char *minecraft) {
} else if (data.rfind(say_command, 0) == 0) { } else if (data.rfind(say_command, 0) == 0) {
// Format Message // Format Message
std::string message = "[Server] " + data.substr(say_command.length()); std::string message = "[Server] " + data.substr(say_command.length());
char *safe_message = to_cp437(message.c_str());
// Post Message To Chat // 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) { } else if (data == list_command) {
// List Players // List Players
INFO("All Players:"); INFO("All Players:");
@ -584,7 +595,7 @@ static void server_init() {
// Init Server // Init Server
void init_server() { void init_server() {
server_init(); server_init();
setenv("MCPI_FEATURE_FLAGS", get_features(), 1); set_and_print_env("MCPI_FEATURE_FLAGS", get_features());
setenv("MCPI_RENDER_DISTANCE", "Tiny", 1); set_and_print_env("MCPI_RENDER_DISTANCE", "Tiny");
setenv("MCPI_USERNAME", get_motd().c_str(), 1); set_and_print_env("MCPI_USERNAME", get_motd().c_str());
} }