fs/Traits: enable _UNICODE on Windows

Use wchar_t for everything on Windows.  Solves a lot of filesystem
charset problems.
This commit is contained in:
Max Kellermann 2015-02-25 16:01:46 +01:00
parent 1da0956331
commit 65ff72cdf8
8 changed files with 114 additions and 5 deletions

View File

@ -103,6 +103,7 @@ mingw32* | windows*)
AM_CPPFLAGS="$AM_CPPFLAGS -DWIN32_LEAN_AND_MEAN" AM_CPPFLAGS="$AM_CPPFLAGS -DWIN32_LEAN_AND_MEAN"
AM_CPPFLAGS="$AM_CPPFLAGS -DWINVER=0x0600 -D_WIN32_WINNT=0x0600" AM_CPPFLAGS="$AM_CPPFLAGS -DWINVER=0x0600 -D_WIN32_WINNT=0x0600"
AM_CPPFLAGS="$AM_CPPFLAGS -DSTRICT" AM_CPPFLAGS="$AM_CPPFLAGS -DSTRICT"
AM_CPPFLAGS="$AM_CPPFLAGS -DUNICODE -D_UNICODE"
LIBS="$LIBS -lws2_32" LIBS="$LIBS -lws2_32"
host_is_windows=yes host_is_windows=yes
host_is_unix=no host_is_unix=no

View File

@ -35,6 +35,7 @@
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#include "fs/FileSystem.hxx" #include "fs/FileSystem.hxx"
#include "fs/StandardDirectory.hxx" #include "fs/StandardDirectory.hxx"
#include "util/Macros.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/OptionDef.hxx" #include "util/OptionDef.hxx"
@ -337,7 +338,19 @@ parse_cmdline(int argc, char **argv, struct options *options,
if (config_file != nullptr) { if (config_file != nullptr) {
/* use specified configuration file */ /* use specified configuration file */
#ifdef _UNICODE
wchar_t buffer[MAX_PATH];
auto result = MultiByteToWideChar(CP_ACP, 0, config_file, -1,
buffer, ARRAY_SIZE(buffer));
if (result <= 0) {
error.SetLastError("MultiByteToWideChar() failed");
return false;
}
return ReadConfigFile(Path::FromFS(buffer), error);
#else
return ReadConfigFile(Path::FromFS(config_file), error); return ReadConfigFile(Path::FromFS(config_file), error);
#endif
} }
/* use default configuration file path */ /* use default configuration file path */

View File

@ -268,7 +268,17 @@ LoadPlaylistFile(const char *utf8path, Error &error)
if (*s == 0 || *s == PLAYLIST_COMMENT) if (*s == 0 || *s == PLAYLIST_COMMENT)
continue; continue;
#ifdef _UNICODE
wchar_t buffer[MAX_PATH];
auto result = MultiByteToWideChar(CP_ACP, 0, s, -1,
buffer, ARRAY_SIZE(buffer));
if (result <= 0)
continue;
const Path path = Path::FromFS(buffer);
#else
const Path path = Path::FromFS(s); const Path path = Path::FromFS(s);
#endif
std::string uri_utf8; std::string uri_utf8;

View File

@ -30,7 +30,7 @@ AllocatedPath::~AllocatedPath() {}
AllocatedPath AllocatedPath
AllocatedPath::FromUTF8(const char *path_utf8) AllocatedPath::FromUTF8(const char *path_utf8)
{ {
#ifdef HAVE_FS_CHARSET #if defined(HAVE_FS_CHARSET) || defined(WIN32)
return AllocatedPath(::PathFromUTF8(path_utf8)); return AllocatedPath(::PathFromUTF8(path_utf8));
#else #else
return FromFS(path_utf8); return FromFS(path_utf8);

View File

@ -25,6 +25,10 @@
#include "lib/icu/Converter.hxx" #include "lib/icu/Converter.hxx"
#include "util/Error.hxx" #include "util/Error.hxx"
#ifdef WIN32
#include <windows.h>
#endif
#include <algorithm> #include <algorithm>
#include <assert.h> #include <assert.h>
@ -95,6 +99,24 @@ PathToUTF8(PathTraitsFS::const_pointer path_fs)
assert(path_fs != nullptr); assert(path_fs != nullptr);
#endif #endif
#ifdef WIN32
int length = WideCharToMultiByte(CP_UTF8, 0, path_fs, -1, nullptr, 0,
nullptr, nullptr);
if (length <= 0)
return PathTraitsUTF8::string();
char *buffer = new char[length];
length = WideCharToMultiByte(CP_UTF8, 0, path_fs, -1, buffer, length,
nullptr, nullptr);
if (length <= 0) {
delete[] buffer;
return PathTraitsUTF8::string();
}
PathTraitsUTF8::string result(buffer);
delete[] buffer;
return FixSeparators(std::move(result));
#else
#ifdef HAVE_FS_CHARSET #ifdef HAVE_FS_CHARSET
if (fs_converter == nullptr) if (fs_converter == nullptr)
#endif #endif
@ -103,9 +125,10 @@ PathToUTF8(PathTraitsFS::const_pointer path_fs)
return FixSeparators(fs_converter->ToUTF8(path_fs)); return FixSeparators(fs_converter->ToUTF8(path_fs));
#endif #endif
#endif
} }
#ifdef HAVE_FS_CHARSET #if defined(HAVE_FS_CHARSET) || defined(WIN32)
PathTraitsFS::string PathTraitsFS::string
PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8) PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8)
@ -115,10 +138,29 @@ PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8)
assert(path_utf8 != nullptr); assert(path_utf8 != nullptr);
#endif #endif
#ifdef WIN32
int length = MultiByteToWideChar(CP_UTF8, 0, path_utf8, -1,
nullptr, 0);
if (length <= 0)
return PathTraitsFS::string();
wchar_t *buffer = new wchar_t[length];
length = MultiByteToWideChar(CP_UTF8, 0, path_utf8, -1,
buffer, length);
if (length <= 0) {
delete[] buffer;
return PathTraitsFS::string();
}
PathTraitsFS::string result(buffer);
delete[] buffer;
return std::move(result);
#else
if (fs_converter == nullptr) if (fs_converter == nullptr)
return path_utf8; return path_utf8;
return fs_converter->FromUTF8(path_utf8); return fs_converter->FromUTF8(path_utf8);
#endif
} }
#endif #endif

