Use wide-string APIs on Windows.

SGPath and simgear::Dir use ‘w’ versions of POSIX APIs on Windows,
and convert UTF-8 SGPath to wide-strings as part of this.

Includes improved unit-tests for this code, with some very basic
tests of creating and iterating files with Unicode characters in
their names.

No user-visible changes should result from this, on any platform; in
particular wide-string support is still incomplete so FlightGear will
not yet work with arbitrary Unicode paths on Windows.
This commit is contained in:
James Turner
2016-07-04 17:23:42 +01:00
parent a5a4bf6d41
commit 19df18fefb
8 changed files with 277 additions and 169 deletions

View File

@@ -9,20 +9,10 @@ using std::cout;
using std::cerr;
using std::endl;
#define COMPARE(a, b) \
if ((a) != (b)) { \
cerr << "failed:" << #a << " != " << #b << endl; \
exit(1); \
}
#define VERIFY(a) \
if (!(a)) { \
cerr << "failed:" << #a << endl; \
exit(1); \
}
#include <simgear/misc/test_macros.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/misc/sgstream.hxx>
void test_dir()
{
@@ -81,6 +71,69 @@ SGPath::Permissions validateWrite(const SGPath&)
return p;
}
void test_path_dir()
{
SGPath p(simgear::Dir::current().path());
p.append("path_dir");
simgear::Dir(p).remove(true);
VERIFY(p.isAbsolute());
COMPARE(p.create_dir(0755), 0);
SGPath sub = p / "subA" / "subB";
VERIFY(!sub.exists());
SGPath subFile = sub / "fileABC.txt";
COMPARE(subFile.create_dir(0755), 0);
VERIFY(!subFile.exists());
sub.set_cached(false);
VERIFY(sub.exists());
VERIFY(sub.isDir());
SGPath sub2 = p / "subA" / "fileA";
{
sg_ofstream os(sub2);
VERIFY(os.is_open());
for (int i = 0; i < 50; ++i) {
os << "ABCD" << endl;
}
}
VERIFY(sub2.isFile());
COMPARE(sub2.sizeInBytes(), 250);
SGPath sub3 = p / "subß" / "file𝕽";
sub3.create_dir(0755);
{
sg_ofstream os(sub3);
VERIFY(os.is_open());
for (int i = 0; i < 20; ++i) {
os << "EFGH" << endl;
}
}
sub3.set_cached(false);
VERIFY(sub3.exists());
COMPARE(sub3.sizeInBytes(), 100);
COMPARE(sub3.file(), "file𝕽");
simgear::Dir subD(p / "subA");
simgear::PathList dirChildren = subD.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT);
COMPARE(dirChildren.size(), 1);
COMPARE(dirChildren[0], subD.path() / "subB");
simgear::PathList fileChildren = subD.children(simgear::Dir::TYPE_FILE | simgear::Dir::NO_DOT_OR_DOTDOT);
COMPARE(fileChildren.size(), 1);
COMPARE(fileChildren[0], subD.path() / "fileA");
simgear::Dir subS(sub3.dirPath());
fileChildren = subS.children(simgear::Dir::TYPE_FILE | simgear::Dir::NO_DOT_OR_DOTDOT);
COMPARE(fileChildren.size(), 1);
COMPARE(fileChildren[0], subS.path() / "file𝕽");
}
int main(int argc, char* argv[])
{
SGPath pa;
@@ -197,6 +250,8 @@ int main(int argc, char* argv[])
test_dir();
test_path_dir();
cout << "all tests passed OK" << endl;
return 0; // passed
}

View File

