Convert path get from windows environment to utf8. (#283)

Convert path get from windows environment to utf8.
This commit is contained in:
Matthieu Gautier 2019-09-25 18:13:59 +02:00 committed by GitHub
commit 7ad6aedd66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 35 deletions

View File

@ -54,6 +54,25 @@
#define PATH_MAX 1024 #define PATH_MAX 1024
#endif #endif
#ifdef _WIN32
std::string WideToUtf8(const std::wstring& wstr)
{
auto needed_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.size(), NULL, 0, NULL, NULL);
std::string ret(needed_size, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr.size(), &ret[0], needed_size, NULL, NULL);
return ret;
}
std::wstring Utf8ToWide(const std::string& str)
{
auto needed_size = MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), NULL, 0);
std::wstring ret(needed_size, 0);
MultiByteToWideChar(CP_UTF8, 0, str.data(), str.size(), &ret[0], needed_size);
return ret;
}
#endif
bool isRelativePath(const std::string& path) bool isRelativePath(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -77,7 +96,9 @@ std::vector<std::string> normalizeParts(std::vector<std::string> parts, bool abs
} }
#endif #endif
size_t index = 0;
for (auto& part: parts) { for (auto& part: parts) {
index++;
if (part == "..") { if (part == "..") {
if (absolute) { if (absolute) {
// We try to remove as far as possible. // We try to remove as far as possible.
@ -97,7 +118,7 @@ std::vector<std::string> normalizeParts(std::vector<std::string> parts, bool abs
} }
if (part == "") { if (part == "") {
#ifndef _WIN32 #ifndef _WIN32
if (ret.empty()) { if (ret.empty() && (absolute || index<parts.size())) {
ret.push_back(""); ret.push_back("");
} }
#endif #endif
@ -135,28 +156,23 @@ std::string computeRelativePath(const std::string& path, const std::string& abso
for (unsigned int i = commonCount; i < absolutePathParts.size(); i++) { for (unsigned int i = commonCount; i < absolutePathParts.size(); i++) {
relativeParts.push_back(absolutePathParts[i]); relativeParts.push_back(absolutePathParts[i]);
} }
return kiwix::join(normalizeParts(relativeParts, false), SEPARATOR); auto ret = kiwix::join(normalizeParts(relativeParts, false), SEPARATOR);
return ret;
} }
std::string computeAbsolutePath(const std::string& path, const std::string& relativePath) std::string computeAbsolutePath(const std::string& path, const std::string& relativePath)
{ {
std::string absolutePath = path; std::string absolutePath = path;
if (path.empty()) { if (path.empty()) {
char* cpath; absolutePath = getCurrentDirectory();
#ifdef _WIN32
cpath = _getcwd(NULL, 0);
#else
cpath = getcwd(NULL, 0);
#endif
absolutePath = cpath;
free(cpath);
} }
auto absoluteParts = normalizeParts(kiwix::split(absolutePath, SEPARATOR, false), true); auto absoluteParts = normalizeParts(kiwix::split(absolutePath, SEPARATOR, false), true);
auto relativeParts = kiwix::split(relativePath, SEPARATOR, false); auto relativeParts = kiwix::split(relativePath, SEPARATOR, false);
absoluteParts.insert(absoluteParts.end(), relativeParts.begin(), relativeParts.end()); absoluteParts.insert(absoluteParts.end(), relativeParts.begin(), relativeParts.end());
return kiwix::join(normalizeParts(absoluteParts, true), SEPARATOR); auto ret = kiwix::join(normalizeParts(absoluteParts, true), SEPARATOR);
return ret;
} }
std::string removeLastPathElement(const std::string& path) std::string removeLastPathElement(const std::string& path)
@ -165,7 +181,8 @@ std::string removeLastPathElement(const std::string& path)
if (!parts.empty()) { if (!parts.empty()) {
parts.pop_back(); parts.pop_back();
} }
return kiwix::join(parts, SEPARATOR); auto ret = kiwix::join(parts, SEPARATOR);
return ret;
} }
std::string appendToDirectory(const std::string& directoryPath, const std::string& filename) std::string appendToDirectory(const std::string& directoryPath, const std::string& filename)
@ -184,7 +201,8 @@ std::string getLastPathElement(const std::string& path)
if (parts.empty()) { if (parts.empty()) {
return ""; return "";
} }
return parts.back(); auto ret = parts.back();
return ret;
} }
unsigned int getFileSize(const std::string& path) unsigned int getFileSize(const std::string& path)
@ -224,7 +242,7 @@ std::string getFileContent(const std::string& path)
bool fileExists(const std::string& path) bool fileExists(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
return PathFileExists(path.c_str()); return PathFileExistsW(Utf8ToWide(path).c_str());
#else #else
bool flag = false; bool flag = false;
std::fstream fin; std::fstream fin;
@ -240,7 +258,7 @@ bool fileExists(const std::string& path)
bool makeDirectory(const std::string& path) bool makeDirectory(const std::string& path)
{ {
#ifdef _WIN32 #ifdef _WIN32
int status = _mkdir(path.c_str()); int status = _wmkdir(Utf8ToWide(path).c_str());
#else #else
int status = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); int status = mkdir(path.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif #endif
@ -250,15 +268,15 @@ bool makeDirectory(const std::string& path)
std::string makeTmpDirectory() std::string makeTmpDirectory()
{ {
#ifdef _WIN32 #ifdef _WIN32
char cbase[MAX_PATH]; wchar_t cbase[MAX_PATH];
char ctmp[MAX_PATH]; wchar_t ctmp[MAX_PATH];
GetTempPath(MAX_PATH-14, cbase); GetTempPathW(MAX_PATH-14, cbase);
// This create a file for us, ensure it is unique. // This create a file for us, ensure it is unique.
// So we need to delete it and create the directory using the same name. // So we need to delete it and create the directory using the same name.
GetTempFileName(cbase, "kiwix", 0, ctmp); GetTempFileNameW(cbase, L"kiwix", 0, ctmp);
DeleteFile(ctmp); DeleteFileW(ctmp);
_mkdir(ctmp); _wmkdir(ctmp);
return std::string(ctmp); return WideToUtf8(ctmp);
#else #else
char _template_array[] = {"/tmp/kiwix-lib_XXXXXX"}; char _template_array[] = {"/tmp/kiwix-lib_XXXXXX"};
std::string dir = mkdtemp(_template_array); std::string dir = mkdtemp(_template_array);
@ -289,34 +307,36 @@ bool copyFile(const std::string& sourcePath, const std::string& destPath)
std::string getExecutablePath(bool realPathOnly) std::string getExecutablePath(bool realPathOnly)
{ {
char binRootPath[PATH_MAX];
if (!realPathOnly) { if (!realPathOnly) {
char* cAppImage = ::getenv("APPIMAGE"); char* cAppImage = ::getenv("APPIMAGE");
if (cAppImage) { if (cAppImage) {
char* cArgv0 = ::getenv("ARGV0"); char* cArgv0 = ::getenv("ARGV0");
char* cOwd = ::getenv("OWD"); char* cOwd = ::getenv("OWD");
if (cArgv0 && cOwd) { if (cArgv0 && cOwd) {
return appendToDirectory(cOwd, cArgv0); auto ret = appendToDirectory(cOwd, cArgv0);
return ret;
} }
} }
} }
#ifdef _WIN32 #ifdef _WIN32
GetModuleFileName(NULL, binRootPath, PATH_MAX); std::wstring binRootPath(PATH_MAX, 0);
return std::string(binRootPath); GetModuleFileNameW(NULL, &binRootPath[0], PATH_MAX);
std::string ret = WideToUtf8(binRootPath);
return ret;
#elif __APPLE__ #elif __APPLE__
char binRootPath[PATH_MAX];
uint32_t max = (uint32_t)PATH_MAX; uint32_t max = (uint32_t)PATH_MAX;
_NSGetExecutablePath(binRootPath, &max); _NSGetExecutablePath(binRootPath, &max);
return std::string(binRootPath); return std::string(binRootPath);
#else #else
char binRootPath[PATH_MAX];
ssize_t size = readlink("/proc/self/exe", binRootPath, PATH_MAX); ssize_t size = readlink("/proc/self/exe", binRootPath, PATH_MAX);
if (size != -1) { if (size != -1) {
return std::string(binRootPath, size); return std::string(binRootPath, size);
} }
#endif
return ""; return "";
#endif
} }
bool writeTextFile(const std::string& path, const std::string& content) bool writeTextFile(const std::string& path, const std::string& content)
@ -330,10 +350,16 @@ bool writeTextFile(const std::string& path, const std::string& content)
std::string getCurrentDirectory() std::string getCurrentDirectory()
{ {
char* a_cwd = getcwd(NULL, 0); #ifdef _WIN32
std::string s_cwd(a_cwd); wchar_t* a_cwd = _wgetcwd(NULL, 0);
std::string ret = WideToUtf8(a_cwd);
free(a_cwd); free(a_cwd);
return s_cwd; #else
char* a_cwd = getcwd(NULL, 0);
std::string ret(a_cwd);
free(a_cwd);
#endif
return ret;
} }
std::string getDataDirectory() std::string getDataDirectory()
@ -344,8 +370,9 @@ std::string getDataDirectory()
char* cDataDir = ::getenv("KIWIX_DATA_DIR"); char* cDataDir = ::getenv("KIWIX_DATA_DIR");
#endif #endif
std::string dataDir = cDataDir==nullptr ? "" : cDataDir; std::string dataDir = cDataDir==nullptr ? "" : cDataDir;
if (!dataDir.empty()) if (!dataDir.empty()) {
return dataDir; return dataDir;
}
#ifdef _WIN32 #ifdef _WIN32
cDataDir = ::getenv("USERPROFILE"); cDataDir = ::getenv("USERPROFILE");
dataDir = cDataDir==nullptr ? getCurrentDirectory() : cDataDir; dataDir = cDataDir==nullptr ? getCurrentDirectory() : cDataDir;
@ -359,7 +386,8 @@ std::string getDataDirectory()
dataDir = appendToDirectory(dataDir, "share"); dataDir = appendToDirectory(dataDir, "share");
} }
#endif #endif
return appendToDirectory(dataDir, "kiwix"); auto ret = appendToDirectory(dataDir, "kiwix");
return ret;
} }
static std::map<std::string, std::string> extMimeTypes = { static std::map<std::string, std::string> extMimeTypes = {

View File

@ -43,6 +43,10 @@
#define A5(a, b, c, d, e) A1(P5(a, b, c, d, e)) #define A5(a, b, c, d, e) A1(P5(a, b, c, d, e))
std::vector<std::string> normalizeParts(std::vector<std::string> parts, bool absolute); std::vector<std::string> normalizeParts(std::vector<std::string> parts, bool absolute);
#ifdef _WIN32
std::wstring Utf8ToWide(const std::string& str);
std::string WideToUtf8(const std::wstring& wstr);
#endif
namespace namespace
{ {
@ -79,7 +83,7 @@ TEST(pathTools, normalizePartsRelative)
{ {
#define N(...) normalizeParts(__VA_ARGS__, false) #define N(...) normalizeParts(__VA_ARGS__, false)
ASSERT_EQ(N({}), V({})); ASSERT_EQ(N({}), V({}));
ASSERT_EQ(N({""}), V({""})); ASSERT_EQ(N({""}), V({}));
ASSERT_EQ(N({"a"}), V({"a"})); ASSERT_EQ(N({"a"}), V({"a"}));
ASSERT_EQ(N({"a", "b"}), V({"a", "b"})); ASSERT_EQ(N({"a", "b"}), V({"a", "b"}));
ASSERT_EQ(N({"a", "b", ".."}), V({"a"})); ASSERT_EQ(N({"a", "b", ".."}), V({"a"}));
@ -205,6 +209,20 @@ TEST(pathTools, dirChange)
ASSERT_EQ(abs_path, p2); ASSERT_EQ(abs_path, p2);
ASSERT_EQ(computeAbsolutePath(p1, "..\\..\\..\\..\\..\\d:\\d\\e\\foo.xml"), p2); ASSERT_EQ(computeAbsolutePath(p1, "..\\..\\..\\..\\..\\d:\\d\\e\\foo.xml"), p2);
} }
TEST(pathTools, Utf8ToWide)
{
ASSERT_EQ(Utf8ToWide(u8""), L"");
ASSERT_EQ(Utf8ToWide(u8"test"), L"test");
ASSERT_EQ(Utf8ToWide(u8"testé`œà"), L"testé`œà");
}
TEST(pathTools, WideToUtf8)
{
ASSERT_EQ(WideToUtf8(L""), u8"");
ASSERT_EQ(WideToUtf8(L"test"), u8"test");
ASSERT_EQ(WideToUtf8(L"testé`œà"), u8"testé`œà");
}
#endif #endif