View File

@ -22,6 +22,11 @@
#include "check.h" #include "check.h"
#include "Path.hxx" #include "Path.hxx"
#include "util/Macros.hxx"
#ifdef _UNICODE
#include <windows.h>
#endif
/** /**
* A path name that uses the regular (narrow) "char". This is used to * A path name that uses the regular (narrow) "char". This is used to
@ -32,10 +37,25 @@ class NarrowPath {
typedef char value_type; typedef char value_type;
typedef const char *const_pointer; typedef const char *const_pointer;
#ifdef _UNICODE
char value[PATH_MAX];
#else
const_pointer value; const_pointer value;
#endif
public: public:
#ifdef _UNICODE
explicit NarrowPath(Path _path) {
auto result = WideCharToMultiByte(CP_ACP, 0,
_path.c_str(), -1,
value, ARRAY_SIZE(value),
nullptr, nullptr);
if (result < 0)
value[0] = 0;
}
#else
explicit NarrowPath(Path _path):value(_path.c_str()) {} explicit NarrowPath(Path _path):value(_path.c_str()) {}
#endif
operator const_pointer() const { operator const_pointer() const {
return value; return value;

View File

@ -43,7 +43,11 @@
* This class describes the nature of a native filesystem path. * This class describes the nature of a native filesystem path.
*/ */
struct PathTraitsFS { struct PathTraitsFS {
#ifdef WIN32
typedef std::wstring string;
#else
typedef std::string string; typedef std::string string;
#endif
typedef string::traits_type char_traits; typedef string::traits_type char_traits;
typedef char_traits::char_type value_type; typedef char_traits::char_type value_type;
typedef value_type *pointer; typedef value_type *pointer;

View File

@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "SocketError.hxx" #include "SocketError.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/Macros.hxx"
#include <string.h> #include <string.h>
@ -29,13 +30,31 @@ const Domain socket_domain("socket");
SocketErrorMessage::SocketErrorMessage(socket_error_t code) SocketErrorMessage::SocketErrorMessage(socket_error_t code)
{ {
#ifdef _UNICODE
wchar_t buffer[ARRAY_SIZE(msg)];
#else
auto *buffer = msg;
#endif
DWORD nbytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | DWORD nbytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK, FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL, code, 0, nullptr, code, 0,
(LPSTR)msg, sizeof(msg), NULL); buffer, ARRAY_SIZE(msg), nullptr);
if (nbytes == 0) if (nbytes == 0) {
strcpy(msg, "Unknown error"); strcpy(msg, "Unknown error");
return;
}
#ifdef _UNICODE
auto length = WideCharToMultiByte(CP_UTF8, 0, buffer, -1,
msg, ARRAY_SIZE(msg),
nullptr, nullptr);
if (length <= 0) {
strcpy(msg, "WideCharToMultiByte() error");
return;
}
#endif
} }
#else #else