Skip to content

Commit

Permalink
FIX(client): Fix Windows Unicode paths when using raw file streams
Browse files Browse the repository at this point in the history
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 mumble-voip#6628
  • Loading branch information
Hartmnt committed Dec 5, 2024
1 parent 1f9fa17 commit 5394f01
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 10 deletions.
13 changes: 13 additions & 0 deletions src/QtUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <QStringList>
#include <QUrl>

#include <boost/filesystem.hpp>

namespace Mumble {
namespace QtUtils {
void deleteQObject(QObject *object) { object->deleteLater(); }
Expand All @@ -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
7 changes: 7 additions & 0 deletions src/QtUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <QCryptographicHash>
#include <QString>

#include <boost/filesystem.hpp>

#include <memory>

class QObject;
Expand All @@ -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

Expand Down
7 changes: 5 additions & 2 deletions src/mumble/PluginInstaller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "PluginInstaller.h"
#include "PluginManager.h"
#include "PluginManifest.h"
#include "QtUtils.h"
#include "Global.h"

#include <QMessageBox>
Expand All @@ -18,9 +19,10 @@
#include <QtGui/QIcon>

#include <exception>
#include <fstream>
#include <string>

#include <boost/filesystem/fstream.hpp>

#include <Poco/Exception.h>
#include <Poco/FileStream.h>
#include <Poco/StreamCopier.h>
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 10 additions & 8 deletions src/mumble/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -35,12 +36,12 @@
# include <QOperatingSystemVersion>
#endif

#include <boost/filesystem/fstream.hpp>
#include <boost/typeof/typeof.hpp>

#include <algorithm>
#include <cassert>
#include <cstring>
#include <fstream>
#include <limits>
#include <memory>

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 5394f01

Please sign in to comment.