diff --git a/include/cdio/utf8.h b/include/cdio/utf8.h index 236105e9..286542bc 100644 --- a/include/cdio/utf8.h +++ b/include/cdio/utf8.h @@ -90,3 +90,17 @@ bool cdio_charset_from_utf8(cdio_utf8_t * src, char ** dst, bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst, const char * src_charset); +#ifdef _WIN32 +/** \brief Convert an UTF8 string to UTF-16 (allocate returned string) + * \param str Source string + * \returns NULL if the conversion was unsuccesful. Caller must free the + * returned string. + * This is a convenience function available on Windows platforms only. + */ +wchar_t* cdio_utf8_to_wchar(const char* str); + +/** \brief Provides an UTF-8 compliant version of fopen for Windows + * The parameters and return value are the same as fopen(). + */ +FILE* fopen_utf8(const char* filename, const char* mode); +#endif diff --git a/lib/driver/_cdio_stdio.c b/lib/driver/_cdio_stdio.c index 1865b35e..3912c8cd 100644 --- a/lib/driver/_cdio_stdio.c +++ b/lib/driver/_cdio_stdio.c @@ -39,6 +39,7 @@ #ifdef HAVE_ERRNO_H #include #endif +#include #include #include @@ -55,11 +56,33 @@ #define CDIO_FSEEK fseek #endif +/* Windows' fopen is not UTF-8 compliant, so we use our own */ +#if defined(_WIN32) +#include +#define CDIO_FOPEN fopen_utf8 +#else +#define CDIO_FOPEN fopen +#endif + /* Use _stati64 if needed, on platforms that don't have transparent LFS support */ #if defined(HAVE__STATI64) && defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64) -#define CDIO_STAT _stati64 +#define CDIO_STAT_STRUCT _stati64 +#if defined(_WIN32) +/* Once again, use our own UTF-8 compliant version */ +static inline int _stati64_utf8(const char *path, struct _stati64 *buffer) { + int ret; + wchar_t* wpath = cdio_utf8_to_wchar(path); + ret = _wstati64(wpath, buffer); + free(wpath); + return ret; +} +#define CDIO_STAT_CALL _stati64_utf8 #else -#define CDIO_STAT stat +#define CDIO_STAT_CALL _stati64 +#endif +#else +#define CDIO_STAT_STRUCT stat +#define CDIO_STAT_CALL stat #endif #define _STRINGIFY(a) #a @@ -80,8 +103,8 @@ static int _stdio_open (void *user_data) { _UserData *const ud = user_data; - - if ((ud->fd = fopen (ud->pathname, "rb"))) + + if ((ud->fd = CDIO_FOPEN (ud->pathname, "rb"))) { ud->fd_buf = calloc (1, CDIO_STDIO_BUFSIZE); setvbuf (ud->fd, ud->fd_buf, _IOFBF, CDIO_STDIO_BUFSIZE); @@ -224,7 +247,7 @@ cdio_stdio_new(const char pathname[]) CdioDataSource_t *new_obj = NULL; cdio_stream_io_functions funcs = { NULL, NULL, NULL, NULL, NULL, NULL }; _UserData *ud = NULL; - struct CDIO_STAT statbuf; + struct CDIO_STAT_STRUCT statbuf; char* pathdup; if (pathname == NULL) @@ -235,7 +258,7 @@ cdio_stdio_new(const char pathname[]) if (pathdup == NULL) return NULL; - if (CDIO_STAT (pathdup, &statbuf) == -1) + if (CDIO_STAT_CALL (pathdup, &statbuf) == -1) { cdio_warn ("could not retrieve file info for `%s': %s", pathdup, strerror (errno)); diff --git a/lib/driver/image/bincue.c b/lib/driver/image/bincue.c index e939f1d0..baf30e25 100644 --- a/lib/driver/image/bincue.c +++ b/lib/driver/image/bincue.c @@ -31,6 +31,7 @@ #include #include +#include #include #ifdef HAVE_STDIO_H @@ -65,6 +66,12 @@ #define DEFAULT_CDIO_DEVICE "videocd.bin" #define DEFAULT_CDIO_CUE "videocd.cue" +#ifdef _WIN32 +#define CDIO_FOPEN fopen_utf8 +#else +#define CDIO_FOPEN fopen +#endif + static lsn_t get_disc_last_lsn_bincue (void *p_user_data); #include "image_common.h" static bool parse_cuefile (_img_private_t *cd, const char *toc_name); @@ -266,7 +273,7 @@ parse_cuefile (_img_private_t *cd, const char *psz_cue_name) if (NULL == psz_cue_name_dup) return false; - fp = fopen (psz_cue_name_dup, "r"); + fp = CDIO_FOPEN (psz_cue_name_dup, "r"); free(psz_cue_name_dup); if (fp == NULL) { cdio_log(log_level, "error opening %s for reading: %s", diff --git a/lib/driver/image/cdrdao.c b/lib/driver/image/cdrdao.c index 658ab681..254ac0b3 100644 --- a/lib/driver/image/cdrdao.c +++ b/lib/driver/image/cdrdao.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #ifdef HAVE_LIMITS_H @@ -69,6 +70,12 @@ #define DEFAULT_CDIO_DEVICE "videocd.bin" #define DEFAULT_CDIO_CDRDAO "videocd.toc" +#ifdef _WIN32 +#define CDIO_FOPEN fopen_utf8 +#else +#define CDIO_FOPEN fopen +#endif + #include "image_common.h" static lsn_t get_disc_last_lsn_cdrdao (void *p_user_data); @@ -312,7 +319,7 @@ parse_tocfile (_img_private_t *cd, const char *psz_cue_name) if (NULL == psz_cue_name_dup) return false; - fp = fopen (psz_cue_name_dup, "r"); + fp = CDIO_FOPEN (psz_cue_name_dup, "r"); free(psz_cue_name_dup); if (fp == NULL) { cdio_log(log_level, "error opening %s for reading: %s", diff --git a/lib/driver/utf8.c b/lib/driver/utf8.c index 64529b1a..bb7ed498 100644 --- a/lib/driver/utf8.c +++ b/lib/driver/utf8.c @@ -23,7 +23,6 @@ # include "config.h" #endif -#ifdef HAVE_JOLIET #ifdef HAVE_STDIO_H #include #endif @@ -43,6 +42,7 @@ #include #include +/* Windows requires some basic UTF-8 support outside of Joliet */ #if defined(_WIN32) #include @@ -80,7 +80,7 @@ static inline char* cdio_wchar_to_utf8(const wchar_t* wstr) * Converts an UTF8 string to UTF-16 (allocate returned string) * Returns NULL on error */ -static inline wchar_t* cdio_utf8_to_wchar(const char* str) +wchar_t* cdio_utf8_to_wchar(const char* str) { int size = 0; wchar_t* wstr = NULL; @@ -99,8 +99,21 @@ static inline wchar_t* cdio_utf8_to_wchar(const char* str) } return wstr; } + +/* UTF-8 compliant version of fopen() */ +FILE* fopen_utf8(const char* filename, const char* mode) +{ + FILE* ret = NULL; + wchar_t* wfilename = cdio_utf8_to_wchar(filename); + wchar_t* wmode = cdio_utf8_to_wchar(mode); + ret = _wfopen(wfilename, wmode); + free(wfilename); + free(wmode); + return ret; +} #endif +#ifdef HAVE_JOLIET #ifdef HAVE_ICONV #include struct cdio_charset_coverter_s