From 584c121f33ac2f879b366ec60591aa9f6af4d604 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 14 Jan 2014 17:20:41 +0400 Subject: [PATCH 01/31] fix windows unicode path handling --- components/files/windowspath.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index ea1ca56d3..a8cbcb24b 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -10,8 +10,12 @@ #pragma comment(lib, "Shlwapi.lib") +#include +namespace bconv = boost::locale::conv; + /** * FIXME: Someone with Windows system should check this and correct if necessary + * FIXME: MAX_PATH is irrelevant for extended-length paths, i.e. \\?\... */ /** @@ -29,16 +33,15 @@ boost::filesystem::path WindowsPath::getUserConfigPath() const { boost::filesystem::path userPath("."); - TCHAR path[MAX_PATH]; + WCHAR path[MAX_PATH + 1]; memset(path, 0, sizeof(path)); - if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path))) + if(SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path))) { - PathAppend(path, TEXT("My Games")); - userPath = boost::filesystem::path(path); + userPath = boost::filesystem::path(bconv::utf_to_utf(path)); } - return userPath / mName; + return userPath / "MyGames" / mName; } boost::filesystem::path WindowsPath::getUserDataPath() const @@ -51,12 +54,12 @@ boost::filesystem::path WindowsPath::getGlobalConfigPath() const { boost::filesystem::path globalPath("."); - TCHAR path[MAX_PATH]; + WCHAR path[MAX_PATH + 1]; memset(path, 0, sizeof(path)); - if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, NULL, 0, path))) + if(SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, NULL, 0, path))) { - globalPath = boost::filesystem::path(path); + globalPath = boost::filesystem::path(bconv::utf_to_utf(path)); } return globalPath / mName; From eafdefe9993b550e1cc5a1edbd3b92183473e9bb Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 14 Jan 2014 23:08:54 +0400 Subject: [PATCH 02/31] using WindowsPath implies utf-8 for boost fs::path --- components/files/windowspath.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index a8cbcb24b..f27c1cc92 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -27,6 +27,7 @@ namespace Files WindowsPath::WindowsPath(const std::string& application_name) : mName(application_name) { + boost::filesystem::path::imbue(boost::locale::generator.generate("")); } boost::filesystem::path WindowsPath::getUserConfigPath() const @@ -41,7 +42,7 @@ boost::filesystem::path WindowsPath::getUserConfigPath() const userPath = boost::filesystem::path(bconv::utf_to_utf(path)); } - return userPath / "MyGames" / mName; + return userPath / "My Games" / mName; } boost::filesystem::path WindowsPath::getUserDataPath() const From cd990a665a5b59770174ceeece71c0b675865cb7 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 14 Jan 2014 23:29:24 +0400 Subject: [PATCH 03/31] create QString from utf-8 when expected --- apps/launcher/maindialog.cpp | 20 ++++++++++---------- apps/launcher/settings/gamesettings.cpp | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 5cf8f8a89..fb4c09b91 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -41,11 +41,11 @@ Launcher::MainDialog::MainDialog(QWidget *parent) // Check if the font is installed if (!fonts.contains("EB Garamond")) { - QString font = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); + QString font = QString::fromUtf8(mCfgMgr.getGlobalDataPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf"); file.setFileName(font); if (!file.exists()) { - font = QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); + font = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf"); } fontDatabase.addApplicationFont(font); @@ -243,7 +243,7 @@ bool Launcher::MainDialog::showFirstRunDialog() } // Create the file if it doesn't already exist, else the importer will fail - QString path = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + QString("openmw.cfg"); + QString path = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()) + QString("openmw.cfg"); QFile file(path); if (!file.exists()) { @@ -358,7 +358,7 @@ bool Launcher::MainDialog::setupLauncherSettings() { mLauncherSettings.setMultiValueEnabled(true); - QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QStringList paths; paths.append(QString("launcher.cfg")); @@ -464,8 +464,8 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd) bool Launcher::MainDialog::setupGameSettings() { - QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); - QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); + QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); // Load the user config file first, separately // So we can write it properly, uncontaminated @@ -594,7 +594,7 @@ bool Launcher::MainDialog::setupGameSettings() while(expansions(cd)); - selectedFile = QString::fromStdString(cd.GetMWEsmPath()); + selectedFile = QString::fromUtf8(cd.GetMWEsmPath().c_str()); } #endif // WIN32 @@ -615,8 +615,8 @@ bool Launcher::MainDialog::setupGraphicsSettings() { mGraphicsSettings.setMultiValueEnabled(false); - QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); - QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); + QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); QFile localDefault(QString("settings-default.cfg")); QFile globalDefault(globalPath + QString("settings-default.cfg")); @@ -702,7 +702,7 @@ bool Launcher::MainDialog::writeSettings() mGraphicsPage->saveSettings(); mDataFilesPage->saveSettings(); - QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); + QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); QDir dir(userPath); if (!dir.exists()) { diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index e7e5cf1ea..0a09c5cc0 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -53,7 +53,7 @@ void Launcher::GameSettings::validatePaths() mDataDirs.clear(); for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { - QString path = QString::fromStdString(it->string()); + QString path = QString::fromUtf8(it->string().c_str()); path.remove(QChar('\"')); QDir dir(path); @@ -73,7 +73,7 @@ void Launcher::GameSettings::validatePaths() mCfgMgr.processPaths(dataDirs); if (!dataDirs.empty()) { - QString path = QString::fromStdString(dataDirs.front().string()); + QString path = QString::fromUtf8(dataDirs.front().string().c_str()); path.remove(QChar('\"')); QDir dir(path); From b4950509bc5e55016f79ad0aa50fb8d9164c35c5 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 14 Jan 2014 23:30:56 +0400 Subject: [PATCH 04/31] use converted widechars in ini importer --- apps/mwiniimporter/main.cpp | 32 ++++++++++++++++++++++++++++++++ components/files/windowspath.cpp | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 364a6b1a4..58ae1d593 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -4,11 +4,43 @@ #include #include #include +#include namespace bpo = boost::program_options; +#ifndef _WIN32 int main(int argc, char *argv[]) { +#else +class utf8argv +{ +public: + + utf8argv(int argc, wchar_t *wargv[]) + { + args.reserve(argc); + argv = new const char *[argc]; + + for (int i = 0; i < argc; ++i) { + args.push_back(boost::locale::conv::utf_to_utf(wargv[i])); + argv[i] = args.back().c_str(); + } + } + + ~utf8argv() { delete[] argv; } + const char * const *get() const { return argv; } + +private: + + const char **argv; + std::vector args; +}; + +int wmain(int argc, wchar_t *wargv[]) { + utf8argv converter(argc, wargv); + char **argv = converter.get(); + boost::filesystem::path::imbue(boost::locale::generator().generate("")); +#endif bpo::options_description desc("Syntax: mwiniimporter inifile configfile\nAllowed options"); bpo::positional_options_description p_desc; desc.add_options() diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index f27c1cc92..41240ae48 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -27,7 +27,7 @@ namespace Files WindowsPath::WindowsPath(const std::string& application_name) : mName(application_name) { - boost::filesystem::path::imbue(boost::locale::generator.generate("")); + boost::filesystem::path::imbue(boost::locale::generator().generate("")); } boost::filesystem::path WindowsPath::getUserConfigPath() const From 18b3cfebdbb4bfe371333c6273480feeca002853 Mon Sep 17 00:00:00 2001 From: greye Date: Wed, 15 Jan 2014 01:43:55 +0400 Subject: [PATCH 05/31] fix importer crash on empty lines (thanks to Ace) --- apps/mwiniimporter/importer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 648ab3ebe..3226278fe 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -674,6 +674,10 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam line = line.substr(0, line.length()-1); } + if(line.empty()) { + continue; + } + if(line[0] == '[') { int pos = line.find(']'); if(pos < 2) { @@ -690,10 +694,6 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam line = line.substr(0,comment_pos); } - if(line.empty()) { - continue; - } - int pos = line.find("="); if(pos < 1) { continue; From a22ec223d86246dc0640701b3637f40fdeaa89da Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 19 Jan 2014 11:34:54 +0400 Subject: [PATCH 06/31] open fstreams from boost::filesystem::path, vol.1 --- apps/launcher/unshieldthread.cpp | 6 +++--- apps/openmw/mwgui/console.cpp | 6 +++++- components/files/configurationmanager.cpp | 4 ++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/launcher/unshieldthread.cpp b/apps/launcher/unshieldthread.cpp index 52f935710..26010faf3 100644 --- a/apps/launcher/unshieldthread.cpp +++ b/apps/launcher/unshieldthread.cpp @@ -1,6 +1,6 @@ #include "unshieldthread.hpp" -#include +#include #include namespace bfs = boost::filesystem; @@ -49,7 +49,7 @@ namespace std::string read_to_string(const bfs::path& path) { - std::ifstream strstream(path.c_str(), std::ios::in | std::ios::binary); + bfs::ifstream strstream(path, std::ios::in | std::ios::binary); std::string str; strstream.seekg(0, std::ios::end); @@ -201,7 +201,7 @@ namespace add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini); } - std::ofstream inistream(ini_path.c_str()); + bfs::ofstream inistream(ini_path) inistream << ini; inistream.close(); } diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index d51d4298f..dd3a67e94 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -1,5 +1,8 @@ #include "console.hpp" +#include +#include + #include #include @@ -194,7 +197,8 @@ namespace MWGui void Console::executeFile (const std::string& path) { - std::ifstream stream (path.c_str()); + namespace bfs = boost::filesystem; + bfs::ifstream stream (bfs::path(path)); if (!stream.is_open()) printError ("failed to open file: " + path); diff --git a/components/files/configurationmanager.cpp b/components/files/configurationmanager.cpp index 761b7ca5a..ffa911b44 100644 --- a/components/files/configurationmanager.cpp +++ b/components/files/configurationmanager.cpp @@ -1,12 +1,12 @@ #include "configurationmanager.hpp" #include -#include #include #include #include #include +#include /** * \namespace Files @@ -125,7 +125,7 @@ void ConfigurationManager::loadConfig(const boost::filesystem::path& path, { std::cout << "Loading config file: " << cfgFile.string() << "... "; - std::ifstream configFileStream(cfgFile.string().c_str()); + boost::filesystem::ifstream configFileStream(cfgFile); if (configFileStream.is_open()) { boost::program_options::store(boost::program_options::parse_config_file( From 2236216344c489503cbd5945478b0ae196237a12 Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 19 Jan 2014 14:55:12 +0400 Subject: [PATCH 07/31] minor simplification --- components/files/multidircollection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/files/multidircollection.cpp b/components/files/multidircollection.cpp index 347de96a6..1abbae3ae 100644 --- a/components/files/multidircollection.cpp +++ b/components/files/multidircollection.cpp @@ -60,10 +60,10 @@ namespace Files { boost::filesystem::path path = *dirIter; - if (!equal (extension, boost::filesystem::path (path.extension()).string())) + if (!equal (extension, path.extension().string())) continue; - std::string filename = boost::filesystem::path (path.filename()).string(); + std::string filename = path.filename().string(); TIter result = mFiles.find (filename); From 424d06a6f88906b4d10f76060c4cd0032440d150 Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 19 Jan 2014 15:20:08 +0400 Subject: [PATCH 08/31] open fstreams from boost::filesystem::path, vol.2 --- components/settings/settings.cpp | 6 ++++-- components/translation/translation.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 13015e39c..3a3a3dddd 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -1,7 +1,8 @@ #include "settings.hpp" -#include #include +#include +#include #include #include @@ -25,7 +26,8 @@ void Manager::loadDefault (const std::string& file) void Manager::saveUser(const std::string& file) { - std::fstream fout(file.c_str(), std::ios::out); + namespace bfs = boost::filesystem; + bfs::ofstream fout(bfs::path(file)); Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator(); diff --git a/components/translation/translation.cpp b/components/translation/translation.cpp index d0ea4b7fb..423c3971a 100644 --- a/components/translation/translation.cpp +++ b/components/translation/translation.cpp @@ -1,7 +1,8 @@ #include "translation.hpp" -#include -#include +#include + +#include namespace Translation { @@ -28,9 +29,8 @@ namespace Translation if (dataFileCollections.getCollection (extension).doesExist (fileName)) { - std::string path = dataFileCollections.getCollection (extension).getPath (fileName).string(); - - std::ifstream stream (path.c_str()); + boost::filesystem::ifstream stream ( + dataFileCollections.getCollection (extension).getPath (fileName)); if (!stream.is_open()) throw std::runtime_error ("failed to open translation file: " + fileName); From e02b04536f8e840cde337fd3cd622e7c765f3050 Mon Sep 17 00:00:00 2001 From: greye Date: Sun, 19 Jan 2014 18:13:35 +0400 Subject: [PATCH 09/31] fix most vexing parse issue --- apps/launcher/unshieldthread.cpp | 2 +- apps/openmw/mwgui/console.cpp | 2 +- components/settings/settings.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/launcher/unshieldthread.cpp b/apps/launcher/unshieldthread.cpp index 26010faf3..3d0f2e5da 100644 --- a/apps/launcher/unshieldthread.cpp +++ b/apps/launcher/unshieldthread.cpp @@ -201,7 +201,7 @@ namespace add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini); } - bfs::ofstream inistream(ini_path) + bfs::ofstream inistream((ini_path)); inistream << ini; inistream.close(); } diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index dd3a67e94..237d145a2 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -198,7 +198,7 @@ namespace MWGui void Console::executeFile (const std::string& path) { namespace bfs = boost::filesystem; - bfs::ifstream stream (bfs::path(path)); + bfs::ifstream stream ((bfs::path(path))); if (!stream.is_open()) printError ("failed to open file: " + path); diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 3a3a3dddd..ac09db9d9 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -27,7 +27,7 @@ void Manager::loadDefault (const std::string& file) void Manager::saveUser(const std::string& file) { namespace bfs = boost::filesystem; - bfs::ofstream fout(bfs::path(file)); + bfs::ofstream fout((bfs::path(file))); Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator(); From 2c82da8e6e5d535e2032c8e21150d7a8d3a60f07 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 10:07:43 +0400 Subject: [PATCH 10/31] load Ogre::ConfigFile from DataStream --- components/settings/settings.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index ac09db9d9..56e937c8e 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -6,9 +6,12 @@ #include #include +#include using namespace Settings; +namespace bfs = boost::filesystem; + Ogre::ConfigFile Manager::mFile = Ogre::ConfigFile(); Ogre::ConfigFile Manager::mDefaultFile = Ogre::ConfigFile(); CategorySettingVector Manager::mChangedSettings = CategorySettingVector(); @@ -16,17 +19,20 @@ CategorySettingValueMap Manager::mNewSettings = CategorySettingValueMap(); void Manager::loadUser (const std::string& file) { - mFile.load(file); + bfs::ifstream fin((bfs::path(file))); + Ogre::DataStreamPtr stream((OGRE_NEW Ogre::FileStreamDataStream(file, &fin, false))); + mFile.load(stream); } void Manager::loadDefault (const std::string& file) { - mDefaultFile.load(file); + bfs::ifstream fin((bfs::path(file))); + Ogre::DataStreamPtr stream((OGRE_NEW Ogre::FileStreamDataStream(file, &fin, false))); + mDefaultFile.load(stream); } void Manager::saveUser(const std::string& file) { - namespace bfs = boost::filesystem; bfs::ofstream fout((bfs::path(file))); Ogre::ConfigFile::SectionIterator seci = mFile.getSectionIterator(); From 6cb795ef7d86f14358f2b497c561de1c226465c4 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 10:47:02 +0400 Subject: [PATCH 11/31] attempt to fix LowLevelFile, minor code reuse --- components/files/lowlevelfile.cpp | 5 ++++- components/settings/settings.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp index 06ee9fb4e..4466e354d 100644 --- a/components/files/lowlevelfile.cpp +++ b/components/files/lowlevelfile.cpp @@ -206,6 +206,8 @@ size_t LowLevelFile::read (void * data, size_t size) } #elif FILE_API == FILE_API_WIN32 + +#include /* * * Implementation of LowLevelFile methods using Win32 API calls @@ -227,7 +229,8 @@ void LowLevelFile::open (char const * filename) { assert (mHandle == INVALID_HANDLE_VALUE); - HANDLE handle = CreateFileA (filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + std::wstring wname = boost::locale::conv::utf_to_utf(filename); + HANDLE handle = CreateFileW (wname.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); if (handle == NULL) { diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 56e937c8e..0def0afdb 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -8,6 +8,8 @@ #include #include +#include + using namespace Settings; namespace bfs = boost::filesystem; @@ -19,15 +21,13 @@ CategorySettingValueMap Manager::mNewSettings = CategorySettingValueMap(); void Manager::loadUser (const std::string& file) { - bfs::ifstream fin((bfs::path(file))); - Ogre::DataStreamPtr stream((OGRE_NEW Ogre::FileStreamDataStream(file, &fin, false))); + Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); mFile.load(stream); } void Manager::loadDefault (const std::string& file) { - bfs::ifstream fin((bfs::path(file))); - Ogre::DataStreamPtr stream((OGRE_NEW Ogre::FileStreamDataStream(file, &fin, false))); + Ogre::DataStreamPtr stream = openConstrainedFileDataStream(file.c_str()); mDefaultFile.load(stream); } From 417e07fbcef11d94d903925bf9a6bd91f3e0bbb4 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 10:59:36 +0400 Subject: [PATCH 12/31] fix irrelevant error reporting --- components/files/lowlevelfile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/files/lowlevelfile.cpp b/components/files/lowlevelfile.cpp index 4466e354d..4cdeec043 100644 --- a/components/files/lowlevelfile.cpp +++ b/components/files/lowlevelfile.cpp @@ -232,7 +232,7 @@ void LowLevelFile::open (char const * filename) std::wstring wname = boost::locale::conv::utf_to_utf(filename); HANDLE handle = CreateFileW (wname.c_str(), GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - if (handle == NULL) + if (handle == INVALID_HANDLE_VALUE) { std::ostringstream os; os << "Failed to open '" << filename << "' for reading."; From 493f8c60504222e5fe51a34548c69907bdec2ae0 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 13:39:07 +0400 Subject: [PATCH 13/31] fix opening BSA on Unicode path --- components/bsa/bsa_file.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/bsa/bsa_file.cpp b/components/bsa/bsa_file.cpp index 25b006fb3..0958c8f0c 100644 --- a/components/bsa/bsa_file.cpp +++ b/components/bsa/bsa_file.cpp @@ -25,6 +25,9 @@ #include +#include +#include + #include "../files/constrainedfiledatastream.hpp" using namespace std; @@ -72,7 +75,8 @@ void BSAFile::readHeader() */ assert(!isLoaded); - std::ifstream input(filename.c_str(), std::ios_base::binary); + namespace bfs = boost::filesystem; + bfs::ifstream input(bfs::path(filename), std::ios_base::binary); // Total archive size size_t fsize = 0; From 9c6224c74d0e19e680a9f22f037503ba28451b10 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 15:43:25 +0400 Subject: [PATCH 14/31] fix saving to Unicode path destination --- apps/openmw/mwstate/statemanagerimp.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 304228010..0cd23eb6f 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -12,6 +12,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" @@ -187,7 +189,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot else slot = mCharacterManager.getCurrentCharacter()->updateSlot (slot, profile); - std::ofstream stream (slot->mPath.string().c_str(), std::ios::binary); + boost::filesystem::ofstream stream (slot->mPath, std::ios::binary); ESM::ESMWriter writer; From db16bb89834954adc94a5bcab82d8f1a72d42502 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 15:52:19 +0400 Subject: [PATCH 15/31] fix OpenCS saving to Unicode path destination --- apps/opencs/model/doc/savingstages.cpp | 4 ++-- apps/opencs/model/doc/savingstate.cpp | 4 ++-- apps/opencs/model/doc/savingstate.hpp | 7 ++++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index eb93d9047..34d93c49a 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -27,7 +27,7 @@ void CSMDoc::OpenSaveStage::perform (int stage, Messages& messages) { mState.start (mDocument, mProjectFile); - mState.getStream().open ((mProjectFile ? mState.getPath() : mState.getTmpPath()).string().c_str()); + mState.getStream().open (mProjectFile ? mState.getPath() : mState.getTmpPath()); if (!mState.getStream().is_open()) throw std::runtime_error ("failed to open stream for saving"); @@ -260,4 +260,4 @@ void CSMDoc::FinalSavingStage::perform (int stage, Messages& messages) mDocument.getUndoStack().setClean(); } -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/savingstate.cpp b/apps/opencs/model/doc/savingstate.cpp index 874214822..07c42a490 100644 --- a/apps/opencs/model/doc/savingstate.cpp +++ b/apps/opencs/model/doc/savingstate.cpp @@ -47,7 +47,7 @@ const boost::filesystem::path& CSMDoc::SavingState::getTmpPath() const return mTmpPath; } -std::ofstream& CSMDoc::SavingState::getStream() +boost::filesystem::ofstream& CSMDoc::SavingState::getStream() { return mStream; } @@ -60,4 +60,4 @@ ESM::ESMWriter& CSMDoc::SavingState::getWriter() bool CSMDoc::SavingState::isProjectFile() const { return mProjectFile; -} \ No newline at end of file +} diff --git a/apps/opencs/model/doc/savingstate.hpp b/apps/opencs/model/doc/savingstate.hpp index 6b4565584..7b0c37386 100644 --- a/apps/opencs/model/doc/savingstate.hpp +++ b/apps/opencs/model/doc/savingstate.hpp @@ -4,6 +4,7 @@ #include #include +#include #include @@ -20,7 +21,7 @@ namespace CSMDoc boost::filesystem::path mPath; boost::filesystem::path mTmpPath; ToUTF8::Utf8Encoder mEncoder; - std::ofstream mStream; + boost::filesystem::ofstream mStream; ESM::ESMWriter mWriter; boost::filesystem::path mProjectPath; bool mProjectFile; @@ -39,7 +40,7 @@ namespace CSMDoc const boost::filesystem::path& getTmpPath() const; - std::ofstream& getStream(); + boost::filesystem::ofstream& getStream(); ESM::ESMWriter& getWriter(); @@ -50,4 +51,4 @@ namespace CSMDoc } -#endif \ No newline at end of file +#endif From 20527e0bd4418b107634247e78b08d6ec9c608fa Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 16:56:41 +0400 Subject: [PATCH 16/31] use boost::filesystem instead of boost::iostreams --- apps/mwiniimporter/importer.cpp | 13 ++++++++----- apps/mwiniimporter/importer.hpp | 5 ++--- apps/mwiniimporter/main.cpp | 9 ++++++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/apps/mwiniimporter/importer.cpp b/apps/mwiniimporter/importer.cpp index 3226278fe..3a52592ae 100644 --- a/apps/mwiniimporter/importer.cpp +++ b/apps/mwiniimporter/importer.cpp @@ -1,6 +1,5 @@ #include "importer.hpp" -#include -#include + #include #include #include @@ -9,6 +8,10 @@ #include #include +#include +#include + +namespace bfs = boost::filesystem; MwIniImporter::MwIniImporter() : mVerbose(false) @@ -661,7 +664,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam std::string section(""); MwIniImporter::multistrmap map; - boost::iostreams::streamfile(filename.c_str()); + bfs::ifstream file((bfs::path(filename))); ToUTF8::Utf8Encoder encoder(mEncoding); std::string line; @@ -720,7 +723,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filenam std::cout << "load cfg file: " << filename << std::endl; MwIniImporter::multistrmap map; - boost::iostreams::streamfile(filename.c_str()); + bfs::ifstream file((bfs::path(filename))); std::string line; while (std::getline(file, line)) { @@ -858,7 +861,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co } } -void MwIniImporter::writeToFile(boost::iostreams::stream &out, const multistrmap &cfg) { +void MwIniImporter::writeToFile(std::ostream &out, const multistrmap &cfg) { for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) { for(std::vector::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) { diff --git a/apps/mwiniimporter/importer.hpp b/apps/mwiniimporter/importer.hpp index 784980e09..72b14ba75 100644 --- a/apps/mwiniimporter/importer.hpp +++ b/apps/mwiniimporter/importer.hpp @@ -1,12 +1,11 @@ #ifndef MWINIIMPORTER_IMPORTER #define MWINIIMPORTER_IMPORTER 1 -#include -#include #include #include #include #include +#include #include @@ -24,7 +23,7 @@ class MwIniImporter { void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const; - static void writeToFile(boost::iostreams::stream &out, const multistrmap &cfg); + static void writeToFile(std::ostream &out, const multistrmap &cfg); private: static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index 58ae1d593..d9c1454fc 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -1,12 +1,15 @@ #include "importer.hpp" -#include #include + #include -#include #include +#include +#include +#include namespace bpo = boost::program_options; +namespace bfs = boost::filesystem; #ifndef _WIN32 int main(int argc, char *argv[]) { @@ -126,7 +129,7 @@ int wmain(int argc, wchar_t *wargv[]) { } std::cout << "write to: " << outputFile << std::endl; - boost::iostreams::stream file(outputFile); + bfs::ofstream file((bfs::path(outputFile))); importer.writeToFile(file, cfg); return 0; From 444a07c01b89b7eda8ae4346d821f65231d79d4d Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 18:12:13 +0400 Subject: [PATCH 17/31] workaround OgreLog Unicode path handling --- components/ogreinit/ogreinit.cpp | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index 01b8764c2..5827645f5 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -1,11 +1,15 @@ #include "ogreinit.hpp" #include +#include +#include +#include #include #include #include #include +#include #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE #include @@ -13,8 +17,47 @@ #include +#include +#include + #include "ogreplugin.hpp" +namespace bfs = boost::filesystem; + +namespace +{ + class LogListener : public Ogre::LogListener + { + bfs::ofstream file; + char buffer[16]; + + + public: + + LogListener(const std::string &path) + : file((bfs::path(path))) + { + memset(buffer, sizeof(buffer), 0); + } + + void timestamp() + { + int local = time(0) % 86400; + int sec = local % 60; + int min = (local / 60) % 60; + int hrs = local / 3600; + sprintf(buffer, "%02d:%02d:%02d: ", hrs, min, sec); + } + + virtual void messageLogged(const std::string &msg, Ogre::LogMessageLevel lvl, bool mask, const std::string &logName, bool &skip) + { + timestamp(); + file << buffer << msg << std::endl; + skip = true; + } + }; +} + namespace OgreInit { @@ -43,6 +86,10 @@ namespace OgreInit new Ogre::LogManager; Ogre::Log *log = Ogre::LogManager::getSingleton().createLog(logPath); + #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + log->addListener(new LogListener(logPath)); + #endif + // Disable logging to cout/cerr log->setDebugOutputEnabled(false); From 86a89663066f20b65a40293eddf85fdb97c24717 Mon Sep 17 00:00:00 2001 From: greye Date: Mon, 19 May 2014 22:56:40 +0400 Subject: [PATCH 18/31] manual screenshot creation and uploading (scrawl) --- libs/openengine/ogre/renderer.cpp | 35 ++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index caf62546e..ae0d477d2 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -15,6 +15,9 @@ #include +#include +#include + #include #include @@ -48,7 +51,37 @@ void OgreRenderer::update(float dt) void OgreRenderer::screenshot(const std::string &file) { - mWindow->writeContentsToFile(file); + namespace bfs = boost::filesystem; + bfs::ofstream out((bfs::path(file))); + + Ogre::Image image; + + Ogre::PixelFormat pf = mWindow->suggestPixelFormat(); + int w = mWindow->getWidth(); + int h = mWindow->getHeight(); + + image.loadDynamicImage( + OGRE_ALLOC_T(Ogre::uchar, w * h * Ogre::PixelUtil::getNumElemBytes(pf), Ogre::MEMCATEGORY_GENERAL), + w, h, 1, pf, true + ); + mWindow->copyContentsToMemory(image.getPixelBox()); + + Ogre::DataStreamPtr stream = image.encode("png"); + Ogre::MemoryDataStream *mem = dynamic_cast(stream.get()); + if (mem != 0) { // likely + const char *ptr = reinterpret_cast(mem->getCurrentPtr()); + out.write(ptr, mem->size()); + } + else { + char buf[4096]; + size_t size = stream->size(); + while (size > 0) { + size_t chunk = (size > sizeof(buf)) ? sizeof(buf) : size; + stream->read(buf, chunk); + out.write(buf, chunk); + size -= chunk; + } + } } float OgreRenderer::getFPS() From 130349e0cd044b3972920380f81655cb6d6ed93f Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 20 May 2014 08:14:29 +0400 Subject: [PATCH 19/31] open files in binary mode when necessary --- apps/opencs/model/doc/savingstages.cpp | 4 +++- libs/openengine/ogre/renderer.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 34d93c49a..066c76734 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -27,7 +27,9 @@ void CSMDoc::OpenSaveStage::perform (int stage, Messages& messages) { mState.start (mDocument, mProjectFile); - mState.getStream().open (mProjectFile ? mState.getPath() : mState.getTmpPath()); + mState.getStream().open ( + mProjectFile ? mState.getPath() : mState.getTmpPath(), + std::ios::binary); if (!mState.getStream().is_open()) throw std::runtime_error ("failed to open stream for saving"); diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index ae0d477d2..64d65ea0d 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -52,7 +52,7 @@ void OgreRenderer::update(float dt) void OgreRenderer::screenshot(const std::string &file) { namespace bfs = boost::filesystem; - bfs::ofstream out((bfs::path(file))); + bfs::ofstream out(bfs::path(file), std::ios::binary); Ogre::Image image; From a46662043ad1f0eab2c0fb9b8c877a067b96815e Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 20 May 2014 09:17:32 +0400 Subject: [PATCH 20/31] tinyxml convert path to UTF-16 on Windows --- extern/oics/tinyxml.cpp | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/extern/oics/tinyxml.cpp b/extern/oics/tinyxml.cpp index 29a4768aa..2cd42eb30 100644 --- a/extern/oics/tinyxml.cpp +++ b/extern/oics/tinyxml.cpp @@ -31,18 +31,33 @@ distribution. #include "tinyxml.h" +#ifdef _WIN32 +#include +#endif + bool TiXmlBase::condenseWhiteSpace = true; // Microsoft compiler security FILE* TiXmlFOpen( const char* filename, const char* mode ) { - #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + #if defined(_WIN32) FILE* fp = 0; - errno_t err = fopen_s( &fp, filename, mode ); - if ( !err && fp ) - return fp; - return 0; + size_t len = strlen(filename); + wchar_t *wname = new wchar_t[len] + wchar_t wmode[32] = { 0 }; + + MultiByteToWideChar(CP_UTF8, 0, filename, len, wname, len); + MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, sizeof(wmode) / sizeof(*wmode)); + + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + errno_t err = _wfopen_s( &fp, wname, wmode ); + #else + fp = _wfopen(wname, wmode) + #endif + delete[] wname; + + return fp; #else return fopen( filename, mode ); #endif From 46c32f6c4753fe7c04ab3e598784d52625de314e Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 20 May 2014 10:37:04 +0400 Subject: [PATCH 21/31] OpenEngine MyGUI logging facility --- CMakeLists.txt | 1 + libs/openengine/gui/loglistener.cpp | 39 +++++++++++++++++++++++++++++ libs/openengine/gui/loglistener.hpp | 35 ++++++++++++++++++++++++++ libs/openengine/gui/manager.cpp | 39 +++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 2 ++ 5 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 libs/openengine/gui/loglistener.cpp create mode 100644 libs/openengine/gui/loglistener.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8179021a4..9abd6ac3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,6 +129,7 @@ set(OENGINE_OGRE ) set(OENGINE_GUI + ${LIBDIR}/openengine/gui/loglistener.cpp ${LIBDIR}/openengine/gui/manager.cpp ${LIBDIR}/openengine/gui/layout.hpp ) diff --git a/libs/openengine/gui/loglistener.cpp b/libs/openengine/gui/loglistener.cpp new file mode 100644 index 000000000..da36b90a2 --- /dev/null +++ b/libs/openengine/gui/loglistener.cpp @@ -0,0 +1,39 @@ +#include "loglistener.hpp" + +#include +#include + +#include + +namespace MyGUI +{ + void CustomLogListener::open() + { + mStream.open(boost::filesystem::path(mFileName), std::ios_base::out); + } + + void CustomLogListener::close() + { + if (mStream.is_open()) + mStream.close(); + } + + void CustomLogListener::flush() + { + if (mStream.is_open()) + mStream.flush(); + } + + void CustomLogListener::log(const std::string& _section, LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line) + { + if (mStream.is_open()) + { + const char* separator = " | "; + mStream << std::setw(2) << std::setfill('0') << _time->tm_hour << ":" + << std::setw(2) << std::setfill('0') << _time->tm_min << ":" + << std::setw(2) << std::setfill('0') << _time->tm_sec << separator + << _section << separator << _level.print() << separator + << _message << separator << _file << separator << _line << std::endl; + } + } +} diff --git a/libs/openengine/gui/loglistener.hpp b/libs/openengine/gui/loglistener.hpp new file mode 100644 index 000000000..20f23cf0c --- /dev/null +++ b/libs/openengine/gui/loglistener.hpp @@ -0,0 +1,35 @@ +#ifndef OPENENGINE_MYGUI_LOGLISTENER_H +#define OPENENGINE_MYGUI_LOGLISTENER_H + +#include +#include + +#include + +namespace MyGUI +{ + class CustomLogListener : public ILogListener + { + public: + CustomLogListener(const std::string &name) + : mFileName(name) + {} + + ~CustomLogListener() {} + + virtual void open(); + virtual void close(); + virtual void flush(); + + virtual void log(const std::string& _section, LogLevel _level, const struct tm* _time, const std::string& _message, const char* _file, int _line); + + const std::string& getFileName() const { return mFileName; } + + private: + boost::filesystem::ofstream mStream; + std::string mFileName; + }; + +} + +#endif diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index 91937d24b..fa7419b32 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -1,9 +1,14 @@ #include "manager.hpp" +#include "loglistener.hpp" #include #include #include +#include +#include +#include + #include #include @@ -554,8 +559,32 @@ public: } }; -} +class LogFacility +{ + ConsoleLogListener mConsole; + CustomLogListener mFile; + LevelLogFilter mFilter; + LogSource mSource; + +public: + + LogFacility(const std::string &output, bool console) + : mFile(output) + { + mConsole.setEnabled(console); + mFilter.setLoggingLevel(LogLevel::Info); + mSource.addLogListener(&mFile); + mSource.addLogListener(&mConsole); + mSource.setLogFilter(&mFilter); + + mSource.open(); + } + + LogSource *getSource() { return &mSource; } +}; + +} void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) { @@ -586,10 +615,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); - LogManager::getInstance().setSTDOutputEnabled(logging); - - if (!theLogFile.empty()) - LogManager::getInstance().createDefaultSource(theLogFile); + mLogFacility = new MyGUI::LogFacility(theLogFile, logging); + LogManager::getInstance().addLogSource(mLogFacility->getSource()); if (mShaderRenderManager) mShaderRenderManager->initialise(wnd, mgr); @@ -648,5 +675,7 @@ void MyGUIManager::shutdown() delete mLogManager; mLogManager = NULL; } + delete mLogFacility; + mGui = NULL; } diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index cca70dfcf..8923a5cc8 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -10,6 +10,7 @@ namespace MyGUI class OgreDataManager; class OgreRenderManager; class ShaderBasedRenderManager; + class LogFacility; } namespace Ogre @@ -25,6 +26,7 @@ namespace GUI { MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; + MyGUI::LogFacility* mLogFacility; MyGUI::OgreDataManager* mDataManager; MyGUI::OgreRenderManager* mRenderManager; MyGUI::ShaderBasedRenderManager* mShaderRenderManager; From 9dbe3f21d987ba307498351fb8437058d43776dd Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 20 May 2014 10:42:21 +0400 Subject: [PATCH 22/31] keep non-const signature for argv after conversion --- apps/mwiniimporter/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index d9c1454fc..a4e5cad4d 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -31,7 +31,7 @@ public: } ~utf8argv() { delete[] argv; } - const char * const *get() const { return argv; } + char **get() const { return const_cast(argv); } private: From 1b7ed98325e6e3b4f43d0b08a6956963d8af3820 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 20 May 2014 12:41:45 +0400 Subject: [PATCH 23/31] fix typos, reset memory before using --- extern/oics/tinyxml.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extern/oics/tinyxml.cpp b/extern/oics/tinyxml.cpp index 2cd42eb30..5be99f166 100644 --- a/extern/oics/tinyxml.cpp +++ b/extern/oics/tinyxml.cpp @@ -44,7 +44,8 @@ FILE* TiXmlFOpen( const char* filename, const char* mode ) #if defined(_WIN32) FILE* fp = 0; size_t len = strlen(filename); - wchar_t *wname = new wchar_t[len] + wchar_t *wname = new wchar_t[len + 1]; + memset(wname, 0, sizeof(*wname) * (len + 1)); wchar_t wmode[32] = { 0 }; MultiByteToWideChar(CP_UTF8, 0, filename, len, wname, len); @@ -53,7 +54,7 @@ FILE* TiXmlFOpen( const char* filename, const char* mode ) #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) errno_t err = _wfopen_s( &fp, wname, wmode ); #else - fp = _wfopen(wname, wmode) + fp = _wfopen(wname, wmode); #endif delete[] wname; From b728a919a2089272a853bf8f31d84e71f3c05915 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 20 May 2014 12:59:58 +0400 Subject: [PATCH 24/31] write dependency on boost::locale to CMake files --- CMakeLists.txt | 2 +- apps/opencs/CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9abd6ac3f..e4d8d1b9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,7 @@ if (HAVE_UNORDERED_MAP) endif () -set(BOOST_COMPONENTS system filesystem program_options) +set(BOOST_COMPONENTS system filesystem program_options locale) IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 35551f97b..6141790a8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -144,7 +144,7 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -set(BOOST_COMPONENTS system filesystem program_options thread wave) +set(BOOST_COMPONENTS system filesystem program_options thread wave locale) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e791ab891..cf72cc732 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,7 @@ add_openmw_dir (mwbase ) # Main executable -set(BOOST_COMPONENTS system filesystem program_options thread wave) +set(BOOST_COMPONENTS system filesystem program_options thread wave locale) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) IF(OGRE_STATIC) From 4346e3b4d09e84aa7f15b2df06b68ed8a08d1541 Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 20 May 2014 21:42:51 +0400 Subject: [PATCH 25/31] try to load plugins from relative paths --- components/ogreinit/ogreinit.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index 5827645f5..44d5fe3d5 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -188,11 +188,6 @@ namespace OgreInit pluginDir = OGRE_PLUGIN_DIR_REL; #endif } - - boost::filesystem::path absPluginPath = boost::filesystem::absolute(boost::filesystem::path(pluginDir)); - - pluginDir = absPluginPath.string(); - Files::loadOgrePlugin(pluginDir, "RenderSystem_GL", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_GLES2", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); From 8b94e310623a2b54fd2ae8488d0dac5f0ff55f25 Mon Sep 17 00:00:00 2001 From: greye Date: Wed, 21 May 2014 15:39:58 +0400 Subject: [PATCH 26/31] try to set relative path to resources --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 66c09b6ff..27739fd26 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -236,7 +236,7 @@ void OMW::Engine::addArchive (const std::string& archive) { // Set resource dir void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir) { - mResDir = boost::filesystem::system_complete(parResDir); + mResDir = parResDir; } // Set start cell name (only interiors for now) From 3721174ae433d530bb872fc4b2c70df37c1ac239 Mon Sep 17 00:00:00 2001 From: greye Date: Wed, 21 May 2014 23:50:58 +0400 Subject: [PATCH 27/31] proof-of-concept boost::wave iteration policy --- extern/shiny/Main/Preprocessor.cpp | 46 +++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/extern/shiny/Main/Preprocessor.cpp b/extern/shiny/Main/Preprocessor.cpp index 1a97668bc..bc2957da1 100644 --- a/extern/shiny/Main/Preprocessor.cpp +++ b/extern/shiny/Main/Preprocessor.cpp @@ -4,6 +4,50 @@ #include #include +#include + +namespace boost { +namespace wave { +namespace iteration_context_policies { + + struct load_utf8_path_to_string + { + template + class inner + { + public: + template + static void init_iterators(IterContextT &iter_ctx, + PositionT const &act_pos, language_support language) + { + typedef typename IterContextT::iterator_type iterator_type; + namespace bfs = boost::filesystem; + + // read in the file + bfs::ifstream instream(bfs::path(iter_ctx.filename.c_str())); + if (!instream.is_open()) { + BOOST_WAVE_THROW_CTX(iter_ctx.ctx, preprocess_exception, + bad_include_file, iter_ctx.filename.c_str(), act_pos); + return; + } + instream.unsetf(std::ios::skipws); + + iter_ctx.instring.assign( + std::istreambuf_iterator(instream.rdbuf()), + std::istreambuf_iterator()); + + iter_ctx.first = iterator_type( + iter_ctx.instring.begin(), iter_ctx.instring.end(), + PositionT(iter_ctx.filename), language); + iter_ctx.last = iterator_type(); + } + + private: + std::string instring; + }; + }; +} } } + namespace sh { std::string Preprocessor::preprocess (std::string source, const std::string& includePath, std::vector definitions, const std::string& name) @@ -29,7 +73,7 @@ namespace sh // match the iterator type used during construction of the context // instance (see below). It is the type of the underlying input stream. typedef boost::wave::context context_type; From 28b59f40084368d85b4659908069e01f08583876 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 22 May 2014 01:08:03 +0400 Subject: [PATCH 28/31] process paths as UTF-8 in launcher --- apps/launcher/settings/gamesettings.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 0a09c5cc0..4ebdb715a 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -45,7 +45,8 @@ void Launcher::GameSettings::validatePaths() Files::PathContainer dataDirs; foreach (const QString &path, paths) { - dataDirs.push_back(Files::PathContainer::value_type(path.toStdString())); + QByteArray bytes = path.toUtf8(); + dataDirs.push_back(Files::PathContainer::value_type(std::string(bytes.constData(), bytes.length()))); } // Parse the data dirs to convert the tokenized paths From cb598f0455b15962fe9f818290acb7b8b31e3d22 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 22 May 2014 01:13:27 +0400 Subject: [PATCH 29/31] the same for data-local entry --- apps/launcher/settings/gamesettings.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/launcher/settings/gamesettings.cpp b/apps/launcher/settings/gamesettings.cpp index 4ebdb715a..2f3dd9a45 100644 --- a/apps/launcher/settings/gamesettings.cpp +++ b/apps/launcher/settings/gamesettings.cpp @@ -69,7 +69,8 @@ void Launcher::GameSettings::validatePaths() return; dataDirs.clear(); - dataDirs.push_back(Files::PathContainer::value_type(local.toStdString())); + QByteArray bytes = local.toUtf8(); + dataDirs.push_back(Files::PathContainer::value_type(std::string(bytes.constData(), bytes.length()))); mCfgMgr.processPaths(dataDirs); From 8f9091550e6097ebd456911889472446860c0033 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 22 May 2014 15:42:47 +0400 Subject: [PATCH 30/31] require boost::locale only on Windows --- CMakeLists.txt | 5 ++++- apps/mwiniimporter/main.cpp | 4 +++- apps/opencs/CMakeLists.txt | 6 +++++- apps/openmw/CMakeLists.txt | 6 +++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4d8d1b9f..b323d4759 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,10 @@ if (HAVE_UNORDERED_MAP) endif () -set(BOOST_COMPONENTS system filesystem program_options locale) +set(BOOST_COMPONENTS system filesystem program_options) +if(WIN32) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) +endif(WIN32) IF(BOOST_STATIC) set(Boost_USE_STATIC_LIBS ON) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index a4e5cad4d..e9e430275 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -15,6 +14,9 @@ namespace bfs = boost::filesystem; int main(int argc, char *argv[]) { #else +// Include on Windows only +#include + class utf8argv { public: diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 6141790a8..4576432e1 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -144,7 +144,11 @@ if(WIN32) set(QT_USE_QTMAIN TRUE) endif(WIN32) -set(BOOST_COMPONENTS system filesystem program_options thread wave locale) +set(BOOST_COMPONENTS system filesystem program_options thread wave) +if(WIN32) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) +endif(WIN32) + find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index cf72cc732..9e959a986 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -82,7 +82,11 @@ add_openmw_dir (mwbase ) # Main executable -set(BOOST_COMPONENTS system filesystem program_options thread wave locale) +set(BOOST_COMPONENTS system filesystem program_options thread wave) +if(WIN32) + set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) +endif(WIN32) + find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) IF(OGRE_STATIC) From 663d5c314e38df474899744cdabdce56d063f792 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 22 May 2014 16:35:57 +0400 Subject: [PATCH 31/31] be more verbose on change reasons --- apps/mwiniimporter/main.cpp | 7 +++++++ components/files/windowspath.cpp | 7 +++++++ components/ogreinit/ogreinit.cpp | 8 ++++++++ extern/oics/tinyxml.cpp | 2 +- extern/shiny/Main/Preprocessor.cpp | 9 +++++++++ libs/openengine/gui/loglistener.hpp | 2 ++ libs/openengine/gui/manager.cpp | 4 ++++ libs/openengine/ogre/renderer.cpp | 4 ++++ 8 files changed, 42 insertions(+), 1 deletion(-) diff --git a/apps/mwiniimporter/main.cpp b/apps/mwiniimporter/main.cpp index e9e430275..c2408a554 100644 --- a/apps/mwiniimporter/main.cpp +++ b/apps/mwiniimporter/main.cpp @@ -41,6 +41,13 @@ private: std::vector args; }; +/* The only way to pass Unicode on Winodws with CLI is to use wide + characters interface which presents UTF-16 encoding. The rest of + OpenMW application stack assumes UTF-8 encoding, therefore this + conversion. + + For boost::filesystem::path::imbue see components/files/windowspath.cpp +*/ int wmain(int argc, wchar_t *wargv[]) { utf8argv converter(argc, wargv); char **argv = converter.get(); diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 41240ae48..6b58304a0 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -27,6 +27,13 @@ namespace Files WindowsPath::WindowsPath(const std::string& application_name) : mName(application_name) { + /* Since on Windows boost::path.string() returns string of narrow + characters in local encoding, it is required to path::imbue() + with UTF-8 encoding (generated for empty name from boost::locale) + to handle Unicode in platform-agnostic way using std::string. + + See boost::filesystem and boost::locale reference for details. + */ boost::filesystem::path::imbue(boost::locale::generator().generate("")); } diff --git a/components/ogreinit/ogreinit.cpp b/components/ogreinit/ogreinit.cpp index 44d5fe3d5..77dbcb1ee 100644 --- a/components/ogreinit/ogreinit.cpp +++ b/components/ogreinit/ogreinit.cpp @@ -26,6 +26,13 @@ namespace bfs = boost::filesystem; namespace { + /** \brief Custom Ogre::LogListener interface implementation being + able to portably handle UTF-8 encoded path. + + Effectively this is used in conjunction with default listener, + but since on every message messageLogged() set 'skip' flag to + true, there should be no troubles sharing same file. + */ class LogListener : public Ogre::LogListener { bfs::ofstream file; @@ -87,6 +94,7 @@ namespace OgreInit Ogre::Log *log = Ogre::LogManager::getSingleton().createLog(logPath); #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 + // Use custom listener only on Windows log->addListener(new LogListener(logPath)); #endif diff --git a/extern/oics/tinyxml.cpp b/extern/oics/tinyxml.cpp index 5be99f166..21b2d9c9a 100644 --- a/extern/oics/tinyxml.cpp +++ b/extern/oics/tinyxml.cpp @@ -32,7 +32,7 @@ distribution. #include "tinyxml.h" #ifdef _WIN32 -#include +#include // import MultiByteToWideChar #endif diff --git a/extern/shiny/Main/Preprocessor.cpp b/extern/shiny/Main/Preprocessor.cpp index bc2957da1..c03879d46 100644 --- a/extern/shiny/Main/Preprocessor.cpp +++ b/extern/shiny/Main/Preprocessor.cpp @@ -6,6 +6,15 @@ #include +/* + Almost exact copy of load_file_to_string policy found in + boost::wave headers with the only change that it uses + boost::filesystem facility to handle UTF-8 paths used + throughout OpenMW (bfs::fstream, bfs::path). + + Original namespace is used due to required bost::wave + internal symbols. +*/ namespace boost { namespace wave { namespace iteration_context_policies { diff --git a/libs/openengine/gui/loglistener.hpp b/libs/openengine/gui/loglistener.hpp index 20f23cf0c..47978ba44 100644 --- a/libs/openengine/gui/loglistener.hpp +++ b/libs/openengine/gui/loglistener.hpp @@ -8,6 +8,8 @@ namespace MyGUI { + /// \brief Custom MyGUI::ILogListener interface implementation + /// being able to portably handle UTF-8 encoded path. class CustomLogListener : public ILogListener { public: diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index fa7419b32..383d37640 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ public: } }; +/// \brief Helper class holding data that required during +/// MyGUI log creation class LogFacility { ConsoleLogListener mConsole; @@ -615,6 +617,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); + // Do not use default log since it don't support Unicode path on Windows. + // Instead, manually create log source using LogFacility and pass it. mLogFacility = new MyGUI::LogFacility(theLogFile, logging); LogManager::getInstance().addLogSource(mLogFacility->getSource()); diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 64d65ea0d..8fcf615ba 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -51,6 +51,10 @@ void OgreRenderer::update(float dt) void OgreRenderer::screenshot(const std::string &file) { + /* Since Ogre uses narrow character interfaces, it does not support + Unicode paths on Windows. Therefore we had to implement screenshot + saving manually. + */ namespace bfs = boost::filesystem; bfs::ofstream out(bfs::path(file), std::ios::binary);