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 &section, 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