From b1ac139d89b9fc55b70ad3411af2f75fe8b17805 Mon Sep 17 00:00:00 2001 From: Kirill Gavrilov Date: Wed, 20 Apr 2011 14:36:44 +0300 Subject: [PATCH] Handle unicode file names on windows MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit All file names should be in UTF-8 within libavformat. This is handled by mapping the open() function to an internal one in os_support.h for windows. fopen() could be overridden in the same way, but if that would be used from ffmpeg.c, it would add a dependency on an ff prefixed internal lavf function. Signed-off-by: Martin Storsjö --- cmdutils.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ libavformat/os_support.c | 28 +++++++++++++++++++++ libavformat/os_support.h | 5 ++++ libavformat/version.h | 2 +- 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/cmdutils.c b/cmdutils.c index f1cbd55373..f25f61d4e5 100644 --- a/cmdutils.c +++ b/cmdutils.c @@ -155,6 +155,66 @@ static const OptionDef* find_option(const OptionDef *po, const char *name){ return po; } +#if defined(_WIN32) && !defined(__MINGW32CE__) +/* Will be leaked on exit */ +static char** win32_argv_utf8 = NULL; +static int win32_argc = 0; + +/** + * Prepare command line arguments for executable. + * For Windows - perform wide-char to UTF-8 conversion. + * Input arguments should be main() function arguments. + * @param argc_ptr Arguments number (including executable) + * @param argv_ptr Arguments list. + */ +static void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) +{ + char *argstr_flat; + wchar_t **argv_w; + int i, buffsize = 0, offset = 0; + + if (win32_argv_utf8) { + *argc_ptr = win32_argc; + *argv_ptr = win32_argv_utf8; + return; + } + + win32_argc = 0; + argv_w = CommandLineToArgvW(GetCommandLineW(), &win32_argc); + if (win32_argc <= 0 || !argv_w) + return; + + /* determine the UTF-8 buffer size (including NULL-termination symbols) */ + for (i = 0; i < win32_argc; i++) + buffsize += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, + NULL, 0, NULL, NULL); + + win32_argv_utf8 = av_mallocz(sizeof(char*) * (win32_argc + 1) + buffsize); + argstr_flat = (char*)win32_argv_utf8 + sizeof(char*) * (win32_argc + 1); + if (win32_argv_utf8 == NULL) { + LocalFree(argv_w); + return; + } + + for (i = 0; i < win32_argc; i++) { + win32_argv_utf8[i] = &argstr_flat[offset]; + offset += WideCharToMultiByte(CP_UTF8, 0, argv_w[i], -1, + &argstr_flat[offset], + buffsize - offset, NULL, NULL); + } + win32_argv_utf8[i] = NULL; + LocalFree(argv_w); + + *argc_ptr = win32_argc; + *argv_ptr = win32_argv_utf8; +} +#else +static inline void prepare_app_arguments(int *argc_ptr, char ***argv_ptr) +{ + /* nothing to do */ +} +#endif /* WIN32 && !__MINGW32CE__ */ + void parse_options(int argc, char **argv, const OptionDef *options, void (* parse_arg_function)(const char*)) { @@ -162,6 +222,9 @@ void parse_options(int argc, char **argv, const OptionDef *options, int optindex, handleoptions=1; const OptionDef *po; + /* perform system-dependent conversions for arguments list */ + prepare_app_arguments(&argc, &argv); + /* parse options */ optindex = 1; while (optindex < argc) { diff --git a/libavformat/os_support.c b/libavformat/os_support.c index 5a3a1bbfe0..05577b7553 100644 --- a/libavformat/os_support.c +++ b/libavformat/os_support.c @@ -28,6 +28,34 @@ #include "avformat.h" #include "os_support.h" +#if defined(_WIN32) && !defined(__MINGW32CE__) +#include + +#undef open +int ff_win32_open(const char *filename_utf8, int oflag, int pmode) +{ + int fd; + int num_chars; + wchar_t *filename_w; + + /* convert UTF-8 to wide chars */ + num_chars = MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, NULL, 0); + if (num_chars <= 0) + return -1; + filename_w = av_mallocz(sizeof(wchar_t) * num_chars); + MultiByteToWideChar(CP_UTF8, 0, filename_utf8, -1, filename_w, num_chars); + + fd = _wopen(filename_w, oflag, pmode); + av_freep(&filename_w); + + /* filename maybe be in CP_ACP */ + if (fd == -1 && !(oflag & O_CREAT)) + return open(filename_utf8, oflag, pmode); + + return fd; +} +#endif + #if CONFIG_NETWORK #include #include diff --git a/libavformat/os_support.h b/libavformat/os_support.h index dc01e6413c..521e9978a2 100644 --- a/libavformat/os_support.h +++ b/libavformat/os_support.h @@ -45,6 +45,11 @@ static inline int is_dos_path(const char *path) return 0; } +#if defined(_WIN32) && !defined(__MINGW32CE__) +int ff_win32_open(const char *filename, int oflag, int pmode); +#define open ff_win32_open +#endif + #if CONFIG_NETWORK #if !HAVE_SOCKLEN_T typedef int socklen_t; diff --git a/libavformat/version.h b/libavformat/version.h index 9041f92626..22b5dc9791 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -25,7 +25,7 @@ #define LIBAVFORMAT_VERSION_MAJOR 53 #define LIBAVFORMAT_VERSION_MINOR 0 -#define LIBAVFORMAT_VERSION_MICRO 2 +#define LIBAVFORMAT_VERSION_MICRO 3 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ -- 2.11.0