Replace implicit convertions from std::filesystem::path to std::string with correctly converting functions.

crashfix_debugdraw
Project579 3 years ago
parent 4d47e8d055
commit a13709c510

@ -9,6 +9,7 @@
#include <components/bsa/compressedbsafile.hpp> #include <components/bsa/compressedbsafile.hpp>
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp>
#define BSATOOL_VERSION 1.1 #define BSATOOL_VERSION 1.1
@ -179,17 +180,17 @@ int list(std::unique_ptr<File>& bsa, Arguments& info)
template<typename File> template<typename File>
int extract(std::unique_ptr<File>& bsa, Arguments& info) int extract(std::unique_ptr<File>& bsa, Arguments& info)
{ {
std::string archivePath = info.extractfile.string(); //TODO(Project579): This will probably break in windows with unicode paths auto archivePath = info.extractfile.u8string();
Misc::StringUtils::replaceAll(archivePath, "/", "\\"); Misc::StringUtils::replaceAll(archivePath, u8"/", u8"\\");
std::string extractPath = info.extractfile.string(); //TODO(Project579): This will probably break in windows with unicode paths auto extractPath = info.extractfile.u8string();
Misc::StringUtils::replaceAll(extractPath, "\\", "/"); Misc::StringUtils::replaceAll(extractPath, u8"\\", u8"/");
Files::IStreamPtr stream; Files::IStreamPtr stream;
// Get a stream for the file to extract // Get a stream for the file to extract
for (auto it = bsa->getList().rbegin(); it != bsa->getList().rend(); ++it) for (auto it = bsa->getList().rbegin(); it != bsa->getList().rend(); ++it)
{ {
if (Misc::StringUtils::ciEqual(std::string(it->name()), archivePath)) if (Misc::StringUtils::ciEqual(Misc::StringUtils::stringToU8String(it->name()), archivePath))
{ {
stream = bsa->getFile(&*it); stream = bsa->getFile(&*it);
break; break;
@ -197,8 +198,8 @@ int extract(std::unique_ptr<File>& bsa, Arguments& info)
} }
if (!stream) if (!stream)
{ {
std::cout << "ERROR: file '" << archivePath << "' not found\n"; std::cout << "ERROR: file '" << Misc::StringUtils::u8StringToString(archivePath) << "' not found\n";
std::cout << "In archive: " << info.filename << std::endl; std::cout << "In archive: " << Files::pathToUnicodeString(info.filename) << std::endl;
return 3; return 3;
} }
@ -217,14 +218,14 @@ int extract(std::unique_ptr<File>& bsa, Arguments& info)
std::filesystem::file_status s = std::filesystem::status(target.parent_path()); std::filesystem::file_status s = std::filesystem::status(target.parent_path());
if (!std::filesystem::is_directory(s)) if (!std::filesystem::is_directory(s))
{ {
std::cout << "ERROR: " << target.parent_path() << " is not a directory." << std::endl; std::cout << "ERROR: " << Files::pathToUnicodeString(target.parent_path()) << " is not a directory." << std::endl;
return 3; return 3;
} }
std::ofstream out(target, std::ios::binary); std::ofstream out(target, std::ios::binary);
// Write the file to disk // Write the file to disk
std::cout << "Extracting " << info.extractfile << " to " << target << std::endl; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "Extracting " << Files::pathToUnicodeString(info.extractfile) << " to " << Files::pathToUnicodeString(target) << std::endl;
out << stream->rdbuf(); out << stream->rdbuf();
out.close(); out.close();
@ -271,7 +272,7 @@ template<typename File>
int add(std::unique_ptr<File>& bsa, Arguments& info) int add(std::unique_ptr<File>& bsa, Arguments& info)
{ {
std::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in); std::fstream stream(info.addfile, std::ios_base::binary | std::ios_base::out | std::ios_base::in);
bsa->addFile(info.addfile.string(), stream); //TODO(Project579): This will probably break in windows with unicode paths bsa->addFile(Files::pathToUnicodeString(info.addfile), stream);
return 0; return 0;
} }

@ -33,7 +33,6 @@ namespace
namespace bpo = boost::program_options; namespace bpo = boost::program_options;
using StringsVector = std::vector<std::string>; using StringsVector = std::vector<std::string>;
using PathsVector = std::vector<std::filesystem::path>;
bpo::options_description makeOptionsDescription() bpo::options_description makeOptionsDescription()
{ {
@ -146,7 +145,7 @@ namespace
const auto fsStrict = variables["fs-strict"].as<bool>(); const auto fsStrict = variables["fs-strict"].as<bool>();
const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>(); const auto resDir = variables["resources"].as<Files::MaybeQuotedPath>();
Version::Version v = Version::getOpenmwVersion(resDir); const auto v = Version::getOpenmwVersion(resDir);
Log(Debug::Info) << v.describe(); Log(Debug::Info) << v.describe();
dataDirs.insert(dataDirs.begin(), resDir / "vfs"); dataDirs.insert(dataDirs.begin(), resDir / "vfs");
const auto fileCollections = Files::Collections(dataDirs, !fsStrict); const auto fileCollections = Files::Collections(dataDirs, !fsStrict);

@ -18,6 +18,7 @@
#include <components/files/openfile.hpp> #include <components/files/openfile.hpp>
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp>
#include "record.hpp" #include "record.hpp"
#include "labels.hpp" #include "labels.hpp"
@ -288,7 +289,7 @@ void loadCell(const Arguments& info, ESM::Cell &cell, ESM::ESMReader &esm, ESMDa
void printRawTes3(const std::filesystem::path &path) void printRawTes3(const std::filesystem::path &path)
{ {
std::cout << "TES3 RAW file listing: " << path << '\n'; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "TES3 RAW file listing: " << path << '\n';
ESM::ESMReader esm; ESM::ESMReader esm;
esm.openRaw(path); esm.openRaw(path);
while(esm.hasMoreRecs()) while(esm.hasMoreRecs())
@ -312,7 +313,7 @@ void printRawTes3(const std::filesystem::path &path)
int loadTes3(const Arguments& info, std::unique_ptr<std::ifstream>&& stream, ESMData* data) int loadTes3(const Arguments& info, std::unique_ptr<std::ifstream>&& stream, ESMData* data)
{ {
std::cout << "Loading TES3 file: " << info.filename << '\n'; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "Loading TES3 file: " << info.filename << '\n';
ESM::ESMReader esm; ESM::ESMReader esm;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
@ -421,7 +422,7 @@ int load(const Arguments& info, ESMData* data)
printRawTes3(info.filename); printRawTes3(info.filename);
break; break;
case ESM::Format::Tes4: case ESM::Format::Tes4:
std::cout << "Printing raw TES4 file is not supported: " << info.filename << "\n"; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "Printing raw TES4 file is not supported: " << Files::pathToUnicodeString(info.filename) << "\n";
break; break;
} }
return 0; return 0;
@ -492,7 +493,7 @@ int clone(const Arguments& info)
if (i % 3 != 0) if (i % 3 != 0)
std::cout << '\n'; std::cout << '\n';
std::cout << "\nSaving records to: " << info.outname << "...\n"; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "\nSaving records to: " << Files::pathToUnicodeString(info.outname) << "...\n";
ESM::ESMWriter esm; ESM::ESMWriter esm;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding)); ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding(info.encoding));
@ -565,14 +566,14 @@ int comp(const Arguments& info)
ESMData dataOne; ESMData dataOne;
if (load(fileOne, &dataOne) != 0) if (load(fileOne, &dataOne) != 0)
{ {
std::cout << "Failed to load " << info.filename << ", aborting comparison." << std::endl; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "Failed to load " << Files::pathToUnicodeString(info.filename) << ", aborting comparison." << std::endl;
return 1; return 1;
} }
ESMData dataTwo; ESMData dataTwo;
if (load(fileTwo, &dataTwo) != 0) if (load(fileTwo, &dataTwo) != 0)
{ {
std::cout << "Failed to load " << info.outname << ", aborting comparison." << std::endl; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "Failed to load " << Files::pathToUnicodeString(info.outname) << ", aborting comparison." << std::endl;
return 1; return 1;
} }

@ -289,7 +289,7 @@ namespace EsmTool
int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream) int loadTes4(const Arguments& info, std::unique_ptr<std::ifstream>&& stream)
{ {
std::cout << "Loading TES4 file: " << info.filename << '\n'; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "Loading TES4 file: " << info.filename << '\n';
try try
{ {

@ -230,9 +230,9 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
if (!mDataLocal.isEmpty()) if (!mDataLocal.isEmpty())
directories.insert(0, mDataLocal); directories.insert(0, mDataLocal);
const auto globalDataDir = QString(mGameSettings.getGlobalDataDir().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths const auto& globalDataDir = mGameSettings.getGlobalDataDir();
if (!globalDataDir.isEmpty()) if (!globalDataDir.empty())
directories.insert(0, globalDataDir); directories.insert(0, QString::fromStdWString(globalDataDir.wstring()));
// normalize user supplied directories: resolve symlink, convert to native separator, make absolute // normalize user supplied directories: resolve symlink, convert to native separator, make absolute
for (auto& currentDir : directories) for (auto& currentDir : directories)
@ -264,7 +264,7 @@ void Launcher::DataFilesPage::populateFileViews(const QString& contentModelName)
} }
// deactivate data-local and global data directory: they are always included // deactivate data-local and global data directory: they are always included
if (currentDir == mDataLocal || currentDir == globalDataDir) if (currentDir == mDataLocal || std::filesystem::path(currentDir.toStdWString()) == globalDataDir)
{ {
auto flags = item->flags(); auto flags = item->flags();
item->setFlags(flags & ~(Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled)); item->setFlags(flags & ~(Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled));

@ -12,6 +12,7 @@
#include <boost/program_options/options_description.hpp> #include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp> #include <boost/program_options/variables_map.hpp>
#include <components/files/conversion.hpp>
#include "playpage.hpp" #include "playpage.hpp"
#include "graphicspage.hpp" #include "graphicspage.hpp"
@ -155,14 +156,14 @@ Launcher::FirstRunDialogResult Launcher::MainDialog::showFirstRunDialog()
return FirstRunDialogResultFailure; return FirstRunDialogResultFailure;
// Dialog wizard and setup will fail if the config directory does not already exist // Dialog wizard and setup will fail if the config directory does not already exist
QDir userConfigDir = QDir(QString::fromStdString(mCfgMgr.getUserConfigPath().string())); //TODO(Project579): This will probably break in windows with unicode paths, in Qt 6 it's possible to convert directly from std::filesystem::path to QDir and that would solve the issue const auto& userConfigDir = mCfgMgr.getUserConfigPath();
if ( ! userConfigDir.exists() ) { if ( ! exists(userConfigDir) ) {
if ( ! userConfigDir.mkpath(".") ) if ( ! create_directory(userConfigDir) )
{ {
cfgError(tr("Error opening OpenMW configuration file"), cfgError(tr("Error opening OpenMW configuration file"),
tr("<br><b>Could not create directory %0</b><br><br> \ tr("<br><b>Could not create directory %0</b><br><br> \
Please make sure you have the right permissions \ Please make sure you have the right permissions \
and try again.<br>").arg(userConfigDir.canonicalPath()) and try again.<br>").arg(QString::fromStdWString(canonical(userConfigDir).wstring()))
); );
return FirstRunDialogResultFailure; return FirstRunDialogResultFailure;
} }
@ -295,7 +296,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
mLauncherSettings.setMultiValueEnabled(true); mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QString userPath = QString::fromStdWString(mCfgMgr.getUserConfigPath().wstring());
QStringList paths; QStringList paths;
paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName)); paths.append(QString(Config::LauncherSettings::sLauncherConfigFileName));
@ -328,9 +329,9 @@ bool Launcher::MainDialog::setupGameSettings()
{ {
mGameSettings.clear(); mGameSettings.clear();
QString localPath = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QString localPath = QString::fromStdWString(mCfgMgr.getLocalPath().wstring());
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QString userPath = QString::fromStdWString(mCfgMgr.getUserConfigPath().wstring());
QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QString globalPath = QString::fromStdWString(mCfgMgr.getGlobalPath().wstring());
QFile file; QFile file;
@ -479,21 +480,20 @@ bool Launcher::MainDialog::writeSettings()
mSettingsPage->saveSettings(); mSettingsPage->saveSettings();
mAdvancedPage->saveSettings(); mAdvancedPage->saveSettings();
QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths const auto& userPath = mCfgMgr.getUserConfigPath();
QDir dir(userPath);
if (!dir.exists()) { if (!exists(userPath)) {
if (!dir.mkpath(userPath)) { if (!create_directory(userPath)) {
cfgError(tr("Error creating OpenMW configuration directory"), cfgError(tr("Error creating OpenMW configuration directory"),
tr("<br><b>Could not create %0</b><br><br> \ tr("<br><b>Could not create %0</b><br><br> \
Please make sure you have the right permissions \ Please make sure you have the right permissions \
and try again.<br>").arg(userPath)); and try again.<br>").arg(QString::fromStdWString(userPath.wstring())));
return false; return false;
} }
} }
// Game settings // Game settings
QFile file(userPath + QString("openmw.cfg")); QFile file(QString::fromStdWString((userPath / "openmw.cfg").wstring()));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) { if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
// File cannot be opened or created // File cannot be opened or created
@ -515,13 +515,13 @@ bool Launcher::MainDialog::writeSettings()
} }
catch (std::exception& e) { catch (std::exception& e) {
std::string msg = "<br><b>Error writing settings.cfg</b><br><br>" + std::string msg = "<br><b>Error writing settings.cfg</b><br><br>" +
settingsPath.string() + "<br><br>" + e.what(); //TODO(Project579): This will probably break in windows with unicode paths Files::pathToUnicodeString(settingsPath) + "<br><br>" + e.what();
cfgError(tr("Error writing user settings file"), tr(msg.c_str())); cfgError(tr("Error writing user settings file"), tr(msg.c_str()));
return false; return false;
} }
// Launcher settings // Launcher settings
file.setFileName(userPath + QString(Config::LauncherSettings::sLauncherConfigFileName)); file.setFileName(QString::fromStdWString((userPath / Config::LauncherSettings::sLauncherConfigFileName).wstring()));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) {
// File cannot be opened or created // File cannot be opened or created

@ -102,9 +102,9 @@ void Launcher::SettingsPage::on_importerButton_clicked()
mMain->writeSettings(); mMain->writeSettings();
// Create the file if it doesn't already exist, else the importer will fail // Create the file if it doesn't already exist, else the importer will fail
QString path(QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str())); //TODO(Project579): This will probably break in windows with unicode paths auto path = mCfgMgr.getUserConfigPath();
path.append(QLatin1String("openmw.cfg")); path /= "openmw.cfg";
QFile file(path); QFile file(QString::fromStdWString(path.wstring()));
if (!file.exists()) { if (!file.exists()) {
if (!file.open(QIODevice::ReadWrite)) { if (!file.open(QIODevice::ReadWrite)) {
@ -137,7 +137,7 @@ void Launcher::SettingsPage::on_importerButton_clicked()
arguments.append(QString("--ini")); arguments.append(QString("--ini"));
arguments.append(settingsComboBox->currentText()); arguments.append(settingsComboBox->currentText());
arguments.append(QString("--cfg")); arguments.append(QString("--cfg"));
arguments.append(path); arguments.append(QString::fromStdWString(path.wstring()));
qDebug() << "arguments " << arguments; qDebug() << "arguments " << arguments;

@ -8,6 +8,7 @@
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/misc/timeconvert.hpp> #include <components/misc/timeconvert.hpp>
#include <components/files/conversion.hpp>
@ -944,7 +945,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini, co
{ {
dependencies.push_back(gameFile.name); dependencies.push_back(gameFile.name);
} }
unsortedFiles.emplace_back(reader.getName().filename().string(), dependencies); //TODO(Project579): This will probably break in windows with unicode paths unsortedFiles.emplace_back(Files::pathToUnicodeString(reader.getName().filename()), dependencies);
reader.close(); reader.close();
} }

@ -24,6 +24,7 @@
#include <components/esm3/readerscache.hpp> #include <components/esm3/readerscache.hpp>
#include <components/platform/platform.hpp> #include <components/platform/platform.hpp>
#include <components/detournavigator/agentbounds.hpp> #include <components/detournavigator/agentbounds.hpp>
#include <components/files/conversion.hpp>
#include <osg/Vec3f> #include <osg/Vec3f>
@ -179,9 +180,9 @@ namespace NavMeshTool
const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game"); const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game");
const DetourNavigator::AgentBounds agentBounds {agentCollisionShape, agentHalfExtents}; const DetourNavigator::AgentBounds agentBounds {agentCollisionShape, agentHalfExtents};
const std::uint64_t maxDbFileSize = static_cast<std::uint64_t>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator")); const std::uint64_t maxDbFileSize = static_cast<std::uint64_t>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
const auto dbPath = config.getUserDataPath() / "navmesh.db"; const auto dbPath = Files::pathToUnicodeString(config.getUserDataPath() / "navmesh.db");
DetourNavigator::NavMeshDb db(dbPath.string(), maxDbFileSize); //TODO(Project579): This will probably break in windows with unicode paths DetourNavigator::NavMeshDb db(dbPath, maxDbFileSize);
ESM::ReadersCache readers; ESM::ReadersCache readers;
EsmLoader::Query query; EsmLoader::Query query;

@ -10,6 +10,7 @@
#include <components/vfs/bsaarchive.hpp> #include <components/vfs/bsaarchive.hpp>
#include <components/vfs/filesystemarchive.hpp> #include <components/vfs/filesystemarchive.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
@ -19,7 +20,7 @@ namespace bpo = boost::program_options;
///See if the file has the named extension ///See if the file has the named extension
bool hasExtension(const std::filesystem::path& filename, const std::string& extensionToFind) bool hasExtension(const std::filesystem::path& filename, const std::string& extensionToFind)
{ {
std::string extension = filename.extension().string(); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break const auto extension = Files::pathToUnicodeString(filename.extension());
return Misc::StringUtils::ciEqual(extension, extensionToFind); return Misc::StringUtils::ciEqual(extension, extensionToFind);
} }
@ -42,7 +43,7 @@ void readVFS(std::unique_ptr<VFS::Archive>&& anArchive, const std::filesystem::p
myManager.addArchive(std::move(anArchive)); myManager.addArchive(std::move(anArchive));
myManager.buildIndex(); myManager.buildIndex();
for(const auto& name : myManager.getRecursiveDirectoryIterator("")) //TODO(Project579): This will probably break in windows with unicode paths for(const auto& name : myManager.getRecursiveDirectoryIterator(""))
{ {
try{ try{
if(isNIF(name)) if(isNIF(name))
@ -142,7 +143,7 @@ int main(int argc, char **argv)
} }
else else
{ {
std::cerr << "ERROR: \"" << path << "\" is not a nif file, bsa file, or directory!" << std::endl; //TODO(Project579): This will probably break in windows with unicode paths std::cerr << "ERROR: \"" << Files::pathToUnicodeString(path) << "\" is not a nif file, bsa file, or directory!" << std::endl;
} }
} }
catch (std::exception& e) catch (std::exception& e)

@ -393,7 +393,7 @@ int CS::Editor::run()
} }
discoveredFiles.push_back(mFileToLoad); discoveredFiles.push_back(mFileToLoad);
QString extension = QString::fromStdString(mFileToLoad.extension().string()).toLower(); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break QString extension = QString::fromStdWString(mFileToLoad.extension().wstring()).toLower();
if (extension == ".esm") if (extension == ".esm")
{ {
mFileToLoad.replace_extension(".omwgame"); mFileToLoad.replace_extension(".omwgame");

@ -89,7 +89,7 @@ namespace CS
void cancelFileDialog(); void cancelFileDialog();
void loadDocument(); void loadDocument();
void openFiles (const std::filesystem::path &path, const std::vector<std::filesystem::path> &discoveredFiles = std::vector<std::filesystem::path>()); void openFiles (const std::filesystem::path &path, const std::vector<std::filesystem::path> &discoveredFiles = {});
void createNewFile (const std::filesystem::path& path); void createNewFile (const std::filesystem::path& path);
void createNewGame (const std::filesystem::path& file); void createNewGame (const std::filesystem::path& file);

@ -25,6 +25,6 @@ void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type,
list.resize (size+ids.size()); list.resize (size+ids.size());
std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase); std::transform (ids.begin(), ids.end(), list.begin()+size, [](const std::string& s) { return Misc::StringUtils::lowerCase(s); } );
std::sort (list.begin(), list.end()); std::sort (list.begin(), list.end());
} }

@ -5,6 +5,7 @@
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include <filesystem> #include <filesystem>
#include <utility>
#include "../world/defaultgmsts.hpp" #include "../world/defaultgmsts.hpp"
@ -13,7 +14,7 @@
#endif #endif
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <utility> #include <components/files/conversion.hpp>
void CSMDoc::Document::addGmsts() void CSMDoc::Document::addGmsts()
{ {
@ -294,11 +295,11 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (mNew || !std::filesystem::exists (mProjectPath)) if (mNew || !std::filesystem::exists (mProjectPath))
{ {
std::filesystem::path filtersPath (configuration.getUserDataPath() / "defaultfilters"); auto filtersPath = configuration.getUserDataPath() / "defaultfilters";
std::ofstream destination(mProjectPath, std::ios::out | std::ios::binary); std::ofstream destination(mProjectPath, std::ios::out | std::ios::binary);
if (!destination.is_open()) if (!destination.is_open())
throw std::runtime_error("Can not create project file: " + mProjectPath.string()); //TODO(Project579): This will probably break in windows with unicode paths throw std::runtime_error("Can not create project file: " + Files::pathToUnicodeString(mProjectPath));
destination.exceptions(std::ios::failbit | std::ios::badbit); destination.exceptions(std::ios::failbit | std::ios::badbit);
if (!std::filesystem::exists (filtersPath)) if (!std::filesystem::exists (filtersPath))
@ -306,7 +307,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
std::ifstream source(filtersPath, std::ios::in | std::ios::binary); std::ifstream source(filtersPath, std::ios::in | std::ios::binary);
if (!source.is_open()) if (!source.is_open())
throw std::runtime_error("Can not read filters file: " + filtersPath.string()); //TODO(Project579): This will probably break in windows with unicode paths throw std::runtime_error("Can not read filters file: " + Files::pathToUnicodeString(filtersPath));
source.exceptions(std::ios::failbit | std::ios::badbit); source.exceptions(std::ios::failbit | std::ios::badbit);
destination << source.rdbuf(); destination << source.rdbuf();
@ -480,11 +481,11 @@ bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id)
void CSMDoc::Document::startRunning (const std::string& profile, void CSMDoc::Document::startRunning (const std::string& profile,
const std::string& startupInstruction) const std::string& startupInstruction)
{ {
std::vector<std::string> contentFiles; std::vector<std::filesystem::path> contentFiles;
for (std::vector<std::filesystem::path>::const_iterator iter (mContentFiles.begin()); for (const auto & mContentFile : mContentFiles) {
iter!=mContentFiles.end(); ++iter) contentFiles.emplace_back(mContentFile.filename());
contentFiles.push_back (iter->filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break }
mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles, mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles,
startupInstruction); startupInstruction);

@ -1,5 +1,7 @@
#include "loader.hpp" #include "loader.hpp"
#include <components/files/conversion.hpp>
#include <iostream> #include <iostream>
#include "../tools/reportmodel.hpp" #include "../tools/reportmodel.hpp"
@ -93,7 +95,7 @@ void CSMDoc::Loader::load()
iter->second.mRecordsLeft = true; iter->second.mRecordsLeft = true;
iter->second.mRecordsLoaded = 0; iter->second.mRecordsLoaded = 0;
emit nextStage (document, path.filename().string(), steps); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break emit nextStage (document, Files::pathToUnicodeString(path.filename()), steps);
} }
else if (iter->second.mFile==size) // start loading the last (project) file else if (iter->second.mFile==size) // start loading the last (project) file
{ {

@ -83,18 +83,17 @@ void CSMDoc::Runner::start (bool delayed)
arguments << ("--script-run="+mStartup->fileName()); arguments << ("--script-run="+mStartup->fileName());
arguments << arguments <<
QString::fromUtf8 (("--data=\""+mProjectPath.parent_path().string()+"\"").c_str()); //TODO(Project579): This will probably break in windows with unicode paths QString::fromStdWString (L"--data=\""+mProjectPath.parent_path().wstring()+L"\"");
arguments << "--replace=content"; arguments << "--replace=content";
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin()); for (const auto & mContentFile : mContentFiles)
iter!=mContentFiles.end(); ++iter)
{ {
arguments << QString::fromUtf8 (("--content="+*iter).c_str()); arguments << QString::fromStdWString (L"--content="+mContentFile.wstring());
} }
arguments arguments
<< QString::fromUtf8 (("--content="+mProjectPath.filename().string()).c_str()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break << QString::fromStdWString (L"--content="+mProjectPath.filename().wstring());
mProcess.start (path, arguments); mProcess.start (path, arguments);
} }
@ -123,7 +122,7 @@ bool CSMDoc::Runner::isRunning() const
} }
void CSMDoc::Runner::configure (const ESM::DebugProfile& profile, void CSMDoc::Runner::configure (const ESM::DebugProfile& profile,
const std::vector<std::string>& contentFiles, const std::string& startupInstruction) const std::vector<std::filesystem::path> &contentFiles, const std::string& startupInstruction)
{ {
mProfile = profile; mProfile = profile;
mContentFiles = contentFiles; mContentFiles = contentFiles;

@ -25,7 +25,7 @@ namespace CSMDoc
QProcess mProcess; QProcess mProcess;
bool mRunning; bool mRunning;
ESM::DebugProfile mProfile; ESM::DebugProfile mProfile;
std::vector<std::string> mContentFiles; std::vector<std::filesystem::path> mContentFiles;
std::string mStartupInstruction; std::string mStartupInstruction;
QTemporaryFile *mStartup; QTemporaryFile *mStartup;
QTextDocument mLog; QTextDocument mLog;
@ -48,7 +48,7 @@ namespace CSMDoc
bool isRunning() const; bool isRunning() const;
void configure (const ESM::DebugProfile& profile, void configure (const ESM::DebugProfile& profile,
const std::vector<std::string>& contentFiles, const std::vector<std::filesystem::path> &contentFiles,
const std::string& startupInstruction); const std::string& startupInstruction);
QTextDocument *getLog(); QTextDocument *getLog();

@ -4,6 +4,7 @@
#include <filesystem> #include <filesystem>
#include <components/esm3/loaddial.hpp> #include <components/esm3/loaddial.hpp>
#include <components/files/conversion.hpp>
#include "../world/infocollection.hpp" #include "../world/infocollection.hpp"
#include "../world/cellcoordinates.hpp" #include "../world/cellcoordinates.hpp"
@ -72,8 +73,8 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages)
for (std::vector<std::filesystem::path>::const_iterator iter (dependencies.begin()); for (std::vector<std::filesystem::path>::const_iterator iter (dependencies.begin());
iter!=end; ++iter) iter!=end; ++iter)
{ {
std::string name = iter->filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break auto name = Files::pathToUnicodeString(iter->filename());
uint64_t size = std::filesystem::file_size (*iter); auto size = std::filesystem::file_size (*iter);
mState.getWriter().addMaster (name, size); mState.getWriter().addMaster (name, size);
} }

@ -95,7 +95,9 @@ void CSMWorld::CommandDispatcher::setEditLock (bool locked)
void CSMWorld::CommandDispatcher::setSelection (const std::vector<std::string>& selection) void CSMWorld::CommandDispatcher::setSelection (const std::vector<std::string>& selection)
{ {
mSelection = selection; mSelection = selection;
std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::lowerCaseInPlace); for (auto& sel : mSelection) {
Misc::StringUtils::lowerCaseInPlace(sel);
}
std::sort (mSelection.begin(), mSelection.end()); std::sort (mSelection.begin(), mSelection.end());
} }

@ -169,7 +169,9 @@ void CSMWorld::RegionMap::updateRegions (const std::vector<std::string>& regions
{ {
std::vector<std::string> regions2 (regions); std::vector<std::string> regions2 (regions);
std::for_each (regions2.begin(), regions2.end(), Misc::StringUtils::lowerCaseInPlace); for (auto& region2 : regions2) {
Misc::StringUtils::lowerCaseInPlace(region2);
}
std::sort (regions2.begin(), regions2.end()); std::sort (regions2.begin(), regions2.end());
for (std::map<CellCoordinates, CellDescription>::const_iterator iter (mMap.begin()); for (std::map<CellCoordinates, CellDescription>::const_iterator iter (mMap.begin());

@ -94,7 +94,9 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
{ {
mIds = mData.getIds(); mIds = mData.getIds();
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCaseInPlace); for (auto& id : mIds) {
Misc::StringUtils::lowerCaseInPlace(id);
}
std::sort (mIds.begin(), mIds.end()); std::sort (mIds.begin(), mIds.end());
mIdsUpdated = true; mIdsUpdated = true;

@ -68,12 +68,12 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
} }
else else
{ {
std::filesystem::path path (name.toUtf8().data()); //TODO(Project579): Replace with char8_t in C++20 std::filesystem::path path (name.toStdWString());
std::string extension = Misc::StringUtils::lowerCase(path.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break const auto extension = Misc::StringUtils::lowerCase(path.extension().u8string());
bool isLegacyPath = (extension == ".esm" || bool isLegacyPath = (extension == u8".esm" ||
extension == ".esp"); extension == u8".esp");
bool isFilePathChanged = (path.parent_path() != mLocalData); bool isFilePathChanged = (path.parent_path() != mLocalData);
@ -85,7 +85,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
if (!isFilePathChanged && !isLegacyPath) if (!isFilePathChanged && !isLegacyPath)
{ {
// path already points to the local data directory // path already points to the local data directory
message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); //TODO(Project579): This is probably broken on windows with unicode paths message = QString::fromStdWString (L"Will be saved as: " + path.wstring());
mResultPath = path; mResultPath = path;
} }
//in all other cases, ensure the path points to data-local and do an existing file check //in all other cases, ensure the path points to data-local and do an existing file check
@ -95,7 +95,7 @@ void CSVDoc::AdjusterWidget::setName (const QString& name, bool addon)
if (isFilePathChanged) if (isFilePathChanged)
path = mLocalData / path.filename(); path = mLocalData / path.filename();
message = QString::fromUtf8 (("Will be saved as: " + path.string()).c_str()); //TODO(Project579): This is probably broken on windows with unicode paths message = QString::fromStdWString (L"Will be saved as: " + path.wstring());
mResultPath = path; mResultPath = path;
if (std::filesystem::exists (path)) if (std::filesystem::exists (path))

@ -19,7 +19,7 @@ void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event)
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document) CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
: mDocument (document), mTotalRecordsLabel (0), mRecordsLabel (0), mAborted (false), mMessages (nullptr), mRecords(0) : mDocument (document), mTotalRecordsLabel (0), mRecordsLabel (0), mAborted (false), mMessages (nullptr), mRecords(0)
{ {
setWindowTitle (QString::fromUtf8((std::string("Opening ") + document->getSavePath().filename().string()).c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break setWindowTitle (QString::fromStdWString(L"Opening " + document->getSavePath().filename().wstring()));
setMinimumWidth (400); setMinimumWidth (400);

@ -30,6 +30,7 @@
#include <components/misc/helpviewer.hpp> #include <components/misc/helpviewer.hpp>
#include <components/version/version.hpp> #include <components/version/version.hpp>
#include <components/files/conversion.hpp>
#include "viewmanager.hpp" #include "viewmanager.hpp"
#include "operations.hpp" #include "operations.hpp"
@ -387,7 +388,7 @@ void CSVDoc::View::updateTitle()
{ {
std::ostringstream stream; std::ostringstream stream;
stream << mDocument->getSavePath().filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break stream << Files::pathToUnicodeString(mDocument->getSavePath().filename());
if (mDocument->getState() & CSMDoc::State_Modified) if (mDocument->getState() & CSMDoc::State_Modified)
stream << " *"; stream << " *";

@ -261,7 +261,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view)
QMessageBox messageBox(view); QMessageBox messageBox(view);
CSMDoc::Document *document = view->getDocument(); CSMDoc::Document *document = view->getDocument();
messageBox.setWindowTitle (QString::fromUtf8(document->getSavePath().filename().string().c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break messageBox.setWindowTitle (QString::fromStdWString(document->getSavePath().filename().wstring()));
messageBox.setText ("The document has been modified."); messageBox.setText ("The document has been modified.");
messageBox.setInformativeText ("Do you want to save your changes?"); messageBox.setInformativeText ("Do you want to save your changes?");
messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);

@ -102,7 +102,7 @@ void CSVTools::Merge::configure (CSMDoc::Document *document)
for (std::vector<std::filesystem::path>::const_iterator iter (files.begin()); for (std::vector<std::filesystem::path>::const_iterator iter (files.begin());
iter!=files.end(); ++iter) iter!=files.end(); ++iter)
mFiles->addItem (QString::fromUtf8 (iter->filename().string().c_str())); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break mFiles->addItem (QString::fromStdWString(iter->filename().wstring()));
} }
void CSVTools::Merge::setLocalData (const std::filesystem::path& localData) void CSVTools::Merge::setLocalData (const std::filesystem::path& localData)
@ -125,7 +125,7 @@ void CSVTools::Merge::accept()
{ {
if ((mDocument->getState() & CSMDoc::State_Merging)==0) if ((mDocument->getState() & CSMDoc::State_Merging)==0)
{ {
std::vector< std::filesystem::path > files (1, mAdjuster->getPath()); std::vector< std::filesystem::path > files { mAdjuster->getPath() };
std::unique_ptr<CSMDoc::Document> target ( std::unique_ptr<CSMDoc::Document> target (
mDocumentManager.makeDocument (files, files[0], true)); mDocumentManager.makeDocument (files, files[0], true));

@ -711,7 +711,7 @@ void OMW::Engine::setWindowIcon()
const auto windowIcon = mResDir / "openmw.png"; const auto windowIcon = mResDir / "openmw.png";
windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary); windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
if (windowIconStream.fail()) if (windowIconStream.fail())
Log(Debug::Error) << "Error: Failed to open " << windowIcon; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Error: Failed to open " << windowIcon;
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!reader) if (!reader)
{ {
@ -720,7 +720,7 @@ void OMW::Engine::setWindowIcon()
} }
osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream); osgDB::ReaderWriter::ReadResult result = reader->readImage(windowIconStream);
if (!result.success()) if (!result.success())
Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status(); //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Error: Failed to read " << windowIcon << ": " << result.message() << " code " << result.status();
else else
{ {
osg::ref_ptr<osg::Image> image = result.getImage(); osg::ref_ptr<osg::Image> image = result.getImage();
@ -790,11 +790,11 @@ void OMW::Engine::prepareEngine()
const auto input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml"); const auto input2 = (mCfgMgr.getUserConfigPath() / "input_v2.xml");
if(std::filesystem::exists(input2)) { if(std::filesystem::exists(input2)) {
keybinderUserExists = std::filesystem::copy_file(input2, keybinderUser); keybinderUserExists = std::filesystem::copy_file(input2, keybinderUser);
Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Loading keybindings file: " << keybinderUser;
} }
} }
else else
Log(Debug::Info) << "Loading keybindings file: " << keybinderUser; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Loading keybindings file: " << keybinderUser;
const auto userdefault = mCfgMgr.getUserConfigPath() / "gamecontrollerdb.txt"; const auto userdefault = mCfgMgr.getUserConfigPath() / "gamecontrollerdb.txt";
const auto localdefault = mCfgMgr.getLocalPath() / "gamecontrollerdb.txt"; const auto localdefault = mCfgMgr.getLocalPath() / "gamecontrollerdb.txt";
@ -1032,13 +1032,17 @@ void OMW::Engine::go()
prepareEngine(); prepareEngine();
std::ofstream stats; std::ofstream stats;
if (const auto path = std::getenv("OPENMW_OSG_STATS_FILE")) //TODO(Project579): This will probably break in windows with unicode paths #ifdef _WIN32
if (const auto path = std::filesystem::path{_wgetenv(L"OPENMW_OSG_STATS_FILE")}; !path.empty())
#else
if (const auto path = std::filesystem::path{std::getenv("OPENMW_OSG_STATS_FILE")}; !path.empty())
#endif
{ {
stats.open(path, std::ios_base::out); //TODO(Project579): This will probably break in windows with unicode paths stats.open(path, std::ios_base::out);
if (stats.is_open()) if (stats.is_open())
Log(Debug::Info) << "Stats will be written to: " << path; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Stats will be written to: " << path;
else else
Log(Debug::Warning) << "Failed to open file for stats: " << path; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Failed to open file for stats: " << path;
} }
// Setup profiler // Setup profiler

@ -21,6 +21,7 @@
#include <components/files/memorystream.hpp> #include <components/files/memorystream.hpp>
#include <components/misc/timeconvert.hpp> #include <components/misc/timeconvert.hpp>
#include <components/files/conversion.hpp>
#include <components/esm3/loadclas.hpp> #include <components/esm3/loadclas.hpp>
@ -200,7 +201,7 @@ namespace MWGui
if (mCurrentCharacter == &*it || if (mCurrentCharacter == &*it ||
(!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase ( (!mCurrentCharacter && !mSaving && directory==Misc::StringUtils::lowerCase (
it->begin()->mPath.parent_path().filename().string()))) //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break Files::pathToUnicodeString(it->begin()->mPath.parent_path().filename()))))
{ {
mCurrentCharacter = &*it; mCurrentCharacter = &*it;
selectedIndex = mCharacterSelection->getItemCount()-1; selectedIndex = mCharacterSelection->getItemCount()-1;

@ -6,6 +6,7 @@
#include <extern/oics/ICSInputControlSystem.h> #include <extern/oics/ICSInputControlSystem.h>
#include <components/sdlutil/sdlmappings.hpp> #include <components/sdlutil/sdlmappings.hpp>
#include <components/files/conversion.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
@ -44,7 +45,7 @@ namespace MWInput
{ {
public: public:
InputControlSystem(const std::filesystem::path &bindingsFile) InputControlSystem(const std::filesystem::path &bindingsFile)
: ICS::InputControlSystem(bindingsFile.string(), true, nullptr, nullptr, A_Last) //TODO(Project579): This is probably broken on windows with unicode paths : ICS::InputControlSystem(Files::pathToUnicodeString(bindingsFile), true, nullptr, nullptr, A_Last)
{ {
} }
}; };
@ -192,7 +193,7 @@ namespace MWInput
BindingsManager::~BindingsManager() BindingsManager::~BindingsManager()
{ {
mInputBinder->save(mUserFile.string()); //TODO(Project579): This will probably break in windows with unicode paths mInputBinder->save(Files::pathToUnicodeString(mUserFile));
} }
void BindingsManager::update(float dt) void BindingsManager::update(float dt)

@ -7,6 +7,8 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/sdlutil/sdlmappings.hpp> #include <components/sdlutil/sdlmappings.hpp>
#include <components/misc/stringops.hpp>
#include <components/files/conversion.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/inputmanager.hpp" #include "../mwbase/inputmanager.hpp"
@ -43,12 +45,12 @@ namespace MWInput
{ {
if (!controllerBindingsFile.empty()) if (!controllerBindingsFile.empty())
{ {
SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths SDL_GameControllerAddMappingsFromFile(Files::pathToUnicodeString(controllerBindingsFile).c_str());
} }
if (!userControllerBindingsFile.empty()) if (!userControllerBindingsFile.empty())
{ {
SDL_GameControllerAddMappingsFromFile(userControllerBindingsFile.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths SDL_GameControllerAddMappingsFromFile(Files::pathToUnicodeString(userControllerBindingsFile).c_str());
} }
// Open all presently connected sticks // Open all presently connected sticks

@ -23,6 +23,7 @@
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/stereo/multiview.hpp> #include <components/stereo/multiview.hpp>
#include <components/stereo/stereomanager.hpp> #include <components/stereo/stereomanager.hpp>
#include <components/files/conversion.hpp>
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -217,12 +218,12 @@ namespace MWRender
{ {
for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir)) for (const auto& name : mVFS->getRecursiveDirectoryIterator(fx::Technique::sSubdir))
{ {
std::filesystem::path path = name; std::filesystem::path path = Files::pathFromUnicodeString(name);
std::string fileExt = Misc::StringUtils::lowerCase(path.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break std::string fileExt = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(path.extension()));
if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt) if (!path.parent_path().has_parent_path() && fileExt == fx::Technique::sExt)
{ {
const auto absolutePath = mVFS->getAbsoluteFileName(name); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break const auto absolutePath = mVFS->getAbsoluteFileName(path);
mTechniqueFileMap[absolutePath.stem().string()] = absolutePath; //TODO(Project579): This will probably break in windows with unicode paths mTechniqueFileMap[Files::pathToUnicodeString(absolutePath.stem())] = absolutePath;
} }
} }
} }
@ -387,7 +388,7 @@ namespace MWRender
std::this_thread::sleep_for(std::chrono::milliseconds(5)); std::this_thread::sleep_for(std::chrono::milliseconds(5));
if (technique->compile()) if (technique->compile())
Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()].string(); //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Reloaded technique : " << mTechniqueFileMap[technique->getName()];
mReload = technique->isValid(); mReload = technique->isValid();
} }

@ -243,16 +243,16 @@ osg::ref_ptr<osg::Image> readPngImage (const std::filesystem::path& file)
std::ifstream inStream; std::ifstream inStream;
inStream.open(file, std::ios_base::in | std::ios_base::binary); inStream.open(file, std::ios_base::in | std::ios_base::binary);
if (inStream.fail()) if (inStream.fail())
Log(Debug::Error) << "Error: Failed to open " << file; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Error: Failed to open " << file;
osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png"); osgDB::ReaderWriter* reader = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!reader) if (!reader)
{ {
Log(Debug::Error) << "Error: Failed to read " << file << ", no png readerwriter found"; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Error: Failed to read " << file << ", no png readerwriter found";
return osg::ref_ptr<osg::Image>(); return osg::ref_ptr<osg::Image>();
} }
osgDB::ReaderWriter::ReadResult result = reader->readImage(inStream); osgDB::ReaderWriter::ReadResult result = reader->readImage(inStream);
if (!result.success()) if (!result.success())
Log(Debug::Error) << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status(); //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Error: Failed to read " << file << ": " << result.message() << " code " << result.status();
return result.getImage(); return result.getImage();
} }

@ -24,6 +24,7 @@
#include <components/esm3/loadcrea.hpp> #include <components/esm3/loadcrea.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/files/conversion.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
@ -1528,7 +1529,7 @@ namespace MWScript
else else
{ {
const auto filename = MWBase::Environment::get().getWorld()->exportSceneGraph(ptr); const auto filename = MWBase::Environment::get().getWorld()->exportSceneGraph(ptr);
runtime.getContext().report("Wrote '" + filename.string() + "'"); //TODO(Project579): This will probably break in windows with unicode paths runtime.getContext().report("Wrote '" + Files::pathToUnicodeString(filename) + "'");
} }
} }
}; };

@ -35,7 +35,7 @@ namespace MWScript
mScriptBlacklist.resize (scriptBlacklist.size()); mScriptBlacklist.resize (scriptBlacklist.size());
std::transform (scriptBlacklist.begin(), scriptBlacklist.end(), std::transform (scriptBlacklist.begin(), scriptBlacklist.end(),
mScriptBlacklist.begin(), Misc::StringUtils::lowerCase); mScriptBlacklist.begin(), [](const std::string& s) { return Misc::StringUtils::lowerCase(s); });
std::sort (mScriptBlacklist.begin(), mScriptBlacklist.end()); std::sort (mScriptBlacklist.begin(), mScriptBlacklist.end());
} }

@ -13,6 +13,7 @@
#include <components/loadinglistener/loadinglistener.hpp> #include <components/loadinglistener/loadinglistener.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/files/conversion.hpp>
#include <osg/Image> #include <osg/Image>
@ -305,7 +306,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
throw std::runtime_error("Write operation failed (file stream)"); throw std::runtime_error("Write operation failed (file stream)");
Settings::Manager::setString ("character", "Saves", Settings::Manager::setString ("character", "Saves",
slot->mPath.parent_path().filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break Files::pathToUnicodeString(slot->mPath.parent_path().filename()));
const auto finish = std::chrono::steady_clock::now(); const auto finish = std::chrono::steady_clock::now();
@ -388,7 +389,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::fil
{ {
cleanup(); cleanup();
Log(Debug::Info) << "Reading save file " << filepath.filename(); //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Reading save file " << filepath.filename();
ESM::ESMReader reader; ESM::ESMReader reader;
reader.open (filepath); reader.open (filepath);
@ -521,7 +522,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::fil
if (character) if (character)
Settings::Manager::setString ("character", "Saves", Settings::Manager::setString ("character", "Saves",
character->getPath().filename().string()); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break Files::pathToUnicodeString(character->getPath().filename()));
MWBase::Environment::get().getWindowManager()->setNewGame(false); MWBase::Environment::get().getWindowManager()->setNewGame(false);
MWBase::Environment::get().getWorld()->saveLoaded(); MWBase::Environment::get().getWorld()->saveLoaded();

@ -3,6 +3,7 @@
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
#include <components/esm3/readerscache.hpp> #include <components/esm3/readerscache.hpp>
#include <components/files/conversion.hpp>
namespace MWWorld namespace MWWorld
{ {
@ -28,7 +29,7 @@ void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading:
assert(reader->getGameFiles().size() == reader->getParentFileIndices().size()); assert(reader->getGameFiles().size() == reader->getParentFileIndices().size());
for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i) for (std::size_t i = 0, n = reader->getParentFileIndices().size(); i < n; ++i)
if (i == static_cast<std::size_t>(reader->getIndex())) if (i == static_cast<std::size_t>(reader->getIndex()))
throw std::runtime_error("File " + reader->getName().string() + " asks for parent file " //TODO(Project579): This will probably break in windows with unicode paths throw std::runtime_error("File " + Files::pathToUnicodeString(reader->getName()) + " asks for parent file "
+ reader->getGameFiles()[i].name + reader->getGameFiles()[i].name
+ ", but it is not available or has been loaded in the wrong order. " + ", but it is not available or has been loaded in the wrong order. "
"Please run the launcher to fix this issue."); "Please run the launcher to fix this issue.");
@ -36,8 +37,8 @@ void EsmLoader::load(const std::filesystem::path& filepath, int& index, Loading:
mESMVersions[index] = reader->getVer(); mESMVersions[index] = reader->getVer();
mStore.load(*reader, listener, mDialogue); mStore.load(*reader, listener, mDialogue);
if (!mMasterFileFormat.has_value() && (Misc::StringUtils::ciEndsWith(reader->getName().string(), ".esm") //TODO(Project579): This will probably break in windows with unicode paths if (!mMasterFileFormat.has_value() && (Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".esm")
|| Misc::StringUtils::ciEndsWith(reader->getName().string(), ".omwgame"))) //TODO(Project579): This will probably break in windows with unicode paths || Misc::StringUtils::ciEndsWith(reader->getName().u8string(), u8".omwgame")))
mMasterFileFormat = reader->getFormat(); mMasterFileFormat = reader->getFormat();
} }

@ -44,6 +44,7 @@
#include <components/detournavigator/navigatorimpl.hpp> #include <components/detournavigator/navigatorimpl.hpp>
#include <components/loadinglistener/loadinglistener.hpp> #include <components/loadinglistener/loadinglistener.hpp>
#include <components/files/conversion.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp" #include "../mwbase/soundmanager.hpp"
@ -104,19 +105,19 @@ namespace MWWorld
void load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) override void load(const std::filesystem::path& filepath, int& index, Loading::Listener* listener) override
{ {
const auto it = mLoaders.find(Misc::StringUtils::lowerCase(filepath.extension().string())); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break const auto it = mLoaders.find(Misc::StringUtils::lowerCase( Files::pathToUnicodeString(filepath.extension())));
if (it != mLoaders.end()) if (it != mLoaders.end())
{ {
const std::string filename = filepath.filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break const auto filename = filepath.filename();
Log(Debug::Info) << "Loading content file " << filename; Log(Debug::Info) << "Loading content file " << filename;
if (listener != nullptr) if (listener != nullptr)
listener->setLabel(MyGUI::TextIterator::toTagsString(filename)); listener->setLabel(MyGUI::TextIterator::toTagsString(Files::pathToUnicodeString(filename)));
it->second->load(filepath, index, listener); it->second->load(filepath, index, listener);
} }
else else
{ {
std::string msg("Cannot load file: "); std::string msg("Cannot load file: ");
msg += filepath.string(); //TODO(Project579): This will probably break in windows with unicode paths msg += Files::pathToUnicodeString(filepath);
throw std::runtime_error(msg.c_str()); throw std::runtime_error(msg.c_str());
} }
} }
@ -2963,8 +2964,8 @@ namespace MWWorld
int idx = 0; int idx = 0;
for (const std::string &file : content) for (const std::string &file : content)
{ {
std::filesystem::path filename(file); const auto filename = Files::pathFromUnicodeString( file);
const Files::MultiDirCollection& col = fileCollections.getCollection(filename.extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break const Files::MultiDirCollection& col = fileCollections.getCollection(Files::pathToUnicodeString(filename.extension()));
if (col.doesExist(file)) if (col.doesExist(file))
{ {
gameContentLoader.load(col.getPath(file), idx, listener); gameContentLoader.load(col.getPath(file), idx, listener);

@ -1,5 +1,6 @@
#include <components/files/hash.hpp> #include <components/files/hash.hpp>
#include <components/files/constrainedfilestream.hpp> #include <components/files/constrainedfilestream.hpp>
#include <components/files/conversion.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock.h> #include <gmock/gmock.h>
@ -50,11 +51,11 @@ namespace
std::replace(fileName.begin(), fileName.end(), '/', '_'); std::replace(fileName.begin(), fileName.end(), '/', '_');
std::string content; std::string content;
std::fill_n(std::back_inserter(content), GetParam().mSize, 'a'); std::fill_n(std::back_inserter(content), GetParam().mSize, 'a');
fileName = outputFilePath(fileName).string(); //TODO(Project579): This will probably break in windows with unicode paths const auto file = outputFilePath(fileName);
std::fstream(fileName, std::ios_base::out | std::ios_base::binary) std::fstream(file, std::ios_base::out | std::ios_base::binary)
.write(content.data(), static_cast<std::streamsize>(content.size())); .write(content.data(), static_cast<std::streamsize>(content.size()));
const auto stream = Files::openConstrainedFileStream(fileName, 0, content.size()); //TODO(Project579): This will probably break in windows with unicode paths const auto stream = Files::openConstrainedFileStream(file, 0, content.size());
EXPECT_EQ(getHash(fileName, *stream), GetParam().mHash); EXPECT_EQ(getHash(file, *stream), GetParam().mHash);
} }
INSTANTIATE_TEST_SUITE_P(Params, FilesGetHash, Values( INSTANTIATE_TEST_SUITE_P(Params, FilesGetHash, Values(

@ -11,6 +11,7 @@
#include <components/esm/records.hpp> #include <components/esm/records.hpp>
#include <components/loadinglistener/loadinglistener.hpp> #include <components/loadinglistener/loadinglistener.hpp>
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include <components/files/conversion.hpp>
#include "apps/openmw/mwworld/esmstore.hpp" #include "apps/openmw/mwworld/esmstore.hpp"
#include "apps/openmw/mwmechanics/spelllist.hpp" #include "apps/openmw/mwmechanics/spelllist.hpp"
@ -124,7 +125,7 @@ TEST_F(ContentFileTest, dialogue_merging_test)
stream << std::endl; stream << std::endl;
} }
std::cout << "dialogue_merging_test successful, results printed to " << file << std::endl; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "dialogue_merging_test successful, results printed to " << Files::pathToUnicodeString(file) << std::endl;
} }
// Note: here we don't test records that don't use string names (e.g. Land, Pathgrid, Cell) // Note: here we don't test records that don't use string names (e.g. Land, Pathgrid, Cell)
@ -194,7 +195,7 @@ TEST_F(ContentFileTest, content_diagnostics_test)
RUN_TEST_FOR_TYPES(printRecords, mEsmStore, stream); RUN_TEST_FOR_TYPES(printRecords, mEsmStore, stream);
std::cout << "diagnostics_test successful, results printed to " << file << std::endl; //TODO(Project579): This will probably break in windows with unicode paths std::cout << "diagnostics_test successful, results printed to " << Files::pathToUnicodeString(file) << std::endl;
} }
// TODO: // TODO:

@ -1,5 +1,6 @@
#include <apps/openmw/options.hpp> #include <apps/openmw/options.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <gmock/gmock.h> #include <gmock/gmock.h>
@ -38,7 +39,7 @@ namespace
return result; return result;
} }
MATCHER_P(IsPath, v, "") { return arg.string() == v; } MATCHER_P(IsPath, v, "") { return Files::pathToUnicodeString(arg) == v; }
template <class T> template <class T>
void parseArgs(const T& arguments, bpo::variables_map& variables, bpo::options_description& description) void parseArgs(const T& arguments, bpo::variables_map& variables, bpo::options_description& description)
@ -52,7 +53,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame=save.omwsave"}; const std::array arguments {"openmw", "--load-savegame=save.omwsave"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save.omwsave");
} }
TEST(OpenMWOptionsFromArguments, should_support_single_word_load_savegame_path) TEST(OpenMWOptionsFromArguments, should_support_single_word_load_savegame_path)
@ -61,7 +62,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", "save.omwsave"}; const std::array arguments {"openmw", "--load-savegame", "save.omwsave"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save.omwsave");
} }
TEST(OpenMWOptionsFromArguments, should_support_multi_component_load_savegame_path) TEST(OpenMWOptionsFromArguments, should_support_multi_component_load_savegame_path)
@ -70,7 +71,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", "/home/user/openmw/save.omwsave"}; const std::array arguments {"openmw", "--load-savegame", "/home/user/openmw/save.omwsave"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "/home/user/openmw/save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "/home/user/openmw/save.omwsave");
} }
TEST(OpenMWOptionsFromArguments, should_support_windows_multi_component_load_savegame_path) TEST(OpenMWOptionsFromArguments, should_support_windows_multi_component_load_savegame_path)
@ -79,7 +80,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", R"(C:\OpenMW\save.omwsave)"}; const std::array arguments {"openmw", "--load-savegame", R"(C:\OpenMW\save.omwsave)"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(C:\OpenMW\save.omwsave)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(C:\OpenMW\save.omwsave)");
} }
TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_spaces) TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_spaces)
@ -88,7 +89,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", "my save.omwsave"}; const std::array arguments {"openmw", "--load-savegame", "my save.omwsave"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "my save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "my save.omwsave");
} }
TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_octothorpe) TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_octothorpe)
@ -97,7 +98,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", "my#save.omwsave"}; const std::array arguments {"openmw", "--load-savegame", "my#save.omwsave"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "my#save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "my#save.omwsave");
} }
TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_at_sign) TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_at_sign)
@ -106,7 +107,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", "my@save.omwsave"}; const std::array arguments {"openmw", "--load-savegame", "my@save.omwsave"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "my@save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "my@save.omwsave");
} }
TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_quote) TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_quote)
@ -115,7 +116,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", R"(my"save.omwsave)"}; const std::array arguments {"openmw", "--load-savegame", R"(my"save.omwsave)"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(my"save.omwsave)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(my"save.omwsave)");
} }
TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path) TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path)
@ -124,7 +125,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", R"("save".omwsave)"}; const std::array arguments {"openmw", "--load-savegame", R"("save".omwsave)"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(save)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(save)");
} }
TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_quote_by_ampersand) TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_quote_by_ampersand)
@ -133,7 +134,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", R"("save&".omwsave")"}; const std::array arguments {"openmw", "--load-savegame", R"("save&".omwsave")"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(save".omwsave)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(save".omwsave)");
} }
TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_ampersand) TEST(OpenMWOptionsFromArguments, should_support_quoted_load_savegame_path_with_escaped_ampersand)
@ -142,7 +143,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", R"("save.omwsave&&")"}; const std::array arguments {"openmw", "--load-savegame", R"("save.omwsave&&")"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save.omwsave&"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save.omwsave&");
} }
TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_ampersand) TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_ampersand)
@ -151,7 +152,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", "save&.omwsave"}; const std::array arguments {"openmw", "--load-savegame", "save&.omwsave"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save&.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save&.omwsave");
} }
TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_multiple_quotes) TEST(OpenMWOptionsFromArguments, should_support_load_savegame_path_with_multiple_quotes)
@ -160,7 +161,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", R"(my"save".omwsave)"}; const std::array arguments {"openmw", "--load-savegame", R"(my"save".omwsave)"};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(my"save".omwsave)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(my"save".omwsave)");
} }
TEST(OpenMWOptionsFromArguments, should_compose_data) TEST(OpenMWOptionsFromArguments, should_compose_data)
@ -199,7 +200,7 @@ namespace
const std::array arguments {"openmw", "--load-savegame", pathArgument.c_str()}; const std::array arguments {"openmw", "--load-savegame", pathArgument.c_str()};
bpo::variables_map variables; bpo::variables_map variables;
parseArgs(arguments, variables, description); parseArgs(arguments, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), path); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), path);
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(
@ -214,7 +215,7 @@ namespace
std::istringstream stream("load-savegame=save.omwsave"); std::istringstream stream("load-savegame=save.omwsave");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save.omwsave");
} }
TEST(OpenMWOptionsFromConfig, should_strip_quotes_from_load_savegame_path) TEST(OpenMWOptionsFromConfig, should_strip_quotes_from_load_savegame_path)
@ -223,7 +224,7 @@ namespace
std::istringstream stream(R"(load-savegame="save.omwsave")"); std::istringstream stream(R"(load-savegame="save.omwsave")");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save.omwsave");
} }
TEST(OpenMWOptionsFromConfig, should_strip_outer_quotes_from_load_savegame_path) TEST(OpenMWOptionsFromConfig, should_strip_outer_quotes_from_load_savegame_path)
@ -232,7 +233,7 @@ namespace
std::istringstream stream(R"(load-savegame=""save".omwsave")"); std::istringstream stream(R"(load-savegame=""save".omwsave")");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), ""); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "");
} }
TEST(OpenMWOptionsFromConfig, should_strip_quotes_from_load_savegame_path_with_space) TEST(OpenMWOptionsFromConfig, should_strip_quotes_from_load_savegame_path_with_space)
@ -241,7 +242,7 @@ namespace
std::istringstream stream(R"(load-savegame="my save.omwsave")"); std::istringstream stream(R"(load-savegame="my save.omwsave")");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "my save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "my save.omwsave");
} }
TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_octothorpe) TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_octothorpe)
@ -250,7 +251,7 @@ namespace
std::istringstream stream("load-savegame=save#.omwsave"); std::istringstream stream("load-savegame=save#.omwsave");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save#.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save#.omwsave");
} }
TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_at_sign) TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_at_sign)
@ -259,7 +260,7 @@ namespace
std::istringstream stream("load-savegame=save@.omwsave"); std::istringstream stream("load-savegame=save@.omwsave");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save@.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save@.omwsave");
} }
TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_quote) TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_quote)
@ -268,7 +269,7 @@ namespace
std::istringstream stream(R"(load-savegame=save".omwsave)"); std::istringstream stream(R"(load-savegame=save".omwsave)");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(save".omwsave)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(save".omwsave)");
} }
TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_lots_going_on) TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_lots_going_on)
@ -277,7 +278,7 @@ namespace
std::istringstream stream(R"(load-savegame="one &"two"three".omwsave")"); std::istringstream stream(R"(load-savegame="one &"two"three".omwsave")");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(one "two)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(one "two)");
} }
TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_even_more_going_on) TEST(OpenMWOptionsFromConfig, should_support_confusing_savegame_path_with_even_more_going_on)
@ -286,7 +287,7 @@ namespace
std::istringstream stream(R"(load-savegame="one &"two"three ".omwsave")"); std::istringstream stream(R"(load-savegame="one &"two"three ".omwsave")");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(one "two)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(one "two)");
} }
TEST(OpenMWOptionsFromConfig, should_ignore_commented_option) TEST(OpenMWOptionsFromConfig, should_ignore_commented_option)
@ -295,7 +296,7 @@ namespace
std::istringstream stream("#load-savegame=save.omwsave"); std::istringstream stream("#load-savegame=save.omwsave");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), ""); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "");
} }
TEST(OpenMWOptionsFromConfig, should_ignore_whitespace_prefixed_commented_option) TEST(OpenMWOptionsFromConfig, should_ignore_whitespace_prefixed_commented_option)
@ -304,7 +305,7 @@ namespace
std::istringstream stream(" \t#load-savegame=save.omwsave"); std::istringstream stream(" \t#load-savegame=save.omwsave");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), ""); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "");
} }
TEST(OpenMWOptionsFromConfig, should_support_whitespace_around_option) TEST(OpenMWOptionsFromConfig, should_support_whitespace_around_option)
@ -313,7 +314,7 @@ namespace
std::istringstream stream(" load-savegame = save.omwsave "); std::istringstream stream(" load-savegame = save.omwsave ");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save.omwsave");
} }
TEST(OpenMWOptionsFromConfig, should_throw_on_multiple_load_savegame) TEST(OpenMWOptionsFromConfig, should_throw_on_multiple_load_savegame)
@ -330,7 +331,7 @@ namespace
std::istringstream stream("load-savegame=/home/user/openmw/save.omwsave"); std::istringstream stream("load-savegame=/home/user/openmw/save.omwsave");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "/home/user/openmw/save.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "/home/user/openmw/save.omwsave");
} }
TEST(OpenMWOptionsFromConfig, should_support_windows_multi_component_load_savegame_path) TEST(OpenMWOptionsFromConfig, should_support_windows_multi_component_load_savegame_path)
@ -339,7 +340,7 @@ namespace
std::istringstream stream(R"(load-savegame=C:\OpenMW\save.omwsave)"); std::istringstream stream(R"(load-savegame=C:\OpenMW\save.omwsave)");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(C:\OpenMW\save.omwsave)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(C:\OpenMW\save.omwsave)");
} }
TEST(OpenMWOptionsFromConfig, should_compose_data) TEST(OpenMWOptionsFromConfig, should_compose_data)
@ -357,7 +358,7 @@ namespace
std::istringstream stream(R"(load-savegame="save&".omwsave")"); std::istringstream stream(R"(load-savegame="save&".omwsave")");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), R"(save".omwsave)"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), R"(save".omwsave)");
} }
TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_ampersand) TEST(OpenMWOptionsFromConfig, should_support_quoted_load_savegame_path_with_escaped_ampersand)
@ -366,7 +367,7 @@ namespace
std::istringstream stream(R"(load-savegame="save.omwsave&&")"); std::istringstream stream(R"(load-savegame="save.omwsave&&")");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save.omwsave&"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save.omwsave&");
} }
TEST(OpenMWOptionsFromConfig, should_support_load_savegame_path_with_ampersand) TEST(OpenMWOptionsFromConfig, should_support_load_savegame_path_with_ampersand)
@ -375,7 +376,7 @@ namespace
std::istringstream stream("load-savegame=save&.omwsave"); std::istringstream stream("load-savegame=save&.omwsave");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), "save&.omwsave"); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), "save&.omwsave");
} }
struct OpenMWOptionsFromConfigStrings : TestWithParam<std::string> {}; struct OpenMWOptionsFromConfigStrings : TestWithParam<std::string> {};
@ -387,7 +388,7 @@ namespace
std::istringstream stream("load-savegame=\"" + path + "\""); std::istringstream stream("load-savegame=\"" + path + "\"");
bpo::variables_map variables; bpo::variables_map variables;
Files::parseConfig(stream, variables, description); Files::parseConfig(stream, variables, description);
EXPECT_EQ(variables["load-savegame"].as<Files::MaybeQuotedPath>().string(), path); EXPECT_EQ(Files::pathToUnicodeString(variables["load-savegame"].as<Files::MaybeQuotedPath>()), path);
} }
INSTANTIATE_TEST_SUITE_P( INSTANTIATE_TEST_SUITE_P(

@ -1,4 +1,5 @@
#include <components/shader/shadermanager.hpp> #include <components/shader/shadermanager.hpp>
#include <components/files/conversion.hpp>
#include <fstream> #include <fstream>
@ -48,7 +49,7 @@ namespace
const std::string content; const std::string content;
withShaderFile(content, [this] (const std::filesystem::path& templateName) { withShaderFile(content, [this] (const std::filesystem::path& templateName) {
EXPECT_TRUE(mManager.getShader(templateName.string(), {}, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths EXPECT_TRUE(mManager.getShader(Files::pathToUnicodeString(templateName), {}, osg::Shader::VERTEX));
}); });
} }
@ -59,7 +60,7 @@ namespace
"void main() {}\n"; "void main() {}\n";
withShaderFile(content, [&] (const std::filesystem::path& templateName) { withShaderFile(content, [&] (const std::filesystem::path& templateName) {
const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX);
ASSERT_TRUE(shader); ASSERT_TRUE(shader);
EXPECT_EQ(shader->getShaderSource(), content); EXPECT_EQ(shader->getShaderSource(), content);
}); });
@ -72,17 +73,17 @@ namespace
withShaderFile("_0", content0, [&] (const std::filesystem::path& templateName0) { withShaderFile("_0", content0, [&] (const std::filesystem::path& templateName0) {
const std::string content1 = const std::string content1 =
"#include \"" + templateName0.string() + "\"\n" //TODO(Project579): This will probably break in windows with unicode paths "#include \"" + Files::pathToUnicodeString(templateName0) + "\"\n"
"void bar() { foo() }\n"; "void bar() { foo() }\n";
withShaderFile("_1", content1, [&] (const std::filesystem::path& templateName1) { withShaderFile("_1", content1, [&] (const std::filesystem::path& templateName1) {
const std::string content2 = const std::string content2 =
"#version 120\n" "#version 120\n"
"#include \"" + templateName1.string() + "\"\n" //TODO(Project579): This will probably break in windows with unicode paths "#include \"" + Files::pathToUnicodeString(templateName1) + "\"\n"
"void main() { bar() }\n"; "void main() { bar() }\n";
withShaderFile(content2, [&] (const std::filesystem::path& templateName2) { withShaderFile(content2, [&] (const std::filesystem::path& templateName2) {
const auto shader = mManager.getShader(templateName2.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName2), mDefines, osg::Shader::VERTEX);
ASSERT_TRUE(shader); ASSERT_TRUE(shader);
const std::string expected = const std::string expected =
"#version 120\n" "#version 120\n"
@ -113,7 +114,7 @@ namespace
withShaderFile(content, [&] (const std::filesystem::path& templateName) { withShaderFile(content, [&] (const std::filesystem::path& templateName) {
mDefines["flag"] = "1"; mDefines["flag"] = "1";
const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX);
ASSERT_TRUE(shader); ASSERT_TRUE(shader);
const std::string expected = const std::string expected =
"#version 120\n" "#version 120\n"
@ -135,7 +136,7 @@ namespace
withShaderFile(content, [&] (const std::filesystem::path& templateName) { withShaderFile(content, [&] (const std::filesystem::path& templateName) {
mDefines["list"] = "1,2,3"; mDefines["list"] = "1,2,3";
const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX);
ASSERT_TRUE(shader); ASSERT_TRUE(shader);
const std::string expected = const std::string expected =
"#version 120\n" "#version 120\n"
@ -176,7 +177,7 @@ namespace
withShaderFile(content, [&] (const std::filesystem::path& templateName) { withShaderFile(content, [&] (const std::filesystem::path& templateName) {
mDefines["list"] = "1,2,3"; mDefines["list"] = "1,2,3";
const auto shader = mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX); //TODO(Project579): This will probably break in windows with unicode paths const auto shader = mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX);
ASSERT_TRUE(shader); ASSERT_TRUE(shader);
const std::string expected = const std::string expected =
"#version 120\n" "#version 120\n"
@ -223,7 +224,7 @@ namespace
; ;
withShaderFile(content, [&] (const std::filesystem::path& templateName) { withShaderFile(content, [&] (const std::filesystem::path& templateName) {
EXPECT_FALSE(mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths EXPECT_FALSE(mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX));
}); });
} }
@ -236,7 +237,7 @@ namespace
; ;
withShaderFile(content, [&] (const std::filesystem::path& templateName) { withShaderFile(content, [&] (const std::filesystem::path& templateName) {
EXPECT_FALSE(mManager.getShader(templateName.string(), mDefines, osg::Shader::VERTEX)); //TODO(Project579): This will probably break in windows with unicode paths EXPECT_FALSE(mManager.getShader(Files::pathToUnicodeString(templateName), mDefines, osg::Shader::VERTEX));
}); });
} }
} }

@ -6,6 +6,7 @@
#include <components/vfs/archive.hpp> #include <components/vfs/archive.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/misc/stringops.hpp>
namespace TestingOpenMW namespace TestingOpenMW
{ {
@ -14,7 +15,7 @@ namespace TestingOpenMW
{ {
std::filesystem::path dir("tests_output"); std::filesystem::path dir("tests_output");
std::filesystem::create_directory(dir); std::filesystem::create_directory(dir);
return dir / name; return dir / Misc::StringUtils::stringToU8String(name);
} }
inline std::filesystem::path temporaryFilePath(const std::string name) inline std::filesystem::path temporaryFilePath(const std::string name)

@ -4,6 +4,8 @@
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#include <components/files/conversion.hpp>
#include "mainwizard.hpp" #include "mainwizard.hpp"
Wizard::InstallationTargetPage::InstallationTargetPage(QWidget *parent, const Files::ConfigurationManager &cfg) : Wizard::InstallationTargetPage::InstallationTargetPage(QWidget *parent, const Files::ConfigurationManager &cfg) :
@ -19,7 +21,7 @@ Wizard::InstallationTargetPage::InstallationTargetPage(QWidget *parent, const Fi
void Wizard::InstallationTargetPage::initializePage() void Wizard::InstallationTargetPage::initializePage()
{ {
QString path(QFile::decodeName(mCfgMgr.getUserDataPath().string().c_str())); //TODO(Project579): This will probably break in windows with unicode paths QString path(QFile::decodeName(Files::pathToUnicodeString(mCfgMgr.getUserDataPath()).c_str()));
path.append(QDir::separator() + QLatin1String("basedata")); path.append(QDir::separator() + QLatin1String("basedata"));
QDir dir(path); QDir dir(path);

@ -471,5 +471,5 @@ bool Wizard::MainWizard::findFiles(const QString &name, const QString &path)
QString Wizard::MainWizard::toQString(const std::filesystem::path& path) QString Wizard::MainWizard::toQString(const std::filesystem::path& path)
{ {
return QString::fromUtf8(path.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths return QString::fromStdWString(path.wstring());
} }

@ -214,7 +214,7 @@ IF(NOT WIN32 AND NOT APPLE)
ENDIF() ENDIF()
add_component_dir (files add_component_dir (files
linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager
constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf constrainedfilestream memorystream hash configfileparser openfile constrainedfilestreambuf conversion
) )
add_component_dir (compiler add_component_dir (compiler

@ -37,7 +37,7 @@ using namespace Bsa;
/// Error handling /// Error handling
[[noreturn]] void BSAFile::fail(const std::string &msg) [[noreturn]] void BSAFile::fail(const std::string &msg)
{ {
throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + mFilepath.string()); //TODO(Project579): This will probably break in windows with unicode paths throw std::runtime_error("BSA Error: " + msg + "\nArchive: " + Files::pathToUnicodeString(mFilepath));
} }
//the getHash code is from bsapack from ghostwheel //the getHash code is from bsapack from ghostwheel

@ -30,6 +30,7 @@
#include <filesystem> #include <filesystem>
#include <components/files/istreamptr.hpp> #include <components/files/istreamptr.hpp>
#include <components/files/conversion.hpp>
namespace Bsa namespace Bsa
{ {
@ -134,7 +135,7 @@ public:
std::string getFilename() const std::string getFilename() const
{ {
return mFilepath.string(); //TODO(Project579): This will probably break in windows with unicode paths return Files::pathToUnicodeString(mFilepath);
} }
}; };

@ -48,6 +48,7 @@
#include <components/bsa/memorystream.hpp> #include <components/bsa/memorystream.hpp>
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/files/constrainedfilestream.hpp> #include <components/files/constrainedfilestream.hpp>
#include <components/files/conversion.hpp>
namespace Bsa namespace Bsa
{ {
@ -214,7 +215,7 @@ void CompressedBSAFile::readHeader()
if ((archiveFlags & 0x1) != 0) if ((archiveFlags & 0x1) != 0)
getBZString(folder, input); getBZString(folder, input);
folderHash = generateHash(folder, std::string()); folderHash = generateHash(folder, {});
auto iter = mFolders.find(folderHash); auto iter = mFolders.find(folderHash);
if (iter == mFolders.end()) if (iter == mFolders.end())
@ -309,13 +310,11 @@ CompressedBSAFile::FileRecord CompressedBSAFile::getFileRecord(const std::string
std::replace(path.begin(), path.end(), '\\', '/'); std::replace(path.begin(), path.end(), '\\', '/');
#endif #endif
std::filesystem::path p(path); auto p = Files::pathFromUnicodeString(path);
std::string stem = p.stem().string(); const auto stem = p.stem();
std::string ext = p.extension().string(); const auto ext = p.extension().u8string();
p.remove_filename();
std::string folder = p.string(); std::uint64_t folderHash = generateHash(p.parent_path(), {});
std::uint64_t folderHash = generateHash(folder, std::string());
auto it = mFolders.find(folderHash); auto it = mFolders.find(folderHash);
if (it == mFolders.end()) if (it == mFolders.end())
@ -358,7 +357,7 @@ Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord)
size_t size = fileRecord.getSizeWithoutCompressionFlag(); size_t size = fileRecord.getSizeWithoutCompressionFlag();
size_t uncompressedSize = size; size_t uncompressedSize = size;
bool compressed = fileRecord.isCompressed(mCompressedByDefault); bool compressed = fileRecord.isCompressed(mCompressedByDefault);
Files::IStreamPtr streamPtr = Files::openConstrainedFileStream(mFilename, fileRecord.offset, size); Files::IStreamPtr streamPtr = Files::openConstrainedFileStream(mFilepath, fileRecord.offset, size);
std::istream* fileStream = streamPtr.get(); std::istream* fileStream = streamPtr.get();
if (mEmbeddedFileNames) if (mEmbeddedFileNames)
{ {
@ -395,10 +394,10 @@ Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord)
LZ4F_decompressOptions_t options = {}; LZ4F_decompressOptions_t options = {};
LZ4F_errorCode_t errorCode = LZ4F_decompress(context, memoryStreamPtr->getRawData(), &uncompressedSize, buffer.data(), &size, &options); LZ4F_errorCode_t errorCode = LZ4F_decompress(context, memoryStreamPtr->getRawData(), &uncompressedSize, buffer.data(), &size, &options);
if (LZ4F_isError(errorCode)) if (LZ4F_isError(errorCode))
fail("LZ4 decompression error (file " + mFilename + "): " + LZ4F_getErrorName(errorCode)); fail("LZ4 decompression error (file " + Files::pathToUnicodeString(mFilepath) + "): " + LZ4F_getErrorName(errorCode));
errorCode = LZ4F_freeDecompressionContext(context); errorCode = LZ4F_freeDecompressionContext(context);
if (LZ4F_isError(errorCode)) if (LZ4F_isError(errorCode))
fail("LZ4 decompression error (file " + mFilename + "): " + LZ4F_getErrorName(errorCode)); fail("LZ4 decompression error (file " + Files::pathToUnicodeString(mFilepath) + "): " + LZ4F_getErrorName(errorCode));
} }
} }
else else
@ -409,9 +408,9 @@ Files::IStreamPtr CompressedBSAFile::getFile(const FileRecord& fileRecord)
return std::make_unique<Files::StreamWithBuffer<MemoryInputStream>>(std::move(memoryStreamPtr)); return std::make_unique<Files::StreamWithBuffer<MemoryInputStream>>(std::move(memoryStreamPtr));
} }
BsaVersion CompressedBSAFile::detectVersion(const std::string& filePath) BsaVersion CompressedBSAFile::detectVersion(const std::filesystem::path &filePath)
{ {
std::ifstream input(std::filesystem::path(filePath), std::ios_base::binary); std::ifstream input(filePath, std::ios_base::binary);
// Total archive size // Total archive size
std::streamoff fsize = 0; std::streamoff fsize = 0;
@ -460,7 +459,7 @@ void CompressedBSAFile::convertCompressedSizesToUncompressed()
continue; continue;
} }
Files::IStreamPtr dataBegin = Files::openConstrainedFileStream(mFilename, fileRecord.offset, fileRecord.getSizeWithoutCompressionFlag()); Files::IStreamPtr dataBegin = Files::openConstrainedFileStream(mFilepath, fileRecord.offset, fileRecord.getSizeWithoutCompressionFlag());
if (mEmbeddedFileNames) if (mEmbeddedFileNames)
{ {
@ -472,30 +471,31 @@ void CompressedBSAFile::convertCompressedSizesToUncompressed()
} }
} }
std::uint64_t CompressedBSAFile::generateHash(std::string stem, std::string extension) std::uint64_t CompressedBSAFile::generateHash(const std::filesystem::path& stem, std::u8string extension)
{ {
size_t len = stem.length(); auto str = stem.u8string();
size_t len = str.length();
if (len == 0) if (len == 0)
return 0; return 0;
std::replace(stem.begin(), stem.end(), '/', '\\'); std::replace(str.begin(), str.end(), u8'/', u8'\\');
Misc::StringUtils::lowerCaseInPlace(stem); Misc::StringUtils::lowerCaseInPlace(str);
uint64_t result = stem[len-1] | (len >= 3 ? (stem[len-2] << 8) : 0) | (len << 16) | (stem[0] << 24); uint64_t result = str[len-1] | (len >= 3 ? (str[len-2] << 8) : 0) | (len << 16) | (str[0] << 24);
if (len >= 4) if (len >= 4)
{ {
uint32_t hash = 0; uint32_t hash = 0;
for (size_t i = 1; i <= len-3; ++i) for (size_t i = 1; i <= len-3; ++i)
hash = hash * 0x1003f + stem[i]; hash = hash * 0x1003f + str[i];
result += static_cast<uint64_t>(hash) << 32; result += static_cast<uint64_t>(hash) << 32;
} }
if (extension.empty()) if (extension.empty())
return result; return result;
Misc::StringUtils::lowerCaseInPlace(extension); Misc::StringUtils::lowerCaseInPlace(extension);
if (extension == ".kf") result |= 0x80; if (extension == u8".kf") result |= 0x80;
else if (extension == ".nif") result |= 0x8000; else if (extension == u8".nif") result |= 0x8000;
else if (extension == ".dds") result |= 0x8080; else if (extension == u8".dds") result |= 0x8080;
else if (extension == ".wav") result |= 0x80000000; else if (extension == u8".wav") result |= 0x80000000;
uint32_t hash = 0; uint32_t hash = 0;
for (const char &c : extension) for (const auto &c : extension)
hash = hash * 0x1003f + c; hash = hash * 0x1003f + c;
result += static_cast<uint64_t>(hash) << 32; result += static_cast<uint64_t>(hash) << 32;
return result; return result;

@ -83,7 +83,7 @@ namespace Bsa
//mFiles used by OpenMW will contain uncompressed file sizes //mFiles used by OpenMW will contain uncompressed file sizes
void convertCompressedSizesToUncompressed(); void convertCompressedSizesToUncompressed();
/// \brief Normalizes given filename or folder and generates format-compatible hash. See https://en.uesp.net/wiki/Tes4Mod:Hash_Calculation. /// \brief Normalizes given filename or folder and generates format-compatible hash. See https://en.uesp.net/wiki/Tes4Mod:Hash_Calculation.
static std::uint64_t generateHash(std::filesystem::path stem, std::string extension) ; static std::uint64_t generateHash(const std::filesystem::path& stem, std::u8string extension) ;
Files::IStreamPtr getFile(const FileRecord& fileRecord); Files::IStreamPtr getFile(const FileRecord& fileRecord);
public: public:
using BSAFile::open; using BSAFile::open;

@ -32,7 +32,7 @@ void Config::GameSettings::validatePaths()
mDataDirs.clear(); mDataDirs.clear();
for (auto & dataDir : dataDirs) { for (auto & dataDir : dataDirs) {
QString path = QString::fromUtf8(dataDir.string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QString path = QString::fromStdWString(dataDir.wstring());
QDir dir(path); QDir dir(path);
if (dir.exists()) if (dir.exists())
@ -57,7 +57,7 @@ void Config::GameSettings::validatePaths()
mCfgMgr.processPaths(dataDirs, /*basePath=*/""); mCfgMgr.processPaths(dataDirs, /*basePath=*/"");
if (!dataDirs.empty()) { if (!dataDirs.empty()) {
QString path = QString::fromUtf8(dataDirs.front().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths QString path = QString::fromStdWString(dataDirs.front().wstring());
QDir dir(path); QDir dir(path);
if (dir.exists()) if (dir.exists())

@ -119,7 +119,7 @@ void Config::LauncherSettings::setContentList(const GameSettings& gameSettings)
} }
// global and local data directories are not part of any profile // global and local data directories are not part of any profile
const auto globalDataDir = QString(gameSettings.getGlobalDataDir().string().c_str()); //TODO(Project579): This will probably break in windows with unicode paths const auto globalDataDir = QString::fromStdWString(gameSettings.getGlobalDataDir().wstring());
const auto dataLocal = gameSettings.getDataLocal(); const auto dataLocal = gameSettings.getDataLocal();
dirs.removeAll(globalDataDir); dirs.removeAll(globalDataDir);
dirs.removeAll(dataLocal); dirs.removeAll(dataLocal);

@ -140,7 +140,7 @@ namespace Crash
const auto str = crashLogPath.u8string(); const auto str = crashLogPath.u8string();
size_t length = str.length(); size_t length = str.length();
if (length >= MAX_LONG_PATH) length = MAX_LONG_PATH - 1; if (length >= MAX_LONG_PATH) length = MAX_LONG_PATH - 1;
strncpy_s(mShm->mStartup.mLogFilePath, sizeof mShm->mStartup.mLogFilePath, Misc::StringUtils::char8_to_char(str.c_str()), length); //TODO(Project579): This will probably break in windows with unicode paths strncpy_s(mShm->mStartup.mLogFilePath, sizeof mShm->mStartup.mLogFilePath, Misc::StringUtils::u8StringToString(str).c_str(), length);
mShm->mStartup.mLogFilePath[length] = '\0'; mShm->mStartup.mLogFilePath[length] = '\0';
// note that we don't need to lock the SHM here, the other process has not started yet // note that we don't need to lock the SHM here, the other process has not started yet

@ -8,9 +8,11 @@
#include <components/crashcatcher/crashcatcher.hpp> #include <components/crashcatcher/crashcatcher.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp>
#ifdef _WIN32 #ifdef _WIN32
#include <components/crashcatcher/windows_crashcatcher.hpp> #include <components/crashcatcher/windows_crashcatcher.hpp>
#include <components/windows.hpp> #include <components/windows.hpp>
#include <components/files/conversion.hpp>
#endif #endif
#include <SDL_messagebox.h> #include <SDL_messagebox.h>
@ -318,12 +320,12 @@ int wrapApplication(int (*innerApplication)(int argc, char *argv[]), int argc, c
{ {
#if defined(_WIN32) #if defined(_WIN32)
const std::string crashLogName = Misc::StringUtils::lowerCase(appName) + "-crash.dmp"; const std::string crashLogName = Misc::StringUtils::lowerCase(appName) + "-crash.dmp";
Crash::CrashCatcher crashy(argc, argv, (cfgMgr.getLogPath() / crashLogName).make_preferred().string()); Crash::CrashCatcher crashy(argc, argv, Files::pathToUnicodeString(cfgMgr.getLogPath() / crashLogName));
#else #else
const std::string crashLogName = Misc::StringUtils::lowerCase(appName) + "-crash.log"; const std::string crashLogName = Misc::StringUtils::lowerCase(appName) + "-crash.log";
// install the crash handler as soon as possible. note that the log path // install the crash handler as soon as possible. note that the log path
// does not depend on config being read. // does not depend on config being read.
crashCatcherInstall(argc, argv, (cfgMgr.getLogPath() / crashLogName).string()); crashCatcherInstall(argc, argv, Files::pathToUnicodeString(cfgMgr.getLogPath() / crashLogName));
#endif #endif
ret = innerApplication(argc, argv); ret = innerApplication(argc, argv);
} }

@ -2,7 +2,8 @@
#include <mutex> #include <mutex>
#include <components/files/configurationmanager.hpp> #include <components/files/conversion.hpp>
#include <components/misc/stringops.hpp>
namespace Debug namespace Debug
{ {

@ -4,6 +4,7 @@
#include "recastglobalallocator.hpp" #include "recastglobalallocator.hpp"
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/files/conversion.hpp>
namespace DetourNavigator namespace DetourNavigator
{ {
@ -16,7 +17,7 @@ namespace DetourNavigator
{ {
try try
{ {
db = std::make_unique<NavMeshDb>((userDataPath / "navmesh.db").string(), settings.mMaxDbFileSize); //TODO(Project579): This will probably break in windows with unicode paths db = std::make_unique<NavMeshDb>(Files::pathToUnicodeString(userDataPath / "navmesh.db"), settings.mMaxDbFileSize);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {

@ -4,6 +4,7 @@
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include <components/files/openfile.hpp> #include <components/files/openfile.hpp>
#include <components/files/conversion.hpp>
#include <stdexcept> #include <stdexcept>
#include <sstream> #include <sstream>
@ -73,7 +74,7 @@ void ESMReader::resolveParentFileIndices(ReadersCache& readers)
const ESM::ReadersCache::BusyItem reader = readers.get(static_cast<std::size_t>(i)); const ESM::ReadersCache::BusyItem reader = readers.get(static_cast<std::size_t>(i));
if (reader->getFileSize() == 0) if (reader->getFileSize() == 0)
continue; // Content file in non-ESM format continue; // Content file in non-ESM format
std::string fnamecandidate = reader->getName().filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break const auto fnamecandidate = Files::pathToUnicodeString(reader->getName().filename());
if (Misc::StringUtils::ciEqual(fname, fnamecandidate)) if (Misc::StringUtils::ciEqual(fname, fnamecandidate))
{ {
index = i; index = i;
@ -359,7 +360,7 @@ std::string ESMReader::getString(int size)
std::stringstream ss; std::stringstream ss;
ss << "ESM Error: " << msg; ss << "ESM Error: " << msg;
ss << "\n File: " << mCtx.filename; //TODO(Project579): This will probably break in windows with unicode paths ss << "\n File: " << Files::pathToUnicodeString(mCtx.filename);
ss << "\n Record: " << mCtx.recName.toStringView(); ss << "\n Record: " << mCtx.recName.toStringView();
ss << "\n Subrecord: " << mCtx.subName.toStringView(); ss << "\n Subrecord: " << mCtx.subName.toStringView();
if (mEsm.get()) if (mEsm.get())

@ -131,7 +131,7 @@ namespace ESM
{ {
if(!overriding) if(!overriding)
mWater = std::numeric_limits<float>::max(); mWater = std::numeric_limits<float>::max();
Log(Debug::Warning) << "Warning: Encountered invalid water level in cell " << mName << " defined in " << esm.getContext().filename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Warning: Encountered invalid water level in cell " << mName << " defined in " << esm.getContext().filename;
} }
else else
mWater = waterLevel; mWater = waterLevel;

@ -51,6 +51,7 @@
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/files/constrainedfilestream.hpp> #include <components/files/constrainedfilestream.hpp>
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
#include <components/files/conversion.hpp>
#include "formid.hpp" #include "formid.hpp"
@ -184,12 +185,7 @@ void Reader::open(Files::IStreamPtr&& stream, const std::filesystem::path &filen
throw std::runtime_error("Unknown file format"); // can't yet use fail() as mCtx is not setup throw std::runtime_error("Unknown file format"); // can't yet use fail() as mCtx is not setup
} }
void Reader::openRaw(const std::string& filename) void Reader::open(const std::filesystem::path& filename)
{
openRaw(Files::openConstrainedFileStream(filename), filename);
}
void Reader::open(const std::string& filename)
{ {
open(Files::openConstrainedFileStream(filename), filename); open(Files::openConstrainedFileStream(filename), filename);
} }
@ -637,7 +633,7 @@ void Reader::adjustGRUPFormId()
std::stringstream ss; std::stringstream ss;
ss << "ESM Error: " << msg; ss << "ESM Error: " << msg;
ss << "\n File: " << mCtx.filename.string(); //TODO(Project579): This will probably break in windows with unicode paths ss << "\n File: " << Files::pathToUnicodeString(mCtx.filename);
ss << "\n Record: " << ESM::printName(mCtx.recordHeader.record.typeId); ss << "\n Record: " << ESM::printName(mCtx.recordHeader.record.typeId);
ss << "\n Subrecord: " << ESM::printName(mCtx.subRecordHeader.typeId); ss << "\n Subrecord: " << ESM::printName(mCtx.subRecordHeader.typeId);
if (mStream.get()) if (mStream.get())

@ -20,6 +20,7 @@
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/esm3/readerscache.hpp> #include <components/esm3/readerscache.hpp>
#include <components/loadinglistener/loadinglistener.hpp> #include <components/loadinglistener/loadinglistener.hpp>
#include <components/files/conversion.hpp>
#include <algorithm> #include <algorithm>
#include <filesystem> #include <filesystem>
@ -228,7 +229,7 @@ namespace EsmLoader
for (std::size_t i = 0; i < contentFiles.size(); ++i) for (std::size_t i = 0; i < contentFiles.size(); ++i)
{ {
const std::string &file = contentFiles[i]; const std::string &file = contentFiles[i];
const std::string extension = Misc::StringUtils::lowerCase(std::filesystem::path(file).extension().string()); //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break const std::string extension = Misc::StringUtils::lowerCase(Files::pathToUnicodeString(std::filesystem::path(file).extension()));
if (supportedFormats.find(extension) == supportedFormats.end()) if (supportedFormats.find(extension) == supportedFormats.end())
{ {

@ -1,4 +1,5 @@
#include "collections.hpp" #include "collections.hpp"
#include "conversion.hpp"
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
@ -42,12 +43,14 @@ namespace Files
std::filesystem::directory_iterator (mDirectorie)) std::filesystem::directory_iterator (mDirectorie))
{ {
const auto& path = iter2.path(); const auto& path = iter2.path();
const auto str = Files::pathToUnicodeString(path.filename());
if (mFoldCase) if (mFoldCase)
{ {
if (Misc::StringUtils::ciEqual(file, path.filename().string())) //TODO(Project579): This will probably break in windows with unicode paths if (Misc::StringUtils::ciEqual(file, str))
return path; return path;
} }
else if (path.filename().string() == file) //TODO(Project579): This will probably break in windows with unicode paths else if (str == file)
return path; return path;
} }
} }
@ -63,13 +66,14 @@ namespace Files
std::filesystem::directory_iterator (mDirectorie)) std::filesystem::directory_iterator (mDirectorie))
{ {
const auto& path = iter2.path(); const auto& path = iter2.path();
const auto str = Files::pathToUnicodeString(path.filename());
if (mFoldCase) if (mFoldCase)
{ {
if (Misc::StringUtils::ciEqual(file, path.filename().string())) //TODO(Project579): This will probably break in windows with unicode paths if (Misc::StringUtils::ciEqual(file, str))
return true; return true;
} }
else if (path.filename().string() == file) //TODO(Project579): This will probably break in windows with unicode paths else if (str == file)
return true; return true;
} }
} }

@ -19,14 +19,14 @@ namespace Files
/// leading dot and must be all lower-case. /// leading dot and must be all lower-case.
const MultiDirCollection& getCollection(const std::string& extension) const; const MultiDirCollection& getCollection(const std::string& extension) const;
std::filesystem::path getPath(const std::string& file) const; //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break std::filesystem::path getPath(const std::string& file) const;
///< Return full path (including filename) of \a file. ///< Return full path (including filename) of \a file.
/// ///
/// If the file does not exist in any of the collection's /// If the file does not exist in any of the collection's
/// directories, an exception is thrown. \a file must include the /// directories, an exception is thrown. \a file must include the
/// extension. /// extension.
bool doesExist(const std::string& file) const; //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break bool doesExist(const std::string& file) const;
///< \return Does a file with the given name exist? ///< \return Does a file with the given name exist?
const Files::PathContainer& getPaths() const; const Files::PathContainer& getPaths() const;

@ -460,29 +460,4 @@ PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathCon
return res; return res;
} }
std::string pathToUnicodeString(const std::filesystem::path& path)
{
return Misc::StringUtils::u8StringToString(path.u8string());
}
std::string pathToUnicodeString(std::filesystem::path&& path)
{
return Misc::StringUtils::u8StringToString(path.u8string());
}
std::filesystem::path unicodeStringToPath(const std::string_view path)
{
return Misc::StringUtils::stringToU8String(path);
}
std::filesystem::path unicodeStringToPath(std::string&& path)
{
return Misc::StringUtils::stringToU8String(std::move(path));
}
std::filesystem::path unicodeStringToPath(const char* path)
{
return Misc::StringUtils::stringToU8String(path);
}
} /* namespace Files */ } /* namespace Files */

@ -105,16 +105,6 @@ typedef std::vector<MaybeQuotedPath> MaybeQuotedPathContainer;
PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathContainer); PathContainer asPathContainer(const MaybeQuotedPathContainer& MaybeQuotedPathContainer);
std::string pathToUnicodeString(const std::filesystem::path& path);
std::string pathToUnicodeString(std::filesystem::path&& path);
std::filesystem::path unicodeStringToPath(const std::string_view path);
std::filesystem::path unicodeStringToPath(std::string&& path);
std::filesystem::path unicodeStringToPath(const char* path);
} /* namespace Files */ } /* namespace Files */
#endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */ #endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */

@ -0,0 +1,29 @@
#include "conversion.hpp"
#include <components/misc/stringops.hpp>
std::string Files::pathToUnicodeString(const std::filesystem::path& path)
{
return Misc::StringUtils::u8StringToString(path.u8string());
}
std::string Files::pathToUnicodeString(std::filesystem::path&& path)
{
return Misc::StringUtils::u8StringToString(path.u8string());
}
std::filesystem::path Files::pathFromUnicodeString(std::string_view path)
{
return Misc::StringUtils::stringToU8String(path);
}
std::filesystem::path Files::pathFromUnicodeString(std::string&& path)
{
return Misc::StringUtils::stringToU8String(std::move(path));
}
std::filesystem::path Files::pathFromUnicodeString(const char* path)
{
return Misc::StringUtils::stringToU8String(path);
}

@ -0,0 +1,18 @@
#ifndef COMPONENTS_FILES_CONVERSION_HPP
#define COMPONENTS_FILES_CONVERSION_HPP
#include <filesystem>
namespace Files {
std::string pathToUnicodeString(const std::filesystem::path& path);
std::string pathToUnicodeString(std::filesystem::path&& path);
std::filesystem::path pathFromUnicodeString(std::string_view path);
std::filesystem::path pathFromUnicodeString(std::string&& path);
std::filesystem::path pathFromUnicodeString(const char* path);
}
#endif //COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP

@ -1,4 +1,5 @@
#include "hash.hpp" #include "hash.hpp"
#include "conversion.hpp"
#include <extern/smhasher/MurmurHash3.h> #include <extern/smhasher/MurmurHash3.h>
@ -34,7 +35,7 @@ namespace Files
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
throw std::runtime_error("Error while reading \"" + fileName.string() + "\" to get hash: " + std::string(e.what())); //TODO(Project579): This will probably break in windows with unicode paths throw std::runtime_error("Error while reading \"" + Files::pathToUnicodeString(fileName) + "\" to get hash: " + e.what());
} }
return hash; return hash;
} }

@ -24,9 +24,9 @@ namespace
} }
} }
if (dir == nullptr) if (dir == nullptr)
return std::filesystem::path(); return {};
else else
return std::filesystem::path(dir); return dir;
} }
std::filesystem::path getEnv(const std::string& envVariable, const std::filesystem::path& fallback) std::filesystem::path getEnv(const std::string& envVariable, const std::filesystem::path& fallback)

@ -1,4 +1,5 @@
#include "multidircollection.hpp" #include "multidircollection.hpp"
#include "conversion.hpp"
#include <filesystem> #include <filesystem>
@ -30,19 +31,18 @@ namespace Files
{ {
if (!std::filesystem::is_directory(directory)) if (!std::filesystem::is_directory(directory))
{ {
Log(Debug::Info) << "Skipping invalid directory: " << directory.string(); //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Skipping invalid directory: " << directory;
continue; continue;
} }
for (std::filesystem::directory_iterator dirIter(directory); for (const auto& dirIter : std::filesystem::directory_iterator(directory))
dirIter != std::filesystem::directory_iterator(); ++dirIter)
{ {
std::filesystem::path path = *dirIter; const auto& path = dirIter.path();
if (!equal (extension, path.extension().string())) //TODO(Project579): let's hope unicode characters are never used in these extensions on windows or this will break if (!equal (extension, Files::pathToUnicodeString(path.extension())))
continue; continue;
std::string filename = path.filename().string(); //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break const auto filename = Files::pathToUnicodeString(path.filename());
TIter result = mFiles.find (filename); TIter result = mFiles.find (filename);

@ -1,4 +1,5 @@
#include "openfile.hpp" #include "openfile.hpp"
#include "conversion.hpp"
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
@ -9,7 +10,7 @@ namespace Files
{ {
auto stream = std::make_unique<std::ifstream>(path, std::ios::binary); auto stream = std::make_unique<std::ifstream>(path, std::ios::binary);
if (!stream->is_open()) if (!stream->is_open())
throw std::runtime_error("Failed to open '" + path.string() + "' for reading: " + std::strerror(errno)); //TODO(Project579): This will probably break in windows with unicode paths throw std::runtime_error("Failed to open '" + Files::pathToUnicodeString(path) + "' for reading: " + std::strerror(errno));
stream->exceptions(std::ios::badbit); stream->exceptions(std::ios::badbit);
return stream; return stream;
} }

@ -2,6 +2,7 @@
#include <array> #include <array>
#include <string> #include <string>
#include <utility>
#include <osg/Texture1D> #include <osg/Texture1D>
#include <osg/Texture2D> #include <osg/Texture2D>
@ -16,6 +17,7 @@
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/files/conversion.hpp>
#include "parse_constants.hpp" #include "parse_constants.hpp"
@ -37,9 +39,9 @@ namespace
namespace fx namespace fx
{ {
Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, const std::string& name, int width, int height, bool ubo, bool supportsNormals) Technique::Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width, int height, bool ubo, bool supportsNormals)
: mName(name) : mName(std::move(name))
, mFileName((std::filesystem::path(Technique::sSubdir) / (mName + Technique::sExt)).string()) //TODO(Project579): let's hope unicode characters are never used in these filenames on windows or this will break , mFileName(Files::pathToUnicodeString((Files::pathFromUnicodeString(Technique::sSubdir) / (mName + Technique::sExt))))
, mLastModificationTime(std::filesystem::file_time_type()) , mLastModificationTime(std::filesystem::file_time_type())
, mWidth(width) , mWidth(width)
, mHeight(height) , mHeight(height)

@ -123,7 +123,7 @@ namespace fx
static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4); static constexpr FlagsType Flag_Disable_SunGlare = (1 << 4);
static constexpr FlagsType Flag_Hidden = (1 << 5); static constexpr FlagsType Flag_Hidden = (1 << 5);
Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, const std::string& name, int width, int height, bool ubo, bool supportsNormals); Technique(const VFS::Manager& vfs, Resource::ImageManager& imageManager, std::string name, int width, int height, bool ubo, bool supportsNormals);
bool compile(); bool compile();

@ -8,6 +8,7 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/files/conversion.hpp>
namespace LuaUtil namespace LuaUtil
{ {
@ -270,7 +271,7 @@ namespace LuaUtil
sol::function LuaState::loadInternalLib(std::string_view libName) sol::function LuaState::loadInternalLib(std::string_view libName)
{ {
const auto path = packageNameToPath(libName, mLibSearchPaths); const auto path = packageNameToPath(libName, mLibSearchPaths);
sol::load_result res = mLua.load_file(path.string(), sol::load_mode::text); //TODO(Project579): This will probably break in windows with unicode paths sol::load_result res = mLua.load_file(Files::pathToUnicodeString(path), sol::load_mode::text);
if (!res.valid()) if (!res.valid())
throw std::runtime_error("Lua error: " + res.get<std::string>()); throw std::runtime_error("Lua error: " + res.get<std::string>());
return res; return res;

@ -160,7 +160,7 @@ namespace LuaUtil
assert(mData.empty()); // Shouldn't be used before loading assert(mData.empty()); // Shouldn't be used before loading
try try
{ {
Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << std::filesystem::file_size(path) << " bytes)"; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Loading Lua storage \"" << path << "\" (" << std::filesystem::file_size(path) << " bytes)";
std::ifstream fin(path, std::fstream::binary); std::ifstream fin(path, std::fstream::binary);
std::string serializedData((std::istreambuf_iterator<char>(fin)), std::istreambuf_iterator<char>()); std::string serializedData((std::istreambuf_iterator<char>(fin)), std::istreambuf_iterator<char>());
sol::table data = deserialize(mLua, serializedData); sol::table data = deserialize(mLua, serializedData);
@ -186,7 +186,7 @@ namespace LuaUtil
data[sectionName] = section->asTable(); data[sectionName] = section->asTable();
} }
std::string serializedData = serialize(data); std::string serializedData = serialize(data);
Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)"; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Saving Lua storage \"" << path << "\" (" << serializedData.size() << " bytes)";
std::ofstream fout(path, std::fstream::binary); std::ofstream fout(path, std::fstream::binary);
fout.write(serializedData.data(), serializedData.size()); fout.write(serializedData.data(), serializedData.size());
fout.close(); fout.close();

@ -7,6 +7,7 @@
#include <MyGUI_DataFileStream.h> #include <MyGUI_DataFileStream.h>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
#include <components/files/conversion.hpp>
namespace namespace
{ {
@ -68,7 +69,7 @@ const std::string &DataManager::getDataPath(const std::string &name) const
if (!isDataExist(name)) if (!isDataExist(name))
return result; return result;
result = (mResourcePath / name).string(); //TODO(Project579): This is broken on windows with unicode paths result = Files::pathToUnicodeString(mResourcePath / name);
return result; return result;
} }

@ -10,7 +10,7 @@ namespace osgMyGUI
{ {
mStream.open(mFileName, std::ios_base::out); mStream.open(mFileName, std::ios_base::out);
if (!mStream.is_open()) if (!mStream.is_open())
Log(Debug::Error) << "Unable to create MyGUI log with path " << mFileName; //TODO(Project579): This is broken on windows with unicode paths Log(Debug::Error) << "Unable to create MyGUI log with path " << mFileName;
} }
void CustomLogListener::close() void CustomLogListener::close()

@ -316,7 +316,7 @@ void NIFFile::parse(Files::IStreamPtr&& stream)
r = entry->second(); r = entry->second();
if (!supportedVersion) if (!supportedVersion)
Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")"; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i << " (" << filename << ")";
assert(r != nullptr); assert(r != nullptr);
assert(r->recType != RC_MISSING); assert(r->recType != RC_MISSING);

@ -21,6 +21,7 @@
#include <components/nif/parent.hpp> #include <components/nif/parent.hpp>
#include <components/settings/settings.hpp> #include <components/settings/settings.hpp>
#include <components/files/conversion.hpp>
namespace namespace
{ {
@ -187,7 +188,7 @@ osg::ref_ptr<Resource::BulletShape> BulletNifLoader::load(const Nif::File& nif)
if (node) if (node)
roots.emplace_back(node); roots.emplace_back(node);
} }
const std::string filename = nif.getFilename().string(); //TODO(Project579): This will probably break in windows with unicode paths const std::string filename = Files::pathToUnicodeString(nif.getFilename());
mShape->mFileName = filename; mShape->mFileName = filename;
if (roots.empty()) if (roots.empty())
{ {

@ -299,7 +299,7 @@ namespace NifOsg
setupController(key, callback, /*animflags*/0); setupController(key, callback, /*animflags*/0);
if (!target.mKeyframeControllers.emplace(strdata->string, callback).second) if (!target.mKeyframeControllers.emplace(strdata->string, callback).second)
Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version"; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Verbose) << "Controller " << strdata->string << " present more than once in " << nif->getFilename() << ", ignoring later version";
} }
} }
@ -485,20 +485,20 @@ namespace NifOsg
{ {
if (nifNode->recType != Nif::RC_NiTextureEffect) if (nifNode->recType != Nif::RC_NiTextureEffect)
{ {
Log(Debug::Info) << "Unhandled effect " << nifNode->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled effect " << nifNode->recName << " in " << mFilename;
return; return;
} }
const Nif::NiTextureEffect* textureEffect = static_cast<const Nif::NiTextureEffect*>(nifNode); const Nif::NiTextureEffect* textureEffect = static_cast<const Nif::NiTextureEffect*>(nifNode);
if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map) if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map)
{ {
Log(Debug::Info) << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in " << mFilename;
return; return;
} }
if (textureEffect->texture.empty()) if (textureEffect->texture.empty())
{ {
Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "NiTextureEffect missing source texture in " << mFilename;
return; return;
} }
@ -515,7 +515,7 @@ namespace NifOsg
texGen->setMode(osg::TexGen::SPHERE_MAP); texGen->setMode(osg::TexGen::SPHERE_MAP);
break; break;
default: default:
Log(Debug::Info) << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << " in " << mFilename;
return; return;
} }
@ -875,7 +875,7 @@ namespace NifOsg
// These controllers are handled elsewhere // These controllers are handled elsewhere
} }
else else
Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename;
} }
} }
@ -915,7 +915,7 @@ namespace NifOsg
composite->addController(osgctrl); composite->addController(osgctrl);
} }
else else
Log(Debug::Info) << "Unexpected material controller " << ctrl->recType << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unexpected material controller " << ctrl->recType << " in " << mFilename;
} }
} }
@ -959,7 +959,7 @@ namespace NifOsg
composite->addController(callback); composite->addController(callback);
} }
else else
Log(Debug::Info) << "Unexpected texture controller " << ctrl->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unexpected texture controller " << ctrl->recName << " in " << mFilename;
} }
} }
@ -994,7 +994,7 @@ namespace NifOsg
// unused // unused
} }
else else
Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled particle modifier " << affectors->recName << " in " << mFilename;
} }
for (; !colliders.empty(); colliders = colliders->next) for (; !colliders.empty(); colliders = colliders->next)
{ {
@ -1009,7 +1009,7 @@ namespace NifOsg
program->addOperator(new SphericalCollider(sphericalcollider)); program->addOperator(new SphericalCollider(sphericalcollider));
} }
else else
Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled particle collider " << colliders->recName << " in " << mFilename;
} }
} }
@ -1152,7 +1152,7 @@ namespace NifOsg
} }
if (!partctrl) if (!partctrl)
{ {
Log(Debug::Info) << "No particle controller found in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "No particle controller found in " << mFilename;
return; return;
} }
@ -1247,7 +1247,7 @@ namespace NifOsg
unsigned int uvSet = *it; unsigned int uvSet = *it;
if (uvSet >= uvlist.size()) if (uvSet >= uvlist.size())
{ {
Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Verbose) << "Out of bounds UV set " << uvSet << " on shape \"" << name << "\" in " << mFilename;
if (uvlist.empty()) if (uvlist.empty())
continue; continue;
uvSet = 0; uvSet = 0;
@ -1419,7 +1419,7 @@ namespace NifOsg
case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA; case 9: return osg::BlendFunc::ONE_MINUS_DST_ALPHA;
case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE; case 10: return osg::BlendFunc::SRC_ALPHA_SATURATE;
default: default:
Log(Debug::Info) << "Unexpected blend mode: "<< mode << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unexpected blend mode: "<< mode << " in " << mFilename;
return osg::BlendFunc::SRC_ALPHA; return osg::BlendFunc::SRC_ALPHA;
} }
} }
@ -1437,7 +1437,7 @@ namespace NifOsg
case 6: return osg::AlphaFunc::GEQUAL; case 6: return osg::AlphaFunc::GEQUAL;
case 7: return osg::AlphaFunc::NEVER; case 7: return osg::AlphaFunc::NEVER;
default: default:
Log(Debug::Info) << "Unexpected blend mode: " << mode << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unexpected blend mode: " << mode << " in " << mFilename;
return osg::AlphaFunc::LEQUAL; return osg::AlphaFunc::LEQUAL;
} }
} }
@ -1455,7 +1455,7 @@ namespace NifOsg
case 6: return osg::Stencil::GEQUAL; case 6: return osg::Stencil::GEQUAL;
case 7: return osg::Stencil::ALWAYS; case 7: return osg::Stencil::ALWAYS;
default: default:
Log(Debug::Info) << "Unexpected stencil function: " << func << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unexpected stencil function: " << func << " in " << mFilename;
return osg::Stencil::NEVER; return osg::Stencil::NEVER;
} }
} }
@ -1471,7 +1471,7 @@ namespace NifOsg
case 4: return osg::Stencil::DECR; case 4: return osg::Stencil::DECR;
case 5: return osg::Stencil::INVERT; case 5: return osg::Stencil::INVERT;
default: default:
Log(Debug::Info) << "Unexpected stencil operation: " << op << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unexpected stencil operation: " << op << " in " << mFilename;
return osg::Stencil::KEEP; return osg::Stencil::KEEP;
} }
} }
@ -1514,7 +1514,7 @@ namespace NifOsg
packing = 4; packing = 4;
break; break;
default: default:
Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled internal pixel format " << pixelData->fmt << " in " << mFilename;
return nullptr; return nullptr;
} }
@ -1572,7 +1572,7 @@ namespace NifOsg
{ {
if (pixelData->palette.empty() || pixelData->bpp != 8) if (pixelData->palette.empty() || pixelData->bpp != 8)
{ {
Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring"; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Palettized texture in " << mFilename << " is invalid, ignoring";
return nullptr; return nullptr;
} }
pixelformat = pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8 ? GL_RGB : GL_RGBA; pixelformat = pixelData->fmt == Nif::NiPixelData::NIPXFMT_PAL8 ? GL_RGB : GL_RGBA;
@ -1644,7 +1644,7 @@ namespace NifOsg
break; break;
default: default:
{ {
Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename;
continue; continue;
} }
} }
@ -1658,7 +1658,7 @@ namespace NifOsg
if(tex.texture.empty() && texprop->controller.empty()) if(tex.texture.empty() && texprop->controller.empty())
{ {
if (i == 0) if (i == 0)
Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Base texture is in use but empty on shape \"" << nodeName << "\" in " << mFilename;
continue; continue;
} }
@ -1815,7 +1815,7 @@ namespace NifOsg
break; break;
default: default:
{ {
Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled texture stage " << i << " on shape \"" << nodeName << "\" in " << mFilename;
continue; continue;
} }
} }
@ -1859,10 +1859,10 @@ namespace NifOsg
case Nif::BSShaderType::ShaderType_Water: case Nif::BSShaderType::ShaderType_Water:
case Nif::BSShaderType::ShaderType_Lighting30: case Nif::BSShaderType::ShaderType_Lighting30:
case Nif::BSShaderType::ShaderType_Tile: case Nif::BSShaderType::ShaderType_Tile:
Log(Debug::Warning) << "Unhandled BSShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Unhandled BSShaderType " << type << " in " << mFilename;
return std::string_view(); return std::string_view();
} }
Log(Debug::Warning) << "Unknown BSShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Unknown BSShaderType " << type << " in " << mFilename;
return std::string_view(); return std::string_view();
} }
@ -1891,10 +1891,10 @@ namespace NifOsg
case Nif::BSLightingShaderType::ShaderType_LODNoise: case Nif::BSLightingShaderType::ShaderType_LODNoise:
case Nif::BSLightingShaderType::ShaderType_MultitexLandLODBlend: case Nif::BSLightingShaderType::ShaderType_MultitexLandLODBlend:
case Nif::BSLightingShaderType::ShaderType_Dismemberment: case Nif::BSLightingShaderType::ShaderType_Dismemberment:
Log(Debug::Warning) << "Unhandled BSLightingShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Unhandled BSLightingShaderType " << type << " in " << mFilename;
return std::string_view(); return std::string_view();
} }
Log(Debug::Warning) << "Unknown BSLightingShaderType " << type << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Unknown BSLightingShaderType " << type << " in " << mFilename;
return std::string_view(); return std::string_view();
} }
@ -2057,7 +2057,7 @@ namespace NifOsg
break; break;
} }
default: default:
Log(Debug::Info) << "Unhandled " << property->recName << " in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Unhandled " << property->recName << " in " << mFilename;
break; break;
} }
} }
@ -2304,7 +2304,7 @@ namespace NifOsg
else if (type == Nif::RC_NiClusterAccumulator) else if (type == Nif::RC_NiClusterAccumulator)
setBin_BackToFront(stateset); setBin_BackToFront(stateset);
else else
Log(Debug::Error) << "Unrecognized NiAccumulator in " << mFilename; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Unrecognized NiAccumulator in " << mFilename;
}; };
switch (mPushedSorter->mMode) switch (mPushedSorter->mMode)

