FileSystem: Use wide strings for FindFiles and StatFile on Windows

This commit is contained in:
Connor McLaughlin 2020-08-01 14:00:58 +10:00
parent 2eb9384275
commit ede8de92f6
3 changed files with 73 additions and 33 deletions

View file

@ -700,8 +700,8 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
tempStr = StringUtil::StdStringFromFormat("%s\\*", OriginPath); tempStr = StringUtil::StdStringFromFormat("%s\\*", OriginPath);
} }
WIN32_FIND_DATA wfd; WIN32_FIND_DATAW wfd;
HANDLE hFind = FindFirstFileA(tempStr.c_str(), &wfd); HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(tempStr).c_str(), &wfd);
if (hFind == INVALID_HANDLE_VALUE) if (hFind == INVALID_HANDLE_VALUE)
return 0; return 0;
@ -715,21 +715,28 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
wildCardMatchAll = !(std::strcmp(Pattern, "*")); wildCardMatchAll = !(std::strcmp(Pattern, "*"));
} }
// holder for utf-8 conversion
std::string utf8_filename;
utf8_filename.reserve(countof(wfd.cFileName) * 2);
// iterate results // iterate results
do do
{ {
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN && !(Flags & FILESYSTEM_FIND_HIDDEN_FILES)) if (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN && !(Flags & FILESYSTEM_FIND_HIDDEN_FILES))
continue; continue;
if (wfd.cFileName[0] == '.') if (wfd.cFileName[0] == L'.')
{ {
if (wfd.cFileName[1] == '\0' || (wfd.cFileName[1] == '.' && wfd.cFileName[2] == '\0')) if (wfd.cFileName[1] == L'\0' || (wfd.cFileName[1] == L'.' && wfd.cFileName[2] == L'\0'))
continue; continue;
if (!(Flags & FILESYSTEM_FIND_HIDDEN_FILES)) if (!(Flags & FILESYSTEM_FIND_HIDDEN_FILES))
continue; continue;
} }
if (!StringUtil::WideStringToUTF8String(utf8_filename, wfd.cFileName))
continue;
FILESYSTEM_FIND_DATA outData; FILESYSTEM_FIND_DATA outData;
outData.Attributes = 0; outData.Attributes = 0;
@ -741,11 +748,11 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
if (ParentPath != nullptr) if (ParentPath != nullptr)
{ {
const std::string recurseDir = StringUtil::StdStringFromFormat("%s\\%s", ParentPath, Path); const std::string recurseDir = StringUtil::StdStringFromFormat("%s\\%s", ParentPath, Path);
nFiles += RecursiveFindFiles(OriginPath, recurseDir.c_str(), wfd.cFileName, Pattern, Flags, pResults); nFiles += RecursiveFindFiles(OriginPath, recurseDir.c_str(), utf8_filename.c_str(), Pattern, Flags, pResults);
} }
else else
{ {
nFiles += RecursiveFindFiles(OriginPath, Path, wfd.cFileName, Pattern, Flags, pResults); nFiles += RecursiveFindFiles(OriginPath, Path, utf8_filename.c_str(), Pattern, Flags, pResults);
} }
} }
@ -766,12 +773,12 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
// match the filename // match the filename
if (hasWildCards) if (hasWildCards)
{ {
if (!wildCardMatchAll && !StringUtil::WildcardMatch(wfd.cFileName, Pattern)) if (!wildCardMatchAll && !StringUtil::WildcardMatch(utf8_filename.c_str(), Pattern))
continue; continue;
} }
else else
{ {
if (std::strcmp(wfd.cFileName, Pattern) != 0) if (std::strcmp(utf8_filename.c_str(), Pattern) != 0)
continue; continue;
} }
@ -781,20 +788,20 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
{ {
if (ParentPath != nullptr) if (ParentPath != nullptr)
outData.FileName = outData.FileName =
StringUtil::StdStringFromFormat("%s\\%s\\%s\\%s", OriginPath, ParentPath, Path, wfd.cFileName); StringUtil::StdStringFromFormat("%s\\%s\\%s\\%s", OriginPath, ParentPath, Path, utf8_filename.c_str());
else if (Path != nullptr) else if (Path != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", OriginPath, Path, wfd.cFileName); outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", OriginPath, Path, utf8_filename.c_str());
else else
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", OriginPath, wfd.cFileName); outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", OriginPath, utf8_filename.c_str());
} }
else else
{ {
if (ParentPath != nullptr) if (ParentPath != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", ParentPath, Path, wfd.cFileName); outData.FileName = StringUtil::StdStringFromFormat("%s\\%s\\%s", ParentPath, Path, utf8_filename.c_str());
else if (Path != nullptr) else if (Path != nullptr)
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", Path, wfd.cFileName); outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", Path, utf8_filename.c_str());
else else
outData.FileName = wfd.cFileName; outData.FileName = utf8_filename;
} }
outData.ModificationTime.SetWindowsFileTime(&wfd.ftLastWriteTime); outData.ModificationTime.SetWindowsFileTime(&wfd.ftLastWriteTime);
@ -802,7 +809,7 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
nFiles++; nFiles++;
pResults->push_back(std::move(outData)); pResults->push_back(std::move(outData));
} while (FindNextFileA(hFind, &wfd) == TRUE); } while (FindNextFileW(hFind, &wfd) == TRUE);
FindClose(hFind); FindClose(hFind);
return nFiles; return nFiles;
@ -822,14 +829,27 @@ bool FileSystem::FindFiles(const char* Path, const char* Pattern, u32 Flags, Fin
return (RecursiveFindFiles(Path, nullptr, nullptr, Pattern, Flags, pResults) > 0); return (RecursiveFindFiles(Path, nullptr, nullptr, Pattern, Flags, pResults) > 0);
} }
bool FileSystem::StatFile(const char* Path, FILESYSTEM_STAT_DATA* pStatData) bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData)
{ {
// has a path // has a path
if (Path[0] == '\0') if (path[0] == '\0')
return false; return false;
// convert to wide string
int len = static_cast<int>(std::strlen(path));
int wlen = MultiByteToWideChar(CP_UTF8, 0, path, len, nullptr, 0);
if (wlen <= 0)
return false;
wchar_t* wpath = static_cast<wchar_t*>(alloca(sizeof(wchar_t) * (wlen + 1)));
wlen = MultiByteToWideChar(CP_UTF8, 0, path, len, wpath, wlen);
if (wlen <= 0)
return false;
wpath[wlen] = 0;
// determine attributes for the path. if it's a directory, things have to be handled differently.. // determine attributes for the path. if it's a directory, things have to be handled differently..
DWORD fileAttributes = GetFileAttributesA(Path); DWORD fileAttributes = GetFileAttributesW(wpath);
if (fileAttributes == INVALID_FILE_ATTRIBUTES) if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false; return false;
@ -837,12 +857,12 @@ bool FileSystem::StatFile(const char* Path, FILESYSTEM_STAT_DATA* pStatData)
HANDLE hFile; HANDLE hFile;
if (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) if (fileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ {
hFile = CreateFileA(Path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, hFile = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
} }
else else
{ {
hFile = CreateFileA(Path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, hFile = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
OPEN_EXISTING, 0, nullptr); OPEN_EXISTING, 0, nullptr);
} }

View file

@ -167,33 +167,51 @@ std::size_t Strlcpy(char* dst, const std::string_view& src, std::size_t size)
std::wstring UTF8StringToWideString(const std::string_view& str) std::wstring UTF8StringToWideString(const std::string_view& str)
{ {
int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (wlen <= 0)
return {};
std::wstring ret; std::wstring ret;
ret.resize(wlen); if (!UTF8StringToWideString(ret, str))
if (MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), ret.data(), wlen) <= 0)
return {}; return {};
return ret; return ret;
} }
bool UTF8StringToWideString(std::wstring& dest, const std::string_view& str)
{
int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (wlen < 0)
return false;
dest.resize(wlen);
if (wlen > 0 && MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), dest.data(), wlen) < 0)
return false;
return true;
}
std::string WideStringToUTF8String(const std::wstring_view& str) std::string WideStringToUTF8String(const std::wstring_view& str)
{ {
int mblen = WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
if (mblen <= 0)
return {};
std::string ret; std::string ret;
ret.resize(mblen); if (!WideStringToUTF8String(ret, str))
if (WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), ret.data(), mblen, nullptr, nullptr) <
0)
return {}; return {};
return ret; return ret;
} }
bool WideStringToUTF8String(std::string& dest, const std::wstring_view& str)
{
int mblen = WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
if (mblen < 0)
return false;
dest.resize(mblen);
if (mblen > 0 && WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), dest.data(), mblen,
nullptr, nullptr) < 0)
{
return false;
}
return true;
}
#endif #endif
} // namespace StringUtil } // namespace StringUtil

View file

@ -117,9 +117,11 @@ ALWAYS_INLINE static bool StartsWith(const std::string_view& str, const char* pr
/// Converts the specified UTF-8 string to a wide string. /// Converts the specified UTF-8 string to a wide string.
std::wstring UTF8StringToWideString(const std::string_view& str); std::wstring UTF8StringToWideString(const std::string_view& str);
bool UTF8StringToWideString(std::wstring& dest, const std::string_view& str);
/// Converts the specified wide string to a UTF-8 string. /// Converts the specified wide string to a UTF-8 string.
std::string WideStringToUTF8String(const std::wstring_view& str); std::string WideStringToUTF8String(const std::wstring_view& str);
bool WideStringToUTF8String(std::string& dest, const std::wstring_view& str);
#endif #endif