[2/2] Handle unicode file names on windows

Message ID 1303592120-14561-1-git-send-email-martin@martin.st
State Superseded
Headers show

Commit Message

Martin Storsjö April 23, 2011, 8:55 p.m.
From: Kirill Gavrilov <gavr.mail@gmail.com>

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.
---
 cmdutils.c               |    4 ++
 cmdutils_args.h          |   86 ++++++++++++++++++++++++++++++++++++++++++++++
 libavformat/os_support.c |   28 +++++++++++++++
 libavformat/os_support.h |    5 +++
 libavformat/version.h    |    2 +-
 5 files changed, 124 insertions(+), 1 deletions(-)
 create mode 100644 cmdutils_args.h

Patch

diff --git a/cmdutils.c b/cmdutils.c
index f1cbd55..c6128e2 100644
--- a/cmdutils.c
+++ b/cmdutils.c
@@ -47,6 +47,7 @@ 
 #if HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
 #endif
+#include "cmdutils_args.h"
 
 const char **opt_names;
 const char **opt_values;
@@ -162,6 +163,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/cmdutils_args.h b/cmdutils_args.h
new file mode 100644
index 0000000..4eccdbb
--- /dev/null
+++ b/cmdutils_args.h
@@ -0,0 +1,86 @@ 
+/*
+ * Character set conversion for command line arguments
+ * Copyright (c) 2011 Kirill Gavrilov
+ *
+ * This file is part of Libav.
+ *
+ * Libav is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * Libav is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CMDUTILS_ARGS_H
+#define CMDUTILS_ARGS_H
+
+#if defined(_WIN32) && !defined(__MINGW32CE__)
+#include <windows.h>
+/* 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__ */
+
+#endif
diff --git a/libavformat/os_support.c b/libavformat/os_support.c
index 5a3a1bb..05577b7 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 <windows.h>
+
+#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 <fcntl.h>
 #include <unistd.h>
diff --git a/libavformat/os_support.h b/libavformat/os_support.h
index dc01e64..521e997 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 9041f92..22b5dc9 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, \