From 5394f01ceae1542d038f61625ccf82beec75ca10 Mon Sep 17 00:00:00 2001 From: Hartmnt Date: Mon, 25 Nov 2024 20:43:13 +0000 Subject: [PATCH] FIX(client): Fix Windows Unicode paths when using raw file streams Presumably a recent Windows update broke the way we were using filepaths. Specifically, the internal representation of non-ASCII characters is weird in Windows and not UTF-8. Why the code we had ever worked before is unclear, but it is now broken either way. This commit introduces the boost::filesystem::path abstraction to handle the creation of raw output files gracefully on all platforms. Fixes #6628 --- src/QtUtils.cpp | 13 +++++++++++++ src/QtUtils.h | 7 +++++++ src/mumble/PluginInstaller.cpp | 7 +++++-- src/mumble/Settings.cpp | 18 ++++++++++-------- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/QtUtils.cpp b/src/QtUtils.cpp index fb08cce6687..646021f116a 100644 --- a/src/QtUtils.cpp +++ b/src/QtUtils.cpp @@ -7,6 +7,8 @@ #include #include +#include + namespace Mumble { namespace QtUtils { void deleteQObject(QObject *object) { object->deleteLater(); } @@ -23,6 +25,17 @@ namespace QtUtils { return QString(); } + boost::filesystem::path qstring_to_path(const QString &input) { + // Path handling uses wide character encoding on Windows. + // When converting from QStrings, we need to take that + // into account, otherwise raw file operations will fail when + // the path contains Unicode characters. +#ifdef Q_OS_WIN + return boost::filesystem::path(input.toStdWString()); +#else + return boost::filesystem::path(input.toUtf8()); +#endif + } } // namespace QtUtils } // namespace Mumble diff --git a/src/QtUtils.h b/src/QtUtils.h index 6fb0bd52216..f25b9c85866 100644 --- a/src/QtUtils.h +++ b/src/QtUtils.h @@ -9,6 +9,8 @@ #include #include +#include + #include class QObject; @@ -34,6 +36,11 @@ namespace QtUtils { */ QString decode_first_utf8_qssl_string(const QStringList &list); + /** + * Creates a platform agnostic path from a QString + */ + boost::filesystem::path qstring_to_path(const QString &input); + } // namespace QtUtils } // namespace Mumble diff --git a/src/mumble/PluginInstaller.cpp b/src/mumble/PluginInstaller.cpp index 942eb69f767..1369cfef2b8 100644 --- a/src/mumble/PluginInstaller.cpp +++ b/src/mumble/PluginInstaller.cpp @@ -6,6 +6,7 @@ #include "PluginInstaller.h" #include "PluginManager.h" #include "PluginManifest.h" +#include "QtUtils.h" #include "Global.h" #include @@ -18,9 +19,10 @@ #include #include -#include #include +#include + #include #include #include @@ -124,7 +126,8 @@ void PluginInstaller::init() { zipInput.clear(); Poco::Zip::ZipInputStream zipin(zipInput, pluginIt->second); - std::ofstream out(tmpPluginPath.toStdString(), std::ios::out | std::ios::binary); + boost::filesystem::ofstream out(Mumble::QtUtils::qstring_to_path(tmpPluginPath), + std::ios::out | std::ios::binary); Poco::StreamCopier::copyStream(zipin, out); m_pluginSource = QFileInfo(tmpPluginPath); diff --git a/src/mumble/Settings.cpp b/src/mumble/Settings.cpp index 0eae32d3076..ea505b36629 100644 --- a/src/mumble/Settings.cpp +++ b/src/mumble/Settings.cpp @@ -10,6 +10,7 @@ #include "EnvUtils.h" #include "JSONSerialization.h" #include "Log.h" +#include "QtUtils.h" #include "SSL.h" #include "SettingsKeys.h" #include "SettingsMacros.h" @@ -35,12 +36,12 @@ # include #endif +#include #include #include #include #include -#include #include #include @@ -157,11 +158,12 @@ void Settings::save(const QString &path) const { QFile tmpFile(QString::fromLatin1("%1/mumble_settings.json.tmp") .arg(QStandardPaths::writableLocation(QStandardPaths::TempLocation))); - { - // The separate scope makes sure, the stream is closed again after the write has finished - std::ofstream stream(tmpFile.fileName().toUtf8()); + boost::filesystem::ofstream stream(Mumble::QtUtils::qstring_to_path(tmpFile.fileName())); + stream << settingsJSON.dump(4) << std::endl; + stream.close(); - stream << settingsJSON.dump(4) << std::endl; + if (stream.fail()) { + qWarning("Failed at writing temporary settings file: %s", qUtf8Printable(tmpFile.fileName())); } QFile targetFile(path); @@ -224,7 +226,7 @@ void Settings::load(const QString &path) { settingsLocation = path; } - std::ifstream stream(path.toUtf8()); + boost::filesystem::ifstream stream(Mumble::QtUtils::qstring_to_path(path)); nlohmann::json settingsJSON; try { @@ -624,13 +626,13 @@ void OverlaySettings::savePresets(const QString &filename) { settingsJSON.erase(SettingsKeys::OVERLAY_LAUNCHERS_KEY); settingsJSON.erase(SettingsKeys::OVERLAY_LAUNCHERS_EXCLUDE_KEY); - std::ofstream stream(filename.toUtf8()); + boost::filesystem::ofstream stream(Mumble::QtUtils::qstring_to_path(filename)); stream << settingsJSON.dump(4) << std::endl; } void OverlaySettings::load(const QString &filename) { - std::ifstream stream(filename.toUtf8()); + boost::filesystem::ifstream stream(Mumble::QtUtils::qstring_to_path(filename)); nlohmann::json settingsJSON; try {