mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-02-01 04:05:38 +00:00
FileSystem: Use PathCchCanonicalizeEx() for GetWin32Path()
This commit is contained in:
parent
ab445ec69d
commit
979b7bd36f
|
@ -11,10 +11,18 @@ TEST(FileSystem, GetWin32Path)
|
|||
ASSERT_EQ(FileSystem::GetWin32Path("test.txt"), L"test.txt");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("D:\\test.txt"), L"\\\\?\\D:\\test.txt");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("C:\\foo"), L"\\\\?\\C:\\foo");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("C:\\foo\\bar\\..\\baz"), L"\\\\?\\C:\\foo\\baz");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("\\\\foo\\bar\\baz"), L"\\\\?\\UNC\\foo\\bar\\baz");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("\\\\foo\\bar\\baz\\sub\\.."), L"\\\\?\\UNC\\foo\\bar\\baz");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱"), L"ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("C:\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱"), L"\\\\?\\C:\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("\\\\foo\\bar\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱"), L"\\\\?\\UNC\\foo\\bar\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("C:\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱"),
|
||||
L"\\\\?\\C:\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("\\\\foo\\bar\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱"),
|
||||
L"\\\\?\\UNC\\foo\\bar\\ŻąłóРстуぬねのはen🍪⟑η∏☉ⴤℹ︎∩₲ ₱⟑♰⫳🐱");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("C:\\ŻąłóРстуぬね\\のはen🍪\\⟑η∏☉ⴤ\\..\\ℹ︎∩₲ ₱⟑♰⫳🐱"),
|
||||
L"\\\\?\\C:\\ŻąłóРстуぬね\\のはen🍪\\ℹ︎∩₲ ₱⟑♰⫳🐱");
|
||||
ASSERT_EQ(FileSystem::GetWin32Path("\\\\foo\\bar\\ŻąłóРстуぬねのはen🍪\\⟑η∏☉ⴤ\\..\\ℹ︎∩₲ ₱⟑♰⫳🐱"),
|
||||
L"\\\\?\\UNC\\foo\\bar\\ŻąłóРстуぬねのはen🍪\\ℹ︎∩₲ ₱⟑♰⫳🐱");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#if defined(_WIN32)
|
||||
#include "windows_headers.h"
|
||||
#include <malloc.h>
|
||||
#include <pathcch.h>
|
||||
#include <share.h>
|
||||
#include <shlobj.h>
|
||||
#include <winioctl.h>
|
||||
|
@ -225,32 +227,50 @@ void Path::RemoveLengthLimits(std::string* path)
|
|||
|
||||
bool FileSystem::GetWin32Path(std::wstring* dest, std::string_view str)
|
||||
{
|
||||
const bool absolute = Path::IsAbsolute(str);
|
||||
const bool unc = IsUNCPath(str);
|
||||
const size_t skip = unc ? 2 : 0;
|
||||
// Just convert to wide if it's a relative path, MAX_PATH still applies.
|
||||
if (!Path::IsAbsolute(str))
|
||||
return StringUtil::UTF8StringToWideString(*dest, str);
|
||||
|
||||
dest->clear();
|
||||
if (str.empty())
|
||||
return true;
|
||||
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data() + skip, static_cast<int>(str.length() - skip), nullptr, 0);
|
||||
if (wlen <= 0)
|
||||
// PathCchCanonicalizeEx() thankfully takes care of everything.
|
||||
// But need to widen the string first, avoid the stack allocation.
|
||||
int wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), nullptr, 0);
|
||||
if (wlen <= 0) [[unlikely]]
|
||||
return false;
|
||||
|
||||
// Can't fix up non-absolute paths. Hopefully they don't go past MAX_PATH.
|
||||
if (absolute)
|
||||
dest->append(unc ? L"\\\\?\\UNC\\" : L"\\\\?\\");
|
||||
|
||||
const size_t start = dest->size();
|
||||
dest->resize(start + static_cast<u32>(wlen));
|
||||
|
||||
wlen = MultiByteToWideChar(CP_UTF8, 0, str.data() + skip, static_cast<int>(str.length() - skip), dest->data() + start,
|
||||
wlen);
|
||||
if (wlen <= 0)
|
||||
// So copy it to a temp wide buffer first.
|
||||
wchar_t* wstr_buf = static_cast<wchar_t*>(_malloca(sizeof(wchar_t) * (static_cast<size_t>(wlen) + 1)));
|
||||
wlen = MultiByteToWideChar(CP_UTF8, 0, str.data(), static_cast<int>(str.length()), wstr_buf, wlen);
|
||||
if (wlen <= 0) [[unlikely]]
|
||||
{
|
||||
_freea(wstr_buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
dest->resize(start + static_cast<u32>(wlen));
|
||||
return true;
|
||||
// And use PathCchCanonicalizeEx() to fix up any non-direct elements.
|
||||
wstr_buf[wlen] = '\0';
|
||||
dest->resize(std::max<size_t>(static_cast<size_t>(wlen) + (IsUNCPath(str) ? 9 : 5), 16));
|
||||
for (;;)
|
||||
{
|
||||
const HRESULT hr =
|
||||
PathCchCanonicalizeEx(dest->data(), dest->size(), wstr_buf, PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
dest->resize(std::wcslen(dest->data()));
|
||||
_freea(wstr_buf);
|
||||
return true;
|
||||
}
|
||||
else if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
|
||||
{
|
||||
dest->resize(dest->size() * 2);
|
||||
continue;
|
||||
}
|
||||
else [[unlikely]]
|
||||
{
|
||||
Log_ErrorFmt("PathCchCanonicalizeEx() returned {:08X}", static_cast<unsigned>(hr));
|
||||
_freea(wstr_buf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring FileSystem::GetWin32Path(std::string_view str)
|
||||
|
|
Loading…
Reference in a new issue