FileSystem: Make more functions UTF-8 compatible on Windows

This commit is contained in:
Connor McLaughlin 2020-08-06 21:53:04 +10:00
parent f1315b182f
commit 512a8b2b39
2 changed files with 54 additions and 98 deletions

View File

@ -927,7 +927,8 @@ bool FileSystem::FileExists(const char* Path)
return false; return false;
// 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); std::wstring wpath(StringUtil::UTF8StringToWideString(Path));
DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES) if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false; return false;
@ -944,7 +945,8 @@ bool FileSystem::DirectoryExists(const char* Path)
return false; return false;
// 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); std::wstring wpath(StringUtil::UTF8StringToWideString(Path));
DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES) if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false; return false;
@ -954,59 +956,24 @@ bool FileSystem::DirectoryExists(const char* Path)
return false; return false;
} }
bool FileSystem::GetFileName(String& Destination, const char* FileName)
{
// fastpath for non-existant files
DWORD fileAttributes = GetFileAttributesA(FileName);
if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false;
// // temp buffer for storing string returned by windows
// char tempName[MAX_PATH];
// DWORD tempNameLength;
//
// // query windows
// if ((tempNameLength = GetFullPathNameA(FileName, countof(tempName), tempName, nullptr)) == 0 || tempNameLength
// >= countof(tempName))
// {
// // something went wrong, or buffer overflow
// return false;
// }
//
// // move it into destination buffer, doesn't matter if it's the same as FileName, as
// // we aren't going to use it any more.
// DebugAssert(Destination[tempNameLength] == '\0');
// Destination = tempName;
if (Destination.GetWriteableCharArray() != FileName)
Destination = FileName;
return true;
}
bool FileSystem::GetFileName(String& FileName)
{
return GetFileName(FileName, FileName);
}
bool FileSystem::CreateDirectory(const char* Path, bool Recursive) bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
{ {
u32 i; std::wstring wpath(StringUtil::UTF8StringToWideString(Path));
DWORD lastError;
// has a path // has a path
if (Path[0] == '\0') if (wpath[0] == L'\0')
return false; return false;
// try just flat-out, might work if there's no other segments that have to be made // try just flat-out, might work if there's no other segments that have to be made
if (CreateDirectoryA(Path, nullptr)) if (CreateDirectoryW(wpath.c_str(), nullptr))
return true; return true;
// check error // check error
lastError = GetLastError(); DWORD lastError = GetLastError();
if (lastError == ERROR_ALREADY_EXISTS) if (lastError == ERROR_ALREADY_EXISTS)
{ {
// check the attributes // check the attributes
u32 Attributes = GetFileAttributesA(Path); u32 Attributes = GetFileAttributesW(wpath.c_str());
if (Attributes != INVALID_FILE_ATTRIBUTES && Attributes & FILE_ATTRIBUTE_DIRECTORY) if (Attributes != INVALID_FILE_ATTRIBUTES && Attributes & FILE_ATTRIBUTE_DIRECTORY)
return true; return true;
else else
@ -1016,16 +983,16 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
{ {
// part of the path does not exist, so we'll create the parent folders, then // part of the path does not exist, so we'll create the parent folders, then
// the full path again. allocate another buffer with the same length // the full path again. allocate another buffer with the same length
u32 pathLength = static_cast<u32>(std::strlen(Path)); u32 pathLength = static_cast<u32>(wpath.size());
char* tempStr = (char*)alloca(pathLength + 1); wchar_t* tempStr = (wchar_t*)alloca(sizeof(wchar_t) * (pathLength + 1));
// create directories along the path // create directories along the path
for (i = 0; i < pathLength; i++) for (u32 i = 0; i < pathLength; i++)
{ {
if (Path[i] == '\\' || Path[i] == '/') if (wpath[i] == L'\\' || wpath[i] == L'/')
{ {
tempStr[i] = '\0'; tempStr[i] = L'\0';
if (!CreateDirectoryA(tempStr, nullptr)) if (!CreateDirectoryW(tempStr, nullptr))
{ {
lastError = GetLastError(); lastError = GetLastError();
if (lastError != ERROR_ALREADY_EXISTS) // fine, continue to next path segment if (lastError != ERROR_ALREADY_EXISTS) // fine, continue to next path segment
@ -1033,13 +1000,13 @@ bool FileSystem::CreateDirectory(const char* Path, bool Recursive)
} }
} }
tempStr[i] = Path[i]; tempStr[i] = wpath[i];
} }
// re-create the end if it's not a separator, check / as well because windows can interpret them // re-create the end if it's not a separator, check / as well because windows can interpret them
if (Path[pathLength - 1] != '\\' && Path[pathLength - 1] != '/') if (wpath[pathLength - 1] != L'\\' && wpath[pathLength - 1] != L'/')
{ {
if (!CreateDirectoryA(Path, nullptr)) if (!CreateDirectoryW(wpath.c_str(), nullptr))
{ {
lastError = GetLastError(); lastError = GetLastError();
if (lastError != ERROR_ALREADY_EXISTS) if (lastError != ERROR_ALREADY_EXISTS)
@ -1062,34 +1029,35 @@ bool FileSystem::DeleteFile(const char* Path)
if (Path[0] == '\0') if (Path[0] == '\0')
return false; return false;
DWORD fileAttributes = GetFileAttributesA(Path); const std::wstring wpath(StringUtil::UTF8StringToWideString(Path));
DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES) if (fileAttributes == INVALID_FILE_ATTRIBUTES)
return false; return false;
if (!(fileAttributes & FILE_ATTRIBUTE_DIRECTORY)) if (!(fileAttributes & FILE_ATTRIBUTE_DIRECTORY))
return (DeleteFileA(Path) == TRUE); return (DeleteFileW(wpath.c_str()) == TRUE);
else else
return false; return false;
} }
bool FileSystem::DeleteDirectory(const char* Path, bool Recursive) static bool RecursiveDeleteDirectory(const std::wstring& wpath, bool Recursive)
{ {
// ensure it exists // ensure it exists
DWORD fileAttributes = GetFileAttributesA(Path); DWORD fileAttributes = GetFileAttributesW(wpath.c_str());
if (fileAttributes == INVALID_FILE_ATTRIBUTES || !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY)) if (fileAttributes == INVALID_FILE_ATTRIBUTES || !(fileAttributes & FILE_ATTRIBUTE_DIRECTORY))
return false; return false;
// non-recursive case just try removing the directory // non-recursive case just try removing the directory
if (!Recursive) if (!Recursive)
return (RemoveDirectoryA(Path) == TRUE); return (RemoveDirectoryW(wpath.c_str()) == TRUE);
// doing a recursive delete // doing a recursive delete
SmallString fileName; std::wstring fileName = wpath;
fileName.Format("%s\\*", Path); fileName += L"\\*";
// is there any files? // is there any files?
WIN32_FIND_DATA findData; WIN32_FIND_DATAW findData;
HANDLE hFind = FindFirstFileA(fileName, &findData); HANDLE hFind = FindFirstFileW(fileName.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE) if (hFind == INVALID_HANDLE_VALUE)
return false; return false;
@ -1097,20 +1065,22 @@ bool FileSystem::DeleteDirectory(const char* Path, bool Recursive)
do do
{ {
// skip . and .. // skip . and ..
if (findData.cFileName[0] == '.') if (findData.cFileName[0] == L'.')
{ {
if ((findData.cFileName[1] == '\0') || (findData.cFileName[1] == '.' && findData.cFileName[2] == '\0')) if ((findData.cFileName[1] == L'\0') || (findData.cFileName[1] == L'.' && findData.cFileName[2] == L'\0'))
{ {
continue; continue;
} }
} }
// found a directory? // found a directory?
fileName.Format("%s\\%s", Path, findData.cFileName); fileName = wpath;
fileName += L"\\";
fileName += findData.cFileName;
if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{ {
// recurse into that // recurse into that
if (!DeleteDirectory(fileName, true)) if (!RecursiveDeleteDirectory(fileName, true))
{ {
FindClose(hFind); FindClose(hFind);
return false; return false;
@ -1119,34 +1089,40 @@ bool FileSystem::DeleteDirectory(const char* Path, bool Recursive)
else else
{ {
// found a file, so delete it // found a file, so delete it
if (!DeleteFileA(fileName)) if (!DeleteFileW(fileName.c_str()))
{ {
FindClose(hFind); FindClose(hFind);
return false; return false;
} }
} }
} while (FindNextFileA(hFind, &findData)); } while (FindNextFileW(hFind, &findData));
FindClose(hFind); FindClose(hFind);
// nuke the directory itself // nuke the directory itself
if (!RemoveDirectoryA(Path)) if (!RemoveDirectoryW(wpath.c_str()))
return false; return false;
// done // done
return true; return true;
} }
bool FileSystem::DeleteDirectory(const char* Path, bool Recursive)
{
const std::wstring wpath(StringUtil::UTF8StringToWideString(Path));
return RecursiveDeleteDirectory(wpath, Recursive);
}
std::string GetProgramPath() std::string GetProgramPath()
{ {
const HANDLE hProcess = GetCurrentProcess(); const HANDLE hProcess = GetCurrentProcess();
std::string buffer; std::wstring buffer;
buffer.resize(MAX_PATH); buffer.resize(MAX_PATH);
for (;;) for (;;)
{ {
DWORD nChars = static_cast<DWORD>(buffer.size()); DWORD nChars = static_cast<DWORD>(buffer.size());
if (!QueryFullProcessImageNameA(GetCurrentProcess(), 0, buffer.data(), &nChars) && if (!QueryFullProcessImageNameW(GetCurrentProcess(), 0, buffer.data(), &nChars) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER) GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{ {
buffer.resize(buffer.size() * 2); buffer.resize(buffer.size() * 2);
@ -1157,28 +1133,30 @@ std::string GetProgramPath()
break; break;
} }
CanonicalizePath(buffer); std::string utf8_path(StringUtil::WideStringToUTF8String(buffer));
return buffer; CanonicalizePath(utf8_path);
return utf8_path;
} }
std::string GetWorkingDirectory() std::string GetWorkingDirectory()
{ {
DWORD required_size = GetCurrentDirectoryA(0, nullptr); DWORD required_size = GetCurrentDirectoryW(0, nullptr);
if (!required_size) if (!required_size)
return {}; return {};
std::string buffer; std::wstring buffer;
buffer.resize(required_size - 1); buffer.resize(required_size - 1);
if (!GetCurrentDirectoryA(static_cast<DWORD>(buffer.size() + 1), buffer.data())) if (!GetCurrentDirectoryW(static_cast<DWORD>(buffer.size() + 1), buffer.data()))
return {}; return {};
return buffer; return StringUtil::WideStringToUTF8String(buffer);
} }
bool SetWorkingDirectory(const char* path) bool SetWorkingDirectory(const char* path)
{ {
return (SetCurrentDirectoryA(path) == TRUE); const std::wstring wpath(StringUtil::UTF8StringToWideString(path));
return (SetCurrentDirectoryW(wpath.c_str()) == TRUE);
} }
#else #else
@ -1387,24 +1365,6 @@ bool DirectoryExists(const char* Path)
return false; return false;
} }
bool GetFileName(String& Destination, const char* FileName)
{
// fastpath for non-existant files
struct stat sysStatData;
if (stat(FileName, &sysStatData) < 0)
return false;
if (Destination.GetWriteableCharArray() != FileName)
Destination = FileName;
return true;
}
bool GetFileName(String& FileName)
{
return GetFileName(FileName, FileName);
}
bool CreateDirectory(const char* Path, bool Recursive) bool CreateDirectory(const char* Path, bool Recursive)
{ {
u32 i; u32 i;

View File

@ -161,10 +161,6 @@ bool DirectoryExists(const char* Path);
// delete file // delete file
bool DeleteFile(const char* Path); bool DeleteFile(const char* Path);
// reads file name
bool GetFileName(String& Destination, const char* FileName);
bool GetFileName(String& FileName);
// open files // open files
std::unique_ptr<ByteStream> OpenFile(const char* FileName, u32 Flags); std::unique_ptr<ByteStream> OpenFile(const char* FileName, u32 Flags);