[MPlayer-dev-eng] [PATCH]Win32: correct the encoding of filename in console message

朱海 zhuhai.mail at 163.com
Sat Aug 8 20:20:57 CEST 2015


1) In Win32, the filename is converted to UTF-8 encoding and stored in memory, but it's not converted back correctly when writing console messages.
This patch converts the filename to suitable encoding before output to console.

I compiled the code under Ubuntu with mingw, and test under Windows 10 with charset CP936, iconv enabled/disabled.

2) When building Linux x86_64 STATIC version mplayer, I got a link error at the last step and fixed it by adding '-lXau' to config.mak by hand.
But I am not sure if this is a platform dependent issue or not (Ubuntu 15.04), anyone can help check and fix it ? I'm not very familiar with config system -.-
build commands:
./configure --enable-static
make -j6
Error messages:
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libaudio.a(ConnSvr.o): In function `_AuConnectServer':
(.text+0x934): undefined reference to `XauDisposeAuth'
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/libaudio.a(ConnSvr.o): In function `_AuConnectServer':
(.text+0x9dc): undefined reference to `XauGetBestAuthByAddr'

Here is the patch fixes filename encoding issue:

Index: mp_msg.c
===================================================================
diff --git a/trunk/mp_msg.c b/trunk/mp_msg.c
--- a/trunk/mp_msg.c    (revision 37444)
+++ b/trunk/mp_msg.c    (working copy)
@@ -30,6 +30,11 @@
 #include <errno.h>
 #endif

+#if defined(__MINGW32__) || defined(__CYGWIN__)
+#include <windows.h>
+#include "mpcommon.h"
+#endif
+
 #include "mp_msg.h"

 /* maximum message length of mp_msg */
@@ -46,21 +51,19 @@
 static iconv_t msgiconv;
 #endif

