From 5b702ae986464fe6dbc8557d4b2da725ac1ed175 Mon Sep 17 00:00:00 2001 From: Fabian Vogt Date: Mon, 26 Jun 2023 09:52:05 +0200 Subject: [PATCH] Session: Parse .desktop files manually again Using QSettings::IniFormat doesn't quite work. Implement a custom parser for those files to handle them according to the specification. Fixes #1745 --- src/common/Session.cpp | 52 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/src/common/Session.cpp b/src/common/Session.cpp index 4bb2142ca..5eec64859 100644 --- a/src/common/Session.cpp +++ b/src/common/Session.cpp @@ -34,6 +34,56 @@ const QString s_entryExtention = QStringLiteral(".desktop"); namespace SDDM { + // QSettings::IniFormat can't be used to read .desktop files due to different + // syntax of values (escape sequences, quoting, automatic QStringList detection). + // So implement yet another .desktop file parser. + class DesktopFileFormat { + static bool readFunc(QIODevice &device, QSettings::SettingsMap &map) + { + QString currentSectionName; + while(!device.atEnd()) + { + // Iterate each line, remove line terminators + const auto line = device.readLine().replace("\r", "").replace("\n", ""); + if(line.isEmpty() || line.startsWith('#')) + continue; // Ignore empty lines and comments + + if(line.startsWith('[')) // Section header + { + // Remove [ and ]. + currentSectionName = QString::fromUtf8(line.mid(1, line.length() - 2)); + } + else if(int equalsPos = line.indexOf('='); equalsPos > 0) // Key=Value + { + const auto key = QString::fromUtf8(line.left(equalsPos)); + + // Read the value, handle escape sequences + auto valueBytes = line.mid(equalsPos + 1); + valueBytes.replace("\\s", " ").replace("\\n", "\n"); + valueBytes.replace("\\t", "\t").replace("\\r", "\r"); + valueBytes.replace("\\\\", "\\"); + + auto value = QString::fromUtf8(valueBytes); + map.insert(currentSectionName + QLatin1Char('/') + key, value); + } + } + + return true; + } + public: + // Register the .desktop file format if necessary, return its id. + static QSettings::Format format() + { + static QSettings::Format s_format = QSettings::InvalidFormat; + if (s_format == QSettings::InvalidFormat) + s_format = QSettings::registerFormat(QStringLiteral("desktop"), + DesktopFileFormat::readFunc, nullptr, + Qt::CaseSensitive); + + return s_format; + } + }; + Session::Session() : m_valid(false) , m_type(UnknownSession) @@ -169,7 +219,7 @@ namespace SDDM { if (!file.isOpen()) return; - QSettings settings(m_fileName, QSettings::IniFormat); + QSettings settings(m_fileName, DesktopFileFormat::format()); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) settings.setIniCodec("UTF-8"); #endif