[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