| 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 | protected: | 
| 247 |     const QList<QConfFile *> &getConfFiles() const { return confFiles; } | 
| 248 |  | 
| 249 | private: | 
| 250 |     void initFormat(); | 
| 251 |     virtual void initAccess(); | 
| 252 |     void syncConfFile(QConfFile *confFile); | 
| 253 |     bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map); | 
| 254 | #ifdef Q_OS_DARWIN | 
| 255 |     bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const; | 
| 256 |     bool writePlistFile(QIODevice &file, const ParsedSettingsMap &map) const; | 
| 257 | #endif | 
| 258 |     void ensureAllSectionsParsed(QConfFile *confFile) const; | 
| 259 |     void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const; | 
| 260 |  | 
| 261 |     QList<QConfFile *> confFiles; | 
| 262 |     QSettings::ReadFunc readFunc; | 
| 263 |     QSettings::WriteFunc writeFunc; | 
| 264 |     QString extension; | 
| 265 |     Qt::CaseSensitivity caseSensitivity; | 
| 266 |     qsizetype nextPosition; | 
| 267 | #ifdef Q_OS_WASM | 
| 268 |     friend class QWasmIDBSettingsPrivate; | 
| 269 | #endif | 
| 270 | }; | 
| 271 |  | 
| 272 | QT_END_NAMESPACE | 
| 273 |  | 
| 274 | #endif // QSETTINGS_P_H | 
| 275 |  |