1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
From 5b702ae986464fe6dbc8557d4b2da725ac1ed175 Mon Sep 17 00:00:00 2001
From: Fabian Vogt <fvogt@suse.de>
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
|