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#ifndef QT_NO_QOBJECT
61#include "private/qobject_p.h"
62#endif
63#include "private/qscopedpointer_p.h"
64
65QT_BEGIN_NAMESPACE
66
67#ifndef Q_OS_WIN
68#define QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
69#endif
70
71#if defined(Q_OS_WINRT)
72#define QT_QTSETTINGS_FORGET_ORIGINAL_KEY_ORDER
73#endif
74
75// used in testing framework
76#define QSETTINGS_P_H_VERSION 3
77
78#ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
79static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseSensitive;
80
81class QSettingsKey : public QString
82{
83public:
84 inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, int /* position */ = -1)
85 : QString(key) { Q_ASSERT(cs == Qt::CaseSensitive); Q_UNUSED(cs); }
86
87 inline QString originalCaseKey() const { return *this; }
88 inline int originalKeyPosition() const { return -1; }
89};
90#else
91static const Qt::CaseSensitivity IniCaseSensitivity = Qt::CaseInsensitive;
92
93class QSettingsKey : public QString
94{
95public:
96 inline QSettingsKey(const QString &key, Qt::CaseSensitivity cs, int position = -1)
97 : QString(key), theOriginalKey(key), theOriginalKeyPosition(position)
98 {
99 if (cs == Qt::CaseInsensitive)
100 QString::operator=(toLower());
101 }
102
103 inline QString originalCaseKey() const { return theOriginalKey; }
104 inline int originalKeyPosition() const { return theOriginalKeyPosition; }
105
106private:
107 QString theOriginalKey;
108 int theOriginalKeyPosition;
109};
110#endif
111
112Q_DECLARE_TYPEINFO(QSettingsKey, Q_MOVABLE_TYPE);
113
114typedef QMap<QSettingsKey, QByteArray> UnparsedSettingsMap;
115typedef QMap<QSettingsKey, QVariant> ParsedSettingsMap;
116
117class QSettingsGroup
118{
119public:
120 inline QSettingsGroup()
121 : num(-1), maxNum(-1) {}
122 inline QSettingsGroup(const QString &s)
123 : str(s), num(-1), maxNum(-1) {}
124 inline QSettingsGroup(const QString &s, bool guessArraySize)
125 : str(s), num(0), maxNum(guessArraySize ? 0 : -1) {}
126
127 inline QString name() const { return str; }
128 inline QString toString() const;
129 inline bool isArray() const { return num != -1; }
130 inline int arraySizeGuess() const { return maxNum; }
131 inline void setArrayIndex(int i)
132 { num = i + 1; if (maxNum != -1 && num > maxNum) maxNum = num; }
133
134 QString str;
135 int num;
136 int maxNum;
137};
138Q_DECLARE_TYPEINFO(QSettingsGroup, Q_MOVABLE_TYPE);
139
140inline QString QSettingsGroup::toString() const
141{
142 QString result;
143 result = str;
144 if (num > 0) {
145 result += QLatin1Char('/');
146 result += QString::number(num);
147 }
148 return result;
149}
150
151class Q_AUTOTEST_EXPORT QConfFile
152{
153public:
154 ~QConfFile();
155
156 ParsedSettingsMap mergedKeyMap() const;
157 bool isWritable() const;
158
159 static QConfFile *fromName(const QString &name, bool _userPerms);
160 static void clearCache();
161
162 QString name;
163 QDateTime timeStamp;
164 qint64 size;
165 UnparsedSettingsMap unparsedIniSections;
166 ParsedSettingsMap originalKeys;
167 ParsedSettingsMap addedKeys;
168 ParsedSettingsMap removedKeys;
169 QAtomicInt ref;
170 QMutex mutex;
171 bool userPerms;
172
173private:
174#ifdef Q_DISABLE_COPY
175 QConfFile(const QConfFile &);
176 QConfFile &operator=(const QConfFile &);
177#endif
178 QConfFile(const QString &name, bool _userPerms);
179
180 friend class QConfFile_createsItself; // silences compiler warning
181};
182
183class Q_AUTOTEST_EXPORT QSettingsPrivate
184#ifndef QT_NO_QOBJECT
185 : public QObjectPrivate
186#endif
187{
188#ifdef QT_NO_QOBJECT
189 QSettings *q_ptr;
190#endif
191 Q_DECLARE_PUBLIC(QSettings)
192
193public:
194 QSettingsPrivate(QSettings::Format format);
195 QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
196 const QString &organization, const QString &application);
197 virtual ~QSettingsPrivate();
198
199 virtual void remove(const QString &key) = 0;
200 virtual void set(const QString &key, const QVariant &value) = 0;
201 virtual bool get(const QString &key, QVariant *value) const = 0;
202
203 enum ChildSpec { AllKeys, ChildKeys, ChildGroups };
204 virtual QStringList children(const QString &prefix, ChildSpec spec) const = 0;
205
206 virtual void clear() = 0;
207 virtual void sync() = 0;
208 virtual void flush() = 0;
209 virtual bool isWritable() const = 0;
210 virtual QString fileName() const = 0;
211
212 QString actualKey(const QString &key) const;
213 void beginGroupOrArray(const QSettingsGroup &group);
214 void setStatus(QSettings::Status status) const;
215 void requestUpdate();
216 void update();
217
218 static QString normalizedKey(const QString &key);
219 static QSettingsPrivate *create(QSettings::Format format, QSettings::Scope scope,
220 const QString &organization, const QString &application);
221 static QSettingsPrivate *create(const QString &fileName, QSettings::Format format);
222
223 static void processChild(QStringRef key, ChildSpec spec, QStringList &result);
224
225 // Variant streaming functions
226 static QStringList variantListToStringList(const QVariantList &l);
227 static QVariant stringListToVariantList(const QStringList &l);
228
229 // parser functions
230 static QString variantToString(const QVariant &v);
231 static QVariant stringToVariant(const QString &s);
232 static void iniEscapedKey(const QString &key, QByteArray &result);
233 static bool iniUnescapedKey(const QByteArray &key, int from, int to, QString &result);
234 static void iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec);
235 static void iniEscapedStringList(const QStringList &strs, QByteArray &result, QTextCodec *codec);
236 static bool iniUnescapedStringList(const QByteArray &str, int from, int to,
237 QString &stringResult, QStringList &stringListResult,
238 QTextCodec *codec);
239 static QStringList splitArgs(const QString &s, int idx);
240
241 QSettings::Format format;
242 QSettings::Scope scope;
243 QString organizationName;
244 QString applicationName;
245 QTextCodec *iniCodec;
246
247protected:
248 QStack<QSettingsGroup> groupStack;
249 QString groupPrefix;
250 bool fallbacks;
251 bool pendingChanges;
252 bool atomicSyncOnly = true;
253 mutable QSettings::Status status;
254};
255
256class QConfFileSettingsPrivate : public QSettingsPrivate
257{
258public:
259 QConfFileSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
260 const QString &organization, const QString &application);
261 QConfFileSettingsPrivate(const QString &fileName, QSettings::Format format);
262 ~QConfFileSettingsPrivate();
263
264 void remove(const QString &key) override;
265 void set(const QString &key, const QVariant &value) override;
266 bool get(const QString &key, QVariant *value) const override;
267
268 QStringList children(const QString &prefix, ChildSpec spec) const override;
269
270 void clear() override;
271 void sync() override;
272 void flush() override;
273 bool isWritable() const override;
274 QString fileName() const override;
275
276 bool readIniFile(const QByteArray &data, UnparsedSettingsMap *unparsedIniSections);
277 static bool readIniSection(const QSettingsKey &section, const QByteArray &data,
278 ParsedSettingsMap *settingsMap, QTextCodec *codec);
279 static bool readIniLine(const QByteArray &data, int &dataPos, int &lineStart, int &lineLen,
280 int &equalsPos);
281
282private:
283 void initFormat();
284 void initAccess();
285 void syncConfFile(QConfFile *confFile);
286 bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
287#ifdef Q_OS_MAC
288 bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
289 bool writePlistFile(QIODevice &file, const ParsedSettingsMap &map) const;
290#endif
291 void ensureAllSectionsParsed(QConfFile *confFile) const;
292 void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
293
294 QVector<QConfFile *> confFiles;
295 QSettings::ReadFunc readFunc;
296 QSettings::WriteFunc writeFunc;
297 QString extension;
298 Qt::CaseSensitivity caseSensitivity;
299 int nextPosition;
300};
301
302QT_END_NAMESPACE
303
304#endif // QSETTINGS_P_H
305