Add functions to handle file in utf8 encoded name

This commit is contained in:
Benau 2019-06-28 20:49:33 +08:00
parent 74f227590e
commit 1cd725586f
7 changed files with 226 additions and 67 deletions

View File

@ -498,16 +498,10 @@ const io::path& CFileSystem::getWorkingDirectory()
#if defined(_IRR_WINDOWS_CE_PLATFORM_)
// does not need this
#elif defined(_IRR_WINDOWS_API_)
fschar_t tmp[_MAX_PATH];
#if defined(_IRR_WCHAR_FILESYSTEM )
_wgetcwd(tmp, _MAX_PATH);
WorkingDirectory[FILESYSTEM_NATIVE] = tmp;
WorkingDirectory[FILESYSTEM_NATIVE].replace(L'\\', L'/');
#else
_getcwd(tmp, _MAX_PATH);
WorkingDirectory[FILESYSTEM_NATIVE] = tmp;
WorkingDirectory[FILESYSTEM_NATIVE].replace('\\', '/');
#endif
wchar_t tmp[_MAX_PATH];
_wgetcwd(tmp, _MAX_PATH);
WorkingDirectory[FILESYSTEM_NATIVE] = StringUtils::wideToUtf8(tmp).c_str();
WorkingDirectory[FILESYSTEM_NATIVE].replace('\\', '/');
#endif
#if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
@ -572,18 +566,10 @@ bool CFileSystem::changeWorkingDirectoryTo(const io::path& newDirectory)
#if defined(_IRR_WINDOWS_CE_PLATFORM_)
success = true;
#elif defined(_MSC_VER)
#if defined(_IRR_WCHAR_FILESYSTEM)
success = (_wchdir(newDirectory.c_str()) == 0);
#else
success = (_chdir(newDirectory.c_str()) == 0);
#endif
#elif defined(_IRR_WINDOWS_API_)
success = (_wchdir(StringUtils::utf8ToWide(newDirectory.c_str()).c_str()) == 0);
#else
#if defined(_IRR_WCHAR_FILESYSTEM)
success = (_wchdir(newDirectory.c_str()) == 0);
#else
success = (chdir(newDirectory.c_str()) == 0);
#endif
success = (chdir(newDirectory.c_str()) == 0);
#endif
}
@ -596,18 +582,12 @@ io::path CFileSystem::getAbsolutePath(const io::path& filename) const
#if defined(_IRR_WINDOWS_CE_PLATFORM_)
return filename;
#elif defined(_IRR_WINDOWS_API_)
fschar_t *p=0;
fschar_t fpath[_MAX_PATH];
#if defined(_IRR_WCHAR_FILESYSTEM )
p = _wfullpath(fpath, filename.c_str(), _MAX_PATH);
core::stringw tmp(p);
tmp.replace(L'\\', L'/');
#else
p = _fullpath(fpath, filename.c_str(), _MAX_PATH);
core::stringc tmp(p);
tmp.replace('\\', '/');
#endif
return tmp;
wchar_t *p=0;
wchar_t fpath[_MAX_PATH];
p = _wfullpath(fpath, StringUtils::utf8ToWide(filename.c_str()).c_str(), _MAX_PATH);
core::stringw tmp(p);
tmp.replace(L'\\', L'/');
return StringUtils::wideToUtf8(tmp).c_str();
#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
c8* p=0;
c8 fpath[4096];
@ -965,19 +945,15 @@ bool CFileSystem::existFile(const io::path& filename) const
#else
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
#if defined(_MSC_VER)
#if defined(_IRR_WCHAR_FILESYSTEM)
return (_waccess(filename.c_str(), 0) != -1);
#else
return (_access(filename.c_str(), 0) != -1);
#endif
return (_waccess(StringUtils::utf8ToWide(filename.c_str()).c_str(), 0) != -1);
#elif defined(F_OK)
#if defined(_IRR_WCHAR_FILESYSTEM)
return (_waccess(filename.c_str(), F_OK) != -1);
#else
return (access(filename.c_str(), F_OK) != -1);
#if defined(_IRR_WINDOWS_API_)
return (_waccess(StringUtils::utf8ToWide(filename.c_str()).c_str(), F_OK) != -1);
#else
return (access(filename.c_str(), F_OK) != -1);
#endif
#else
return (access(filename.c_str(), 0) != -1);
return (access(filename.c_str(), 0) != -1);
#endif
#endif
}

View File

