# HG changeset patch # User reimar # Date 1363291464 0 # Node ID 3edaed3c1d60552a7f3084008ff411376f184b5a # Parent 6ac59489c81509b2559e5af6fdc1c5277b35e79e Win32: support file names with characters outside system code-page This is done by trying to interpret the file name as being UTF-8 encoded first. The command-line is fetched as UTF-16 and converted to UTF-8 to match with this. diff -r 6ac59489c815 -r 3edaed3c1d60 Changelog --- a/Changelog Thu Mar 14 19:59:35 2013 +0000 +++ b/Changelog Thu Mar 14 20:04:24 2013 +0000 @@ -15,6 +15,10 @@ * Support teletext and CC subtitles in WTV. * Support binding keys corresponding to non-ASCII characters. + Ports: + * Windows: support file names as UTF-8 in slave mode and passing + file names as wchar command line arguments. + 1.1: "We gave up on 1.0" Decoders: diff -r 6ac59489c815 -r 3edaed3c1d60 mencoder.c --- a/mencoder.c Thu Mar 14 19:59:35 2013 +0000 +++ b/mencoder.c Thu Mar 14 20:04:24 2013 +0000 @@ -578,7 +578,7 @@ user_correct_pts = 0; - common_preinit(); + common_preinit(&argc, &argv); // Create the config context and register the options mconfig = m_config_new(); diff -r 6ac59489c815 -r 3edaed3c1d60 mpcommon.c --- a/mpcommon.c Thu Mar 14 19:59:35 2013 +0000 +++ b/mpcommon.c Thu Mar 14 20:04:24 2013 +0000 @@ -456,6 +456,73 @@ {NULL, NULL, 0, 0, 0, 0, NULL} }; +#ifdef __MINGW32__ +static int get_win32_cmdline(int *argc_ptr, char **argv_ptr[]) +{ + int i; + int argv_size, size; + int argc_n; + char **argv_n; + LPWSTR *argv_w = NULL; + void *buffer = NULL; + char *strs, *strs_end; + + HMODULE kernel32 = GetModuleHandle("Kernel32.dll"); + HMODULE shell32 = GetModuleHandle("shell32.dll"); + int WINAPI (*wc2mb)(UINT, DWORD, LPCWSTR, int, LPSTR, int, LPCSTR, LPBOOL) = NULL; + LPCWSTR WINAPI (*getCmdlW)(void) = NULL; + LPWSTR * WINAPI (*cmdl2argv)(LPCWSTR, int *) = NULL; + + if (!kernel32 || !shell32) + goto err_out; + wc2mb = GetProcAddress(kernel32, "WideCharToMultiByte"); + getCmdlW = GetProcAddress(kernel32, "GetCommandLineW"); + cmdl2argv = GetProcAddress(shell32, "CommandLineToArgvW"); + if (!wc2mb || !getCmdlW || !cmdl2argv) + goto err_out; + + argv_w = cmdl2argv(getCmdlW(), &argc_n); + if (!argv_w || argc_n < 0 || argc_n >= INT_MAX / sizeof(char *)) + goto err_out; + + size = argv_size = (argc_n + 1) * sizeof(char *); + for (i = 0; i < argc_n; i++) { + int conv_size = wc2mb(CP_UTF8, 0, argv_w[i], -1, NULL, 0, NULL, NULL); + if (conv_size < 0 || conv_size > INT_MAX - size) + goto err_out; + size += conv_size; + } + + buffer = calloc(1, size); + if (!buffer) + goto err_out; + argv_n = buffer; + strs_end = strs = buffer; + strs += argv_size; + strs_end += size; + + for (i = 0; i < argc_n; i++) { + int conv_size = wc2mb(CP_UTF8, 0, argv_w[i], -1, + strs, strs_end - strs, NULL, NULL); + if (conv_size < 0 || conv_size > strs_end - strs) + goto err_out; + argv_n[i] = strs; + strs += conv_size; + } + argv_n[i] = NULL; + + *argc_ptr = argc_n; + *argv_ptr = argv_n; + LocalFree(argv_w); + return 0; + +err_out: + free(buffer); + LocalFree(argv_w); + return -1; +} +#endif + /** * Code to fix any kind of insane defaults some OS might have. * Currently mostly fixes for insecure-by-default Windows. @@ -483,8 +550,14 @@ * Initialization code to be run at the very start, must not depend * on option values. */ -void common_preinit(void) +void common_preinit(int *argc_ptr, char **argv_ptr[]) { +#ifdef __MINGW32__ + get_win32_cmdline(argc_ptr, argv_ptr); +#else + (void)argc_ptr; + (void)argv_ptr; +#endif sanitize_os(); InitTimer(); srand(GetTimerMS()); diff -r 6ac59489c815 -r 3edaed3c1d60 mpcommon.h --- a/mpcommon.h Thu Mar 14 19:59:35 2013 +0000 +++ b/mpcommon.h Thu Mar 14 20:04:24 2013 +0000 @@ -80,7 +80,7 @@ int cfg_inc_verbose(m_option_t *conf); int cfg_include(m_option_t *conf, const char *filename); -void common_preinit(void); +void common_preinit(int *argc_ptr, char **argv_ptr[]); int common_init(void); double calc_a_pts(struct sh_audio *sh_audio, demux_stream_t *d_audio); diff -r 6ac59489c815 -r 3edaed3c1d60 mplayer.c --- a/mplayer.c Thu Mar 14 19:59:35 2013 +0000 +++ b/mplayer.c Thu Mar 14 20:04:24 2013 +0000 @@ -2769,7 +2769,7 @@ int profile_config_loaded; int i; - common_preinit(); + common_preinit(&argc, &argv); // Create the config context and register the options mconfig = m_config_new(); diff -r 6ac59489c815 -r 3edaed3c1d60 stream/stream_file.c --- a/stream/stream_file.c Thu Mar 14 19:59:35 2013 +0000 +++ b/stream/stream_file.c Thu Mar 14 20:04:24 2013 +0000 @@ -26,6 +26,10 @@ #if HAVE_SETMODE #include #endif +#ifdef __MINGW32__ +#include +#include +#endif #include "mp_msg.h" #include "stream.h" @@ -114,6 +118,28 @@ return STREAM_UNSUPPORTED; } +#ifdef __MINGW32__ +static int win32_open(const char *fname, int m, int omode) +{ + int cnt; + int fd = -1; + wchar_t fname_w[MAX_PATH]; + int WINAPI (*mb2wc)(UINT, DWORD, LPCSTR, int, LPWSTR, int) = NULL; + HMODULE kernel32 = GetModuleHandle("Kernel32.dll"); + if (!kernel32) goto fallback; + mb2wc = GetProcAddress(kernel32, "MultiByteToWideChar"); + if (!mb2wc) goto fallback; + cnt = mb2wc(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, fname_w, sizeof(fname_w) / sizeof(*fname_w)); + if (cnt <= 0) goto fallback; + fd = _wsopen(fname_w, m, SH_DENYNO, omode); + if (fd != -1 || (m & O_CREAT)) + return fd; + +fallback: + return _sopen(fname, m, SH_DENYNO, omode); +} +#endif + static int open_f(stream_t *stream,int mode, void* opts, int* file_format) { int f; mode_t m = 0; @@ -168,10 +194,12 @@ } } else { mode_t openmode = S_IRUSR|S_IWUSR; -#ifndef __MINGW32__ +#ifdef __MINGW32__ + f = win32_open(filename, m, openmode); +#else openmode |= S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH; + f=open(filename,m, openmode); #endif - f=open(filename,m, openmode); if(f<0) { mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename); m_struct_free(&stream_opts,opts);