diff --git a/.gitmodules b/.gitmodules index 0e102ee..c70e3c3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,3 +17,6 @@ [submodule "dependencies/stb_image/include"] path = dependencies/stb_image/include url = https://github.com/nothings/stb.git +[submodule "dependencies/utf8cpp/src"] + path = dependencies/utf8cpp/src + url = https://github.com/nemtrif/utfcpp.git diff --git a/cmake/prebuilt-armhf-toolchain.cmake b/cmake/prebuilt-armhf-toolchain.cmake index 2b33add..34a279e 100644 --- a/cmake/prebuilt-armhf-toolchain.cmake +++ b/cmake/prebuilt-armhf-toolchain.cmake @@ -50,6 +50,7 @@ if("${toolchain_dir}/bin/arm-none-linux-gnueabihf-gcc" IS_NEWER_THAN "${sysroot_ # 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}/*") @@ -61,13 +62,6 @@ if("${toolchain_dir}/bin/arm-none-linux-gnueabihf-gcc" IS_NEWER_THAN "${sysroot_ 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/dependencies/CMakeLists.txt b/dependencies/CMakeLists.txt index 1e919a4..c15c120 100644 --- a/dependencies/CMakeLists.txt +++ b/dependencies/CMakeLists.txt @@ -28,3 +28,5 @@ endif() if(BUILD_NATIVE_COMPONENTS AND NOT MCPI_HEADLESS_MODE AND MCPI_USE_GLES1_COMPATIBILITY_LAYER) add_subdirectory(gles-compatibility-layer) endif() +# UTF8-CPP +add_subdirectory(utf8cpp) diff --git a/dependencies/stb_image/CMakeLists.txt b/dependencies/stb_image/CMakeLists.txt index 3dca232..e4961b8 100644 --- a/dependencies/stb_image/CMakeLists.txt +++ b/dependencies/stb_image/CMakeLists.txt @@ -21,6 +21,8 @@ install(TARGETS stb_image DESTINATION "${MCPI_LIB_DIR}") install( DIRECTORY "include/" DESTINATION "${MCPI_SDK_INCLUDE_DIR}/stb_image" + FILES_MATCHING + PATTERN "*.h" ) install(TARGETS stb_image EXPORT sdk DESTINATION "${MCPI_SDK_LIB_DIR}") diff --git a/dependencies/utf8cpp/CMakeLists.txt b/dependencies/utf8cpp/CMakeLists.txt new file mode 100644 index 0000000..8a62c7d --- /dev/null +++ b/dependencies/utf8cpp/CMakeLists.txt @@ -0,0 +1,12 @@ +project(utf8cpp) + +# Silence Warnings +add_compile_options(-w) + +## stb_image + +# Build +add_subdirectory(src EXCLUDE_FROM_ALL) + +# License +install(FILES src/LICENSE DESTINATION "${MCPI_LEGAL_DIR}/utf8cpp") diff --git a/dependencies/utf8cpp/src b/dependencies/utf8cpp/src new file mode 160000 index 0000000..f6780f7 --- /dev/null +++ b/dependencies/utf8cpp/src @@ -0,0 +1 @@ +Subproject commit f6780f77f6824aa0fbe69f9b97ef7d8aba26ed92 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 499311b..c648802 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -29,7 +29,6 @@ This component configures the various environmental variables required for MCPI- The environmental variables configured by this component includes: * ``LD_PRELOAD`` * ``LD_LIBRARY_PATH`` -* ``GCONV_PATH`` * ``MCPI_FEATURE_FLAGS`` * ``MCPI_RENDER_DISTANCE`` * ``MCPI_USERNAME`` diff --git a/launcher/src/bootstrap.c b/launcher/src/bootstrap.c index b62d7f8..af7cc36 100644 --- a/launcher/src/bootstrap.c +++ b/launcher/src/bootstrap.c @@ -370,23 +370,6 @@ void bootstrap(int argc, char *argv[]) { 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 Preloaded Objects diff --git a/libreborn/CMakeLists.txt b/libreborn/CMakeLists.txt index 9fbe54c..59bfa3f 100644 --- a/libreborn/CMakeLists.txt +++ b/libreborn/CMakeLists.txt @@ -5,7 +5,7 @@ file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn") configure_file(include/libreborn/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/libreborn/config.h" ESCAPE_QUOTES @ONLY) # Util -add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.c) +add_library(reborn-util SHARED src/util/elf.c src/util/exec.c src/util/string.c src/util/util.c src/util/log.c src/util/cp437.cpp) target_include_directories( reborn-util PUBLIC @@ -13,6 +13,7 @@ target_include_directories( "$" "$" ) +target_link_libraries(reborn-util PRIVATE utf8cpp) # Install install(TARGETS reborn-util DESTINATION "${MCPI_LIB_DIR}") # SDK diff --git a/libreborn/include/libreborn/exec.h b/libreborn/include/libreborn/exec.h index 3114603..8921174 100644 --- a/libreborn/include/libreborn/exec.h +++ b/libreborn/include/libreborn/exec.h @@ -22,7 +22,6 @@ 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[]); diff --git a/libreborn/include/libreborn/string.h b/libreborn/include/libreborn/string.h index 9754200..c2593a5 100644 --- a/libreborn/include/libreborn/string.h +++ b/libreborn/include/libreborn/string.h @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "util.h" @@ -36,7 +35,6 @@ extern "C" { 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); diff --git a/libreborn/src/util/cp437.cpp b/libreborn/src/util/cp437.cpp new file mode 100644 index 0000000..8dd0e81 --- /dev/null +++ b/libreborn/src/util/cp437.cpp @@ -0,0 +1,91 @@ +#include +#include + +#include "utf8.h" + +#include + +// Conversion Functions +static std::u32string to_utf32(const std::string &s) { + return utf8::utf8to32(s); +} +static std::string to_utf8(const std::u32string &s) { + return utf8::utf32to8(s); +} + +// Minecraft-Flavored CP437 +#define CP437_CHARACTERS 256 +static const std::string 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 + for (int i = 0; i < CP437_CHARACTERS; i++) { + // Convert to UTF-32, Then Extract Codepoint + std::u32string str = to_utf32(cp437_characters_map[i]); + // Extract + map[i] = str[0]; + } + is_setup = 1; + } + return map; +} +char *to_cp437(const char *input) { + // Convert To UTF-32 For Easier Parsing + std::u32string utf32_str = to_utf32(input); + + // Allocate String + std::string cp437_str; + + // Handle Characters + for (size_t i = 0; i < utf32_str.length(); i++) { + uint32_t codepoint = utf32_str[i]; + bool valid = false; + for (int j = 0; j < CP437_CHARACTERS; j++) { + uint32_t test_codepoint = get_cp437_characters_codepoint_map()[j]; + if (codepoint == test_codepoint) { + valid = true; + cp437_str += j; + break; + } + } + if (!valid) { + cp437_str += '?'; + } + } + + // Return + return strdup(cp437_str.c_str()); +} +char *from_cp437(const char *raw_input) { + // Convert To UTF-32 For Easier Parsing + std::string input = raw_input; + std::u32string utf32_str; + + // Handle Characters + for (size_t i = 0; i < input.length(); i++) { + unsigned char c = (unsigned char) input[i]; + utf32_str += get_cp437_characters_codepoint_map()[(uint32_t) c]; + } + + // Convert To UTF-8 + return strdup(to_utf8(utf32_str).c_str()); +} diff --git a/libreborn/src/util/string.c b/libreborn/src/util/string.c index 2c375a1..bf08000 100644 --- a/libreborn/src/util/string.c +++ b/libreborn/src/util/string.c @@ -1,4 +1,3 @@ -#include #include #include @@ -23,125 +22,6 @@ void sanitize_string(char **str, int max_length, unsigned int allow_newlines) { } } -// 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;