Make all ofstream creation utf8 path aware

This commit is contained in:
Benau 2019-06-28 22:54:02 +08:00
parent 12a9237016
commit cbf55b6ecf
8 changed files with 87 additions and 26 deletions

View File

@ -34,6 +34,7 @@
#include "states_screens/kart_selection.hpp" #include "states_screens/kart_selection.hpp"
#include "tracks/track.hpp" #include "tracks/track.hpp"
#include "tracks/track_manager.hpp" #include "tracks/track_manager.hpp"
#include "utils/file_utils.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
@ -605,7 +606,8 @@ void AddonsManager::saveInstalled()
{ {
// Put the addons in the xml file // Put the addons in the xml file
// Manually because the irrlicht xml writer doesn't seem finished, FIXME ? // 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 // Write the header of the xml file
xml_installed << "<?xml version=\"1.0\"?>" << std::endl; xml_installed << "<?xml version=\"1.0\"?>" << std::endl;

View File

@ -38,6 +38,7 @@ static std::vector<UserConfigParam*> all_params;
#include "io/utf_writer.hpp" #include "io/utf_writer.hpp"
#include "io/xml_node.hpp" #include "io/xml_node.hpp"
#include "race/race_manager.hpp" #include "race/race_manager.hpp"
#include "utils/file_utils.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
@ -744,7 +745,8 @@ void UserConfig::saveConfig()
try try
{ {
std::string s = ss.str(); 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 << ss.rdbuf();
configfile.close(); configfile.close();
} }

View File

@ -31,6 +31,7 @@
#include "io/file_manager.hpp" #include "io/file_manager.hpp"
#include "states_screens/kart_selection.hpp" #include "states_screens/kart_selection.hpp"
#include "states_screens/state_manager.hpp" #include "states_screens/state_manager.hpp"
#include "utils/file_utils.hpp"
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
@ -634,8 +635,7 @@ void DeviceManager::save()
if(UserConfigParams::logMisc()) Log::info("Device manager","Serializing input.xml..."); if(UserConfigParams::logMisc()) Log::info("Device manager","Serializing input.xml...");
std::ofstream configfile; std::ofstream configfile(FileUtils::getPortableWritingPath(filepath));
configfile.open (filepath.c_str());
if(!configfile.is_open()) if(!configfile.is_open())
{ {

View File

@ -17,6 +17,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "io/utf_writer.hpp" #include "io/utf_writer.hpp"
#include "utils/file_utils.hpp"
#include <wchar.h> #include <wchar.h>
#include <string> #include <string>
@ -26,7 +27,8 @@ using namespace irr;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
UTFWriter::UTFWriter(const char* dest, bool wide) 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; m_wide = wide;

View File

@ -17,6 +17,7 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/file_utils.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
@ -191,8 +192,8 @@ void writeServerConfigToDisk()
const std::string& config_xml = getServerConfigXML(); const std::string& config_xml = getServerConfigXML();
try try
{ {
std::ofstream configfile(g_server_config_path.c_str(), std::ofstream configfile(FileUtils::getPortableWritingPath(
std::ofstream::out); g_server_config_path), std::ofstream::out);
configfile << config_xml; configfile << config_xml;
configfile.close(); configfile.close();
} }

View File

@ -26,24 +26,40 @@
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#if defined(WIN32) #if defined(WIN32)
#include <windows.h> #include <windows.h>
// ----------------------------------------------------------------------------
namespace u8checker
{
bool hasUnicode(const std::string& u8_path)
{
bool has_unicode = false;
for (char c : u8_path)
{
if (static_cast<unsigned char>(c) > 127)
{
has_unicode = true;
break;
}
}
return has_unicode;
} // hasUnicode
} // namespace u8checker
// ----------------------------------------------------------------------------
/** Return a 8.3 filename if u8_path contains unicode character /** Return a 8.3 filename if u8_path contains unicode character
*/ */
std::string FileUtils::Private::getShortPath(const std::string& u8_path) std::string FileUtils::Private::getShortPath(const std::string& u8_path)
{ {
bool has_unicode = false; if (!u8checker::hasUnicode(u8_path))
for (char c : u8_path)
{
if (static_cast<unsigned char>(c) > 127)
{
has_unicode = true;
break;
}
}
if (!has_unicode)
return u8_path; return u8_path;
irr::core::stringw wpath = StringUtils::utf8ToWide(u8_path); irr::core::stringw w_path = StringUtils::utf8ToWide(u8_path);
size_t length = GetShortPathNameW(wpath.c_str(), NULL, 0); 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) if (length == 0)
{ {
Log::error("FileUtils", Log::error("FileUtils",
@ -52,7 +68,8 @@ std::string FileUtils::Private::getShortPath(const std::string& u8_path)
} }
std::vector<wchar_t> short_path; std::vector<wchar_t> short_path;
short_path.resize(length); 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) if (length == 0)
{ {
Log::error("FileUtils", Log::error("FileUtils",
@ -65,12 +82,34 @@ std::string FileUtils::Private::getShortPath(const std::string& u8_path)
// Reserve enough space for conversion // Reserve enough space for conversion
result.resize(length * 4); result.resize(length * 4);
length = WideCharToMultiByte(CP_ACP, 0, short_path.data(), -1, &result[0], 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 // Passing -1 as input string length will null terminated the output, so
// length written included a null terminator // length written included a null terminator
result.resize(length - 1); result.resize(length - 1);
return result; 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 #endif
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

View File

@ -21,12 +21,15 @@
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <sys/stat.h> #include <sys/stat.h>
#include "irrString.h"
namespace FileUtils namespace FileUtils
{ {
namespace Private namespace Private
{ {
std::string getShortPath(const std::string& u8_path); 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); FILE* fopenU8Path(const std::string& u8_path, const char* mode);
@ -36,11 +39,22 @@ namespace FileUtils
int renameU8Path(const std::string& u8_path_old, int renameU8Path(const std::string& u8_path_old,
const std::string& u8_path_new); 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 /* Return a path which can be opened in all systems, as long as u8_path
* is unicode encoded. */ * is unicode encoded. */
inline std::string getPortablePath(const std::string& u8_path) inline std::string getPortablePath(const std::string& u8_path)
{ {
#ifdef WIN32 #if defined(WIN32)
return Private::getShortPath(u8_path); return Private::getShortPath(u8_path);
#else #else
return u8_path; return u8_path;

View File

@ -26,6 +26,7 @@
#include "graphics/irr_driver.hpp" #include "graphics/irr_driver.hpp"
#include "guiengine/scalable_font.hpp" #include "guiengine/scalable_font.hpp"
#include "io/file_manager.hpp" #include "io/file_manager.hpp"
#include "utils/file_utils.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/vs.hpp" #include "utils/vs.hpp"
@ -545,8 +546,8 @@ void Profiler::writeToFile()
// First CPU data // First CPU data
for (int thread_id = 0; thread_id < m_threads_used; thread_id++) for (int thread_id = 0; thread_id < m_threads_used; thread_id++)
{ {
std::ofstream f(base_name + ".profile-cpu-" + std::ofstream f(FileUtils::getPortableWritingPath(
StringUtils::toString(thread_id) ); base_name + ".profile-cpu-" + StringUtils::toString(thread_id)));
ThreadData &td = m_all_threads_data[thread_id]; ThreadData &td = m_all_threads_data[thread_id];
f << "# "; f << "# ";
for (unsigned int i = 0; i < td.m_ordered_headings.size(); i++) for (unsigned int i = 0; i < td.m_ordered_headings.size(); i++)
@ -567,7 +568,7 @@ void Profiler::writeToFile()
f.close(); f.close();
} // for all thread_ids } // for all thread_ids
std::ofstream f_gpu(base_name + ".profile-gpu"); std::ofstream f_gpu(FileUtils::getPortableWritingPath(base_name + ".profile-gpu"));
f_gpu << "# "; f_gpu << "# ";
for (unsigned i = 0; i < Q_LAST; i++) for (unsigned i = 0; i < Q_LAST; i++)