@ -48,6 +48,7 @@
#include <components/files/hash.hpp> #include <components/files/hash.hpp>
#include <components/files/memorystream.hpp> #include <components/files/memorystream.hpp>
#include <components/files/conversion.hpp>
#include "imagemanager.hpp" #include "imagemanager.hpp"
#include "niffilemanager.hpp" #include "niffilemanager.hpp"
@ -498,14 +499,14 @@ namespace Resource
osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options) override osgDB::ReaderWriter::ReadResult readImage(const std::string& filename, const osgDB::Options* options) override
{ {
std::filesystem::path filePath(filename); //TODO(Project579): This will probably break in windows with unicode paths auto filePath = Files::pathFromUnicodeString(filename);
if (filePath.is_absolute()) if (filePath.is_absolute())
// It is a hack. Needed because either OSG or libcollada-dom tries to make an absolute path from // It is a hack. Needed because either OSG or libcollada-dom tries to make an absolute path from
// our relative VFS path by adding current working directory. // our relative VFS path by adding current working directory.
filePath = std::filesystem::relative(filename, osgDB::getCurrentWorkingDirectory()); filePath = std::filesystem::relative(filename, osgDB::getCurrentWorkingDirectory());
try try
{ {
return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(filePath.string()), //TODO(Project579): This will probably break in windows with unicode paths return osgDB::ReaderWriter::ReadResult(mImageManager->getImage(Files::pathToUnicodeString(filePath)),
osgDB::ReaderWriter::ReadResult::FILE_LOADED); osgDB::ReaderWriter::ReadResult::FILE_LOADED);
} }
catch (std::exception& e) catch (std::exception& e)