@ -4,6 +4,7 @@
#include "CReadFile.h"
#include "utils/file_utils.hpp"
namespace irr
{
namespace io
@ -73,11 +74,7 @@ void CReadFile::openFile()
return;
}
#if defined ( _IRR_WCHAR_FILESYSTEM )
File = _wfopen(Filename.c_str(), L"rb");
#else
File = fopen(Filename.c_str(), "rb");
#endif
File = FileUtils::fopenU8Path(Filename.c_str(), "rb");
if (File)
{

View File

@ -3,6 +3,8 @@
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CWriteFile.h"
#include "utils/file_utils.hpp"
#include <stdio.h>
namespace irr
@ -81,11 +83,7 @@ void CWriteFile::openFile(bool append)
return;
}
#if defined(_IRR_WCHAR_FILESYSTEM)
File = _wfopen(Filename.c_str(), append ? L"ab" : L"wb");
#else
File = fopen(Filename.c_str(), append ? "ab" : "wb");
#endif
File = FileUtils::fopenU8Path(Filename.c_str(), append ? "ab" : "wb");
if (File)
{

View File

@ -1,5 +1,5 @@
# Modify this file to change the last-modified date when you add/remove a file.
# This will then trigger a new cmake run automatically.
# This will then trigger a new cmake run automatically.
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")

View File

@ -26,6 +26,7 @@
#include "karts/kart_properties_manager.hpp"
#include "tracks/track_manager.hpp"
#include "utils/command_line.hpp"
#include "utils/file_utils.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
@ -385,7 +386,7 @@ FileManager::~FileManager()
continue;
}
struct stat mystat;
stat(full_path.c_str(), &mystat);
FileUtils::statU8Path(full_path, &mystat);
StkTime::TimeType current = StkTime::getTimeSinceEpoch();
if(current - mystat.st_ctime <24*3600)
{
@ -797,7 +798,7 @@ bool FileManager::checkAndCreateDirectory(const std::string &path)
// Otherwise try to create the directory:
#if defined(WIN32) && !defined(__CYGWIN__)
bool error = _mkdir(path.c_str()) != 0;
bool error = _wmkdir(StringUtils::utf8ToWide(path).c_str()) != 0;
#else
bool error = mkdir(path.c_str(), 0755) != 0;
#endif
@ -1192,8 +1193,8 @@ void FileManager::setStdoutDir(const std::string& dir)
if (!m_stdout_dir.empty() && m_stdout_dir[m_stdout_dir.size() - 1] != '/')
{
m_stdout_dir += "/";
}
m_stdout_dir += "/";
}
} // setStdoutDir
//-----------------------------------------------------------------------------
@ -1215,7 +1216,7 @@ void FileManager::redirectOutput()
out_new << logoutfile << "." << i-1;
if(fileExists(out_new.str()))
{
rename(out_new.str().c_str(), out_old.str().c_str());
FileUtils::renameU8Path(out_new.str(), out_old.str());
}
} // for i in NUM_BACKUPS
@ -1224,7 +1225,7 @@ void FileManager::redirectOutput()
std::ostringstream out;
out << logoutfile<<".1";
// No good place to log error messages when log is not yet initialised
rename(logoutfile.c_str(), out.str().c_str());
FileUtils::renameU8Path(logoutfile, out.str());
}
//Enable logging of stdout and stderr to logfile
@ -1313,7 +1314,7 @@ bool FileManager::isDirectory(const std::string &path) const
// a '/' at the end of the path.
if(s[s.size()-1]=='/')
s.erase(s.end()-1, s.end());
if(stat(s.c_str(), &mystat) < 0) return false;
if(FileUtils::statU8Path(s, &mystat) < 0) return false;
return S_ISDIR(mystat.st_mode);
} // isDirectory
@ -1373,9 +1374,15 @@ bool FileManager::removeFile(const std::string &name) const
return true;
struct stat mystat;
if(stat(name.c_str(), &mystat) < 0) return false;
if(FileUtils::statU8Path(name, &mystat) < 0) return false;
if( S_ISREG(mystat.st_mode))
return remove(name.c_str())==0;
{
#if defined(WIN32)
return _wremove(StringUtils::utf8ToWide(name).c_str()) == 0;
#else
return remove(name.c_str()) == 0;
#endif
}
return false;
} // removeFile
@ -1434,10 +1441,10 @@ bool FileManager::removeDirectory(const std::string &name) const
*/
bool FileManager::copyFile(const std::string &source, const std::string &dest)
{
FILE *f_source = fopen(source.c_str(), "rb");
FILE *f_source = FileUtils::fopenU8Path(source, "rb");
if(!f_source) return false;
FILE *f_dest = fopen(dest.c_str(), "wb");
FILE *f_dest = FileUtils::fopenU8Path(dest, "wb");
if(!f_dest)
{
fclose(f_source);
@ -1472,6 +1479,7 @@ bool FileManager::copyFile(const std::string &source, const std::string &dest)
fclose(f_dest);
return true;
} // copyFile
// ----------------------------------------------------------------------------
/** Returns true if the first file is newer than the second. The comparison is
* based on the modification time of the two files.
@ -1480,7 +1488,7 @@ bool FileManager::fileIsNewer(const std::string& f1, const std::string& f2) cons
{
struct stat stat1;
struct stat stat2;
stat(f1.c_str(), &stat1);
stat(f2.c_str(), &stat2);
FileUtils::statU8Path(f1, &stat1);
FileUtils::statU8Path(f2, &stat2);
return stat1.st_mtime > stat2.st_mtime;
} // fileIsNewer

129
src/utils/file_utils.cpp Normal file
View File

@ -0,0 +1,129 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2019 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "utils/file_utils.hpp"
#include "utils/log.hpp"
#include "utils/string_utils.hpp"
#include <stdio.h>
#include <string>
#include <sys/stat.h>
// ----------------------------------------------------------------------------
#if defined(WIN32)
#include <windows.h>
/** 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)
return u8_path;
irr::core::stringw wpath = StringUtils::utf8ToWide(u8_path);
size_t length = GetShortPathNameW(wpath.c_str(), NULL, 0);
if (length == 0)
{
Log::error("FileUtils",
"Failed to GetShortPathNameW with getting required length.");
return "";
}
std::vector<wchar_t> short_path;
short_path.resize(length);
length = GetShortPathNameW(wpath.c_str(), short_path.data(), length);
if (length == 0)
{
Log::error("FileUtils",
"Failed to GetShortPathNameW with writing short path.");
return "";
}
short_path.push_back(0);
std::string result;
// Reserve enough space for conversion
result.resize(length * 4);
length = WideCharToMultiByte(CP_ACP, 0, short_path.data(), -1, &result[0],
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
#endif
// ----------------------------------------------------------------------------
/** fopen() with unicode path capability.
*/
FILE* FileUtils::fopenU8Path(const std::string& u8_path, const char* mode)
{
#if defined(WIN32)
std::vector<wchar_t> mode_str;
for (unsigned i = 0; i < strlen(mode); i++)
mode_str.push_back((wchar_t)mode[i]);
mode_str.push_back(0);
return _wfopen(StringUtils::utf8ToWide(u8_path).c_str(), mode_str.data());
#else
return fopen(u8_path.c_str(), mode);
#endif
} // fopenU8Path
// ----------------------------------------------------------------------------
/** stat() with unicode path capability.
*/
int FileUtils::statU8Path(const std::string& u8_path, struct stat *buf)
{
#if defined(WIN32)
struct _stat st;
int ret = _wstat(StringUtils::utf8ToWide(u8_path).c_str(), &st);
buf->st_dev = st.st_dev;
buf->st_ino = st.st_ino;
buf->st_mode = st.st_mode;
buf->st_nlink = st.st_nlink;
buf->st_uid = st.st_uid;
buf->st_gid = st.st_gid;
buf->st_rdev = st.st_rdev;
buf->st_size = (_off_t)st.st_size;
buf->st_atime = st.st_atime;
buf->st_mtime = st.st_mtime;
buf->st_ctime = st.st_ctime;
return ret;
#else
return stat(u8_path.c_str(), buf);
#endif
} // statU8Path
// ----------------------------------------------------------------------------
/** rename() with unicode path capability.
*/
int FileUtils::renameU8Path(const std::string& u8_path_old,
const std::string& u8_path_new)
{
#if defined(WIN32)
return _wrename(StringUtils::utf8ToWide(u8_path_old).c_str(),
StringUtils::utf8ToWide(u8_path_new).c_str());
#else
return rename(u8_path_old.c_str(), u8_path_new.c_str());
#endif
} // renameU8Path

51
src/utils/file_utils.hpp Normal file
View File

@ -0,0 +1,51 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2019 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_FILE_UTILS_HPP
#define HEADER_FILE_UTILS_HPP
#include <stdio.h>
#include <string>
#include <sys/stat.h>
namespace FileUtils
{
namespace Private
{
std::string getShortPath(const std::string& u8_path);
}
// ------------------------------------------------------------------------
FILE* fopenU8Path(const std::string& u8_path, const char* mode);
// ------------------------------------------------------------------------
int statU8Path(const std::string& u8_path, struct stat *buf);
// ------------------------------------------------------------------------
int renameU8Path(const std::string& u8_path_old,
const std::string& u8_path_new);
// ------------------------------------------------------------------------
/* 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
return Private::getShortPath(u8_path);
#else
return u8_path;
#endif
}
} // namespace FileUtils
#endif