win32: use unicode functions for file IO if supported

This commit is contained in:
Brad Parker 2017-10-15 17:41:25 -04:00
parent f3c57ee343
commit 1b1d5c468d
4 changed files with 139 additions and 4 deletions

View File

@ -20,7 +20,6 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
@ -350,3 +349,68 @@ char* local_to_utf8_string_alloc(const char *str)
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
wchar_t* utf8_to_utf16_string_alloc(const char *str)
{
size_t len, out_len;
wchar_t *buf;
if (!str || !*str)
return NULL;
#ifdef _WIN32
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
#else
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
len = mbstowcs(NULL, str, 0) + 1;
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
out_len = mbstowcs(buf, str, len);
#endif
if (out_len < 0)
{
free(buf);
return NULL;
}
return buf;
}
/* Returned pointer MUST be freed by the caller if non-NULL. */
char* utf16_to_utf8_string_alloc(const wchar_t *str)
{
size_t len, out_len;
char *buf;
if (!str || !*str)
return NULL;
#ifdef _WIN32
len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
buf = (char*)calloc(len, sizeof(char));
out_len = WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, len, NULL, NULL);
#else
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
len = wcstombs(NULL, str, 0) + 1;
buf = (char*)calloc(len, sizeof(char));
out_len = wcstombs(buf, str, len);
#endif
if (out_len < 0)
{
free(buf);
return NULL;
}
return buf;
}

View File

@ -116,11 +116,17 @@ static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
return false;
#elif defined(_WIN32)
struct _stat buf;
char *path_local;
wchar_t *path_wide;
if (!path || !*path)
return false;
char *path_local = utf8_to_local_string_alloc(path);
#if defined(_MSC_VER) && _MSC_VER < 1400
(void)path_wide;
/* assume W-functions do not work below VC2005 */
path_local = utf8_to_local_string_alloc(path);
DWORD file_info = GetFileAttributes(path_local);
@ -128,6 +134,18 @@ static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
if (path_local)
free(path_local);
#else
(void)path_local;
path_wide = utf8_to_utf16_string_alloc(path);
DWORD file_info = GetFileAttributesW(path_wide);
_wstat(path_wide, &buf);
if (path_wide)
free(path_wide);
#endif
if (file_info == INVALID_FILE_ATTRIBUTES)
return false;
@ -897,10 +915,16 @@ void fill_short_pathname_representation_noext(char* out_rep,
int path_file_remove(const char *path)
{
char *path_local;
wchar_t *path_wide;
if (!path || !*path)
return false;
#if defined(_WIN32) && !defined(_XBOX)
char *path_local = utf8_to_local_string_alloc(path);
#if defined(_MSC_VER) && _MSC_VER < 1400
(void)path_wide;
path_local = utf8_to_local_string_alloc(path);
if (path_local)
{
@ -909,6 +933,19 @@ int path_file_remove(const char *path)
return ret;
}
#else
(void)path_local;
path_wide = utf8_to_utf16_string_alloc(path);
if (path_wide)
{
bool ret = _wremove(path_wide);
free(path_wide);
return ret;
}
#endif
#else
return remove(path);
#endif

View File

@ -70,7 +70,11 @@
struct RDIR
{
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER < 1400
WIN32_FIND_DATA entry;
#else
WIN32_FIND_DATAW entry;
#endif
HANDLE directory;
bool next;
char path[PATH_MAX_LENGTH];
@ -92,6 +96,7 @@ struct RDIR *retro_opendir(const char *name)
#if defined(_WIN32)
char path_buf[1024];
char *path_local = NULL;
wchar_t *path_wide = NULL;
#endif
struct RDIR *rdir = (struct RDIR*)calloc(1, sizeof(*rdir));
@ -101,11 +106,23 @@ struct RDIR *retro_opendir(const char *name)
#if defined(_WIN32)
path_buf[0] = '\0';
snprintf(path_buf, sizeof(path_buf), "%s\\*", name);
#if defined(_MSC_VER) && _MSC_VER < 1400
(void)path_wide;
path_local = utf8_to_local_string_alloc(path_buf);
rdir->directory = FindFirstFile(path_local, &rdir->entry);
if (path_local)
free(path_local);
#else
(void)path_local;
path_wide = utf8_to_utf16_string_alloc(path_buf);
rdir->directory = FindFirstFileW(path_wide, &rdir->entry);
if (path_wide)
free(path_wide);
#endif
#elif defined(VITA) || defined(PSP)
rdir->directory = sceIoDopen(name);
#elif defined(_3DS)
@ -138,7 +155,11 @@ int retro_readdir(struct RDIR *rdir)
{
#if defined(_WIN32)
if(rdir->next)
#if defined(_MSC_VER) && _MSC_VER < 1400
return (FindNextFile(rdir->directory, &rdir->entry) != 0);
#else
return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
#endif
rdir->next = true;
return (rdir->directory != INVALID_HANDLE_VALUE);
@ -156,13 +177,22 @@ int retro_readdir(struct RDIR *rdir)
const char *retro_dirent_get_name(struct RDIR *rdir)
{
#if defined(_WIN32)
#if defined(_MSC_VER) && _MSC_VER < 1400
char *name_local = local_to_utf8_string_alloc(rdir->entry.cFileName);
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
strlcpy(rdir->entry.cFileName, name_local, sizeof(rdir->entry.cFileName));
if (name_local)
free(name_local);
return rdir->entry.cFileName;
#else
char *name = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
if (name)
free(name);
#endif
return (char*)rdir->entry.cFileName;
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__)
return rdir->entry.d_name;
#else

View File

@ -58,6 +58,10 @@ char* utf8_to_local_string_alloc(const char *str);
char* local_to_utf8_string_alloc(const char *str);
wchar_t* utf8_to_utf16_string_alloc(const char *str);
char* utf16_to_utf8_string_alloc(const wchar_t *str);
RETRO_END_DECLS
#endif