@ -2,6 +2,7 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/sceneutil/workqueue.hpp> #include <components/sceneutil/workqueue.hpp>
#include <components/files/conversion.hpp>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <osg/Image> #include <osg/Image>
@ -129,7 +130,7 @@ namespace SceneUtil
if (fileName.empty()) if (fileName.empty())
mCallback("Failed to save screenshot"); mCallback("Failed to save screenshot");
else else
mCallback(fileName.string() + " has been saved"); //TODO(Project579): This will probably break in windows with unicode paths mCallback(Files::pathToUnicodeString(fileName) + " has been saved");
} }
AsyncScreenCaptureOperation::AsyncScreenCaptureOperation(osg::ref_ptr<WorkQueue> queue, AsyncScreenCaptureOperation::AsyncScreenCaptureOperation(osg::ref_ptr<WorkQueue> queue,

@ -304,7 +304,7 @@ void Settings::SettingsFileParser::saveSettingsFile(const std::filesystem::path
// Now install the newly written file in the requested place. // Now install the newly written file in the requested place.
if (changed) { if (changed) {
Log(Debug::Info) << "Updating settings file: " << file; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Updating settings file: " << file;
std::ofstream ofstream; std::ofstream ofstream;
ofstream.open(file); ofstream.open(file);
ofstream << ostream.rdbuf(); ofstream << ostream.rdbuf();

@ -15,6 +15,7 @@
#include <components/serialization/osgyaml.hpp> #include <components/serialization/osgyaml.hpp>
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/files/conversion.hpp>
namespace Settings namespace Settings
{ {
@ -109,7 +110,7 @@ namespace Settings
mData = YAML::Null; mData = YAML::Null;
mPath = path; mPath = path;
Log(Debug::Info) << "Loading shader settings file: " << mPath; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Loading shader settings file: " << mPath;
if (!std::filesystem::exists(mPath)) if (!std::filesystem::exists(mPath))
{ {
@ -123,7 +124,7 @@ namespace Settings
try try
{ {
mData = YAML::LoadFile(mPath.string()); //TODO(Project579): This will probably break in windows with unicode paths mData = YAML::LoadFile(Files::pathToUnicodeString(mPath));
mData.SetStyle(YAML::EmitterStyle::Block); mData.SetStyle(YAML::EmitterStyle::Block);
if (!mData["config"]) if (!mData["config"])

@ -126,7 +126,7 @@ namespace Shader
includeFstream.open(includePath); includeFstream.open(includePath);
if (includeFstream.fail()) if (includeFstream.fail())
{ {
Log(Debug::Error) << "Shader " << fileName << " error: Failed to open include " << includePath.string(); //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Shader " << fileName << " error: Failed to open include " << includePath;
return false; return false;
} }
int includedFileNumber = fileNumber++; int includedFileNumber = fileNumber++;
@ -472,7 +472,7 @@ namespace Shader
stream.open(path); stream.open(path);
if (stream.fail()) if (stream.fail())
{ {
Log(Debug::Error) << "Failed to open " << path.string(); //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Error) << "Failed to open " << path;
return nullptr; return nullptr;
} }
std::stringstream buffer; std::stringstream buffer;

@ -17,7 +17,7 @@ Version getOpenmwVersion(const std::filesystem::path &resourcePath)
return v; return v;
} }
std::string Version::describe() std::string Version::describe() const
{ {
std::string str = "OpenMW version " + mVersion; std::string str = "OpenMW version " + mVersion;
std::string rev = mCommitHash; std::string rev = mCommitHash;

@ -13,7 +13,7 @@ namespace Version
std::string mCommitHash; std::string mCommitHash;
std::string mTagHash; std::string mTagHash;
std::string describe(); std::string describe() const;
}; };
/// Read OpenMW version from the version file located in resourcePath. /// Read OpenMW version from the version file located in resourcePath.

@ -6,6 +6,7 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/files/constrainedfilestream.hpp> #include <components/files/constrainedfilestream.hpp>
#include <components/files/conversion.hpp>
namespace VFS namespace VFS
{ {
@ -21,7 +22,7 @@ namespace VFS
{ {
if (!mBuiltIndex) if (!mBuiltIndex)
{ {
const auto str = mPath.string(); //TODO(Project579): This will probably break in windows with unicode paths const auto str = mPath.u8string();
size_t prefix = str.size (); size_t prefix = str.size ();
if (!mPath.empty() && str [prefix - 1] != '\\' && str [prefix - 1] != '/') if (!mPath.empty() && str [prefix - 1] != '\\' && str [prefix - 1] != '/')
@ -34,7 +35,7 @@ namespace VFS
continue; continue;
const auto& path = i.path (); const auto& path = i.path ();
const auto& proper = path.string (); //TODO(Project579): This will probably break in windows with unicode paths const auto& proper = Files::pathToUnicodeString(path);
FileSystemArchiveFile file(path); FileSystemArchiveFile file(path);
@ -44,7 +45,7 @@ namespace VFS
const auto inserted = mIndex.insert(std::make_pair(searchable, file)); const auto inserted = mIndex.insert(std::make_pair(searchable, file));
if (!inserted.second) if (!inserted.second)
Log(Debug::Warning) << "Warning: found duplicate file for '" << proper << "', please check your file system for two files with the same name in different cases."; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Warning) << "Warning: found duplicate file for '" << proper << "', please check your file system for two files with the same name in different cases.";
else else
out[inserted.first->first] = &inserted.first->second; out[inserted.first->first] = &inserted.first->second;
} }
@ -66,7 +67,7 @@ namespace VFS
std::string FileSystemArchive::getDescription() const std::string FileSystemArchive::getDescription() const
{ {
return std::string{"DIR: "} + mPath.string(); //TODO(Project579): This will probably break in windows with unicode paths return "DIR: " + Files::pathToUnicodeString(mPath);
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------

@ -5,6 +5,8 @@
#include <algorithm> #include <algorithm>
#include <components/misc/strings/lower.hpp> #include <components/misc/strings/lower.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/files/conversion.hpp>
#include "archive.hpp" #include "archive.hpp"
@ -56,7 +58,7 @@ namespace VFS
mIndex.clear(); mIndex.clear();
for (const auto& archive : mArchives) for (const auto& archive : mArchives)
archive->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char); //TODO(Project579): This will probably break in windows with unicode paths archive->listResources(mIndex, mStrict ? &strict_normalize_char : &nonstrict_normalize_char);
} }
Files::IStreamPtr Manager::get(std::string_view name) const Files::IStreamPtr Manager::get(std::string_view name) const
@ -104,13 +106,13 @@ namespace VFS
std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path &name) const std::filesystem::path Manager::getAbsoluteFileName(const std::filesystem::path &name) const
{ {
std::string normalized(name); //TODO(Project579): This will probably break in windows with unicode paths std::string normalized = Files::pathToUnicodeString(name);
normalize_path(normalized, mStrict); //TODO(Project579): This will probably break in windows with unicode paths normalize_path(normalized, mStrict);
const auto found = mIndex.find(normalized); const auto found = mIndex.find(normalized);
if (found == mIndex.end()) if (found == mIndex.end())
throw std::runtime_error("Resource '" + normalized + "' not found"); throw std::runtime_error("Resource '" + normalized + "' not found");
return found->second->getPath();//TODO(Project579): This will probably break in windows with unicode paths return found->second->getPath();
} }
namespace namespace

@ -23,7 +23,7 @@ namespace VFS
{ {
// Last BSA has the highest priority // Last BSA has the highest priority
const auto archivePath = collections.getPath(*archive); const auto archivePath = collections.getPath(*archive);
Log(Debug::Info) << "Adding BSA archive " << archivePath; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Adding BSA archive " << archivePath;
Bsa::BsaVersion bsaVersion = Bsa::CompressedBSAFile::detectVersion(archivePath); Bsa::BsaVersion bsaVersion = Bsa::CompressedBSAFile::detectVersion(archivePath);
if (bsaVersion == Bsa::BSAVER_COMPRESSED) if (bsaVersion == Bsa::BSAVER_COMPRESSED)
@ -49,7 +49,7 @@ namespace VFS
vfs->addArchive(std::make_unique<FileSystemArchive>(dataDir)); vfs->addArchive(std::make_unique<FileSystemArchive>(dataDir));
} }
else else
Log(Debug::Info) << "Ignoring duplicate data directory " << dataDir; //TODO(Project579): This will probably break in windows with unicode paths Log(Debug::Info) << "Ignoring duplicate data directory " << dataDir;
} }
} }

Loading…
Cancel
Save