[MPlayer-dev-eng] [PATCH] Win32: support file names with characters outside system code-page

Reimar Döffinger Reimar.Doeffinger at gmx.de
Sun Mar 10 20:14:04 CET 2013


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.
---
 mencoder.c           |    2 +-
 mpcommon.c           |   75 +++++++++++++++++++++++++++++++++++++++++++++++++-
 mpcommon.h           |    2 +-
 mplayer.c            |    2 +-
 stream/stream_file.c |   34 +++++++++++++++++++++--
 5 files changed, 108 insertions(+), 7 deletions(-)

diff --git a/mencoder.c b/mencoder.c
index 6542be7..984e95a 100644
--- a/mencoder.c
+++ b/mencoder.c
@@ -578,7 +578,7 @@ audio_encoder_t *aencoder = NULL;
 
 user_correct_pts = 0;
 
-  common_preinit();
+  common_preinit(&argc, &argv);
 
   // Create the config context and register the options
   mconfig = m_config_new();
diff --git a/mpcommon.c b/mpcommon.c
index ed872d2..5b58440 100644
--- a/mpcommon.c
+++ b/mpcommon.c
@@ -456,6 +456,73 @@ const m_option_t noconfig_opts[] = {
     {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 @@ static void sanitize_os(void)
  * 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 --git a/mpcommon.h b/mpcommon.h
index f36d843..472125b 100644
--- a/mpcommon.h
+++ b/mpcommon.h
@@ -80,7 +80,7 @@ void set_osd_subtitle(subtitle *subs);
 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 --git a/mplayer.c b/mplayer.c
index fdf77d8..64bec9b 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -2769,7 +2769,7 @@ int main(int argc, char *argv[])
     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 --git a/stream/stream_file.c b/stream/stream_file.c
index dea1306..e80d326 100644
--- a/stream/stream_file.c
+++ b/stream/stream_file.c
@@ -26,6 +26,10 @@
 #if HAVE_SETMODE
 #include <io.h>
 #endif
+#ifdef __MINGW32__
+#include <windows.h>
+#include <share.h>
+#endif
 
 #include "mp_msg.h"
 #include "stream.h"
@@ -114,8 +118,30 @@ static int control(stream_t *s, int cmd, void *arg) {
   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;
+  int f = -1;
   mode_t m = 0;
   off_t len;
   unsigned char *filename;
@@ -168,10 +194,12 @@ static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
     }
   } 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;
-#endif
       f=open(filename,m, openmode);
+#endif
     if(f<0) {
       mp_msg(MSGT_OPEN,MSGL_ERR,MSGTR_FileNotFound,filename);
       m_struct_free(&stream_opts,opts);
-- 
1.7.10.4



More information about the MPlayer-dev-eng mailing list