@@ -18,9 +18,8 @@
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <simgear_config.h>
#endif
#include <simgear_config.h>
#include <simgear/compiler.h>
#include <simgear/misc/sg_dir.hxx>
#include <simgear/structure/exception.hxx>
@@ -41,6 +40,7 @@
# include <errno.h>
#endif
#include <simgear/misc/strutils.hxx>
#include <simgear/debug/logstream.hxx>
#include <boost/foreach.hpp>
@@ -85,11 +85,10 @@ void Dir::setRemoveOnDestroy()
_removeOnDestroy = true;
}
#include <stdio.h>
Dir Dir::current()
{
#ifdef _WIN32
char* buf = _getcwd(NULL, 0);
#if defined(SG_WINDOWS)
wchar_t* buf = _wgetcwd(NULL, 0);
#else
char *buf = ::getcwd(NULL, 0);
#endif
@@ -124,8 +123,15 @@ Dir Dir::tempDir(const std::string& templ)
}
return Dir(SGPath(buf));
#else
#if defined(SG_WINDOWS)
std::wstring wideTemplate = simgear::strutils::convertUtf8ToWString(templ);
wchar_t* buf = _wtempnam(0, wideTemplate.c_str());
SGPath p(buf);
free(buf); // unlike tempnam(), _wtempnam mallocs its result buffer
#else
SGPath p(tempnam(0, templ.c_str()));
#endif
Dir t(p);
if (!t.create(0700)) {
SG_LOG(SG_IO, SG_WARN, "failed to create temporary directory at " << p);
@@ -147,16 +153,16 @@ PathList Dir::children(int types, const std::string& nameFilter) const
types = TYPE_FILE | TYPE_DIR | NO_DOT_OR_DOTDOT;
}
#ifdef _WIN32
std::string search(_path.local8BitStr());
#if defined(SG_WINDOWS)
std::wstring search(_path.wstr());
if (nameFilter.empty()) {
search += "\\*"; // everything
search += simgear::strutils::convertUtf8ToWString("\\*"); // everything
} else {
search += "\\*" + nameFilter;
search += simgear::strutils::convertUtf8ToWString("\\*" + nameFilter);
}
WIN32_FIND_DATA fData;
HANDLE find = FindFirstFile(search.c_str(), &fData);
WIN32_FIND_DATAW fData;
HANDLE find = FindFirstFileW(search.c_str(), &fData);
if (find == INVALID_HANDLE_VALUE) {
int err = GetLastError();
if (err != ERROR_FILE_NOT_FOUND) {
@@ -167,16 +173,17 @@ PathList Dir::children(int types, const std::string& nameFilter) const
}
bool done = false;
for (bool done = false; !done; done = (FindNextFile(find, &fData) == 0)) {
for (bool done = false; !done; done = (FindNextFileW(find, &fData) == 0)) {
if (fData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
if (!(types & INCLUDE_HIDDEN)) {
continue;
}
}
std::string utf8File = simgear::strutils::convertWStringToUtf8(fData.cFileName);
if (fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (types & NO_DOT_OR_DOTDOT) {
if (!strcmp(fData.cFileName,".") || !strcmp(fData.cFileName,"..")) {
if ((utf8File == ".") || (utf8File == "..")) {
continue;
}
}
@@ -192,7 +199,7 @@ PathList Dir::children(int types, const std::string& nameFilter) const
continue;
}
result.push_back(file(fData.cFileName));
result.push_back(file(utf8File));
}
FindClose(find);
@@ -272,10 +279,11 @@ PathList Dir::children(int types, const std::string& nameFilter) const
bool Dir::isEmpty() const
{
std::string ps = _path.local8BitStr();
#ifdef _WIN32
return PathIsDirectoryEmpty( ps.c_str() );
#if defined(SG_WINDOWS)
std::wstring ps = _path.wstr();
return PathIsDirectoryEmptyW( ps.c_str() );
#else
std::string ps = _path.local8BitStr();
DIR* dp = opendir( ps.c_str() );
if (!dp) return true;
@@ -301,12 +309,6 @@ SGPath Dir::file(const std::string& name) const
return childPath;
}
#ifdef _WIN32
# define sgMkDir(d,m) _mkdir(d)
#else
# define sgMkDir(d,m) mkdir(d,m)
#endif
bool Dir::create(mode_t mode)
{
if (exists()) {
@@ -323,8 +325,13 @@ bool Dir::create(mode_t mode)
}
// finally, create ourselves
#if defined(SG_WINDOWS)
std::wstring ps = _path.wstr();
int err = _wmkdir(ps.c_str());
#else
std::string ps = _path.local8BitStr();
int err = sgMkDir(ps.c_str(), mode);
int err = mkdir(ps.c_str(), mode);
#endif
if (err) {
SG_LOG(SG_IO, SG_WARN, "directory creation failed: (" << _path << ") " << strerror(errno) );
}
@@ -367,10 +374,11 @@ bool Dir::remove(bool recursive)
}
} // of recursive deletion
std::string ps = _path.local8BitStr();
#ifdef _WIN32
int err = _rmdir(ps.c_str());
#if defined(SG_WINDOWS)
std::wstring ps = _path.wstr();
int err = _wrmdir(ps.c_str());
#else
std::string ps = _path.local8BitStr();
int err = rmdir(ps.c_str());
#endif
if (err) {

View File

@@ -68,22 +68,22 @@ static const char sgSearchPathSep = ':';
static SGPath pathForCSIDL(int csidl, const SGPath& def)
{
typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPSTR, int, BOOL);
typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, PWSTR, int, BOOL);
static GetSpecialFolderPath SHGetSpecialFolderPath = NULL;
// lazy open+resolve of shell32
if (!SHGetSpecialFolderPath) {
HINSTANCE shellDll = ::LoadLibrary("shell32");
SHGetSpecialFolderPath = (GetSpecialFolderPath) GetProcAddress(shellDll, "SHGetSpecialFolderPathA");
SHGetSpecialFolderPath = (GetSpecialFolderPath) GetProcAddress(shellDll, "SHGetSpecialFolderPathW");
}
if (!SHGetSpecialFolderPath){
return def;
}
char path[MAX_PATH];
wchar_t path[MAX_PATH];
if (SHGetSpecialFolderPath(0, path, csidl, false)) {
return SGPath(path, def.getPermissionChecker());
return SGPath(std::wstring(path), def.getPermissionChecker());
}
return def;
@@ -101,16 +101,7 @@ static SGPath pathForKnownFolder(REFKNOWNFOLDERID folderId, const SGPath& def)
wchar_t* localFolder = 0;
if (pSHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT_PATH, NULL, &localFolder) == S_OK) {
// copy into local memory
char path[MAX_PATH];
size_t len;
if (wcstombs_s(&len, path, localFolder, MAX_PATH) != S_OK) {
path[0] = '\0';
SG_LOG(SG_GENERAL, SG_WARN, "WCS to MBS failed");
}
SGPath folder_path = SGPath(path, def.getPermissionChecker());
SGPath folder_path = SGPath(localFolder, def.getPermissionChecker());
// release dynamic memory
CoTaskMemFree(static_cast<void*>(localFolder));
@@ -213,6 +204,18 @@ SGPath::SGPath( const std::string& p, PermissionChecker validator )
fix();
}
// create a path based on "path"
SGPath::SGPath(const std::wstring& p, PermissionChecker validator) :
_permission_checker(validator),
_cached(false),
_rwCached(false),
_cacheEnabled(true)
{
path = simgear::strutils::convertWStringToUtf8(p);
fix();
}
// create a path based on "path" and a "subpath"
SGPath::SGPath( const SGPath& p,
const std::string& r,
@@ -463,12 +466,12 @@ void SGPath::validate() const
#ifdef _WIN32
struct _stat buf ;
bool remove_trailing = false;
string statPath(local8BitStr());
std::wstring statPath(wstr());
if ((path.length() > 1) && (path.back() == '/')) {
statPath.pop_back();
}
if (_stat(statPath.c_str(), &buf ) < 0) {
if (_wstat(statPath.c_str(), &buf ) < 0) {
_exists = false;
} else {
_exists = true;
@@ -549,11 +552,6 @@ bool SGPath::isFile() const
}
//------------------------------------------------------------------------------
#ifdef _WIN32
# define sgMkDir(d,m) _mkdir(d)
#else
# define sgMkDir(d,m) mkdir(d,m)
#endif
int SGPath::create_dir(mode_t mode)
{
@@ -565,49 +563,57 @@ int SGPath::create_dir(mode_t mode)
return -3;
}
string_list dirlist = sgPathSplit(dir());
if ( dirlist.empty() )
SGPath dirP = dirPath();
if (dirP.isNull() )
return -1;
string path = dirlist[0];
string_list path_elements = sgPathBranchSplit(path);
bool absolute = !path.empty() && path[0] == sgDirPathSep;
string_list path_elements = sgPathBranchSplit(dirP.utf8Str());
bool absolute = dirP.isAbsolute();
unsigned int i = 1;
SGPath dir(absolute ? string( 1, sgDirPathSep ) : "", _permission_checker);
dir.concat( path_elements[0] );
std::string ds = dir.local8BitStr();
#ifdef _WIN32
if ( ds.find(':') != string::npos && path_elements.size() >= 2 ) {
dir.append( path_elements[1] );
i = 2;
ds = dir.local8BitStr();
}
#if defined(SG_WINDOWS)
SGPath dir(path_elements.front(), _permission_checker);
// exists() does not work for drive letter paths, eg 'C:\'.
// Detect this case and skip to the next element immediately
if (absolute && path_elements.size() >= 2) {
dir.append(path_elements[i++]);
}
#else
SGPath dir((absolute ? "/" : "") + path_elements.front(), _permission_checker);
#endif
struct stat info;
int r;
for(; (r = stat(dir.c_str(), &info)) == 0 && i < path_elements.size(); ++i) {
dir.append(path_elements[i]);
}
if( r == 0 )
return 0; // Directory already exists
while (dir.exists() && (i < path_elements.size())) {
dir.append(path_elements[i++]);
}
// already exists
if (dir.exists() && (i == path_elements.size())) {
return 0;
}
for(;;)
{
if( sgMkDir(dir.c_str(), mode) )
#if defined (SG_WINDOWS)
std::wstring ds = dir.wstr();
if (_wmkdir(ds.c_str()))
#else
std::string ds = dir.utf8Str();
if( mkdir(ds.c_str(), mode) )
#endif
{
SG_LOG( SG_IO,
SG_ALERT, "Error creating directory: (" << dir << ")" );
return -2;
SG_LOG( SG_IO, SG_ALERT, "Error creating directory: (" << dir << "):"
<< simgear::strutils::error_string(errno) );
return errno;
}
else
SG_LOG(SG_IO, SG_DEBUG, "Directory created: " << dir);
if( i >= path_elements.size() )
return 0;
if (i >= path_elements.size()) {
break;
}
dir.append(path_elements[i++]);
}
_cached = false; // re-stat on next query
return 0;
}
@@ -704,8 +710,13 @@ bool SGPath::remove()
return false;
}
#if defined(SG_WINDOWS)
std::wstring ps = wstr();
int err = _wunlink(ps.c_str());
#else
std::string ps = local8BitStr();
int err = ::unlink(ps.c_str());
#endif
if( err )
{
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << *this << ") "
@@ -759,10 +770,17 @@ bool SGPath::rename(const SGPath& newName)
}
}
#endif
#if defined(SG_WINDOWS)
std::wstring p = wstr();
std::wstring np = newName.wstr();
if (_wrename(p.c_str(), np.c_str()) != 0)
#else
std::string p = local8BitStr();
std::string np = newName.local8BitStr();
if( ::rename(p.c_str(), np.c_str()) != 0 )
#endif
if( ::rename(p.c_str(), np.c_str()) != 0 )
{
SG_LOG( SG_IO, SG_WARN, "rename failed: from " << *this <<
" to " << newName <<
@@ -851,9 +869,16 @@ SGPath SGPath::standardLocation(StandardLocation type, const SGPath& def)
//------------------------------------------------------------------------------
SGPath SGPath::fromEnv(const char* name, const SGPath& def)
{
#if defined(SG_WINDOWS)
std::wstring wname = simgear::strutils::convertUtf8ToWString(name);
const wchar_t* val = _wgetenv(wname.c_str());
if (val && val[0])
return SGPath(val, def._permission_checker);
#else
const char* val = getenv(name);
if( val && val[0] )
return SGPath(val, def._permission_checker);
#endif
return def;
}
@@ -862,18 +887,21 @@ SGPath SGPath::fromEnv(const char* name, const SGPath& def)
std::vector<SGPath> SGPath::pathsFromEnv(const char *name)
{
std::vector<SGPath> r;
const char* val = getenv(name);
if (!val) {
return r;
}
string_list items = sgPathSplit(val);
string_list_iterator it;
for (it = items.begin(); it != items.end(); ++it) {
r.push_back(SGPath::fromLocal8Bit(it->c_str()));
}
return r;
#if defined(SG_WINDOWS)
std::wstring wname = simgear::strutils::convertUtf8ToWString(name);
const wchar_t* val = _wgetenv(wname.c_str());
#else
const char* val = getenv(name);
#endif
if (!val) {
return r;
}
#if defined(SG_WINDOWS)
return pathsFromUtf8(simgear::strutils::convertWStringToUtf8(val));
#else
return pathsFromUtf8(val);
#endif
}
//------------------------------------------------------------------------------
@@ -929,9 +957,10 @@ SGPath SGPath::documents(const SGPath& def)
//------------------------------------------------------------------------------
SGPath SGPath::realpath() const
{
#if defined(_MSC_VER) /*for MS compilers */ || defined(_WIN32) /*needed for non MS windows compilers like MingW*/
#if defined(SG_WINDOWS)
// with absPath NULL, will allocate, and ignore length
char *buf = _fullpath( NULL, path.c_str(), _MAX_PATH );
std::wstring ws = wstr();
wchar_t *buf = _wfullpath( NULL, ws.c_str(), _MAX_PATH );
#else
// POSIX
char* buf = ::realpath(path.c_str(), NULL);
@@ -956,9 +985,15 @@ SGPath SGPath::realpath() const
}
return SGPath(this_dir).realpath() / file();
}
SGPath p(SGPath::fromLocal8Bit(buf));
#if defined(SG_WINDOWS)
SGPath p = SGPath(std::wstring(buf), NULL);
#else
SGPath p(SGPath::fromLocal8Bit(buf));
#endif
free(buf);
return p;
}
//------------------------------------------------------------------------------
@@ -981,24 +1016,5 @@ std::string SGPath::join(const std::vector<SGPath>& paths, const std::string& jo
//------------------------------------------------------------------------------
std::wstring SGPath::wstr() const
{
#ifdef SG_WINDOWS
simgear::strutils::WCharVec ws = simgear::strutils::convertUtf8ToWString(path);
return std::wstring(ws.data(), ws.size());
#else
const size_t buflen = mbstowcs(NULL, path.c_str(), 0)+1;
wchar_t* wideBuf = (wchar_t*)malloc(buflen * sizeof(wchar_t));
if (wideBuf) {
size_t count = mbstowcs(wideBuf, path.c_str(), buflen);
if (count == (size_t)-1) {
return std::wstring();
}
std::wstring rv(wideBuf, count);
free(wideBuf);
return rv;
} else {
SG_LOG( SG_GENERAL, SG_ALERT, "SGPath::wstr: unable to allocate enough memory for " << *this );
}
#endif
return std::wstring();
return simgear::strutils::convertUtf8ToWString(path);
}

View File

@@ -73,6 +73,8 @@ public:
*/
SGPath( const std::string& p, PermissionChecker validator = NULL );
explicit SGPath(const std::wstring& p, PermissionChecker validator = NULL);
/**
* Construct a path based on the starting path provided and a relative subpath
* @param p initial path

View File

@@ -185,8 +185,7 @@ sg_gzofstream::sg_gzofstream( int fd, ios_openmode io_mode )
void
sg_gzofstream::open( const SGPath& name, ios_openmode io_mode )
{
std::string ps = name.local8BitStr();
gzbuf.open( ps.c_str(), io_mode );
gzbuf.open( name.c_str(), io_mode );
}
void
@@ -198,24 +197,40 @@ sg_gzofstream::attach( int fd, ios_openmode io_mode )
sg_ifstream::sg_ifstream(const SGPath& path, ios_openmode io_mode)
{
#if defined(SG_WINDOWS)
std::wstring ps = path.wstr();
#else
std::string ps = path.local8BitStr();
std::ifstream::open(ps.c_str(), io_mode);
#endif
std::ifstream::open(ps.c_str(), io_mode);
}
void sg_ifstream::open( const SGPath& name, ios_openmode io_mode )
{
std::string ps = name.local8BitStr();
#if defined(SG_WINDOWS)
std::wstring ps = name.wstr();
#else
std::string ps = name.local8BitStr();
#endif
std::ifstream::open(ps.c_str(), io_mode);
}
sg_ofstream::sg_ofstream(const SGPath& path, ios_openmode io_mode)
{
std::string ps = path.local8BitStr();
#if defined(SG_WINDOWS)
std::wstring ps = path.wstr();
#else
std::string ps = path.local8BitStr();
#endif
std::ofstream::open(ps.c_str(), io_mode);
}
void sg_ofstream::open( const SGPath& name, ios_openmode io_mode )
{
std::string ps = name.local8BitStr();
#if defined(SG_WINDOWS)
std::wstring ps = name.wstr();
#else
std::string ps = name.local8BitStr();
#endif
std::ofstream::open(ps.c_str(), io_mode);
}

View File

@@ -34,6 +34,11 @@
#include <simgear/compiler.h> // SG_WINDOWS
#include <simgear/structure/exception.hxx>
#if defined(SG_WINDOWS)
#include <windows.h>
#endif
using std::string;
using std::vector;
using std::stringstream;
@@ -363,12 +368,9 @@ namespace simgear {
}
#if defined(SG_WINDOWS)
#include <windows.h>
static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a)
static std::wstring convertMultiByteToWString(DWORD encoding, const std::string& a)
{
WCharVec result;
std::vector<wchar_t> result;
DWORD flags = 0;
int requiredWideChars = MultiByteToWideChar(encoding, flags,
a.c_str(), a.size(),
@@ -376,32 +378,45 @@ static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a)
result.resize(requiredWideChars);
MultiByteToWideChar(encoding, flags, a.c_str(), a.size(),
result.data(), result.size());
return result;
return std::wstring(result.data(), result.size());
}
WCharVec convertUtf8ToWString(const std::string& a)
static std::string convertWStringToMultiByte(DWORD encoding, const std::wstring& w)
{
return convertMultiByteToWString(CP_UTF8, a);
std::vector<char> result;
DWORD flags = 0;
int requiredMBChars = WideCharToMultiByte(encoding, flags,
w.data(), w.size(),
NULL, 0, NULL, NULL);
result.resize(requiredMBChars);
WideCharToMultiByte(encoding, flags,
w.data(), w.size(),
result.data(), result.size(), NULL, NULL);
return std::string(result.data(), result.size());
}
#endif
std::wstring convertUtf8ToWString(const std::string& a)
{
#ifdef SG_WINDOWS
return convertMultiByteToWString(CP_UTF8, a);
#else
#endif
}
std::string convertWStringToUtf8(const std::wstring& w)
{
#ifdef SG_WINDOWS
return convertWStringToMultiByte(CP_UTF8, w);
#else
#endif
}
std::string convertWindowsLocal8BitToUtf8(const std::string& a)
{
#ifdef SG_WINDOWS
DWORD flags = 0;
WCharVec wideString = convertMultiByteToWString(CP_ACP, a);
// convert down to UTF-8
std::vector<char> result;
int requiredUTF8Chars = WideCharToMultiByte(CP_UTF8, flags,
wideString.data(), wideString.size(),
NULL, 0, NULL, NULL);
result.resize(requiredUTF8Chars);
WideCharToMultiByte(CP_UTF8, flags,
wideString.data(), wideString.size(),
result.data(), result.size(), NULL, NULL);
return std::string(result.data(), result.size());
return convertWStringToMultiByte(CP_UTF8, convertMultiByteToWString(CP_ACP, a));
#else
return a;
#endif
@@ -410,19 +425,7 @@ std::string convertWindowsLocal8BitToUtf8(const std::string& a)
std::string convertUtf8ToWindowsLocal8Bit(const std::string& a)
{
#ifdef SG_WINDOWS
DWORD flags = 0;
WCharVec wideString = convertMultiByteToWString(CP_UTF8, a);
// convert down to local multi-byte
std::vector<char> result;
int requiredChars = WideCharToMultiByte(CP_ACP, flags,
wideString.data(), wideString.size(),
NULL, 0, NULL, NULL);
result.resize(requiredChars);
WideCharToMultiByte(CP_ACP, flags,
wideString.data(), wideString.size(),
result.data(), result.size(), NULL, NULL);
return std::string(result.data(), result.size());
return convertWStringToMultiByte(CP_ACP, convertMultiByteToWString(CP_UTF8, a));
#else
return a;
#endif

View File

@@ -176,10 +176,8 @@ namespace simgear {
*/
std::string convertUtf8ToWindowsLocal8Bit(const std::string& a);
#if defined(SG_WINDOWS)
typedef std::vector<wchar_t> WCharVec;
WCharVec convertUtf8ToWString(const std::string& a);
#endif
std::wstring convertUtf8ToWString(const std::string& a);
std::string convertWStringToUtf8(const std::wstring& w);
/**
* Get md5 hash of raw data.

View File

@@ -22,10 +22,14 @@
// $Id$
#include <simgear/compiler.h>
#include <simgear_config.h>
#include <cerrno>
#include <memory.h>
#include <stdio.h>
#include <fcntl.h>
#include <simgear/misc/strutils.hxx>
#include "zfstream.hxx"
@@ -110,7 +114,14 @@ gzfilebuf::open( const char *name, ios_openmode io_mode )
char char_mode[10];
cvt_iomode( char_mode, io_mode );
#if defined(SG_WINDOWS)
std::wstring ws = simgear::strutils::convertUtf8ToWString(std::string(name));
if ( (file = gzopen_w(ws.c_str(), char_mode)) == NULL ) {
#else
if ( (file = gzopen(name, char_mode)) == NULL ) {
#endif
// perror( "gzfilebuf::open(): " );
errno = 0;
return NULL;