win32: support local multibyte encoding for file paths
This commit is contained in:
parent
38c30667c5
commit
a7c8cc88e5
|
@ -3701,15 +3701,15 @@ bool config_save_file(const char *path)
|
||||||
if (settings->bools.ssh_enable)
|
if (settings->bools.ssh_enable)
|
||||||
fclose(fopen(LAKKA_SSH_PATH, "w"));
|
fclose(fopen(LAKKA_SSH_PATH, "w"));
|
||||||
else
|
else
|
||||||
remove(LAKKA_SSH_PATH);
|
path_file_remove(LAKKA_SSH_PATH);
|
||||||
if (settings->bools.samba_enable)
|
if (settings->bools.samba_enable)
|
||||||
fclose(fopen(LAKKA_SAMBA_PATH, "w"));
|
fclose(fopen(LAKKA_SAMBA_PATH, "w"));
|
||||||
else
|
else
|
||||||
remove(LAKKA_SAMBA_PATH);
|
path_file_remove(LAKKA_SAMBA_PATH);
|
||||||
if (settings->bools.bluetooth_enable)
|
if (settings->bools.bluetooth_enable)
|
||||||
fclose(fopen(LAKKA_BLUETOOTH_PATH, "w"));
|
fclose(fopen(LAKKA_BLUETOOTH_PATH, "w"));
|
||||||
else
|
else
|
||||||
remove(LAKKA_BLUETOOTH_PATH);
|
path_file_remove(LAKKA_BLUETOOTH_PATH);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < MAX_USERS; i++)
|
for (i = 0; i < MAX_USERS; i++)
|
||||||
|
|
|
@ -241,7 +241,7 @@ bool input_remapping_remove_file(const char *path)
|
||||||
|
|
||||||
fill_pathname_noext(remap_file, buf, ".rmp", path_size);
|
fill_pathname_noext(remap_file, buf, ".rmp", path_size);
|
||||||
|
|
||||||
ret = remove(remap_file) == 0 ? true : false;;
|
ret = path_file_remove(remap_file) == 0 ? true : false;;
|
||||||
free(buf);
|
free(buf);
|
||||||
free(remap_file);
|
free(remap_file);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -31,6 +32,15 @@
|
||||||
|
|
||||||
#include <encodings/utf.h>
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
/* Starting with Windows 8: MultiByteToWideChar is declared in stringapiset.h. Before Windows 8, it was declared in winnls.h (which windows.h includes for us). */
|
||||||
|
#ifndef MultiByteToWideChar
|
||||||
|
#include <stringapiset.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static INLINE unsigned leading_ones(uint8_t c)
|
static INLINE unsigned leading_ones(uint8_t c)
|
||||||
{
|
{
|
||||||
unsigned ones = 0;
|
unsigned ones = 0;
|
||||||
|
@ -260,3 +270,81 @@ bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
static char* mb_to_mb_string_alloc(const char *str, enum CodePage cp_in, enum CodePage cp_out)
|
||||||
|
{
|
||||||
|
char *path_buf = NULL;
|
||||||
|
wchar_t *path_buf_wide = NULL;
|
||||||
|
int path_buf_len = 0;
|
||||||
|
int path_buf_wide_len = 0;
|
||||||
|
|
||||||
|
if (!str || !*str)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
#if !defined(_WIN32) || defined(_XBOX)
|
||||||
|
/* assume string needs no modification if not on Windows */
|
||||||
|
return strdup(str);
|
||||||
|
#else
|
||||||
|
#ifdef UNICODE
|
||||||
|
/* TODO/FIXME: Not implemented. */
|
||||||
|
return strdup(str);
|
||||||
|
#else
|
||||||
|
|
||||||
|
path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||||
|
|
||||||
|
if (path_buf_wide_len)
|
||||||
|
{
|
||||||
|
path_buf_wide = (wchar_t*)calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||||
|
|
||||||
|
if (path_buf_wide)
|
||||||
|
{
|
||||||
|
MultiByteToWideChar(cp_in, 0, str, -1, path_buf_wide, path_buf_wide_len);
|
||||||
|
|
||||||
|
if (*path_buf_wide)
|
||||||
|
{
|
||||||
|
path_buf_len = WideCharToMultiByte(cp_out, 0, path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
if (path_buf_len)
|
||||||
|
{
|
||||||
|
path_buf = (char*)calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||||
|
|
||||||
|
if (path_buf)
|
||||||
|
{
|
||||||
|
WideCharToMultiByte(cp_out, 0, path_buf_wide, -1, path_buf, path_buf_len, NULL, NULL);
|
||||||
|
|
||||||
|
free(path_buf_wide);
|
||||||
|
|
||||||
|
if (*path_buf)
|
||||||
|
return path_buf;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free(path_buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (path_buf_wide)
|
||||||
|
free(path_buf_wide);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* utf8_to_local_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||||
|
char* local_to_utf8_string_alloc(const char *str)
|
||||||
|
{
|
||||||
|
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include <compat/strcasestr.h>
|
#include <compat/strcasestr.h>
|
||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -115,9 +116,18 @@ static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
|
||||||
return false;
|
return false;
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
struct _stat buf;
|
struct _stat buf;
|
||||||
DWORD file_info = GetFileAttributes(path);
|
|
||||||
|
|
||||||
_stat(path, &buf);
|
if (!path || !*path)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char *path_local = utf8_to_local_string_alloc(path);
|
||||||
|
|
||||||
|
DWORD file_info = GetFileAttributes(path_local);
|
||||||
|
|
||||||
|
_stat(path_local, &buf);
|
||||||
|
|
||||||
|
if (path_local)
|
||||||
|
free(path_local);
|
||||||
|
|
||||||
if (file_info == INVALID_FILE_ATTRIBUTES)
|
if (file_info == INVALID_FILE_ATTRIBUTES)
|
||||||
return false;
|
return false;
|
||||||
|
@ -365,8 +375,8 @@ bool path_is_compressed_file(const char* path)
|
||||||
* Returns: true (1) if file already exists, otherwise false (0).
|
* Returns: true (1) if file already exists, otherwise false (0).
|
||||||
*/
|
*/
|
||||||
bool path_file_exists(const char *path)
|
bool path_file_exists(const char *path)
|
||||||
{
|
{
|
||||||
FILE *dummy;
|
FILE *dummy;
|
||||||
|
|
||||||
if (!path || !*path)
|
if (!path || !*path)
|
||||||
return false;
|
return false;
|
||||||
|
@ -884,3 +894,24 @@ void fill_short_pathname_representation_noext(char* out_rep,
|
||||||
fill_short_pathname_representation(out_rep, in_path, size);
|
fill_short_pathname_representation(out_rep, in_path, size);
|
||||||
path_remove_extension(out_rep);
|
path_remove_extension(out_rep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int path_file_remove(const char *path)
|
||||||
|
{
|
||||||
|
if (!path || !*path)
|
||||||
|
return false;
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
char *path_local = utf8_to_local_string_alloc(path);
|
||||||
|
|
||||||
|
if (path_local)
|
||||||
|
{
|
||||||
|
bool ret = remove(path_local);
|
||||||
|
free(path_local);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
return remove(path);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
|
|
||||||
#include <boolean.h>
|
#include <boolean.h>
|
||||||
#include <retro_dirent.h>
|
#include <retro_dirent.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
#include <compat/strl.h>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
# ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
|
@ -89,6 +91,7 @@ struct RDIR *retro_opendir(const char *name)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
char path_buf[1024];
|
char path_buf[1024];
|
||||||
|
char *path_local = NULL;
|
||||||
#endif
|
#endif
|
||||||
struct RDIR *rdir = (struct RDIR*)calloc(1, sizeof(*rdir));
|
struct RDIR *rdir = (struct RDIR*)calloc(1, sizeof(*rdir));
|
||||||
|
|
||||||
|
@ -98,7 +101,11 @@ struct RDIR *retro_opendir(const char *name)
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
path_buf[0] = '\0';
|
path_buf[0] = '\0';
|
||||||
snprintf(path_buf, sizeof(path_buf), "%s\\*", name);
|
snprintf(path_buf, sizeof(path_buf), "%s\\*", name);
|
||||||
rdir->directory = FindFirstFile(path_buf, &rdir->entry);
|
path_local = utf8_to_local_string_alloc(path_buf);
|
||||||
|
rdir->directory = FindFirstFile(path_local, &rdir->entry);
|
||||||
|
|
||||||
|
if (path_local)
|
||||||
|
free(path_local);
|
||||||
#elif defined(VITA) || defined(PSP)
|
#elif defined(VITA) || defined(PSP)
|
||||||
rdir->directory = sceIoDopen(name);
|
rdir->directory = sceIoDopen(name);
|
||||||
#elif defined(_3DS)
|
#elif defined(_3DS)
|
||||||
|
@ -149,6 +156,12 @@ int retro_readdir(struct RDIR *rdir)
|
||||||
const char *retro_dirent_get_name(struct RDIR *rdir)
|
const char *retro_dirent_get_name(struct RDIR *rdir)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
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;
|
return rdir->entry.cFileName;
|
||||||
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__)
|
#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__)
|
||||||
return rdir->entry.d_name;
|
return rdir->entry.d_name;
|
||||||
|
|
|
@ -32,6 +32,12 @@
|
||||||
|
|
||||||
RETRO_BEGIN_DECLS
|
RETRO_BEGIN_DECLS
|
||||||
|
|
||||||
|
enum CodePage
|
||||||
|
{
|
||||||
|
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||||
|
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||||
|
};
|
||||||
|
|
||||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||||
const char *in, size_t in_size);
|
const char *in, size_t in_size);
|
||||||
|
|
||||||
|
@ -48,6 +54,10 @@ uint32_t utf8_walk(const char **string);
|
||||||
|
|
||||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
||||||
|
|
||||||
|
char* utf8_to_local_string_alloc(const char *str);
|
||||||
|
|
||||||
|
char* local_to_utf8_string_alloc(const char *str);
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -466,6 +466,8 @@ bool path_is_valid(const char *path);
|
||||||
|
|
||||||
int32_t path_get_size(const char *path);
|
int32_t path_get_size(const char *path);
|
||||||
|
|
||||||
|
int path_file_remove(const char *path);
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -65,6 +65,7 @@
|
||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <memmap.h>
|
#include <memmap.h>
|
||||||
#include <retro_miscellaneous.h>
|
#include <retro_miscellaneous.h>
|
||||||
|
#include <encodings/utf.h>
|
||||||
|
|
||||||
struct RFILE
|
struct RFILE
|
||||||
{
|
{
|
||||||
|
@ -140,6 +141,9 @@ RFILE *filestream_open(const char *path, unsigned mode, ssize_t len)
|
||||||
const char *mode_str = NULL;
|
const char *mode_str = NULL;
|
||||||
#endif
|
#endif
|
||||||
RFILE *stream = (RFILE*)calloc(1, sizeof(*stream));
|
RFILE *stream = (RFILE*)calloc(1, sizeof(*stream));
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
char *path_local = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!stream)
|
if (!stream)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -228,7 +232,14 @@ RFILE *filestream_open(const char *path, unsigned mode, ssize_t len)
|
||||||
#if defined(HAVE_BUFFERED_IO)
|
#if defined(HAVE_BUFFERED_IO)
|
||||||
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 && mode_str)
|
if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0 && mode_str)
|
||||||
{
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
path_local = utf8_to_local_string_alloc(path);
|
||||||
|
stream->fp = fopen(path_local, mode_str);
|
||||||
|
if (path_local)
|
||||||
|
free(path_local);
|
||||||
|
#else
|
||||||
stream->fp = fopen(path, mode_str);
|
stream->fp = fopen(path, mode_str);
|
||||||
|
#endif
|
||||||
if (!stream->fp)
|
if (!stream->fp)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -236,7 +247,14 @@ RFILE *filestream_open(const char *path, unsigned mode, ssize_t len)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* FIXME: HAVE_BUFFERED_IO is always 1, but if it is ever changed, open() needs to be changed to _wopen() for WIndows. */
|
/* FIXME: HAVE_BUFFERED_IO is always 1, but if it is ever changed, open() needs to be changed to _wopen() for WIndows. */
|
||||||
|
#if defined(_WIN32) && !defined(_XBOX)
|
||||||
|
path_local = utf8_to_local_string_alloc(path);
|
||||||
|
stream->fd = open(path_local, flags, mode_int);
|
||||||
|
if (path_local)
|
||||||
|
free(path_local);
|
||||||
|
#else
|
||||||
stream->fd = open(path, flags, mode_int);
|
stream->fd = open(path, flags, mode_int);
|
||||||
|
#endif
|
||||||
if (stream->fd == -1)
|
if (stream->fd == -1)
|
||||||
goto error;
|
goto error;
|
||||||
#ifdef HAVE_MMAP
|
#ifdef HAVE_MMAP
|
||||||
|
|
|
@ -2643,7 +2643,7 @@ static void cb_decompressed(void *task_data, void *user_data, const char *err)
|
||||||
if (dec)
|
if (dec)
|
||||||
{
|
{
|
||||||
if (path_file_exists(dec->source_file))
|
if (path_file_exists(dec->source_file))
|
||||||
remove(dec->source_file);
|
path_file_remove(dec->source_file);
|
||||||
|
|
||||||
free(dec->source_file);
|
free(dec->source_file);
|
||||||
free(dec);
|
free(dec);
|
||||||
|
@ -4242,7 +4242,7 @@ static int action_ok_core_delete(const char *path,
|
||||||
generic_action_ok_command(CMD_EVENT_UNLOAD_CORE);
|
generic_action_ok_command(CMD_EVENT_UNLOAD_CORE);
|
||||||
menu_entries_flush_stack(0, 0);
|
menu_entries_flush_stack(0, 0);
|
||||||
|
|
||||||
if (remove(core_path) != 0) { }
|
if (path_file_remove(core_path) != 0) { }
|
||||||
|
|
||||||
free(core_path);
|
free(core_path);
|
||||||
|
|
||||||
|
|
|
@ -1860,7 +1860,7 @@ static void systemd_service_toggle(const char *path, char *unit, bool enable)
|
||||||
if (enable)
|
if (enable)
|
||||||
fclose(fopen(path, "w"));
|
fclose(fopen(path, "w"));
|
||||||
else
|
else
|
||||||
remove(path);
|
path_file_remove(path);
|
||||||
|
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
|
|
|
@ -1717,7 +1717,7 @@ void content_deinit(void)
|
||||||
|
|
||||||
RARCH_LOG("%s: %s.\n",
|
RARCH_LOG("%s: %s.\n",
|
||||||
msg_hash_to_str(MSG_REMOVING_TEMPORARY_CONTENT_FILE), path);
|
msg_hash_to_str(MSG_REMOVING_TEMPORARY_CONTENT_FILE), path);
|
||||||
if (remove(path) < 0)
|
if (path_file_remove(path) < 0)
|
||||||
RARCH_ERR("%s: %s.\n",
|
RARCH_ERR("%s: %s.\n",
|
||||||
msg_hash_to_str(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE),
|
msg_hash_to_str(MSG_FAILED_TO_REMOVE_TEMPORARY_FILE),
|
||||||
path);
|
path);
|
||||||
|
|
Loading…
Reference in New Issue