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);
}
WIN32_FIND_DATA wfd;
HANDLE hFind = FindFirstFileA(tempStr.c_str(), &wfd);
WIN32_FIND_DATAW wfd;
HANDLE hFind = FindFirstFileW(StringUtil::UTF8StringToWideString(tempStr).c_str(), &wfd);
if (hFind == INVALID_HANDLE_VALUE)
return 0;
@ -715,21 +715,28 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
wildCardMatchAll = !(std::strcmp(Pattern, "*"));
}
// holder for utf-8 conversion
std::string utf8_filename;
utf8_filename.reserve(countof(wfd.cFileName) * 2);
// iterate results
do
{
if (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN && !(Flags & FILESYSTEM_FIND_HIDDEN_FILES))
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;
if (!(Flags & FILESYSTEM_FIND_HIDDEN_FILES))
continue;
}
if (!StringUtil::WideStringToUTF8String(utf8_filename, wfd.cFileName))
continue;
FILESYSTEM_FIND_DATA outData;
outData.Attributes = 0;
@ -741,11 +748,11 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
if (ParentPath != nullptr)
{
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
{
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
if (hasWildCards)
{
if (!wildCardMatchAll && !StringUtil::WildcardMatch(wfd.cFileName, Pattern))
if (!wildCardMatchAll && !StringUtil::WildcardMatch(utf8_filename.c_str(), Pattern))
continue;
}
else
{
if (std::strcmp(wfd.cFileName, Pattern) != 0)
if (std::strcmp(utf8_filename.c_str(), Pattern) != 0)
continue;
}
@ -781,20 +788,20 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
{
if (ParentPath != nullptr)
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)
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
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", OriginPath, wfd.cFileName);
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", OriginPath, utf8_filename.c_str());
}
else
{
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)
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", Path, wfd.cFileName);
outData.FileName = StringUtil::StdStringFromFormat("%s\\%s", Path, utf8_filename.c_str());
else
outData.FileName = wfd.cFileName;
outData.FileName = utf8_filename;
}
outData.ModificationTime.SetWindowsFileTime(&wfd.ftLastWriteTime);
@ -802,7 +809,7 @@ static u32 RecursiveFindFiles(const char* OriginPath, const char* ParentPath, co
nFiles++;
pResults->push_back(std::move(outData));
} while (FindNextFileA(hFind, &wfd) == TRUE);
} while (FindNextFileW(hFind, &wfd) == TRUE);
FindClose(hFind);
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);
}
bool FileSystem::StatFile(const char* Path, FILESYSTEM_STAT_DATA* pStatData)
bool FileSystem::StatFile(const char* path, FILESYSTEM_STAT_DATA* pStatData)
{
// has a path
if (Path[0] == '\0')
if (path[0] == '\0')
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..
DWORD fileAttributes = GetFileAttributesA(Path);
DWORD fileAttributes = GetFileAttributesW(wpath);
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false;
@ -837,12 +857,12 @@ bool FileSystem::StatFile(const char* Path, FILESYSTEM_STAT_DATA* pStatData)
HANDLE hFile;
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);
}
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);
}

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)
{
int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
if (wlen <= 0)
return {};
std::wstring ret;
ret.resize(wlen);
if (MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), ret.data(), wlen) <= 0)
if (!UTF8StringToWideString(ret, str))
return {};
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)
{
int mblen = WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0, nullptr, nullptr);
if (mblen <= 0)
return {};
std::string ret;
ret.resize(mblen);
if (WideCharToMultiByte(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), ret.data(), mblen, nullptr, nullptr) <
0)
if (!WideStringToUTF8String(ret, str))
return {};
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
} // 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.
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.
std::string WideStringToUTF8String(const std::wstring_view& str);
bool WideStringToUTF8String(std::string& dest, const std::wstring_view& str);
#endif