Add functions to handle file in utf8 encoded name
This commit is contained in:
parent
74f227590e
commit
1cd725586f
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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/*")
|
||||
|
@ -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
129
src/utils/file_utils.cpp
Normal 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
51
src/utils/file_utils.hpp
Normal 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
|
Loading…
Reference in New Issue
Block a user