-const char* filename_recode(const char* filename)
+#if defined(CONFIG_ICONV) && defined(MSG_CHARSET)
+static const char *convert_charset(const char* filename, const char *to, const char *from)
 {
-#if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET)
-    return filename;
-#else
     static iconv_t inv_msgiconv = (iconv_t)(-1);
     static char recoded_filename[MSGSIZE_MAX];
     size_t filename_len, max_path;
     char* precoded;
-    if (!mp_msg_charset ||
-        !strcasecmp(mp_msg_charset, MSG_CHARSET) ||
-        !strcasecmp(mp_msg_charset, "noconv"))
+    if (!from || !to ||
+        !strcasecmp(from, to) ||
+        !strcasecmp(from, "noconv"))
         return filename;
     if (inv_msgiconv == (iconv_t)(-1)) {
-        inv_msgiconv = iconv_open(MSG_CHARSET, mp_msg_charset);
+        inv_msgiconv = iconv_open(to, from);
         if (inv_msgiconv == (iconv_t)(-1))
             return filename;
     }
@@ -67,7 +70,7 @@
     filename_len = strlen(filename);
     max_path = MSGSIZE_MAX - 4;
     precoded = recoded_filename;
-    if (iconv(inv_msgiconv, &filename, &filename_len,
+    if (iconv(inv_msgiconv, (char **)&filename, &filename_len,
               &precoded, &max_path) == (size_t)(-1) && errno == E2BIG) {
         precoded[0] = precoded[1] = precoded[2] = '.';
         precoded += 3;
@@ -74,9 +77,70 @@
     }
     *precoded = '\0';
     return recoded_filename;
+}
+
 #endif
+
+#if defined(__MINGW32__) || defined(__CYGWIN__)
+
+// convert filename to system default charset
+static const char * win_default_charset(const char* filename)
+{
+    int cnt;
+    wchar_t fname_w[MSGSIZE_MAX];
+    static char recoded_filename[MSGSIZE_MAX];
+    typedef int WINAPI (*PWC2MB)(UINT, DWORD, LPCWSTR, int, LPSTR, int, LPCSTR, LPBOOL);
+    typedef int WINAPI (*PMB2WC)(UINT, DWORD, LPCSTR, int, LPWSTR, int);
+    PWC2MB wc2mb;
+    PMB2WC mb2wc;
+
+    HMODULE WINAPI kernel32 = GetModuleHandle("Kernel32.dll");
+    if (!kernel32) goto fallback;
+
+    mb2wc = (PMB2WC)GetProcAddress(kernel32, "MultiByteToWideChar");
+    wc2mb = (PWC2MB)GetProcAddress(kernel32, "WideCharToMultiByte");
+    if (!mb2wc || !wc2mb) goto fallback;
+    cnt = mb2wc(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, fname_w, sizeof(fname_w) / sizeof(*fname_w));
+    if (cnt <= 0) goto fallback;
+
+    cnt = wc2mb(CP_ACP, 0, fname_w, -1, recoded_filename, sizeof(recoded_filename) / sizeof(char), NULL, NULL);
+    if (cnt <= 0) goto fallback;
+    return recoded_filename;
+
+fallback:
+    return filename;
 }
+#endif

+//   if have iconv and msg_charset, ensure the filename is 'msg_charset' encoding
+//   if no iconv nor msg_charset, keep it as system default encoding
+const char* filename_recode(const char* filename)
+{
+#if !defined(CONFIG_ICONV) || !defined(MSG_CHARSET)
+
+#if defined(__MINGW32__) || defined(__CYGWIN__)
+    if (win32_use_utf8)
+        return win_default_charset(filename);
+#endif
+    return filename;
+
+#else // CONFIG_ICONV && MSG_CHARSET
+
+#if defined(__MINGW32__) || defined(__CYGWIN__)
+    if (win32_use_utf8) {
+        if (!mp_msg_charset || !strcasecmp(mp_msg_charset, "noconv")) {
+            return win_default_charset(filename);
+        }
+        if (!strcasecmp(MSG_CHARSET, "UTF-8") || !strcasecmp(MSG_CHARSET, "UTF8"))
+            return filename;
+        return convert_charset(filename, MSG_CHARSET, "UTF-8");
+    }
+#endif // fallback if not using utf8 filename for win32
+
+    return convert_charset(filename, MSG_CHARSET, mp_msg_charset);
+#endif
+}
+
 void mp_msg_init(void){
     int i;
     char *env = getenv("MPLAYER_VERBOSE");
@@ -198,7 +262,8 @@
     tmp[MSGSIZE_MAX-1] = 0;

 #if defined(CONFIG_ICONV) && defined(MSG_CHARSET)
-    if (mp_msg_charset && strcasecmp(mp_msg_charset, "noconv")) {
+    if (mp_msg_charset && strcasecmp(mp_msg_charset, "noconv")
+            && strcasecmp(mp_msg_charset, MSG_CHARSET)) {
       char tmp2[MSGSIZE_MAX];
       size_t inlen = strlen(tmp), outlen = MSGSIZE_MAX;
       char *in = tmp, *out = tmp2;
Index: mpcommon.c
===================================================================
diff --git a/trunk/mpcommon.c b/trunk/mpcommon.c
--- a/trunk/mpcommon.c  (revision 37444)
+++ b/trunk/mpcommon.c  (working copy)
@@ -466,7 +466,10 @@
     {NULL, NULL, 0, 0, 0, 0, NULL}
 };

-#ifdef __MINGW32__
+#if defined(__MINGW32__) || defined(__CYGWIN__)
+
+int win32_use_utf8 = 0;
+
 static int get_win32_cmdline(int *argc_ptr, char **argv_ptr[])
 {
     int i;
@@ -524,6 +527,9 @@
     *argc_ptr = argc_n;
     *argv_ptr = argv_n;
     LocalFree(argv_w);
+   
+    win32_use_utf8 = 1;
+
     return 0;

 err_out:
Index: mpcommon.h
===================================================================
diff --git a/trunk/mpcommon.h b/trunk/mpcommon.h
--- a/trunk/mpcommon.h  (revision 37444)
+++ b/trunk/mpcommon.h  (working copy)
@@ -70,6 +70,10 @@
 extern m_config_t *mconfig;
 extern const m_option_t noconfig_opts[];

+#if defined(__MINGW32__) || defined(__CYGWIN__)
+extern int win32_use_utf8;
+#endif
+
 void print_version(const char* name);
 void init_vo_spudec(struct stream *stream, struct sh_video *sh_video, struct sh_sub *sh_sub);
 void update_subtitles(struct sh_video *sh_video, double refpts, demux_stream_t *d_dvdsub, int reset);
Index: stream/stream_file.c
===================================================================
diff --git a/trunk/stream/stream_file.c b/trunk/stream/stream_file.c
--- a/trunk/stream/stream_file.c        (revision 37444)
+++ b/trunk/stream/stream_file.c        (working copy)
@@ -26,9 +26,10 @@
 #if HAVE_SETMODE
 #include <io.h>
 #endif
-#ifdef __MINGW32__
+#if defined(__MINGW32__) || defined(__CYGWIN__)
 #include <windows.h>
 #include <share.h>
+#include "mpcommon.h"
 #endif

 #include "mp_msg.h"
@@ -120,7 +121,7 @@
   return STREAM_UNSUPPORTED;
 }

-#ifdef __MINGW32__
+#if defined(__MINGW32__) || defined(__CYGWIN__)
 static int win32_open(const char *fname, int m, int omode)
 {
     int cnt;
@@ -127,7 +128,11 @@
     int fd = -1;
     wchar_t fname_w[MAX_PATH];
     int WINAPI (*mb2wc)(UINT, DWORD, LPCSTR, int, LPWSTR, int) = NULL;
-    HMODULE kernel32 = GetModuleHandle("Kernel32.dll");
+    HMODULE kernel32;
+
+    if (!win32_use_utf8) goto fallback;
+
+    kernel32 = GetModuleHandle("Kernel32.dll");
     if (!kernel32) goto fallback;
     mb2wc = GetProcAddress(kernel32, "MultiByteToWideChar");
     if (!mb2wc) goto fallback;



More information about the MPlayer-dev-eng mailing list