1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #ifndef QSETTINGS_P_H
41 #define QSETTINGS_P_H
42
43 //
44 // W A R N I N G
45 // -------------
46 //
47 // This file is not part of the Qt API. It exists purely as an
48 // implementation detail. This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53
54 #include "QtCore/qdatetime.h"
55 #include "QtCore/qmap.h"
56 #include "QtCore/qmutex.h"
57 #include "QtCore/qiodevice.h"
58 #include "QtCore/qstack.h"
59 #include "QtCore/qstringlist.h"
60
61 #include <QtCore/qvariant.h>
62 #include "qsettings.h"
63
64 #ifndef QT_NO_QOBJECT
65 #include "private/qobject_p.h"
66 #endif
67 #include "private/qscopedpointer_p.h"
68
69 QT_BEGIN_NAMESPACE
70
71 #ifndef Q_OS_WIN
72 #define QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
73 #endif
74
75 #if defined(Q_OS_WINRT)
76 #define QT_QTSETTINGS_FORGET_ORIGINAL_KEY_ORDER
77 #endif
78
79 // used in testing framework
80 #define QSETTINGS_P_H_VERSION 3
81
82 #ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
83 static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseSensitive;
84
85 class QSettingsKey : public QString
86 {
87 public:
88 inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, int /* position */ = -1)
QString(key)89 : QString(key) { Q_ASSERT(cs == Qt::CaseSensitive); Q_UNUSED(cs); }
90
originalCaseKey()91 inline QString originalCaseKey() const { return *this; }
originalKeyPosition()92 inline int originalKeyPosition() const { return -1; }
93 };
94 #else
95 static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseInsensitive;
96
97 class QSettingsKey : public QString
98 {
99 public:
100 inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, int position = -1)
101 : QString(key), theOriginalKey(key), theOriginalKeyPosition(position)
102 {
103 if (cs == Qt::CaseInsensitive)
104 QString::operator=(toLower());
105 }
106
107 inline QString originalCaseKey() const { return theOriginalKey; }
108 inline int originalKeyPosition() const { return theOriginalKeyPosition; }
109
110 private:
111 QString theOriginalKey;
112 int theOriginalKeyPosition;
113 };
114 #endif
115
116 Q_DECLARE_TYPEINFO(QSettingsKey, Q_MOVABLE_TYPE);
117
118 typedef QMap<QSettingsKey, QByteArray> UnparsedSettingsMap;
119 typedef QMap<QSettingsKey, QVariant> ParsedSettingsMap;
120
121 class QSettingsGroup
122 {
123 public:
QSettingsGroup()124 inline QSettingsGroup()
125 : num(-1), maxNum(-1) {}
QSettingsGroup(const QString & s)126 inline QSettingsGroup(const QString &s)
127 : str(s), num(-1), maxNum(-1) {}
QSettingsGroup(const QString & s,bool guessArraySize)128 inline QSettingsGroup(const QString &s, bool guessArraySize)
129 : str(s), num(0), maxNum(guessArraySize ? 0 : -1) {}
130
name()131 inline QString name() const { return str; }
132 inline QString toString() const;
isArray()133 inline bool isArray() const { return num != -1; }
arraySizeGuess()134 inline int arraySizeGuess() const { return maxNum; }
setArrayIndex(int i)135 inline void setArrayIndex(int i)
136 { num = i + 1; if (maxNum != -1 && num > maxNum) maxNum = num; }
137
138 QString str;
139 int num;
140 int maxNum;
141 };
142 Q_DECLARE_TYPEINFO(QSettingsGroup, Q_MOVABLE_TYPE);
143
toString()144 inline QString QSettingsGroup::toString() const
145 {
146 QString result;
147 result = str;
148 if (num > 0) {
149 result += QLatin1Char('/');
150 result += QString::number(num);
151 }
152 return result;
153 }
154
155 class Q_AUTOTEST_EXPORT QConfFile
156 {
157 public:
158 ~QConfFile();
159
160 ParsedSettingsMap mergedKeyMap() const;
161 bool isWritable() const;
162
163 static QConfFile *fromName(const QString &name, bool _userPerms);
164 static void clearCache();
165
166 QString name;
167 QDateTime timeStamp;
168 qint64 size;
169 UnparsedSettingsMap unparsedIniSections;
170 ParsedSettingsMap originalKeys;
171 ParsedSettingsMap addedKeys;
172 ParsedSettingsMap removedKeys;
173 QAtomicInt ref;
174 QMutex mutex;
175 bool userPerms;
176
177 private:
178 #ifdef Q_DISABLE_COPY
179 QConfFile(const QConfFile &);
180 QConfFile &operator=(const QConfFile &);
181 #endif
182 QConfFile(const QString &name, bool _userPerms);
183
184 friend class QConfFile_createsItself; // silences compiler warning
185 };
186
187 class Q_AUTOTEST_EXPORT QSettingsPrivate
188 #ifndef QT_NO_QOBJECT
189 : public QObjectPrivate
190 #endif
191 {
192 #ifdef QT_NO_QOBJECT
193 QSettings *q_ptr;
194 #endif
195 Q_DECLARE_PUBLIC(QSettings)
196
197 public:
198 QSettingsPrivate(QSettings::Format format);
199 QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
200 const QString &organization, const QString &application);
201 virtual ~QSettingsPrivate();
202
203 virtual void remove(const QString &key) = 0;
204 virtual void set(const QString &key, const QVariant &value) = 0;
205 virtual bool get(const QString &key, QVariant *value) const = 0;
206
207 enum ChildSpec { AllKeys, ChildKeys, ChildGroups };
208 virtual QStringList children(const QString &prefix, ChildSpec spec) const = 0;
209
210 virtual void clear() = 0;
211 virtual void sync() = 0;
212 virtual void flush() = 0;
213 virtual bool isWritable() const = 0;
214 virtual QString fileName() const = 0;
215
216 QString actualKey(const QString &key) const;
217 void beginGroupOrArray(const QSettingsGroup &group);
218 void setStatus(QSettings::Status status) const;
219 void requestUpdate();
220 void update();
221
222 static QString normalizedKey(const QString &key);
223 static QSettingsPrivate *create(QSettings::Format format, QSettings::Scope scope,
224 const QString &organization, const QString &application);
225 static QSettingsPrivate *create(const QString &fileName, QSettings::Format format);
226
227 static void processChild(QStringRef key, ChildSpec spec, QStringList &result);
228
229 // Variant streaming functions
230 static QStringList variantListToStringList(const QVariantList &l);
231 static QVariant stringListToVariantList(const QStringList &l);
232
233 // parser functions
234 static QString variantToString(const QVariant &v);
235 static QVariant stringToVariant(const QString &s);
236 static void iniEscapedKey(const QString &key, QByteArray &result);
237 static bool iniUnescapedKey(const QByteArray &key, int from, int to, QString &result);
238 static void iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec);
239 static void iniEscapedStringList(const QStringList &strs, QByteArray &result, QTextCodec *codec);
240 static bool iniUnescapedStringList(const QByteArray &str, int from, int to,
241 QString &stringResult, QStringList &stringListResult,
242 QTextCodec *codec);
243 static QStringList splitArgs(const QString &s, int idx);
244
245 QSettings::Format format;
246 QSettings::Scope scope;
247 QString organizationName;
248 QString applicationName;
249 QTextCodec *iniCodec;
250
251 protected:
252 QStack<QSettingsGroup> groupStack;
253 QString groupPrefix;
254 bool fallbacks;
255 bool pendingChanges;
256 bool atomicSyncOnly = true;
257 mutable QSettings::Status status;
258 };
259
260 #ifdef Q_OS_WASM
261 class QWasmSettingsPrivate;
262 #endif
263
264 class QConfFileSettingsPrivate : public QSettingsPrivate
265 {
266 public:
267 QConfFileSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
268 const QString &organization, const QString &application);
269 QConfFileSettingsPrivate(const QString &fileName, QSettings::Format format);
270 ~QConfFileSettingsPrivate();
271
272 void remove(const QString &key) override;
273 void set(const QString &key, const QVariant &value) override;
274 bool get(const QString &key, QVariant *value) const override;
275
276 QStringList children(const QString &prefix, ChildSpec spec) const override;
277
278 void clear() override;
279 void sync() override;
280 void flush() override;
281 bool isWritable() const override;
282 QString fileName() const override;
283
284 bool readIniFile(const QByteArray &data, UnparsedSettingsMap *unparsedIniSections);
285 static bool readIniSection(const QSettingsKey §ion, const QByteArray &data,
286 ParsedSettingsMap *settingsMap, QTextCodec *codec);
287 static bool readIniLine(const QByteArray &data, int &dataPos, int &lineStart, int &lineLen,
288 int &equalsPos);
289
290 private:
291 void initFormat();
292 virtual void initAccess();
293 void syncConfFile(QConfFile *confFile);
294 bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
295 #ifdef Q_OS_MAC
296 bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
297 bool writePlistFile(QIODevice &file, const ParsedSettingsMap &map) const;
298 #endif
299 void ensureAllSectionsParsed(QConfFile *confFile) const;
300 void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
301
302 QVector<QConfFile *> confFiles;
303 QSettings::ReadFunc readFunc;
304 QSettings::WriteFunc writeFunc;
305 QString extension;
306 Qt::CaseSensitivity caseSensitivity;
307 int nextPosition;
308 #ifdef Q_OS_WASM
309 friend class QWasmSettingsPrivate;
310 #endif
311 };
312
313 QT_END_NAMESPACE
314
315 #endif // QSETTINGS_P_H
316