mirror of
https://github.com/opencv/opencv.git
synced 2026-07-21 19:33:03 +04:00
Merge pull request #28935 from molhamfetnah:fix/21960-unicode-temp-path
core: fix Unicode temp path handling on Windows (fix #21960) #28935 ## Summary Fixes getCacheDirectoryForDownloads and related temp file functions failing when the user home directory contains Unicode characters like C:\\Users\\テスト\\AppData\\Local\\Temp. ## Root Cause On Windows, OpenCV was using ANSI versions of GetTempPath and GetTempFileName which fail with Unicode paths. ## Fix Replace with wide-character GetTempPathW plus UTF-8 conversion: - modules/core/src/utils/filesystem.cpp - getCacheDirectory for cache paths - modules/core/src/system.cpp - temporary file creation - modules/ts/src/ts_gtest.cpp - test stream capture ## Testing The fix has been verified compiles. Manual testing on Windows with Unicode username required. ## Risk Low: Uses same output format, just different encoding path. Existing ASCII functionality preserved. --- Fixes opencv/opencv#21960
This commit is contained in:
@@ -1118,12 +1118,19 @@ String tempfile( const char* suffix )
|
||||
#else
|
||||
// Use GUID-based naming to avoid race condition with GetTempFileNameA
|
||||
// See issue #19648
|
||||
char temp_dir2[MAX_PATH] = { 0 };
|
||||
wchar_t temp_dir2_w[MAX_PATH] = { 0 };
|
||||
|
||||
if (temp_dir.empty())
|
||||
{
|
||||
::GetTempPathA(sizeof(temp_dir2), temp_dir2);
|
||||
temp_dir = std::string(temp_dir2);
|
||||
::GetTempPathW(sizeof(temp_dir2_w)/sizeof(wchar_t), temp_dir2_w);
|
||||
// Convert from UTF-16 to UTF-8 to support Unicode paths
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, temp_dir2_w, -1, NULL, 0, NULL, NULL);
|
||||
if (len > 0)
|
||||
{
|
||||
std::vector<char> utf8_buf(len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, temp_dir2_w, -1, utf8_buf.data(), len, NULL, NULL);
|
||||
temp_dir = std::string(utf8_buf.data());
|
||||
}
|
||||
}
|
||||
|
||||
GUID g;
|
||||
|
||||
@@ -438,11 +438,18 @@ cv::String getCacheDirectory(const char* sub_directory_name, const char* configu
|
||||
{
|
||||
cv::String default_cache_path;
|
||||
#ifdef _WIN32
|
||||
char tmp_path_buf[MAX_PATH+1] = {0};
|
||||
DWORD res = GetTempPath(MAX_PATH, tmp_path_buf);
|
||||
wchar_t tmp_path_buf_w[MAX_PATH+1] = {0};
|
||||
DWORD res = GetTempPathW(MAX_PATH, tmp_path_buf_w);
|
||||
if (res > 0 && res <= MAX_PATH)
|
||||
{
|
||||
default_cache_path = tmp_path_buf;
|
||||
// Convert from UTF-16 to UTF-8 to support Unicode paths
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, tmp_path_buf_w, -1, NULL, 0, NULL, NULL);
|
||||
if (len > 0)
|
||||
{
|
||||
std::vector<char> utf8_buf(len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, tmp_path_buf_w, -1, utf8_buf.data(), len, NULL, NULL);
|
||||
default_cache_path = std::string(utf8_buf.data());
|
||||
}
|
||||
}
|
||||
#elif defined __ANDROID__
|
||||
// no defaults
|
||||
|
||||
+33
-12
@@ -10452,20 +10452,41 @@ class CapturedStream {
|
||||
// The ctor redirects the stream to a temporary file.
|
||||
explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
|
||||
# if GTEST_OS_WINDOWS
|
||||
char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||
char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
|
||||
wchar_t temp_dir_path_w[MAX_PATH + 1] = { L'\0' };
|
||||
wchar_t temp_file_path_w[MAX_PATH + 1] = { L'\0' };
|
||||
|
||||
::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
|
||||
const UINT success = ::GetTempFileNameA(temp_dir_path,
|
||||
"gtest_redir",
|
||||
::GetTempPathW(sizeof(temp_dir_path_w)/sizeof(wchar_t), temp_dir_path_w);
|
||||
// Convert to UTF-8 to support Unicode paths
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, temp_dir_path_w, -1, NULL, 0, NULL, NULL);
|
||||
std::string temp_dir_path;
|
||||
if (len > 0)
|
||||
{
|
||||
std::vector<char> utf8_buf(len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, temp_dir_path_w, -1, utf8_buf.data(), len, NULL, NULL);
|
||||
temp_dir_path = std::string(utf8_buf.data());
|
||||
}
|
||||
const UINT success = ::GetTempFileNameW(temp_dir_path_w,
|
||||
L"gtest_redir",
|
||||
0, // Generate unique file name.
|
||||
temp_file_path);
|
||||
GTEST_CHECK_(success != 0)
|
||||
<< "Unable to create a temporary file in " << temp_dir_path;
|
||||
const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
|
||||
GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
|
||||
<< temp_file_path;
|
||||
filename_ = temp_file_path;
|
||||
temp_file_path_w);
|
||||
// Convert filename back to UTF-8
|
||||
std::string temp_file_path;
|
||||
int captured_fd = -1;
|
||||
if (success != 0)
|
||||
{
|
||||
len = WideCharToMultiByte(CP_UTF8, 0, temp_file_path_w, -1, NULL, 0, NULL, NULL);
|
||||
if (len > 0)
|
||||
{
|
||||
std::vector<char> utf8_buf(len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, temp_file_path_w, -1, utf8_buf.data(), len, NULL, NULL);
|
||||
temp_file_path = std::string(utf8_buf.data());
|
||||
}
|
||||
// Create file and get fd for redirect
|
||||
captured_fd = _open(temp_file_path.c_str(), _O_CREAT | _O_WRONLY | _O_TRUNC, _S_IREAD | _S_IWRITE);
|
||||
GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
|
||||
<< temp_file_path;
|
||||
filename_ = temp_file_path;
|
||||
}
|
||||
# else
|
||||
// There's no guarantee that a test has write access to the current
|
||||
// directory, so we create the temporary file in the /tmp directory
|
||||
|
||||
Reference in New Issue
Block a user