From 2ee3855c2aa71964856b3a9bd5edde63e5da8b41 Mon Sep 17 00:00:00 2001 From: Rare Breeds Date: Sat, 29 Jul 2023 14:33:56 -0700 Subject: [PATCH] Support UTF-8 paths on Windows Faceplates aren't loading if the RACK_USER_DIR has non-ASCII characters in it. See: https://community.vcvrack.com/t/rarebreeds-eugene-not-working/20266 Resolves issue #4. --- src/OrbitsConfig.cpp | 67 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/src/OrbitsConfig.cpp b/src/OrbitsConfig.cpp index 8dac9fa..9e52a6d 100644 --- a/src/OrbitsConfig.cpp +++ b/src/OrbitsConfig.cpp @@ -1,8 +1,55 @@ -#include - #include "OrbitsConfig.hpp" #include "plugin.hpp" +static json_t *orbits_json_load_file(const char *path, size_t flags, json_error_t *error) +{ + FILE *fp = std::fopen(path, "rb"); + json_t *json = json_loadf(fp, flags, error); + if (fp) + { + std::fclose(fp); + } + return json; +} + +static std::string read_file_contents(const std::string& filename) +{ + // Read a file into a string without using ifstream. + // MINGW doesn't have an ifstream that supports being constructed + // from a wide string, which is required on Windows for opening + // paths containing UTF8 characters. + FILE* file = std::fopen(filename.c_str(), "rb"); + if (file == NULL) + { + return ""; + } + + fseek(file, 0, SEEK_END); + long ftell_result = ftell(file); + fseek(file, 0, SEEK_SET); + + if (ftell_result <= 0) + { + std::fclose(file); + return ""; + } + + size_t file_size = (size_t) ftell_result; + std::vector buffer(file_size + 1); + size_t bytes_read = fread(buffer.data(), 1, file_size, file); + + std::fclose(file); + + if (bytes_read != static_cast(file_size)) + { + return ""; + } + + buffer[file_size] = '\0'; + + return std::string(buffer.data()); +} + OrbitsConfig::OrbitsConfig(std::string path) { m_path = path; @@ -33,7 +80,7 @@ std::string OrbitsConfig::getSvg(std::string component, int theme) { json_error_t error; std::string path = asset::plugin(pluginInstance, m_path); - json_t *root = json_load_file(path.c_str(), 0, &error); + json_t *root = orbits_json_load_file(path.c_str(), 0, &error); json_t *themes = json_object_get(root, "themes"); json_t *entry = json_array_get(themes, theme); json_t *obj = json_object_get(entry, component.c_str()); @@ -50,8 +97,7 @@ std::string OrbitsConfig::getSvg(std::string component) Vec OrbitsConfig::getPos(std::string component) { - std::ifstream ifs(getSvg("panel")); - std::string content((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); + std::string content = read_file_contents(getSvg("panel")); size_t search = content.find("inkscape:label=\"components\""); if(search == std::string::npos) { @@ -73,8 +119,7 @@ Vec OrbitsConfig::getPos(std::string component) Vec OrbitsConfig::getSize(std::string component) { - std::ifstream ifs(getSvg("panel")); - std::string content((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); + std::string content = read_file_contents(getSvg("panel")); size_t search = content.find("inkscape:label=\"components\""); search = content.find("inkscape:label=\"" + component, search); float w = rFindFloatAttribute(content, "width", search); @@ -86,7 +131,7 @@ std::string OrbitsConfig::getThemeName(int theme) { json_error_t error; std::string path = asset::plugin(pluginInstance, m_path); - json_t *root = json_load_file(path.c_str(), 0, &error); + json_t *root = orbits_json_load_file(path.c_str(), 0, &error); json_t *themes = json_object_get(root, "themes"); json_t *entry = json_array_get(themes, theme); json_t *name = json_object_get(entry, "name"); @@ -106,7 +151,7 @@ int OrbitsConfig::getDefaultThemeId() int default_theme_id = 0; json_error_t error; std::string path = asset::plugin(pluginInstance, m_path); - json_t *root = json_load_file(path.c_str(), 0, &error); + json_t *root = orbits_json_load_file(path.c_str(), 0, &error); json_t *def = json_object_get(root, "default"); const char *default_name = json_string_value(def); json_t *themes = json_object_get(root, "themes"); @@ -131,7 +176,7 @@ size_t OrbitsConfig::numThemes() { json_error_t error; std::string path = asset::plugin(pluginInstance, m_path); - json_t *root = json_load_file(path.c_str(), 0, &error); + json_t *root = orbits_json_load_file(path.c_str(), 0, &error); json_t *themes = json_object_get(root, "themes"); size_t count = json_array_size(themes); json_decref(root); @@ -142,7 +187,7 @@ std::array OrbitsConfig::getColour(std::string component, int theme) { json_error_t error; std::string path = asset::plugin(pluginInstance, m_path); - json_t *root = json_load_file(path.c_str(), 0, &error); + json_t *root = orbits_json_load_file(path.c_str(), 0, &error); json_t *themes = json_object_get(root, "themes"); json_t *entry = json_array_get(themes, theme); json_t *obj = json_object_get(entry, component.c_str());