From 44eb715e8f77a2b03ad1fc30b187cecc77ab7a9a Mon Sep 17 00:00:00 2001 From: Dmitry Baryshev Date: Tue, 26 Mar 2024 20:29:54 +0300 Subject: [PATCH] COMMON: Added SAIL_WINDOWS_UTF8_PATHS (#207) * COMMON: Added SAIL_WINDOWS_UTF8_PATHS * COMMON: Fix allocation size * SAIL: Print SAIL_WINDOWS_UTF8_PATHS --- CMakeLists.txt | 6 ++ src/config.h.in | 2 + src/sail-common/utils.c | 165 ++++++++++++++++++++++++++++++++-------- src/sail-common/utils.h | 9 +++ 4 files changed, 152 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ac81279e..cb4ff55e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,9 @@ dynamically loaded plugins." OFF "BUILD_SHARED_LIBS" ON) option(SAIL_THIRD_PARTY_CODECS_PATH "Enable loading third-party codecs from the ';'-separated paths specified in \ the SAIL_THIRD_PARTY_CODECS_PATH environment variable." ON) option(SAIL_THREAD_SAFE "Enable working in multi-threaded environments by locking the internal context with a mutex." ON) +if (WIN32) + option(SAIL_WINDOWS_UTF8_PATHS "Convert file paths to UTF-8 on Windows." ON) +endif() if (SAIL_ENABLE_OPENMP) sail_check_openmp() @@ -341,6 +344,9 @@ message("* SAIL_OPENMP_SCHEDULE: ${SAIL_OPENMP_SCHEDULE}") message("* SAIL_OPENMP_FLAGS: ${SAIL_OPENMP_FLAGS}") message("* SAIL_OPENMP_INCLUDE_DIRS: ${SAIL_OPENMP_INCLUDE_DIRS}") message("* SAIL_OPENMP_LIBS: ${SAIL_OPENMP_LIBS}") +if (WIN32) + message("* SAIL_WINDOWS_UTF8_PATHS: ${SAIL_WINDOWS_UTF8_PATHS}") +endif() message("*") message("* [*] - these options depend on other options, their values may be altered by CMake.") message("* For example, if you configure with -DBUILD_SHARED_LIBS=OFF -DSAIL_COMBINE_CODECS=OFF,") diff --git a/src/config.h.in b/src/config.h.in index 6a51a8d2..e85ddfcf 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -90,4 +90,6 @@ /* OpenMP scheduling algorithm. */ #cmakedefine SAIL_OPENMP_SCHEDULE @SAIL_OPENMP_SCHEDULE@ +#cmakedefine SAIL_WINDOWS_UTF8_PATHS + #endif diff --git a/src/sail-common/utils.c b/src/sail-common/utils.c index 4d21b623..b8a10981 100644 --- a/src/sail-common/utils.c +++ b/src/sail-common/utils.c @@ -549,10 +549,22 @@ bool sail_path_exists(const char *path) { return false; } -#ifdef _MSC_VER - return _access(path, 0) == 0; +#ifdef SAIL_WINDOWS_UTF8_PATHS + wchar_t *wpath; + SAIL_TRY_OR_EXECUTE(sail_multibyte_to_wchar(path, &wpath), + /* on error */ return false); + + bool result = _waccess(wpath, 0) == 0; + + sail_free(wpath); + + return result; #else - return access(path, 0) == 0; + #ifdef _MSC_VER + return _access(path, 0) == 0; + #else + return access(path, 0) == 0; + #endif #endif } @@ -563,22 +575,39 @@ bool sail_is_dir(const char *path) { return false; } -#ifdef _MSC_VER +#ifdef SAIL_WINDOWS_UTF8_PATHS + wchar_t *wpath; + SAIL_TRY_OR_EXECUTE(sail_multibyte_to_wchar(path, &wpath), + /* on error */ return false); + struct _stat attrs; - if (_stat(path, &attrs) != 0) { + if (_wstat(wpath, &attrs) != 0) { + sail_free(wpath); return false; } + sail_free(wpath); + return (attrs.st_mode & _S_IFMT) == _S_IFDIR; #else - struct stat attrs; + #ifdef _MSC_VER + struct _stat attrs; - if (stat(path, &attrs) != 0) { - return false; - } + if (_stat(path, &attrs) != 0) { + return false; + } + + return (attrs.st_mode & _S_IFMT) == _S_IFDIR; + #else + struct stat attrs; + + if (stat(path, &attrs) != 0) { + return false; + } - return S_ISDIR(attrs.st_mode); + return S_ISDIR(attrs.st_mode); + #endif #endif } @@ -589,22 +618,39 @@ bool sail_is_file(const char *path) { return false; } -#ifdef _MSC_VER +#ifdef SAIL_WINDOWS_UTF8_PATHS + wchar_t *wpath; + SAIL_TRY_OR_EXECUTE(sail_multibyte_to_wchar(path, &wpath), + /* on error */ return false); + struct _stat attrs; - if (_stat(path, &attrs) != 0) { + if (_wstat(wpath, &attrs) != 0) { + sail_free(wpath); return false; } + sail_free(wpath); + return (attrs.st_mode & _S_IFMT) == _S_IFREG; #else - struct stat attrs; + #ifdef _MSC_VER + struct _stat attrs; - if (stat(path, &attrs) != 0) { - return false; - } + if (_stat(path, &attrs) != 0) { + return false; + } - return S_ISREG(attrs.st_mode); + return (attrs.st_mode & _S_IFMT) == _S_IFREG; + #else + struct stat attrs; + + if (stat(path, &attrs) != 0) { + return false; + } + + return S_ISREG(attrs.st_mode); + #endif #endif } @@ -614,31 +660,48 @@ sail_status_t sail_file_size(const char *path, size_t *size) { bool is_file; -#ifdef _MSC_VER +#ifdef SAIL_WINDOWS_UTF8_PATHS + wchar_t *wpath; + SAIL_TRY_OR_EXECUTE(sail_multibyte_to_wchar(path, &wpath), + /* on error */ return false); + struct _stat attrs; - if (_stat(path, &attrs) != 0) { + if (_wstat(wpath, &attrs) != 0) { + sail_free(wpath); return false; } + sail_free(wpath); + is_file = (attrs.st_mode & _S_IFMT) == _S_IFREG; #else - struct stat attrs; + #ifdef _MSC_VER + struct _stat attrs; - if (stat(path, &attrs) != 0) { - return false; - } + if (_stat(path, &attrs) != 0) { + return false; + } + + is_file = (attrs.st_mode & _S_IFMT) == _S_IFREG; + #else + struct stat attrs; + + if (stat(path, &attrs) != 0) { + return false; + } - is_file = S_ISREG(attrs.st_mode); + is_file = S_ISREG(attrs.st_mode); + #endif #endif - if (!is_file) { + if (is_file) { + *size = attrs.st_size; + } else { SAIL_LOG_ERROR("'%s' is not a file", path); SAIL_LOG_AND_RETURN(SAIL_ERROR_OPEN_FILE); } - *size = attrs.st_size; - return SAIL_OK; } @@ -650,10 +713,20 @@ sail_status_t sail_file_contents_into_data(const char *path, void *data) { size_t size; SAIL_TRY(sail_file_size(path, &size)); -#ifdef _MSC_VER - FILE *f = _fsopen(path, "rb", _SH_DENYWR); +#ifdef SAIL_WINDOWS_UTF8_PATHS + /* FIXME: We convert to UTF-8 twice, in sail_file_size() and here. */ + wchar_t *wpath; + SAIL_TRY(sail_multibyte_to_wchar(path, &wpath)); + + FILE *f = _wfsopen(wpath, L"rb", _SH_DENYWR); + + sail_free(wpath); #else - FILE *f = fopen(path, "rb"); + #ifdef _MSC_VER + FILE *f = _fsopen(path, "rb", _SH_DENYWR); + #else + FILE *f = fopen(path, "rb"); + #endif #endif if (f == NULL) { @@ -810,3 +883,35 @@ uint64_t sail_reverse_uint64(uint64_t v) (view[7] << 0); #endif } + +#ifdef SAIL_WINDOWS_UTF8_PATHS +sail_status_t sail_multibyte_to_wchar(const char *str, wchar_t **wstr) { + + SAIL_CHECK_PTR(str); + SAIL_CHECK_PTR(wstr); + + /* Detect buffer size. */ + int chars_needed = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + + if (chars_needed <= 0) { + SAIL_LOG_ERROR("MultiByteToWideChar() failed. Error: 0x%X", GetLastError()); + SAIL_LOG_AND_RETURN(SAIL_ERROR_INVALID_ARGUMENT); + } + + wchar_t *wstr_local; + SAIL_TRY(sail_malloc(chars_needed * sizeof(wchar_t), &wstr_local)); + + /* Actually convert. */ + int result = MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr_local, chars_needed); + + if (result <= 0) { + sail_free(wstr_local); + SAIL_LOG_ERROR("MultiByteToWideChar() failed. Error: 0x%X", GetLastError()); + SAIL_LOG_AND_RETURN(SAIL_ERROR_INVALID_ARGUMENT); + } + + *wstr = wstr_local; + + return SAIL_OK; +} +#endif diff --git a/src/sail-common/utils.h b/src/sail-common/utils.h index e9a5fea9..08f5e1f3 100644 --- a/src/sail-common/utils.h +++ b/src/sail-common/utils.h @@ -255,6 +255,15 @@ SAIL_EXPORT uint32_t sail_reverse_uint32(uint32_t v); */ SAIL_EXPORT uint64_t sail_reverse_uint64(uint64_t v); +/* + * Converts a character string to a UTF-16 string. Available on Windows only. + * + * Returns SAIL_OK on success. + */ +#ifdef SAIL_WINDOWS_UTF8_PATHS +SAIL_EXPORT sail_status_t sail_multibyte_to_wchar(const char *str, wchar_t **wstr); +#endif + /* extern "C" */ #ifdef __cplusplus }