1 | // Copyright (C) 2022 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QSETTINGS_P_H |
5 | #define QSETTINGS_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "QtCore/qdatetime.h" |
19 | #include "QtCore/qmap.h" |
20 | #include "QtCore/qmutex.h" |
21 | #include "QtCore/qiodevice.h" |
22 | #include "QtCore/qstack.h" |
23 | #include "QtCore/qstringlist.h" |
24 | |
25 | #include <QtCore/qvariant.h> |
26 | #include "qsettings.h" |
27 | |
28 | #ifndef QT_NO_QOBJECT |
29 | #include "private/qobject_p.h" |
30 | #endif |
31 | |
32 | QT_BEGIN_NAMESPACE |
33 | |
34 | #ifndef Q_OS_WIN |
35 | #define QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER |
36 | #endif |
37 | |
38 | // used in testing framework |
39 | #define QSETTINGS_P_H_VERSION 3 |
40 | |
41 | #ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER |
42 | static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseSensitive; |
43 | |
44 | class QSettingsKey : public QString |
45 | { |
46 | public: |
47 | inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, qsizetype /* position */ = -1) |
48 | : QString(key) { Q_ASSERT(cs == Qt::CaseSensitive); Q_UNUSED(cs); } |
49 | |
50 | inline QString originalCaseKey() const { return *this; } |
51 | inline qsizetype originalKeyPosition() const { return -1; } |
52 | }; |
53 | #else |
54 | static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseInsensitive; |
55 | |
56 | class QSettingsKey : public QString |
57 | { |
58 | public: |
59 | inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, qsizetype position = -1) |
60 | : QString(key), theOriginalKey(key), theOriginalKeyPosition(position) |
61 | { |
62 | if (cs == Qt::CaseInsensitive) |
63 | QString::operator=(toLower()); |
64 | } |
65 | |
66 | inline QString originalCaseKey() const { return theOriginalKey; } |
67 | inline qsizetype originalKeyPosition() const { return theOriginalKeyPosition; } |
68 | |
69 | private: |
70 | QString theOriginalKey; |
71 | qsizetype theOriginalKeyPosition; |
72 | }; |
73 | #endif |
74 | |
75 | Q_DECLARE_TYPEINFO(QSettingsKey, Q_RELOCATABLE_TYPE); |
76 | |
77 | typedef QMap<QSettingsKey, QByteArray> UnparsedSettingsMap; |
78 | typedef QMap<QSettingsKey, QVariant> ParsedSettingsMap; |
79 | |
80 | class QSettingsGroup |
81 | { |
82 | public: |
83 | inline QSettingsGroup() |
84 | : num(-1), maxNum(-1) {} |
85 | inline QSettingsGroup(const QString &s) |
86 | : str(s), num(-1), maxNum(-1) {} |
87 | inline QSettingsGroup(const QString &s, bool guessArraySize) |
88 | : str(s), num(0), maxNum(guessArraySize ? 0 : -1) {} |
89 | |
90 | inline QString name() const { return str; } |
91 | inline QString toString() const; |
92 | inline bool isArray() const { return num != -1; } |
93 | inline qsizetype arraySizeGuess() const { return maxNum; } |
94 | inline void setArrayIndex(qsizetype i) |
95 | { num = i + 1; if (maxNum != -1 && num > maxNum) maxNum = num; } |
96 | |
97 | QString str; |
98 | qsizetype num; |
99 | qsizetype maxNum; |
100 | }; |
101 | Q_DECLARE_TYPEINFO(QSettingsGroup, Q_RELOCATABLE_TYPE); |
102 | |
103 | inline QString QSettingsGroup::toString() const |
104 | { |
105 | QString result; |
106 | result = str; |
107 | if (num > 0) { |
108 | result += u'/'; |
109 | result += QString::number(num); |
110 | } |
111 | return result; |
112 | } |
113 | |
114 | class QConfFile |
115 | { |
116 | public: |
117 | ~QConfFile(); |
118 | |
119 | ParsedSettingsMap mergedKeyMap() const; |
120 | bool isWritable() const; |
121 | |
122 | static QConfFile *fromName(const QString &name, bool _userPerms); |
123 | Q_AUTOTEST_EXPORT |
124 | static void clearCache(); |
125 | |
126 | QString name; |
127 | QDateTime timeStamp; |
128 | qint64 size; |
129 | UnparsedSettingsMap unparsedIniSections; |
130 | ParsedSettingsMap originalKeys; |
131 | ParsedSettingsMap addedKeys; |
132 | ParsedSettingsMap removedKeys; |
133 | QAtomicInt ref; |
134 | QMutex mutex; |
135 | bool userPerms; |
136 | |
137 | private: |
138 | #ifdef Q_DISABLE_COPY |
139 | QConfFile(const QConfFile &); |
140 | QConfFile &operator=(const QConfFile &); |
141 | #endif |
142 | QConfFile(const QString &name, bool _userPerms); |
143 | |
144 | friend class QConfFile_createsItself; // silences compiler warning |
145 | }; |
146 | |
147 | class Q_AUTOTEST_EXPORT QSettingsPrivate |
148 | #ifndef QT_NO_QOBJECT |
149 | : public QObjectPrivate |
150 | #endif |
151 | { |
152 | #ifdef QT_NO_QOBJECT |
153 | QSettings *q_ptr; |
154 | #endif |
155 | Q_DECLARE_PUBLIC(QSettings) |
156 | |
157 | public: |
158 | QSettingsPrivate(QSettings::Format format); |
159 | QSettingsPrivate(QSettings::Format format, QSettings::Scope scope, |
160 | const QString &organization, const QString &application); |
161 | virtual ~QSettingsPrivate(); |
162 | |
163 | virtual void remove(const QString &key) = 0; |
164 | virtual void set(const QString &key, const QVariant &value) = 0; |
165 | virtual std::optional<QVariant> get(const QString &key) const = 0; |
166 | |
167 | enum ChildSpec { AllKeys, ChildKeys, ChildGroups }; |
168 | virtual QStringList children(const QString &prefix, ChildSpec spec) const = 0; |
169 | |
170 | virtual void clear() = 0; |
171 | virtual void sync() = 0; |
172 | virtual void flush() = 0; |
173 | virtual bool isWritable() const = 0; |
174 | virtual QString fileName() const = 0; |
175 | |
176 | QVariant value(QAnyStringView key, const QVariant *defaultValue) const; |
177 | QString actualKey(QAnyStringView key) const; |
178 | void beginGroupOrArray(const QSettingsGroup &group); |
179 | void setStatus(QSettings::Status status) const; |
180 | void requestUpdate(); |
181 | void update(); |
182 | |
183 | static QString normalizedKey(QAnyStringView key); |
184 | static QSettingsPrivate *create(QSettings::Format format, QSettings::Scope scope, |
185 | const QString &organization, const QString &application); |
186 | static QSettingsPrivate *create(const QString &fileName, QSettings::Format format); |
187 | |
188 | static void processChild(QStringView key, ChildSpec spec, QStringList &result); |
189 | |
190 | // Variant streaming functions |
191 | static QStringList variantListToStringList(const QVariantList &l); |
192 | static QVariant stringListToVariantList(const QStringList &l); |
193 | |
194 | // parser functions |
195 | static QString variantToString(const QVariant &v); |
196 | static QVariant stringToVariant(const QString &s); |
197 | static void iniEscapedKey(const QString &key, QByteArray &result); |
198 | static bool iniUnescapedKey(QByteArrayView key, QString &result); |
199 | static void iniEscapedString(const QString &str, QByteArray &result); |
200 | static void iniEscapedStringList(const QStringList &strs, QByteArray &result); |
201 | static bool iniUnescapedStringList(QByteArrayView str, QString &stringResult, |
202 | QStringList &stringListResult); |
203 | static QStringList splitArgs(const QString &s, qsizetype idx); |
204 | |
205 | QSettings::Format format; |
206 | QSettings::Scope scope; |
207 | QString organizationName; |
208 | QString applicationName; |
209 | |
210 | protected: |
211 | QStack<QSettingsGroup> groupStack; |
212 | QString groupPrefix; |
213 | bool fallbacks; |
214 | bool pendingChanges; |
215 | bool atomicSyncOnly = true; |
216 | mutable QSettings::Status status; |
217 | }; |
218 | |
219 | class QConfFileSettingsPrivate : public QSettingsPrivate |
220 | { |
221 | public: |
222 | QConfFileSettingsPrivate(QSettings::Format format, QSettings::Scope scope, |
223 | const QString &organization, const QString &application); |
224 | QConfFileSettingsPrivate(const QString &fileName, QSettings::Format format); |
225 | ~QConfFileSettingsPrivate(); |
226 | |
227 | void remove(const QString &key) override; |
228 | void set(const QString &key, const QVariant &value) override; |
229 | std::optional<QVariant> get(const QString &key) const override; |
230 | |
231 | QStringList children(const QString &prefix, ChildSpec spec) const override; |
232 | |
233 | void clear() override; |
234 | void sync() override; |
235 | void flush() override; |
236 | bool isWritable() const override; |
237 | QString fileName() const override; |
238 | |
239 | bool readIniFile(QByteArrayView data, UnparsedSettingsMap *unparsedIniSections); |
240 | static bool readIniSection(const QSettingsKey §ion, QByteArrayView data, |
241 | ParsedSettingsMap *settingsMap); |
242 | static bool readIniLine(QByteArrayView data, qsizetype &dataPos, |
243 | qsizetype &lineStart, qsizetype &lineLen, |
244 | qsizetype &equalsPos); |
245 | |
246 | private: |
247 | void initFormat(); |
248 | virtual void initAccess(); |
249 | void syncConfFile(QConfFile *confFile); |
250 | bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map); |
251 | #ifdef Q_OS_DARWIN |
252 | bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const; |
253 | bool writePlistFile(QIODevice &file, const ParsedSettingsMap &map) const; |
254 | #endif |
255 | void ensureAllSectionsParsed(QConfFile *confFile) const; |
256 | void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const; |
257 | |
258 | QList<QConfFile *> confFiles; |
259 | QSettings::ReadFunc readFunc; |
260 | QSettings::WriteFunc writeFunc; |
261 | QString extension; |
262 | Qt::CaseSensitivity caseSensitivity; |
263 | qsizetype nextPosition; |
264 | #ifdef Q_OS_WASM |
265 | friend class QWasmIDBSettingsPrivate; |
266 | #endif |
267 | }; |
268 | |
269 | QT_END_NAMESPACE |
270 | |
271 | #endif // QSETTINGS_P_H |
272 | |