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 "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 << "<?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/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();
}

View File

@ -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())
{

View File

@ -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 <wchar.h>
#include <string>
@ -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;

View File

@ -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();
}

View File

@ -26,24 +26,40 @@
// ----------------------------------------------------------------------------
#if defined(WIN32)
#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
*/
std::string FileUtils::Private::getShortPath(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;
}
}
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<wchar_t> 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
// ----------------------------------------------------------------------------

View File

@ -21,12 +21,15 @@
#include <stdio.h>
#include <string>
#include <sys/stat.h>
#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;

View File

@ -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++)