From cbf55b6ecfa7c5c2f7f3ea4aee429350a00952aa Mon Sep 17 00:00:00 2001 From: Benau Date: Fri, 28 Jun 2019 22:54:02 +0800 Subject: [PATCH] Make all ofstream creation utf8 path aware --- src/addons/addons_manager.cpp | 4 +- src/config/user_config.cpp | 4 +- src/input/device_manager.cpp | 4 +- src/io/utf_writer.cpp | 4 +- src/network/server_config.cpp | 5 ++- src/utils/file_utils.cpp | 69 +++++++++++++++++++++++++++-------- src/utils/file_utils.hpp | 16 +++++++- src/utils/profiler.cpp | 7 ++-- 8 files changed, 87 insertions(+), 26 deletions(-) diff --git a/src/addons/addons_manager.cpp b/src/addons/addons_manager.cpp index 3183fca48..adb8cf0a1 100644 --- a/src/addons/addons_manager.cpp +++ b/src/addons/addons_manager.cpp @@ -34,6 +34,7 @@ #include "states_screens/kart_selection.hpp" #include "tracks/track.hpp" #include "tracks/track_manager.hpp" +#include "utils/file_utils.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -605,7 +606,8 @@ void AddonsManager::saveInstalled() { // Put the addons in the xml file // Manually because the irrlicht xml writer doesn't seem finished, FIXME ? - std::ofstream xml_installed(m_file_installed.c_str()); + std::ofstream xml_installed( + FileUtils::getPortableWritingPath(m_file_installed)); // Write the header of the xml file xml_installed << "" << std::endl; diff --git a/src/config/user_config.cpp b/src/config/user_config.cpp index b75144378..ac6164a0c 100644 --- a/src/config/user_config.cpp +++ b/src/config/user_config.cpp @@ -38,6 +38,7 @@ static std::vector all_params; #include "io/utf_writer.hpp" #include "io/xml_node.hpp" #include "race/race_manager.hpp" +#include "utils/file_utils.hpp" #include "utils/log.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -744,7 +745,8 @@ void UserConfig::saveConfig() try { std::string s = ss.str(); - std::ofstream configfile(filename.c_str(), std::ofstream::out); + std::ofstream configfile(FileUtils::getPortableWritingPath(filename), + std::ofstream::out); configfile << ss.rdbuf(); configfile.close(); } diff --git a/src/input/device_manager.cpp b/src/input/device_manager.cpp index 2b52cbe7f..13683860e 100644 --- a/src/input/device_manager.cpp +++ b/src/input/device_manager.cpp @@ -31,6 +31,7 @@ #include "io/file_manager.hpp" #include "states_screens/kart_selection.hpp" #include "states_screens/state_manager.hpp" +#include "utils/file_utils.hpp" #include "utils/log.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -634,8 +635,7 @@ void DeviceManager::save() if(UserConfigParams::logMisc()) Log::info("Device manager","Serializing input.xml..."); - std::ofstream configfile; - configfile.open (filepath.c_str()); + std::ofstream configfile(FileUtils::getPortableWritingPath(filepath)); if(!configfile.is_open()) { diff --git a/src/io/utf_writer.cpp b/src/io/utf_writer.cpp index 9e12f3770..873359017 100644 --- a/src/io/utf_writer.cpp +++ b/src/io/utf_writer.cpp @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "io/utf_writer.hpp" +#include "utils/file_utils.hpp" #include #include @@ -26,7 +27,8 @@ using namespace irr; // ---------------------------------------------------------------------------- UTFWriter::UTFWriter(const char* dest, bool wide) - : m_base(dest, std::ios::out | std::ios::binary) + : m_base(FileUtils::getPortableWritingPath(dest), + std::ios::out | std::ios::binary) { m_wide = wide; diff --git a/src/network/server_config.cpp b/src/network/server_config.cpp index 189b5562a..ea88e9d9d 100644 --- a/src/network/server_config.cpp +++ b/src/network/server_config.cpp @@ -17,6 +17,7 @@ // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "utils/log.hpp" +#include "utils/file_utils.hpp" #include "utils/string_utils.hpp" #include "utils/translation.hpp" @@ -191,8 +192,8 @@ void writeServerConfigToDisk() const std::string& config_xml = getServerConfigXML(); try { - std::ofstream configfile(g_server_config_path.c_str(), - std::ofstream::out); + std::ofstream configfile(FileUtils::getPortableWritingPath( + g_server_config_path), std::ofstream::out); configfile << config_xml; configfile.close(); } diff --git a/src/utils/file_utils.cpp b/src/utils/file_utils.cpp index 8d62ac9a4..b2ca319f3 100644 --- a/src/utils/file_utils.cpp +++ b/src/utils/file_utils.cpp @@ -26,24 +26,40 @@ // ---------------------------------------------------------------------------- #if defined(WIN32) #include +// ---------------------------------------------------------------------------- +namespace u8checker +{ + bool hasUnicode(const std::string& u8_path) + { + bool has_unicode = false; + for (char c : u8_path) + { + if (static_cast(c) > 127) + { + has_unicode = true; + break; + } + } + return has_unicode; + } // hasUnicode +} // namespace u8checker + +// ---------------------------------------------------------------------------- /** Return a 8.3 filename if u8_path contains unicode character */ std::string FileUtils::Private::getShortPath(const std::string& u8_path) { - bool has_unicode = false; - for (char c : u8_path) - { - if (static_cast(c) > 127) - { - has_unicode = true; - break; - } - } - if (!has_unicode) + if (!u8checker::hasUnicode(u8_path)) return u8_path; - irr::core::stringw wpath = StringUtils::utf8ToWide(u8_path); - size_t length = GetShortPathNameW(wpath.c_str(), NULL, 0); + irr::core::stringw w_path = StringUtils::utf8ToWide(u8_path); + return FileUtils::Private::getShortPathW(w_path); +} // getShortPath + +// ---------------------------------------------------------------------------- +std::string FileUtils::Private::getShortPathW(const irr::core::stringw& w_path) +{ + size_t length = GetShortPathNameW(w_path.c_str(), NULL, 0); if (length == 0) { Log::error("FileUtils", @@ -52,7 +68,8 @@ std::string FileUtils::Private::getShortPath(const std::string& u8_path) } std::vector short_path; short_path.resize(length); - length = GetShortPathNameW(wpath.c_str(), short_path.data(), length); + length = GetShortPathNameW(w_path.c_str(), short_path.data(), + (DWORD)length); if (length == 0) { Log::error("FileUtils", @@ -65,12 +82,34 @@ std::string FileUtils::Private::getShortPath(const std::string& u8_path) // Reserve enough space for conversion result.resize(length * 4); length = WideCharToMultiByte(CP_ACP, 0, short_path.data(), -1, &result[0], - result.size(), NULL, NULL); + (int)result.size(), NULL, NULL); // Passing -1 as input string length will null terminated the output, so // length written included a null terminator result.resize(length - 1); return result; -} // getShortPath +} // getShortPathW + +// ---------------------------------------------------------------------------- +std::string FileUtils::Private::getShortPathWriting(const std::string& u8_path) +{ + if (!u8checker::hasUnicode(u8_path)) + return u8_path; + + // Create an empty file first if not exist so we can get the short path + irr::core::stringw w_path = StringUtils::utf8ToWide(u8_path); + if (_waccess(w_path.c_str(), 0) == -1) + { + FILE* fp = _wfopen(w_path.c_str(), L"wb"); + if (!fp) + { + Log::error("FileUtils", + "Failed to create empty file before writing."); + return ""; + } + fclose(fp); + } + return FileUtils::Private::getShortPathW(w_path); +} // getShortPathWriting #endif // ---------------------------------------------------------------------------- diff --git a/src/utils/file_utils.hpp b/src/utils/file_utils.hpp index 542cacfeb..efd56a55b 100644 --- a/src/utils/file_utils.hpp +++ b/src/utils/file_utils.hpp @@ -21,12 +21,15 @@ #include #include #include +#include "irrString.h" namespace FileUtils { namespace Private { std::string getShortPath(const std::string& u8_path); + std::string getShortPathW(const irr::core::stringw& w_path); + std::string getShortPathWriting(const std::string& u8_path); } // ------------------------------------------------------------------------ FILE* fopenU8Path(const std::string& u8_path, const char* mode); @@ -36,11 +39,22 @@ namespace FileUtils int renameU8Path(const std::string& u8_path_old, const std::string& u8_path_new); // ------------------------------------------------------------------------ + /* Return a path which can be opened for writing in all systems, as long as + * u8_path is unicode encoded. */ + inline std::string getPortableWritingPath(const std::string& u8_path) + { +#if defined(WIN32) + return Private::getShortPathWriting(u8_path); +#else + return u8_path; +#endif + } + // ------------------------------------------------------------------------ /* Return a path which can be opened in all systems, as long as u8_path * is unicode encoded. */ inline std::string getPortablePath(const std::string& u8_path) { -#ifdef WIN32 +#if defined(WIN32) return Private::getShortPath(u8_path); #else return u8_path; diff --git a/src/utils/profiler.cpp b/src/utils/profiler.cpp index c228333a6..7b017b848 100644 --- a/src/utils/profiler.cpp +++ b/src/utils/profiler.cpp @@ -26,6 +26,7 @@ #include "graphics/irr_driver.hpp" #include "guiengine/scalable_font.hpp" #include "io/file_manager.hpp" +#include "utils/file_utils.hpp" #include "utils/string_utils.hpp" #include "utils/vs.hpp" @@ -545,8 +546,8 @@ void Profiler::writeToFile() // First CPU data for (int thread_id = 0; thread_id < m_threads_used; thread_id++) { - std::ofstream f(base_name + ".profile-cpu-" + - StringUtils::toString(thread_id) ); + std::ofstream f(FileUtils::getPortableWritingPath( + base_name + ".profile-cpu-" + StringUtils::toString(thread_id))); ThreadData &td = m_all_threads_data[thread_id]; f << "# "; for (unsigned int i = 0; i < td.m_ordered_headings.size(); i++) @@ -567,7 +568,7 @@ void Profiler::writeToFile() f.close(); } // for all thread_ids - std::ofstream f_gpu(base_name + ".profile-gpu"); + std::ofstream f_gpu(FileUtils::getPortableWritingPath(base_name + ".profile-gpu")); f_gpu << "# "; for (unsigned i = 0; i < Q_LAST; i++)