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-15 09:50:44 +01:00
parent a5a4bf6d41
commit 19df18fefb
8 changed files with 277 additions and 169 deletions
+67 -12
View File
@@ -9,20 +9,10 @@ using std::cout;
using std::cerr; using std::cerr;
using std::endl; using std::endl;
#define COMPARE(a, b) \ #include <simgear/misc/test_macros.hxx>
if ((a) != (b)) { \
cerr << "failed:" << #a << " != " << #b << endl; \
exit(1); \
}
#define VERIFY(a) \
if (!(a)) { \
cerr << "failed:" << #a << endl; \
exit(1); \
}
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx> #include <simgear/misc/sg_dir.hxx>
#include <simgear/misc/sgstream.hxx>
void test_dir() void test_dir()
{ {
@@ -81,6 +71,69 @@ SGPath::Permissions validateWrite(const SGPath&)
return p; 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[]) int main(int argc, char* argv[])
{ {
SGPath pa; SGPath pa;
@@ -197,6 +250,8 @@ int main(int argc, char* argv[])
test_dir(); test_dir();
test_path_dir();
cout << "all tests passed OK" << endl; cout << "all tests passed OK" << endl;
return 0; // passed return 0; // passed
} }
+36 -28
View File
@@ -18,9 +18,8 @@
// //
// $Id$ // $Id$
#ifdef HAVE_CONFIG_H #include <simgear_config.h>
# include <simgear_config.h> #include <simgear/compiler.h>
#endif
#include <simgear/misc/sg_dir.hxx> #include <simgear/misc/sg_dir.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
@@ -41,6 +40,7 @@
# include <errno.h> # include <errno.h>
#endif #endif
#include <simgear/misc/strutils.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@@ -85,11 +85,10 @@ void Dir::setRemoveOnDestroy()
_removeOnDestroy = true; _removeOnDestroy = true;
} }
#include <stdio.h>
Dir Dir::current() Dir Dir::current()
{ {
#ifdef _WIN32 #if defined(SG_WINDOWS)
char* buf = _getcwd(NULL, 0); wchar_t* buf = _wgetcwd(NULL, 0);
#else #else
char *buf = ::getcwd(NULL, 0); char *buf = ::getcwd(NULL, 0);
#endif #endif
@@ -124,8 +123,15 @@ Dir Dir::tempDir(const std::string& templ)
} }
return Dir(SGPath(buf)); 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 #else
SGPath p(tempnam(0, templ.c_str())); SGPath p(tempnam(0, templ.c_str()));
#endif
Dir t(p); Dir t(p);
if (!t.create(0700)) { if (!t.create(0700)) {
SG_LOG(SG_IO, SG_WARN, "failed to create temporary directory at " << p); 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; types = TYPE_FILE | TYPE_DIR | NO_DOT_OR_DOTDOT;
} }
#ifdef _WIN32 #if defined(SG_WINDOWS)
std::string search(_path.local8BitStr()); std::wstring search(_path.wstr());
if (nameFilter.empty()) { if (nameFilter.empty()) {
search += "\\*"; // everything search += simgear::strutils::convertUtf8ToWString("\\*"); // everything
} else { } else {
search += "\\*" + nameFilter; search += simgear::strutils::convertUtf8ToWString("\\*" + nameFilter);
} }
WIN32_FIND_DATA fData; WIN32_FIND_DATAW fData;
HANDLE find = FindFirstFile(search.c_str(), &fData); HANDLE find = FindFirstFileW(search.c_str(), &fData);
if (find == INVALID_HANDLE_VALUE) { if (find == INVALID_HANDLE_VALUE) {
int err = GetLastError(); int err = GetLastError();
if (err != ERROR_FILE_NOT_FOUND) { if (err != ERROR_FILE_NOT_FOUND) {
@@ -167,16 +173,17 @@ PathList Dir::children(int types, const std::string& nameFilter) const
} }
bool done = false; 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 (fData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
if (!(types & INCLUDE_HIDDEN)) { if (!(types & INCLUDE_HIDDEN)) {
continue; continue;
} }
} }
std::string utf8File = simgear::strutils::convertWStringToUtf8(fData.cFileName);
if (fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (types & NO_DOT_OR_DOTDOT) { if (types & NO_DOT_OR_DOTDOT) {
if (!strcmp(fData.cFileName,".") || !strcmp(fData.cFileName,"..")) { if ((utf8File == ".") || (utf8File == "..")) {
continue; continue;
} }
} }
@@ -192,7 +199,7 @@ PathList Dir::children(int types, const std::string& nameFilter) const
continue; continue;
} }
result.push_back(file(fData.cFileName)); result.push_back(file(utf8File));
} }
FindClose(find); FindClose(find);
@@ -272,10 +279,11 @@ PathList Dir::children(int types, const std::string& nameFilter) const
bool Dir::isEmpty() const bool Dir::isEmpty() const
{ {
std::string ps = _path.local8BitStr(); #if defined(SG_WINDOWS)
#ifdef _WIN32 std::wstring ps = _path.wstr();
return PathIsDirectoryEmpty( ps.c_str() ); return PathIsDirectoryEmptyW( ps.c_str() );
#else #else
std::string ps = _path.local8BitStr();
DIR* dp = opendir( ps.c_str() ); DIR* dp = opendir( ps.c_str() );
if (!dp) return true; if (!dp) return true;
@@ -301,12 +309,6 @@ SGPath Dir::file(const std::string& name) const
return childPath; 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) bool Dir::create(mode_t mode)
{ {
if (exists()) { if (exists()) {
@@ -323,8 +325,13 @@ bool Dir::create(mode_t mode)
} }
// finally, create ourselves // finally, create ourselves
#if defined(SG_WINDOWS)
std::wstring ps = _path.wstr();
int err = _wmkdir(ps.c_str());
#else
std::string ps = _path.local8BitStr(); std::string ps = _path.local8BitStr();
int err = sgMkDir(ps.c_str(), mode); int err = mkdir(ps.c_str(), mode);
#endif
if (err) { if (err) {
SG_LOG(SG_IO, SG_WARN, "directory creation failed: (" << _path << ") " << strerror(errno) ); SG_LOG(SG_IO, SG_WARN, "directory creation failed: (" << _path << ") " << strerror(errno) );
} }
@@ -367,10 +374,11 @@ bool Dir::remove(bool recursive)
} }
} // of recursive deletion } // of recursive deletion
std::string ps = _path.local8BitStr(); #if defined(SG_WINDOWS)
#ifdef _WIN32 std::wstring ps = _path.wstr();
int err = _rmdir(ps.c_str()); int err = _wrmdir(ps.c_str());
#else #else
std::string ps = _path.local8BitStr();
int err = rmdir(ps.c_str()); int err = rmdir(ps.c_str());
#endif #endif
if (err) { if (err) {
+101 -85
View File
@@ -68,22 +68,22 @@ static const char sgSearchPathSep = ':';
static SGPath pathForCSIDL(int csidl, const SGPath& def) 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; static GetSpecialFolderPath SHGetSpecialFolderPath = NULL;
// lazy open+resolve of shell32 // lazy open+resolve of shell32
if (!SHGetSpecialFolderPath) { if (!SHGetSpecialFolderPath) {
HINSTANCE shellDll = ::LoadLibrary("shell32"); HINSTANCE shellDll = ::LoadLibrary("shell32");
SHGetSpecialFolderPath = (GetSpecialFolderPath) GetProcAddress(shellDll, "SHGetSpecialFolderPathA"); SHGetSpecialFolderPath = (GetSpecialFolderPath) GetProcAddress(shellDll, "SHGetSpecialFolderPathW");
} }
if (!SHGetSpecialFolderPath){ if (!SHGetSpecialFolderPath){
return def; return def;
} }
char path[MAX_PATH]; wchar_t path[MAX_PATH];
if (SHGetSpecialFolderPath(0, path, csidl, false)) { if (SHGetSpecialFolderPath(0, path, csidl, false)) {
return SGPath(path, def.getPermissionChecker()); return SGPath(std::wstring(path), def.getPermissionChecker());
} }
return def; return def;
@@ -101,16 +101,7 @@ static SGPath pathForKnownFolder(REFKNOWNFOLDERID folderId, const SGPath& def)
wchar_t* localFolder = 0; wchar_t* localFolder = 0;
if (pSHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT_PATH, NULL, &localFolder) == S_OK) { if (pSHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT_PATH, NULL, &localFolder) == S_OK) {
// copy into local memory SGPath folder_path = SGPath(localFolder, def.getPermissionChecker());
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());
// release dynamic memory // release dynamic memory
CoTaskMemFree(static_cast<void*>(localFolder)); CoTaskMemFree(static_cast<void*>(localFolder));
@@ -213,6 +204,18 @@ SGPath::SGPath( const std::string& p, PermissionChecker validator )
fix(); 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" // create a path based on "path" and a "subpath"
SGPath::SGPath( const SGPath& p, SGPath::SGPath( const SGPath& p,
const std::string& r, const std::string& r,
@@ -463,12 +466,12 @@ void SGPath::validate() const
#ifdef _WIN32 #ifdef _WIN32
struct _stat buf ; struct _stat buf ;
bool remove_trailing = false; bool remove_trailing = false;
string statPath(local8BitStr()); std::wstring statPath(wstr());
if ((path.length() > 1) && (path.back() == '/')) { if ((path.length() > 1) && (path.back() == '/')) {
statPath.pop_back(); statPath.pop_back();
} }
if (_stat(statPath.c_str(), &buf ) < 0) { if (_wstat(statPath.c_str(), &buf ) < 0) {
_exists = false; _exists = false;
} else { } else {
_exists = true; _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) int SGPath::create_dir(mode_t mode)
{ {
@@ -565,49 +563,57 @@ int SGPath::create_dir(mode_t mode)
return -3; return -3;
} }
string_list dirlist = sgPathSplit(dir()); SGPath dirP = dirPath();
if ( dirlist.empty() ) if (dirP.isNull() )
return -1; return -1;
string path = dirlist[0]; string_list path_elements = sgPathBranchSplit(dirP.utf8Str());
string_list path_elements = sgPathBranchSplit(path); bool absolute = dirP.isAbsolute();
bool absolute = !path.empty() && path[0] == sgDirPathSep;
unsigned int i = 1; unsigned int i = 1;
SGPath dir(absolute ? string( 1, sgDirPathSep ) : "", _permission_checker);
dir.concat( path_elements[0] ); #if defined(SG_WINDOWS)
std::string ds = dir.local8BitStr(); SGPath dir(path_elements.front(), _permission_checker);
#ifdef _WIN32 // exists() does not work for drive letter paths, eg 'C:\'.
if ( ds.find(':') != string::npos && path_elements.size() >= 2 ) { // Detect this case and skip to the next element immediately
dir.append( path_elements[1] ); if (absolute && path_elements.size() >= 2) {
i = 2; dir.append(path_elements[i++]);
ds = dir.local8BitStr(); }
} #else
SGPath dir((absolute ? "/" : "") + path_elements.front(), _permission_checker);
#endif #endif
struct stat info; while (dir.exists() && (i < path_elements.size())) {
int r; dir.append(path_elements[i++]);
for(; (r = stat(dir.c_str(), &info)) == 0 && i < path_elements.size(); ++i) { }
dir.append(path_elements[i]);
} // already exists
if( r == 0 ) if (dir.exists() && (i == path_elements.size())) {
return 0; // Directory already exists return 0;
}
for(;;) 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_LOG( SG_IO, SG_ALERT, "Error creating directory: (" << dir << "):"
SG_ALERT, "Error creating directory: (" << dir << ")" ); << simgear::strutils::error_string(errno) );
return -2; return errno;
} }
else else
SG_LOG(SG_IO, SG_DEBUG, "Directory created: " << dir); SG_LOG(SG_IO, SG_DEBUG, "Directory created: " << dir);
if( i >= path_elements.size() ) if (i >= path_elements.size()) {
return 0; break;
}
dir.append(path_elements[i++]); dir.append(path_elements[i++]);
} }
_cached = false; // re-stat on next query
return 0; return 0;
} }
@@ -704,8 +710,13 @@ bool SGPath::remove()
return false; return false;
} }
#if defined(SG_WINDOWS)
std::wstring ps = wstr();
int err = _wunlink(ps.c_str());
#else
std::string ps = local8BitStr(); std::string ps = local8BitStr();
int err = ::unlink(ps.c_str()); int err = ::unlink(ps.c_str());
#endif
if( err ) if( err )
{ {
SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << *this << ") " SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << *this << ") "
@@ -759,10 +770,17 @@ bool SGPath::rename(const SGPath& newName)
} }
} }
#endif #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 p = local8BitStr();
std::string np = newName.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 << SG_LOG( SG_IO, SG_WARN, "rename failed: from " << *this <<
" to " << newName << " to " << newName <<
@@ -851,9 +869,16 @@ SGPath SGPath::standardLocation(StandardLocation type, const SGPath& def)
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
SGPath SGPath::fromEnv(const char* name, 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); const char* val = getenv(name);
if( val && val[0] ) if( val && val[0] )
return SGPath(val, def._permission_checker); return SGPath(val, def._permission_checker);
#endif
return def; 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> SGPath::pathsFromEnv(const char *name)
{ {
std::vector<SGPath> r; std::vector<SGPath> r;
const char* val = getenv(name); #if defined(SG_WINDOWS)
if (!val) { std::wstring wname = simgear::strutils::convertUtf8ToWString(name);
return r; const wchar_t* val = _wgetenv(wname.c_str());
} #else
const char* val = getenv(name);
string_list items = sgPathSplit(val); #endif
string_list_iterator it; if (!val) {
for (it = items.begin(); it != items.end(); ++it) { return r;
r.push_back(SGPath::fromLocal8Bit(it->c_str())); }
}
#if defined(SG_WINDOWS)
return r; 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 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 // 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 #else
// POSIX // POSIX
char* buf = ::realpath(path.c_str(), NULL); char* buf = ::realpath(path.c_str(), NULL);
@@ -956,9 +985,15 @@ SGPath SGPath::realpath() const
} }
return SGPath(this_dir).realpath() / file(); 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); free(buf);
return p; return p;
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -981,24 +1016,5 @@ std::string SGPath::join(const std::vector<SGPath>& paths, const std::string& jo
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
std::wstring SGPath::wstr() const std::wstring SGPath::wstr() const
{ {
#ifdef SG_WINDOWS return simgear::strutils::convertUtf8ToWString(path);
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();
} }
+2
View File
@@ -73,6 +73,8 @@ public:
*/ */
SGPath( const std::string& p, PermissionChecker validator = NULL ); 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 * Construct a path based on the starting path provided and a relative subpath
* @param p initial path * @param p initial path
+21 -6
View File
@@ -185,8 +185,7 @@ sg_gzofstream::sg_gzofstream( int fd, ios_openmode io_mode )
void void
sg_gzofstream::open( const SGPath& name, ios_openmode io_mode ) sg_gzofstream::open( const SGPath& name, ios_openmode io_mode )
{ {
std::string ps = name.local8BitStr(); gzbuf.open( name.c_str(), io_mode );
gzbuf.open( ps.c_str(), io_mode );
} }
void 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) 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::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 ) 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); std::ifstream::open(ps.c_str(), io_mode);
} }
sg_ofstream::sg_ofstream(const SGPath& path, ios_openmode 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); std::ofstream::open(ps.c_str(), io_mode);
} }
void sg_ofstream::open( const SGPath& name, ios_openmode 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); std::ofstream::open(ps.c_str(), io_mode);
} }
+37 -34
View File
@@ -34,6 +34,11 @@
#include <simgear/compiler.h> // SG_WINDOWS #include <simgear/compiler.h> // SG_WINDOWS
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#if defined(SG_WINDOWS)
#include <windows.h>
#endif
using std::string; using std::string;
using std::vector; using std::vector;
using std::stringstream; using std::stringstream;
@@ -363,12 +368,9 @@ namespace simgear {
} }
#if defined(SG_WINDOWS) #if defined(SG_WINDOWS)
static std::wstring convertMultiByteToWString(DWORD encoding, const std::string& a)
#include <windows.h>
static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a)
{ {
WCharVec result; std::vector<wchar_t> result;
DWORD flags = 0; DWORD flags = 0;
int requiredWideChars = MultiByteToWideChar(encoding, flags, int requiredWideChars = MultiByteToWideChar(encoding, flags,
a.c_str(), a.size(), a.c_str(), a.size(),
@@ -376,32 +378,45 @@ static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a)
result.resize(requiredWideChars); result.resize(requiredWideChars);
MultiByteToWideChar(encoding, flags, a.c_str(), a.size(), MultiByteToWideChar(encoding, flags, a.c_str(), a.size(),
result.data(), result.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 #endif
}
std::string convertWindowsLocal8BitToUtf8(const std::string& a) std::string convertWindowsLocal8BitToUtf8(const std::string& a)
{ {
#ifdef SG_WINDOWS #ifdef SG_WINDOWS
DWORD flags = 0; return convertWStringToMultiByte(CP_UTF8, convertMultiByteToWString(CP_ACP, a));
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());
#else #else
return a; return a;
#endif #endif
@@ -410,19 +425,7 @@ std::string convertWindowsLocal8BitToUtf8(const std::string& a)
std::string convertUtf8ToWindowsLocal8Bit(const std::string& a) std::string convertUtf8ToWindowsLocal8Bit(const std::string& a)
{ {
#ifdef SG_WINDOWS #ifdef SG_WINDOWS
DWORD flags = 0; return convertWStringToMultiByte(CP_ACP, convertMultiByteToWString(CP_UTF8, a));
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());
#else #else
return a; return a;
#endif #endif
+2 -4
View File
@@ -176,10 +176,8 @@ namespace simgear {
*/ */
std::string convertUtf8ToWindowsLocal8Bit(const std::string& a); std::string convertUtf8ToWindowsLocal8Bit(const std::string& a);
#if defined(SG_WINDOWS) std::wstring convertUtf8ToWString(const std::string& a);
typedef std::vector<wchar_t> WCharVec; std::string convertWStringToUtf8(const std::wstring& w);
WCharVec convertUtf8ToWString(const std::string& a);
#endif
/** /**
* Get md5 hash of raw data. * Get md5 hash of raw data.
+11
View File
@@ -22,10 +22,14 @@
// $Id$ // $Id$
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <simgear_config.h>
#include <cerrno> #include <cerrno>
#include <memory.h> #include <memory.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h>
#include <simgear/misc/strutils.hxx>
#include "zfstream.hxx" #include "zfstream.hxx"
@@ -110,7 +114,14 @@ gzfilebuf::open( const char *name, ios_openmode io_mode )
char char_mode[10]; char char_mode[10];
cvt_iomode( char_mode, io_mode ); 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 ) { if ( (file = gzopen(name, char_mode)) == NULL ) {
#endif
// perror( "gzfilebuf::open(): " ); // perror( "gzfilebuf::open(): " );
errno = 0; errno = 0;
return NULL; return NULL;