From 3a023e6160b2c73d071a525f8246659e1921e5e6 Mon Sep 17 00:00:00 2001 From: James Turner Date: Mon, 4 Jul 2016 17:23:42 +0100 Subject: [PATCH] Use wide-string APIs on Windows. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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. --- simgear/misc/path_test.cxx | 79 +++++++++++++--- simgear/misc/sg_dir.cxx | 64 +++++++------ simgear/misc/sg_path.cxx | 186 ++++++++++++++++++++----------------- simgear/misc/sg_path.hxx | 2 + simgear/misc/sgstream.cxx | 27 ++++-- simgear/misc/strutils.cxx | 69 +++++++------- simgear/misc/strutils.hxx | 6 +- simgear/misc/zfstream.cxx | 11 +++ 8 files changed, 276 insertions(+), 168 deletions(-) diff --git a/simgear/misc/path_test.cxx b/simgear/misc/path_test.cxx index bfe87546..a640389e 100644 --- a/simgear/misc/path_test.cxx +++ b/simgear/misc/path_test.cxx @@ -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 #include #include +#include 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 } diff --git a/simgear/misc/sg_dir.cxx b/simgear/misc/sg_dir.cxx index 18f14b19..208a05ed 100644 --- a/simgear/misc/sg_dir.cxx +++ b/simgear/misc/sg_dir.cxx @@ -18,9 +18,8 @@ // // $Id$ -#ifdef HAVE_CONFIG_H -# include -#endif +#include +#include #include #include @@ -41,6 +40,7 @@ # include #endif +#include #include #include @@ -85,11 +85,10 @@ void Dir::setRemoveOnDestroy() _removeOnDestroy = true; } -#include 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) { diff --git a/simgear/misc/sg_path.cxx b/simgear/misc/sg_path.cxx index ffc2641a..2ff8f40b 100644 --- a/simgear/misc/sg_path.cxx +++ b/simgear/misc/sg_path.cxx @@ -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(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::pathsFromEnv(const char *name) { std::vector 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& 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); } diff --git a/simgear/misc/sg_path.hxx b/simgear/misc/sg_path.hxx index f30b6a4b..a35c64e4 100644 --- a/simgear/misc/sg_path.hxx +++ b/simgear/misc/sg_path.hxx @@ -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 diff --git a/simgear/misc/sgstream.cxx b/simgear/misc/sgstream.cxx index 41289a63..8f289c40 100644 --- a/simgear/misc/sgstream.cxx +++ b/simgear/misc/sgstream.cxx @@ -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); } diff --git a/simgear/misc/strutils.cxx b/simgear/misc/strutils.cxx index ff18ec72..48d8fea8 100644 --- a/simgear/misc/strutils.cxx +++ b/simgear/misc/strutils.cxx @@ -34,6 +34,11 @@ #include // SG_WINDOWS #include + +#if defined(SG_WINDOWS) + #include +#endif + using std::string; using std::vector; using std::stringstream; @@ -363,12 +368,9 @@ namespace simgear { } #if defined(SG_WINDOWS) - -#include - -static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a) +static std::wstring convertMultiByteToWString(DWORD encoding, const std::string& a) { - WCharVec result; + std::vector 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) +{ + std::vector 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 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 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 diff --git a/simgear/misc/strutils.hxx b/simgear/misc/strutils.hxx index baad38cb..dd78863c 100644 --- a/simgear/misc/strutils.hxx +++ b/simgear/misc/strutils.hxx @@ -176,10 +176,8 @@ namespace simgear { */ std::string convertUtf8ToWindowsLocal8Bit(const std::string& a); -#if defined(SG_WINDOWS) - typedef std::vector 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. diff --git a/simgear/misc/zfstream.cxx b/simgear/misc/zfstream.cxx index eae24f78..f1a07d07 100644 --- a/simgear/misc/zfstream.cxx +++ b/simgear/misc/zfstream.cxx @@ -22,10 +22,14 @@ // $Id$ #include +#include #include #include #include +#include + +#include #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; -- 2.39.2