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 #include <qdebug.h>
41 #include "qplatformdefs.h"
42 #include "qsettings.h"
43 
44 #include "qsettings_p.h"
45 #include "qcache.h"
46 #include "qfile.h"
47 #include "qdir.h"
48 #include "qfileinfo.h"
49 #include "qmutex.h"
50 #include "private/qlocking_p.h"
51 #include "qlibraryinfo.h"
52 #include "qtemporaryfile.h"
53 #include "qstandardpaths.h"
54 #include <qdatastream.h>
55 
56 #if QT_CONFIG(textcodec)
57 #  include "qtextcodec.h"
58 #endif
59 
60 #ifndef QT_NO_GEOM_VARIANT
61 #include "qsize.h"
62 #include "qpoint.h"
63 #include "qrect.h"
64 #endif // !QT_NO_GEOM_VARIANT
65 
66 #ifndef QT_BUILD_QMAKE
67 #  include "qcoreapplication.h"
68 #endif
69 
70 #ifndef QT_BOOTSTRAPPED
71 #include "qsavefile.h"
72 #include "qlockfile.h"
73 #endif
74 
75 #ifdef Q_OS_VXWORKS
76 #  include <ioLib.h>
77 #endif
78 
79 #include <algorithm>
80 #include <stdlib.h>
81 
82 #ifdef Q_OS_WIN // for homedirpath reading from registry
83 #  include <qt_windows.h>
84 #  ifndef Q_OS_WINRT
85 #    include <shlobj.h>
86 #  endif
87 #endif
88 
89 #ifdef Q_OS_WINRT
90 #include <wrl.h>
91 #include <windows.foundation.h>
92 #include <windows.storage.h>
93 using namespace Microsoft::WRL;
94 using namespace Microsoft::WRL::Wrappers;
95 using namespace ABI::Windows::Foundation;
96 using namespace ABI::Windows::Storage;
97 #endif
98 
99 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
100 #define Q_XDG_PLATFORM
101 #endif
102 
103 #if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT))
104 #define QSETTINGS_USE_QSTANDARDPATHS
105 #endif
106 
107 // ************************************************************************
108 // QConfFile
109 
110 /*
111     QConfFile objects are explicitly shared within the application.
112     This ensures that modification to the settings done through one
113     QSettings object are immediately reflected in other setting
114     objects of the same application.
115 */
116 
117 QT_BEGIN_NAMESPACE
118 
119 struct QConfFileCustomFormat
120 {
121     QString extension;
122     QSettings::ReadFunc readFunc;
123     QSettings::WriteFunc writeFunc;
124     Qt::CaseSensitivity caseSensitivity;
125 };
126 Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
127 
128 typedef QHash<QString, QConfFile *> ConfFileHash;
129 typedef QCache<QString, QConfFile> ConfFileCache;
130 namespace {
131     struct Path
132     {
133         // Note: Defining constructors explicitly because of buggy C++11
134         // implementation in MSVC (uniform initialization).
Path__anondcdcbd280111::Path135         Path() {}
Path__anondcdcbd280111::Path136         Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
137         QString path;
138         bool userDefined; //!< true - user defined, overridden by setPath
139     };
140 }
141 typedef QHash<int, Path> PathHash;
142 typedef QVector<QConfFileCustomFormat> CustomFormatVector;
143 
144 Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
145 Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)
146 Q_GLOBAL_STATIC(PathHash, pathHashFunc)
147 Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
148 
149 static QBasicMutex settingsGlobalMutex;
150 
151 static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
152 
QConfFile(const QString & fileName,bool _userPerms)153 QConfFile::QConfFile(const QString &fileName, bool _userPerms)
154     : name(fileName), size(0), ref(1), userPerms(_userPerms)
155 {
156     usedHashFunc()->insert(name, this);
157 }
158 
~QConfFile()159 QConfFile::~QConfFile()
160 {
161     if (usedHashFunc())
162         usedHashFunc()->remove(name);
163 }
164 
mergedKeyMap() const165 ParsedSettingsMap QConfFile::mergedKeyMap() const
166 {
167     ParsedSettingsMap result = originalKeys;
168     ParsedSettingsMap::const_iterator i;
169 
170     for (i = removedKeys.begin(); i != removedKeys.end(); ++i)
171         result.remove(i.key());
172     for (i = addedKeys.begin(); i != addedKeys.end(); ++i)
173         result.insert(i.key(), i.value());
174     return result;
175 }
176 
isWritable() const177 bool QConfFile::isWritable() const
178 {
179     QFileInfo fileInfo(name);
180 
181 #ifndef QT_NO_TEMPORARYFILE
182     if (fileInfo.exists()) {
183 #endif
184         QFile file(name);
185         return file.open(QFile::ReadWrite);
186 #ifndef QT_NO_TEMPORARYFILE
187     } else {
188         // Create the directories to the file.
189         QDir dir(fileInfo.absolutePath());
190         if (!dir.exists()) {
191             if (!dir.mkpath(dir.absolutePath()))
192                 return false;
193         }
194 
195         // we use a temporary file to avoid race conditions
196         QTemporaryFile file(name);
197         return file.open();
198     }
199 #endif
200 }
201 
fromName(const QString & fileName,bool _userPerms)202 QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms)
203 {
204     QString absPath = QFileInfo(fileName).absoluteFilePath();
205 
206     ConfFileHash *usedHash = usedHashFunc();
207     ConfFileCache *unusedCache = unusedCacheFunc();
208 
209     QConfFile *confFile = nullptr;
210     const auto locker = qt_scoped_lock(settingsGlobalMutex);
211 
212     if (!(confFile = usedHash->value(absPath))) {
213         if ((confFile = unusedCache->take(absPath)))
214             usedHash->insert(absPath, confFile);
215     }
216     if (confFile) {
217         confFile->ref.ref();
218         return confFile;
219     }
220     return new QConfFile(absPath, _userPerms);
221 }
222 
clearCache()223 void QConfFile::clearCache()
224 {
225     const auto locker = qt_scoped_lock(settingsGlobalMutex);
226     unusedCacheFunc()->clear();
227 }
228 
229 // ************************************************************************
230 // QSettingsPrivate
231 
QSettingsPrivate(QSettings::Format format)232 QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
233     : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(nullptr), fallbacks(true),
234       pendingChanges(false), status(QSettings::NoError)
235 {
236 }
237 
QSettingsPrivate(QSettings::Format format,QSettings::Scope scope,const QString & organization,const QString & application)238 QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
239                                    const QString &organization, const QString &application)
240     : format(format), scope(scope), organizationName(organization), applicationName(application),
241       iniCodec(nullptr), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
242 {
243 }
244 
~QSettingsPrivate()245 QSettingsPrivate::~QSettingsPrivate()
246 {
247 }
248 
actualKey(const QString & key) const249 QString QSettingsPrivate::actualKey(const QString &key) const
250 {
251     QString n = normalizedKey(key);
252     Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key");
253     return groupPrefix + n;
254 }
255 
256 /*
257     Returns a string that never starts nor ends with a slash (or an
258     empty string). Examples:
259 
260             "foo"            becomes   "foo"
261             "/foo//bar///"   becomes   "foo/bar"
262             "///"            becomes   ""
263 
264     This function is optimized to avoid a QString deep copy in the
265     common case where the key is already normalized.
266 */
normalizedKey(const QString & key)267 QString QSettingsPrivate::normalizedKey(const QString &key)
268 {
269     QString result = key;
270 
271     int i = 0;
272     while (i < result.size()) {
273         while (result.at(i) == QLatin1Char('/')) {
274             result.remove(i, 1);
275             if (i == result.size())
276                 goto after_loop;
277         }
278         while (result.at(i) != QLatin1Char('/')) {
279             ++i;
280             if (i == result.size())
281                 return result;
282         }
283         ++i; // leave the slash alone
284     }
285 
286 after_loop:
287     if (!result.isEmpty())
288         result.truncate(i - 1); // remove the trailing slash
289     return result;
290 }
291 
292 // see also qsettings_win.cpp, qsettings_winrt.cpp and qsettings_mac.cpp
293 
294 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
create(QSettings::Format format,QSettings::Scope scope,const QString & organization,const QString & application)295 QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
296                                            const QString &organization, const QString &application)
297 {
298     return new QConfFileSettingsPrivate(format, scope, organization, application);
299 }
300 #endif
301 
302 #if !defined(Q_OS_WIN)
create(const QString & fileName,QSettings::Format format)303 QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
304 {
305     return new QConfFileSettingsPrivate(fileName, format);
306 }
307 #endif
308 
processChild(QStringRef key,ChildSpec spec,QStringList & result)309 void QSettingsPrivate::processChild(QStringRef key, ChildSpec spec, QStringList &result)
310 {
311     if (spec != AllKeys) {
312         int slashPos = key.indexOf(QLatin1Char('/'));
313         if (slashPos == -1) {
314             if (spec != ChildKeys)
315                 return;
316         } else {
317             if (spec != ChildGroups)
318                 return;
319             key.truncate(slashPos);
320         }
321     }
322     result.append(key.toString());
323 }
324 
beginGroupOrArray(const QSettingsGroup & group)325 void QSettingsPrivate::beginGroupOrArray(const QSettingsGroup &group)
326 {
327     groupStack.push(group);
328     const QString name = group.name();
329     if (!name.isEmpty())
330         groupPrefix += name + QLatin1Char('/');
331 }
332 
333 /*
334     We only set an error if there isn't one set already. This way the user always gets the
335     first error that occurred. We always allow clearing errors.
336 */
337 
setStatus(QSettings::Status status) const338 void QSettingsPrivate::setStatus(QSettings::Status status) const
339 {
340     if (status == QSettings::NoError || this->status == QSettings::NoError)
341         this->status = status;
342 }
343 
update()344 void QSettingsPrivate::update()
345 {
346     flush();
347     pendingChanges = false;
348 }
349 
requestUpdate()350 void QSettingsPrivate::requestUpdate()
351 {
352     if (!pendingChanges) {
353         pendingChanges = true;
354 #ifndef QT_NO_QOBJECT
355         Q_Q(QSettings);
356         QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
357 #else
358         update();
359 #endif
360     }
361 }
362 
variantListToStringList(const QVariantList & l)363 QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l)
364 {
365     QStringList result;
366     result.reserve(l.count());
367     QVariantList::const_iterator it = l.constBegin();
368     for (; it != l.constEnd(); ++it)
369         result.append(variantToString(*it));
370     return result;
371 }
372 
stringListToVariantList(const QStringList & l)373 QVariant QSettingsPrivate::stringListToVariantList(const QStringList &l)
374 {
375     QStringList outStringList = l;
376     for (int i = 0; i < outStringList.count(); ++i) {
377         const QString &str = outStringList.at(i);
378 
379         if (str.startsWith(QLatin1Char('@'))) {
380             if (str.length() >= 2 && str.at(1) == QLatin1Char('@')) {
381                 outStringList[i].remove(0, 1);
382             } else {
383                 QVariantList variantList;
384                 const int stringCount = l.count();
385                 variantList.reserve(stringCount);
386                 for (int j = 0; j < stringCount; ++j)
387                     variantList.append(stringToVariant(l.at(j)));
388                 return variantList;
389             }
390         }
391     }
392     return outStringList;
393 }
394 
variantToString(const QVariant & v)395 QString QSettingsPrivate::variantToString(const QVariant &v)
396 {
397     QString result;
398 
399     switch (v.userType()) {
400         case QMetaType::UnknownType:
401             result = QLatin1String("@Invalid()");
402             break;
403 
404         case QMetaType::QByteArray: {
405             QByteArray a = v.toByteArray();
406             result = QLatin1String("@ByteArray(")
407                      + QLatin1String(a.constData(), a.size())
408                      + QLatin1Char(')');
409             break;
410         }
411 
412         case QMetaType::QString:
413         case QMetaType::LongLong:
414         case QMetaType::ULongLong:
415         case QMetaType::Int:
416         case QMetaType::UInt:
417         case QMetaType::Bool:
418         case QMetaType::Double:
419         case QMetaType::QKeySequence: {
420             result = v.toString();
421             if (result.contains(QChar::Null))
422                 result = QLatin1String("@String(") + result + QLatin1Char(')');
423             else if (result.startsWith(QLatin1Char('@')))
424                 result.prepend(QLatin1Char('@'));
425             break;
426         }
427 #ifndef QT_NO_GEOM_VARIANT
428         case QMetaType::QRect: {
429             QRect r = qvariant_cast<QRect>(v);
430             result = QString::asprintf("@Rect(%d %d %d %d)", r.x(), r.y(), r.width(), r.height());
431             break;
432         }
433         case QMetaType::QSize: {
434             QSize s = qvariant_cast<QSize>(v);
435             result = QString::asprintf("@Size(%d %d)", s.width(), s.height());
436             break;
437         }
438         case QMetaType::QPoint: {
439             QPoint p = qvariant_cast<QPoint>(v);
440             result = QString::asprintf("@Point(%d %d)", p.x(), p.y());
441             break;
442         }
443 #endif // !QT_NO_GEOM_VARIANT
444 
445         default: {
446 #ifndef QT_NO_DATASTREAM
447             QDataStream::Version version;
448             const char *typeSpec;
449             if (v.userType() == QMetaType::QDateTime) {
450                 version = QDataStream::Qt_5_6;
451                 typeSpec = "@DateTime(";
452             } else {
453                 version = QDataStream::Qt_4_0;
454                 typeSpec = "@Variant(";
455             }
456             QByteArray a;
457             {
458                 QDataStream s(&a, QIODevice::WriteOnly);
459                 s.setVersion(version);
460                 s << v;
461             }
462 
463             result = QLatin1String(typeSpec)
464                      + QLatin1String(a.constData(), a.size())
465                      + QLatin1Char(')');
466 #else
467             Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
468 #endif
469             break;
470         }
471     }
472 
473     return result;
474 }
475 
476 
stringToVariant(const QString & s)477 QVariant QSettingsPrivate::stringToVariant(const QString &s)
478 {
479     if (s.startsWith(QLatin1Char('@'))) {
480         if (s.endsWith(QLatin1Char(')'))) {
481             if (s.startsWith(QLatin1String("@ByteArray("))) {
482                 return QVariant(s.midRef(11, s.size() - 12).toLatin1());
483             } else if (s.startsWith(QLatin1String("@String("))) {
484                 return QVariant(s.midRef(8, s.size() - 9).toString());
485             } else if (s.startsWith(QLatin1String("@Variant("))
486                        || s.startsWith(QLatin1String("@DateTime("))) {
487 #ifndef QT_NO_DATASTREAM
488                 QDataStream::Version version;
489                 int offset;
490                 if (s.at(1) == QLatin1Char('D')) {
491                     version = QDataStream::Qt_5_6;
492                     offset = 10;
493                 } else {
494                     version = QDataStream::Qt_4_0;
495                     offset = 9;
496                 }
497                 QByteArray a = s.midRef(offset).toLatin1();
498                 QDataStream stream(&a, QIODevice::ReadOnly);
499                 stream.setVersion(version);
500                 QVariant result;
501                 stream >> result;
502                 return result;
503 #else
504                 Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
505 #endif
506 #ifndef QT_NO_GEOM_VARIANT
507             } else if (s.startsWith(QLatin1String("@Rect("))) {
508                 QStringList args = QSettingsPrivate::splitArgs(s, 5);
509                 if (args.size() == 4)
510                     return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
511             } else if (s.startsWith(QLatin1String("@Size("))) {
512                 QStringList args = QSettingsPrivate::splitArgs(s, 5);
513                 if (args.size() == 2)
514                     return QVariant(QSize(args[0].toInt(), args[1].toInt()));
515             } else if (s.startsWith(QLatin1String("@Point("))) {
516                 QStringList args = QSettingsPrivate::splitArgs(s, 6);
517                 if (args.size() == 2)
518                     return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
519 #endif
520             } else if (s == QLatin1String("@Invalid()")) {
521                 return QVariant();
522             }
523 
524         }
525         if (s.startsWith(QLatin1String("@@")))
526             return QVariant(s.mid(1));
527     }
528 
529     return QVariant(s);
530 }
531 
532 static const char hexDigits[] = "0123456789ABCDEF";
533 
iniEscapedKey(const QString & key,QByteArray & result)534 void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result)
535 {
536     result.reserve(result.length() + key.length() * 3 / 2);
537     for (int i = 0; i < key.size(); ++i) {
538         uint ch = key.at(i).unicode();
539 
540         if (ch == '/') {
541             result += '\\';
542         } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
543                 || ch == '_' || ch == '-' || ch == '.') {
544             result += (char)ch;
545         } else if (ch <= 0xFF) {
546             result += '%';
547             result += hexDigits[ch / 16];
548             result += hexDigits[ch % 16];
549         } else {
550             result += "%U";
551             QByteArray hexCode;
552             for (int i = 0; i < 4; ++i) {
553                 hexCode.prepend(hexDigits[ch % 16]);
554                 ch >>= 4;
555             }
556             result += hexCode;
557         }
558     }
559 }
560 
iniUnescapedKey(const QByteArray & key,int from,int to,QString & result)561 bool QSettingsPrivate::iniUnescapedKey(const QByteArray &key, int from, int to, QString &result)
562 {
563     bool lowercaseOnly = true;
564     int i = from;
565     result.reserve(result.length() + (to - from));
566     while (i < to) {
567         int ch = (uchar)key.at(i);
568 
569         if (ch == '\\') {
570             result += QLatin1Char('/');
571             ++i;
572             continue;
573         }
574 
575         if (ch != '%' || i == to - 1) {
576             if (uint(ch - 'A') <= 'Z' - 'A') // only for ASCII
577                 lowercaseOnly = false;
578             result += QLatin1Char(ch);
579             ++i;
580             continue;
581         }
582 
583         int numDigits = 2;
584         int firstDigitPos = i + 1;
585 
586         ch = key.at(i + 1);
587         if (ch == 'U') {
588             ++firstDigitPos;
589             numDigits = 4;
590         }
591 
592         if (firstDigitPos + numDigits > to) {
593             result += QLatin1Char('%');
594             // ### missing U
595             ++i;
596             continue;
597         }
598 
599         bool ok;
600         ch = key.mid(firstDigitPos, numDigits).toInt(&ok, 16);
601         if (!ok) {
602             result += QLatin1Char('%');
603             // ### missing U
604             ++i;
605             continue;
606         }
607 
608         QChar qch(ch);
609         if (qch.isUpper())
610             lowercaseOnly = false;
611         result += qch;
612         i = firstDigitPos + numDigits;
613     }
614     return lowercaseOnly;
615 }
616 
iniEscapedString(const QString & str,QByteArray & result,QTextCodec * codec)617 void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec)
618 {
619     bool needsQuotes = false;
620     bool escapeNextIfDigit = false;
621     bool useCodec = codec && !str.startsWith(QLatin1String("@ByteArray("))
622                     && !str.startsWith(QLatin1String("@Variant("));
623 
624     int i;
625     int startPos = result.size();
626 
627     result.reserve(startPos + str.size() * 3 / 2);
628     const QChar *unicode = str.unicode();
629     for (i = 0; i < str.size(); ++i) {
630         uint ch = unicode[i].unicode();
631         if (ch == ';' || ch == ',' || ch == '=')
632             needsQuotes = true;
633 
634         if (escapeNextIfDigit
635                 && ((ch >= '0' && ch <= '9')
636                     || (ch >= 'a' && ch <= 'f')
637                     || (ch >= 'A' && ch <= 'F'))) {
638             result += "\\x" + QByteArray::number(ch, 16);
639             continue;
640         }
641 
642         escapeNextIfDigit = false;
643 
644         switch (ch) {
645         case '\0':
646             result += "\\0";
647             escapeNextIfDigit = true;
648             break;
649         case '\a':
650             result += "\\a";
651             break;
652         case '\b':
653             result += "\\b";
654             break;
655         case '\f':
656             result += "\\f";
657             break;
658         case '\n':
659             result += "\\n";
660             break;
661         case '\r':
662             result += "\\r";
663             break;
664         case '\t':
665             result += "\\t";
666             break;
667         case '\v':
668             result += "\\v";
669             break;
670         case '"':
671         case '\\':
672             result += '\\';
673             result += (char)ch;
674             break;
675         default:
676             if (ch <= 0x1F || (ch >= 0x7F && !useCodec)) {
677                 result += "\\x" + QByteArray::number(ch, 16);
678                 escapeNextIfDigit = true;
679 #if QT_CONFIG(textcodec)
680             } else if (useCodec) {
681                 // slow
682                 result += codec->fromUnicode(&unicode[i], 1);
683 #endif
684             } else {
685                 result += (char)ch;
686             }
687         }
688     }
689 
690     if (needsQuotes
691             || (startPos < result.size() && (result.at(startPos) == ' '
692                                                 || result.at(result.size() - 1) == ' '))) {
693         result.insert(startPos, '"');
694         result += '"';
695     }
696 }
697 
iniChopTrailingSpaces(QString & str,int limit)698 inline static void iniChopTrailingSpaces(QString &str, int limit)
699 {
700     int n = str.size() - 1;
701     QChar ch;
702     while (n >= limit && ((ch = str.at(n)) == QLatin1Char(' ') || ch == QLatin1Char('\t')))
703         str.truncate(n--);
704 }
705 
iniEscapedStringList(const QStringList & strs,QByteArray & result,QTextCodec * codec)706 void QSettingsPrivate::iniEscapedStringList(const QStringList &strs, QByteArray &result, QTextCodec *codec)
707 {
708     if (strs.isEmpty()) {
709         /*
710             We need to distinguish between empty lists and one-item
711             lists that contain an empty string. Ideally, we'd have a
712             @EmptyList() symbol but that would break compatibility
713             with Qt 4.0. @Invalid() stands for QVariant(), and
714             QVariant().toStringList() returns an empty QStringList,
715             so we're in good shape.
716         */
717         result += "@Invalid()";
718     } else {
719         for (int i = 0; i < strs.size(); ++i) {
720             if (i != 0)
721                 result += ", ";
722             iniEscapedString(strs.at(i), result, codec);
723         }
724     }
725 }
726 
iniUnescapedStringList(const QByteArray & str,int from,int to,QString & stringResult,QStringList & stringListResult,QTextCodec * codec)727 bool QSettingsPrivate::iniUnescapedStringList(const QByteArray &str, int from, int to,
728                                               QString &stringResult, QStringList &stringListResult,
729                                               QTextCodec *codec)
730 {
731     static const char escapeCodes[][2] =
732     {
733         { 'a', '\a' },
734         { 'b', '\b' },
735         { 'f', '\f' },
736         { 'n', '\n' },
737         { 'r', '\r' },
738         { 't', '\t' },
739         { 'v', '\v' },
740         { '"', '"' },
741         { '?', '?' },
742         { '\'', '\'' },
743         { '\\', '\\' }
744     };
745 
746     bool isStringList = false;
747     bool inQuotedString = false;
748     bool currentValueIsQuoted = false;
749     char16_t escapeVal = 0;
750     int i = from;
751     char ch;
752 
753 StSkipSpaces:
754     while (i < to && ((ch = str.at(i)) == ' ' || ch == '\t'))
755         ++i;
756     // fallthrough
757 
758 StNormal:
759     int chopLimit = stringResult.length();
760     while (i < to) {
761         switch (str.at(i)) {
762         case '\\':
763             ++i;
764             if (i >= to)
765                 goto end;
766 
767             ch = str.at(i++);
768             for (const auto &escapeCode : escapeCodes) {
769                 if (ch == escapeCode[0]) {
770                     stringResult += QLatin1Char(escapeCode[1]);
771                     goto StNormal;
772                 }
773             }
774 
775             if (ch == 'x') {
776                 escapeVal = 0;
777 
778                 if (i >= to)
779                     goto end;
780 
781                 ch = str.at(i);
782                 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
783                     goto StHexEscape;
784             } else if (ch >= '0' && ch <= '7') {
785                 escapeVal = ch - '0';
786                 goto StOctEscape;
787             } else if (ch == '\n' || ch == '\r') {
788                 if (i < to) {
789                     char ch2 = str.at(i);
790                     // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
791                     if ((ch2 == '\n' || ch2 == '\r') && ch2 != ch)
792                         ++i;
793                 }
794             } else {
795                 // the character is skipped
796             }
797             chopLimit = stringResult.length();
798             break;
799         case '"':
800             ++i;
801             currentValueIsQuoted = true;
802             inQuotedString = !inQuotedString;
803             if (!inQuotedString)
804                 goto StSkipSpaces;
805             break;
806         case ',':
807             if (!inQuotedString) {
808                 if (!currentValueIsQuoted)
809                     iniChopTrailingSpaces(stringResult, chopLimit);
810                 if (!isStringList) {
811                     isStringList = true;
812                     stringListResult.clear();
813                     stringResult.squeeze();
814                 }
815                 stringListResult.append(stringResult);
816                 stringResult.clear();
817                 currentValueIsQuoted = false;
818                 ++i;
819                 goto StSkipSpaces;
820             }
821             Q_FALLTHROUGH();
822         default: {
823             int j = i + 1;
824             while (j < to) {
825                 ch = str.at(j);
826                 if (ch == '\\' || ch == '"' || ch == ',')
827                     break;
828                 ++j;
829             }
830 
831 #if !QT_CONFIG(textcodec)
832             Q_UNUSED(codec)
833 #else
834             if (codec) {
835                 stringResult += codec->toUnicode(str.constData() + i, j - i);
836             } else
837 #endif
838             {
839                 int n = stringResult.size();
840                 stringResult.resize(n + (j - i));
841                 QChar *resultData = stringResult.data() + n;
842                 for (int k = i; k < j; ++k)
843                     *resultData++ = QLatin1Char(str.at(k));
844             }
845             i = j;
846         }
847         }
848     }
849     if (!currentValueIsQuoted)
850         iniChopTrailingSpaces(stringResult, chopLimit);
851     goto end;
852 
853 StHexEscape:
854     if (i >= to) {
855         stringResult += QChar(escapeVal);
856         goto end;
857     }
858 
859     ch = str.at(i);
860     if (ch >= 'a')
861         ch -= 'a' - 'A';
862     if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
863         escapeVal <<= 4;
864         escapeVal += strchr(hexDigits, ch) - hexDigits;
865         ++i;
866         goto StHexEscape;
867     } else {
868         stringResult += QChar(escapeVal);
869         goto StNormal;
870     }
871 
872 StOctEscape:
873     if (i >= to) {
874         stringResult += QChar(escapeVal);
875         goto end;
876     }
877 
878     ch = str.at(i);
879     if (ch >= '0' && ch <= '7') {
880         escapeVal <<= 3;
881         escapeVal += ch - '0';
882         ++i;
883         goto StOctEscape;
884     } else {
885         stringResult += QChar(escapeVal);
886         goto StNormal;
887     }
888 
889 end:
890     if (isStringList)
891         stringListResult.append(stringResult);
892     return isStringList;
893 }
894 
splitArgs(const QString & s,int idx)895 QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
896 {
897     int l = s.length();
898     Q_ASSERT(l > 0);
899     Q_ASSERT(s.at(idx) == QLatin1Char('('));
900     Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
901 
902     QStringList result;
903     QString item;
904 
905     for (++idx; idx < l; ++idx) {
906         QChar c = s.at(idx);
907         if (c == QLatin1Char(')')) {
908             Q_ASSERT(idx == l - 1);
909             result.append(item);
910         } else if (c == QLatin1Char(' ')) {
911             result.append(item);
912             item.clear();
913         } else {
914             item.append(c);
915         }
916     }
917 
918     return result;
919 }
920 
921 // ************************************************************************
922 // QConfFileSettingsPrivate
923 
initFormat()924 void QConfFileSettingsPrivate::initFormat()
925 {
926     extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini");
927     readFunc = nullptr;
928     writeFunc = nullptr;
929 #if defined(Q_OS_MAC)
930     caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity;
931 #else
932     caseSensitivity = IniCaseSensitivity;
933 #endif
934 
935     if (format > QSettings::IniFormat) {
936         const auto locker = qt_scoped_lock(settingsGlobalMutex);
937         const CustomFormatVector *customFormatVector = customFormatVectorFunc();
938 
939         int i = (int)format - (int)QSettings::CustomFormat1;
940         if (i >= 0 && i < customFormatVector->size()) {
941             QConfFileCustomFormat info = customFormatVector->at(i);
942             extension = info.extension;
943             readFunc = info.readFunc;
944             writeFunc = info.writeFunc;
945             caseSensitivity = info.caseSensitivity;
946         }
947     }
948 }
949 
initAccess()950 void QConfFileSettingsPrivate::initAccess()
951 {
952     if (!confFiles.isEmpty()) {
953         if (format > QSettings::IniFormat) {
954             if (!readFunc)
955                 setStatus(QSettings::AccessError);
956         }
957     }
958 
959     sync();       // loads the files the first time
960 }
961 
962 #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
windowsConfigPath(const KNOWNFOLDERID & type)963 static QString windowsConfigPath(const KNOWNFOLDERID &type)
964 {
965     QString result;
966 
967     PWSTR path = nullptr;
968     if (SHGetKnownFolderPath(type, KF_FLAG_DONT_VERIFY, NULL, &path) == S_OK) {
969         result = QString::fromWCharArray(path);
970         CoTaskMemFree(path);
971     }
972 
973     if (result.isEmpty()) {
974         if (type == FOLDERID_ProgramData) {
975             result = QLatin1String("C:\\temp\\qt-common");
976         } else if (type == FOLDERID_RoamingAppData) {
977             result = QLatin1String("C:\\temp\\qt-user");
978         }
979     }
980 
981     return result;
982 }
983 #elif defined(Q_OS_WINRT) // Q_OS_WIN && !Q_OS_WINRT
984 
985 enum ConfigPathType {
986     ConfigPath_CommonAppData,
987     ConfigPath_UserAppData
988 };
989 
windowsConfigPath(ConfigPathType type)990 static QString windowsConfigPath(ConfigPathType type)
991 {
992     static QString result;
993     while (result.isEmpty()) {
994         ComPtr<IApplicationDataStatics> applicationDataStatics;
995         if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
996             return result;
997         ComPtr<IApplicationData> applicationData;
998         if (FAILED(applicationDataStatics->get_Current(&applicationData)))
999             return result;
1000         ComPtr<IStorageFolder> localFolder;
1001         if (FAILED(applicationData->get_LocalFolder(&localFolder)))
1002             return result;
1003         ComPtr<IStorageItem> localFolderItem;
1004         if (FAILED(localFolder.As(&localFolderItem)))
1005             return result;
1006         HString path;
1007         if (FAILED(localFolderItem->get_Path(path.GetAddressOf())))
1008             return result;
1009         result = QString::fromWCharArray(path.GetRawBuffer(nullptr));
1010     }
1011 
1012     switch (type) {
1013     case ConfigPath_CommonAppData:
1014         return result + QLatin1String("\\qt-common");
1015     case ConfigPath_UserAppData:
1016         return result + QLatin1String("\\qt-user");
1017     }
1018     return result;
1019 }
1020 #endif // Q_OS_WINRT
1021 
pathHashKey(QSettings::Format format,QSettings::Scope scope)1022 static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
1023 {
1024     return int((uint(format) << 1) | uint(scope == QSettings::SystemScope));
1025 }
1026 
1027 #ifndef Q_OS_WIN
make_user_path()1028 static QString make_user_path()
1029 {
1030     static Q_CONSTEXPR QChar sep = QLatin1Char('/');
1031 #ifndef QSETTINGS_USE_QSTANDARDPATHS
1032     // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
1033     // for some time now. Moving away from that would require migrating existing settings.
1034     QByteArray env = qgetenv("XDG_CONFIG_HOME");
1035     if (env.isEmpty()) {
1036         return QDir::homePath() + QLatin1String("/.config/");
1037     } else if (env.startsWith('/')) {
1038         return QFile::decodeName(env) + sep;
1039     } else {
1040         return QDir::homePath() + sep + QFile::decodeName(env) + sep;
1041     }
1042 #else
1043     // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code;
1044     // it makes the use of test mode from unit tests possible.
1045     // Ideally all platforms should use this, but see above for the migration issue.
1046     return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep;
1047 #endif
1048 }
1049 #endif // !Q_OS_WIN
1050 
initDefaultPaths(std::unique_lock<QBasicMutex> locker)1051 static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMutex> locker)
1052 {
1053     PathHash *pathHash = pathHashFunc();
1054 
1055     locker.unlock();
1056 
1057     /*
1058        QLibraryInfo::location() uses QSettings, so in order to
1059        avoid a dead-lock, we can't hold the global mutex while
1060        calling it.
1061     */
1062     QString systemPath = QLibraryInfo::location(QLibraryInfo::SettingsPath) + QLatin1Char('/');
1063 
1064     locker.lock();
1065     if (pathHash->isEmpty()) {
1066         /*
1067            Lazy initialization of pathHash. We initialize the
1068            IniFormat paths and (on Unix) the NativeFormat paths.
1069            (The NativeFormat paths are not configurable for the
1070            Windows registry and the Mac CFPreferences.)
1071        */
1072 #ifdef Q_OS_WIN
1073 
1074 #  ifdef Q_OS_WINRT
1075         const QString roamingAppDataFolder = windowsConfigPath(ConfigPath_UserAppData);
1076         const QString programDataFolder = windowsConfigPath(ConfigPath_CommonAppData);
1077 #  else
1078         const QString roamingAppDataFolder = windowsConfigPath(FOLDERID_RoamingAppData);
1079         const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
1080 #  endif
1081         pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
1082                          Path(roamingAppDataFolder + QDir::separator(), false));
1083         pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
1084                          Path(programDataFolder + QDir::separator(), false));
1085 #else
1086         const QString userPath = make_user_path();
1087         pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
1088         pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
1089 #ifndef Q_OS_MAC
1090         pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
1091         pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
1092 #endif
1093 #endif // Q_OS_WIN
1094     }
1095 
1096     return locker;
1097 }
1098 
getPath(QSettings::Format format,QSettings::Scope scope)1099 static Path getPath(QSettings::Format format, QSettings::Scope scope)
1100 {
1101     Q_ASSERT((int)QSettings::NativeFormat == 0);
1102     Q_ASSERT((int)QSettings::IniFormat == 1);
1103 
1104     auto locker = qt_unique_lock(settingsGlobalMutex);
1105     PathHash *pathHash = pathHashFunc();
1106     if (pathHash->isEmpty())
1107         locker = initDefaultPaths(std::move(locker));
1108 
1109     Path result = pathHash->value(pathHashKey(format, scope));
1110     if (!result.path.isEmpty())
1111         return result;
1112 
1113     // fall back on INI path
1114     return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
1115 }
1116 
1117 #if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1118 // Note: Suitable only for autotests.
clearDefaultPaths()1119 void Q_AUTOTEST_EXPORT clearDefaultPaths()
1120 {
1121     const auto locker = qt_scoped_lock(settingsGlobalMutex);
1122     pathHashFunc()->clear();
1123 }
1124 #endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1125 
QConfFileSettingsPrivate(QSettings::Format format,QSettings::Scope scope,const QString & organization,const QString & application)1126 QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
1127                                                    QSettings::Scope scope,
1128                                                    const QString &organization,
1129                                                    const QString &application)
1130     : QSettingsPrivate(format, scope, organization, application),
1131       nextPosition(0x40000000) // big positive number
1132 {
1133     initFormat();
1134 
1135     QString org = organization;
1136     if (org.isEmpty()) {
1137         setStatus(QSettings::AccessError);
1138         org = QLatin1String("Unknown Organization");
1139     }
1140 
1141     QString appFile = org + QDir::separator() + application + extension;
1142     QString orgFile = org + extension;
1143 
1144     if (scope == QSettings::UserScope) {
1145         Path userPath = getPath(format, QSettings::UserScope);
1146         if (!application.isEmpty())
1147             confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
1148         confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
1149     }
1150 
1151     Path systemPath = getPath(format, QSettings::SystemScope);
1152 #if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1153     // check if the systemPath wasn't overridden by QSettings::setPath()
1154     if (!systemPath.userDefined) {
1155         // Note: We can't use QStandardPaths::locateAll() as we need all the
1156         // possible files (not just the existing ones) and there is no way
1157         // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
1158         QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
1159         // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
1160         if (!dirs.isEmpty())
1161             dirs.takeFirst();
1162         QStringList paths;
1163         if (!application.isEmpty()) {
1164             paths.reserve(dirs.size() * 2);
1165             for (const auto &dir : qAsConst(dirs))
1166                 paths.append(dir + QLatin1Char('/') + appFile);
1167         } else {
1168             paths.reserve(dirs.size());
1169         }
1170         for (const auto &dir : qAsConst(dirs))
1171             paths.append(dir + QLatin1Char('/') + orgFile);
1172 
1173         // Note: No check for existence of files is done intentionaly.
1174         for (const auto &path : qAsConst(paths))
1175             confFiles.append(QConfFile::fromName(path, false));
1176     } else
1177 #endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1178     {
1179         if (!application.isEmpty())
1180             confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
1181         confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
1182     }
1183 
1184 #ifndef Q_OS_WASM // wasm needs to delay access until after file sync
1185     initAccess();
1186 #endif
1187 }
1188 
QConfFileSettingsPrivate(const QString & fileName,QSettings::Format format)1189 QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
1190                                                    QSettings::Format format)
1191     : QSettingsPrivate(format),
1192       nextPosition(0x40000000) // big positive number
1193 {
1194     initFormat();
1195 
1196     confFiles.append(QConfFile::fromName(fileName, true));
1197 
1198     initAccess();
1199 }
1200 
~QConfFileSettingsPrivate()1201 QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
1202 {
1203     const auto locker = qt_scoped_lock(settingsGlobalMutex);
1204     ConfFileHash *usedHash = usedHashFunc();
1205     ConfFileCache *unusedCache = unusedCacheFunc();
1206 
1207     for (auto conf_file : qAsConst(confFiles)) {
1208         if (!conf_file->ref.deref()) {
1209             if (conf_file->size == 0) {
1210                 delete conf_file;
1211             } else {
1212                 if (usedHash)
1213                     usedHash->remove(conf_file->name);
1214                 if (unusedCache) {
1215                     QT_TRY {
1216                         // compute a better size?
1217                         unusedCache->insert(conf_file->name, conf_file,
1218                                             10 + (conf_file->originalKeys.size() / 4));
1219                     } QT_CATCH(...) {
1220                         // out of memory. Do not cache the file.
1221                         delete conf_file;
1222                     }
1223                 } else {
1224                     // unusedCache is gone - delete the entry to prevent a memory leak
1225                     delete conf_file;
1226                 }
1227             }
1228         }
1229     }
1230 }
1231 
remove(const QString & key)1232 void QConfFileSettingsPrivate::remove(const QString &key)
1233 {
1234     if (confFiles.isEmpty())
1235         return;
1236 
1237     // Note: First config file is always the most specific.
1238     QConfFile *confFile = confFiles.at(0);
1239 
1240     QSettingsKey theKey(key, caseSensitivity);
1241     QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
1242     const auto locker = qt_scoped_lock(confFile->mutex);
1243 
1244     ensureSectionParsed(confFile, theKey);
1245     ensureSectionParsed(confFile, prefix);
1246 
1247     ParsedSettingsMap::iterator i = confFile->addedKeys.lowerBound(prefix);
1248     while (i != confFile->addedKeys.end() && i.key().startsWith(prefix))
1249         i = confFile->addedKeys.erase(i);
1250     confFile->addedKeys.remove(theKey);
1251 
1252     ParsedSettingsMap::const_iterator j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
1253     while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) {
1254         confFile->removedKeys.insert(j.key(), QVariant());
1255         ++j;
1256     }
1257     if (confFile->originalKeys.contains(theKey))
1258         confFile->removedKeys.insert(theKey, QVariant());
1259 }
1260 
set(const QString & key,const QVariant & value)1261 void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
1262 {
1263     if (confFiles.isEmpty())
1264         return;
1265 
1266     // Note: First config file is always the most specific.
1267     QConfFile *confFile = confFiles.at(0);
1268 
1269     QSettingsKey theKey(key, caseSensitivity, nextPosition++);
1270     const auto locker = qt_scoped_lock(confFile->mutex);
1271     confFile->removedKeys.remove(theKey);
1272     confFile->addedKeys.insert(theKey, value);
1273 }
1274 
get(const QString & key,QVariant * value) const1275 bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
1276 {
1277     QSettingsKey theKey(key, caseSensitivity);
1278     ParsedSettingsMap::const_iterator j;
1279     bool found = false;
1280 
1281     for (auto confFile : qAsConst(confFiles)) {
1282         const auto locker = qt_scoped_lock(confFile->mutex);
1283 
1284         if (!confFile->addedKeys.isEmpty()) {
1285             j = confFile->addedKeys.constFind(theKey);
1286             found = (j != confFile->addedKeys.constEnd());
1287         }
1288         if (!found) {
1289             ensureSectionParsed(confFile, theKey);
1290             j = confFile->originalKeys.constFind(theKey);
1291             found = (j != confFile->originalKeys.constEnd()
1292                      && !confFile->removedKeys.contains(theKey));
1293         }
1294 
1295         if (found && value)
1296             *value = *j;
1297 
1298         if (found)
1299             return true;
1300         if (!fallbacks)
1301             break;
1302     }
1303     return false;
1304 }
1305 
children(const QString & prefix,ChildSpec spec) const1306 QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
1307 {
1308     QStringList result;
1309     ParsedSettingsMap::const_iterator j;
1310 
1311     QSettingsKey thePrefix(prefix, caseSensitivity);
1312     int startPos = prefix.size();
1313 
1314     for (auto confFile : qAsConst(confFiles)) {
1315         const auto locker = qt_scoped_lock(confFile->mutex);
1316 
1317         if (thePrefix.isEmpty())
1318             ensureAllSectionsParsed(confFile);
1319         else
1320             ensureSectionParsed(confFile, thePrefix);
1321 
1322         j = const_cast<const ParsedSettingsMap *>(
1323                 &confFile->originalKeys)->lowerBound( thePrefix);
1324         while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
1325             if (!confFile->removedKeys.contains(j.key()))
1326                 processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
1327             ++j;
1328         }
1329 
1330         j = const_cast<const ParsedSettingsMap *>(
1331                 &confFile->addedKeys)->lowerBound(thePrefix);
1332         while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
1333             processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
1334             ++j;
1335         }
1336 
1337         if (!fallbacks)
1338             break;
1339     }
1340     std::sort(result.begin(), result.end());
1341     result.erase(std::unique(result.begin(), result.end()),
1342                  result.end());
1343     return result;
1344 }
1345 
clear()1346 void QConfFileSettingsPrivate::clear()
1347 {
1348     if (confFiles.isEmpty())
1349         return;
1350 
1351     // Note: First config file is always the most specific.
1352     QConfFile *confFile = confFiles.at(0);
1353 
1354     const auto locker = qt_scoped_lock(confFile->mutex);
1355     ensureAllSectionsParsed(confFile);
1356     confFile->addedKeys.clear();
1357     confFile->removedKeys = confFile->originalKeys;
1358 }
1359 
sync()1360 void QConfFileSettingsPrivate::sync()
1361 {
1362     // people probably won't be checking the status a whole lot, so in case of
1363     // error we just try to go on and make the best of it
1364 
1365     for (auto confFile : qAsConst(confFiles)) {
1366         const auto locker = qt_scoped_lock(confFile->mutex);
1367         syncConfFile(confFile);
1368     }
1369 }
1370 
flush()1371 void QConfFileSettingsPrivate::flush()
1372 {
1373     sync();
1374 }
1375 
fileName() const1376 QString QConfFileSettingsPrivate::fileName() const
1377 {
1378     if (confFiles.isEmpty())
1379         return QString();
1380 
1381     // Note: First config file is always the most specific.
1382     return confFiles.at(0)->name;
1383 }
1384 
isWritable() const1385 bool QConfFileSettingsPrivate::isWritable() const
1386 {
1387     if (format > QSettings::IniFormat && !writeFunc)
1388         return false;
1389 
1390     if (confFiles.isEmpty())
1391         return false;
1392 
1393     return confFiles.at(0)->isWritable();
1394 }
1395 
syncConfFile(QConfFile * confFile)1396 void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
1397 {
1398     bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
1399 
1400     /*
1401         We can often optimize the read-only case, if the file on disk
1402         hasn't changed.
1403     */
1404     if (readOnly && confFile->size > 0) {
1405         QFileInfo fileInfo(confFile->name);
1406         if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified())
1407             return;
1408     }
1409 
1410     if (!readOnly && !confFile->isWritable()) {
1411         setStatus(QSettings::AccessError);
1412         return;
1413     }
1414 
1415 #ifndef QT_BOOTSTRAPPED
1416     /*
1417         Use a lockfile in order to protect us against other QSettings instances
1418         trying to write the same settings at the same time.
1419 
1420         We only need to lock if we are actually writing as only concurrent writes are a problem.
1421         Concurrent read and write are not a problem because the writing operation is atomic.
1422     */
1423     QLockFile lockFile(confFile->name + QLatin1String(".lock"));
1424     if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
1425         setStatus(QSettings::AccessError);
1426         return;
1427     }
1428 #endif
1429 
1430     /*
1431         We hold the lock. Let's reread the file if it has changed
1432         since last time we read it.
1433     */
1434     QFileInfo fileInfo(confFile->name);
1435     bool mustReadFile = true;
1436     bool createFile = !fileInfo.exists();
1437 
1438     if (!readOnly)
1439         mustReadFile = (confFile->size != fileInfo.size()
1440                         || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified()));
1441 
1442     if (mustReadFile) {
1443         confFile->unparsedIniSections.clear();
1444         confFile->originalKeys.clear();
1445 
1446         QFile file(confFile->name);
1447         if (!createFile && !file.open(QFile::ReadOnly)) {
1448             setStatus(QSettings::AccessError);
1449             return;
1450         }
1451 
1452         /*
1453             Files that we can't read (because of permissions or
1454             because they don't exist) are treated as empty files.
1455         */
1456         if (file.isReadable() && file.size() != 0) {
1457             bool ok = false;
1458 #ifdef Q_OS_MAC
1459             if (format == QSettings::NativeFormat) {
1460                 QByteArray data = file.readAll();
1461                 ok = readPlistFile(data, &confFile->originalKeys);
1462             } else
1463 #endif
1464             if (format <= QSettings::IniFormat) {
1465                 QByteArray data = file.readAll();
1466                 ok = readIniFile(data, &confFile->unparsedIniSections);
1467             } else if (readFunc) {
1468                 QSettings::SettingsMap tempNewKeys;
1469                 ok = readFunc(file, tempNewKeys);
1470 
1471                 if (ok) {
1472                     QSettings::SettingsMap::const_iterator i = tempNewKeys.constBegin();
1473                     while (i != tempNewKeys.constEnd()) {
1474                         confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
1475                                                       i.value());
1476                         ++i;
1477                     }
1478                 }
1479             }
1480 
1481             if (!ok)
1482                 setStatus(QSettings::FormatError);
1483         }
1484 
1485         confFile->size = fileInfo.size();
1486         confFile->timeStamp = fileInfo.lastModified();
1487     }
1488 
1489     /*
1490         We also need to save the file. We still hold the file lock,
1491         so everything is under control.
1492     */
1493     if (!readOnly) {
1494         bool ok = false;
1495         ensureAllSectionsParsed(confFile);
1496         ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
1497 
1498 #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1499         QSaveFile sf(confFile->name);
1500         sf.setDirectWriteFallback(!atomicSyncOnly);
1501 #else
1502         QFile sf(confFile->name);
1503 #endif
1504         if (!sf.open(QIODevice::WriteOnly)) {
1505             setStatus(QSettings::AccessError);
1506             return;
1507         }
1508 
1509 #ifdef Q_OS_MAC
1510         if (format == QSettings::NativeFormat) {
1511             ok = writePlistFile(sf, mergedKeys);
1512         } else
1513 #endif
1514         if (format <= QSettings::IniFormat) {
1515             ok = writeIniFile(sf, mergedKeys);
1516         } else if (writeFunc) {
1517             QSettings::SettingsMap tempOriginalKeys;
1518 
1519             ParsedSettingsMap::const_iterator i = mergedKeys.constBegin();
1520             while (i != mergedKeys.constEnd()) {
1521                 tempOriginalKeys.insert(i.key(), i.value());
1522                 ++i;
1523             }
1524             ok = writeFunc(sf, tempOriginalKeys);
1525         }
1526 
1527 #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1528         if (ok)
1529             ok = sf.commit();
1530 #endif
1531 
1532         if (ok) {
1533             confFile->unparsedIniSections.clear();
1534             confFile->originalKeys = mergedKeys;
1535             confFile->addedKeys.clear();
1536             confFile->removedKeys.clear();
1537 
1538             QFileInfo fileInfo(confFile->name);
1539             confFile->size = fileInfo.size();
1540             confFile->timeStamp = fileInfo.lastModified();
1541 
1542             // If we have created the file, apply the file perms
1543             if (createFile) {
1544                 QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
1545                 if (!confFile->userPerms)
1546                     perms |= QFile::ReadGroup | QFile::ReadOther;
1547                 QFile(confFile->name).setPermissions(perms);
1548             }
1549         } else {
1550             setStatus(QSettings::AccessError);
1551         }
1552     }
1553 }
1554 
1555 enum { Space = 0x1, Special = 0x2 };
1556 
1557 static const char charTraits[256] =
1558 {
1559     // Space: '\t', '\n', '\r', ' '
1560     // Special: '\n', '\r', '"', ';', '=', '\\'
1561 
1562     0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0,
1563     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1564     Space, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1565     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0,
1566     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1567     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, 0, 0,
1568     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1569     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1570 
1571     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1572     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1573     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1574     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1575     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1576     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1577     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1578     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1579 };
1580 
readIniLine(const QByteArray & data,int & dataPos,int & lineStart,int & lineLen,int & equalsPos)1581 bool QConfFileSettingsPrivate::readIniLine(const QByteArray &data, int &dataPos,
1582                                            int &lineStart, int &lineLen, int &equalsPos)
1583 {
1584     int dataLen = data.length();
1585     bool inQuotes = false;
1586 
1587     equalsPos = -1;
1588 
1589     lineStart = dataPos;
1590     while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space))
1591         ++lineStart;
1592 
1593     int i = lineStart;
1594     while (i < dataLen) {
1595         char ch = data.at(i);
1596         while (!(charTraits[uchar(ch)] & Special)) {
1597             if (++i == dataLen)
1598                 goto break_out_of_outer_loop;
1599             ch = data.at(i);
1600         }
1601 
1602         ++i;
1603         if (ch == '=') {
1604             if (!inQuotes && equalsPos == -1)
1605                 equalsPos = i - 1;
1606         } else if (ch == '\n' || ch == '\r') {
1607             if (i == lineStart + 1) {
1608                 ++lineStart;
1609             } else if (!inQuotes) {
1610                 --i;
1611                 goto break_out_of_outer_loop;
1612             }
1613         } else if (ch == '\\') {
1614             if (i < dataLen) {
1615                 char ch = data.at(i++);
1616                 if (i < dataLen) {
1617                     char ch2 = data.at(i);
1618                     // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
1619                     if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n'))
1620                         ++i;
1621                 }
1622             }
1623         } else if (ch == '"') {
1624             inQuotes = !inQuotes;
1625         } else {
1626             Q_ASSERT(ch == ';');
1627 
1628             if (i == lineStart + 1) {
1629                 while (i < dataLen && (((ch = data.at(i)) != '\n') && ch != '\r'))
1630                     ++i;
1631                 while (i < dataLen && charTraits[uchar(data.at(i))] & Space)
1632                     ++i;
1633                 lineStart = i;
1634             } else if (!inQuotes) {
1635                 --i;
1636                 goto break_out_of_outer_loop;
1637             }
1638         }
1639     }
1640 
1641 break_out_of_outer_loop:
1642     dataPos = i;
1643     lineLen = i - lineStart;
1644     return lineLen > 0;
1645 }
1646 
1647 /*
1648     Returns \c false on parse error. However, as many keys are read as
1649     possible, so if the user doesn't check the status he will get the
1650     most out of the file anyway.
1651 */
readIniFile(const QByteArray & data,UnparsedSettingsMap * unparsedIniSections)1652 bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data,
1653                                            UnparsedSettingsMap *unparsedIniSections)
1654 {
1655 #define FLUSH_CURRENT_SECTION() \
1656     { \
1657         QByteArray &sectionData = (*unparsedIniSections)[QSettingsKey(currentSection, \
1658                                                                       IniCaseSensitivity, \
1659                                                                       sectionPosition)]; \
1660         if (!sectionData.isEmpty()) \
1661             sectionData.append('\n'); \
1662         sectionData += data.mid(currentSectionStart, lineStart - currentSectionStart); \
1663         sectionPosition = ++position; \
1664     }
1665 
1666     QString currentSection;
1667     int currentSectionStart = 0;
1668     int dataPos = 0;
1669     int lineStart;
1670     int lineLen;
1671     int equalsPos;
1672     int position = 0;
1673     int sectionPosition = 0;
1674     bool ok = true;
1675 
1676     // detect utf8 BOM
1677     const uchar *dd = (const uchar *)data.constData();
1678     if (data.size() >= 3 && dd[0] == 0xef && dd[1] == 0xbb && dd[2] == 0xbf) {
1679 #if QT_CONFIG(textcodec)
1680         iniCodec = QTextCodec::codecForName("UTF-8");
1681 #else
1682         ok = false;
1683 #endif
1684         dataPos = 3;
1685     }
1686 
1687     while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1688         char ch = data.at(lineStart);
1689         if (ch == '[') {
1690             FLUSH_CURRENT_SECTION();
1691 
1692             // this is a section
1693             QByteArray iniSection;
1694             int idx = data.indexOf(']', lineStart);
1695             if (idx == -1 || idx >= lineStart + lineLen) {
1696                 ok = false;
1697                 iniSection = data.mid(lineStart + 1, lineLen - 1);
1698             } else {
1699                 iniSection = data.mid(lineStart + 1, idx - lineStart - 1);
1700             }
1701 
1702             iniSection = iniSection.trimmed();
1703 
1704             if (iniSection.compare("general", Qt::CaseInsensitive) == 0) {
1705                 currentSection.clear();
1706             } else {
1707                 if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) {
1708                     currentSection = QLatin1String(iniSection.constData() + 1);
1709                 } else {
1710                     currentSection.clear();
1711                     iniUnescapedKey(iniSection, 0, iniSection.size(), currentSection);
1712                 }
1713                 currentSection += QLatin1Char('/');
1714             }
1715             currentSectionStart = dataPos;
1716         }
1717         ++position;
1718     }
1719 
1720     Q_ASSERT(lineStart == data.length());
1721     FLUSH_CURRENT_SECTION();
1722 
1723     return ok;
1724 
1725 #undef FLUSH_CURRENT_SECTION
1726 }
1727 
readIniSection(const QSettingsKey & section,const QByteArray & data,ParsedSettingsMap * settingsMap,QTextCodec * codec)1728 bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey &section, const QByteArray &data,
1729                                               ParsedSettingsMap *settingsMap, QTextCodec *codec)
1730 {
1731     QStringList strListValue;
1732     bool sectionIsLowercase = (section == section.originalCaseKey());
1733     int equalsPos;
1734 
1735     bool ok = true;
1736     int dataPos = 0;
1737     int lineStart;
1738     int lineLen;
1739     int position = section.originalKeyPosition();
1740 
1741     while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1742         char ch = data.at(lineStart);
1743         Q_ASSERT(ch != '[');
1744 
1745         if (equalsPos == -1) {
1746             if (ch != ';')
1747                 ok = false;
1748             continue;
1749         }
1750 
1751         int keyEnd = equalsPos;
1752         while (keyEnd > lineStart && ((ch = data.at(keyEnd - 1)) == ' ' || ch == '\t'))
1753             --keyEnd;
1754         int valueStart = equalsPos + 1;
1755 
1756         QString key = section.originalCaseKey();
1757         bool keyIsLowercase = (iniUnescapedKey(data, lineStart, keyEnd, key) && sectionIsLowercase);
1758 
1759         QString strValue;
1760         strValue.reserve(lineLen - (valueStart - lineStart));
1761         bool isStringList = iniUnescapedStringList(data, valueStart, lineStart + lineLen,
1762                                                    strValue, strListValue, codec);
1763         QVariant variant;
1764         if (isStringList) {
1765             variant = stringListToVariantList(strListValue);
1766         } else {
1767             variant = stringToVariant(strValue);
1768         }
1769 
1770         /*
1771             We try to avoid the expensive toLower() call in
1772             QSettingsKey by passing Qt::CaseSensitive when the
1773             key is already in lowercase.
1774         */
1775         settingsMap->insert(QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive
1776                                                              : IniCaseSensitivity,
1777                                          position),
1778                             variant);
1779         ++position;
1780     }
1781 
1782     return ok;
1783 }
1784 
1785 class QSettingsIniKey : public QString
1786 {
1787 public:
QSettingsIniKey()1788     inline QSettingsIniKey() : position(-1) {}
QSettingsIniKey(const QString & str,int pos=-1)1789     inline QSettingsIniKey(const QString &str, int pos = -1) : QString(str), position(pos) {}
1790 
1791     int position;
1792 };
1793 Q_DECLARE_TYPEINFO(QSettingsIniKey, Q_MOVABLE_TYPE);
1794 
operator <(const QSettingsIniKey & k1,const QSettingsIniKey & k2)1795 static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2)
1796 {
1797     if (k1.position != k2.position)
1798         return k1.position < k2.position;
1799     return static_cast<const QString &>(k1) < static_cast<const QString &>(k2);
1800 }
1801 
1802 typedef QMap<QSettingsIniKey, QVariant> IniKeyMap;
1803 
1804 struct QSettingsIniSection
1805 {
1806     int position;
1807     IniKeyMap keyMap;
1808 
QSettingsIniSectionQSettingsIniSection1809     inline QSettingsIniSection() : position(-1) {}
1810 };
1811 
1812 Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE);
1813 
1814 typedef QMap<QString, QSettingsIniSection> IniMap;
1815 
1816 /*
1817     This would be more straightforward if we didn't try to remember the original
1818     key order in the .ini file, but we do.
1819 */
writeIniFile(QIODevice & device,const ParsedSettingsMap & map)1820 bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map)
1821 {
1822     IniMap iniMap;
1823     IniMap::const_iterator i;
1824 
1825 #ifdef Q_OS_WIN
1826     const char * const eol = "\r\n";
1827 #else
1828     const char eol = '\n';
1829 #endif
1830 
1831     for (ParsedSettingsMap::const_iterator j = map.constBegin(); j != map.constEnd(); ++j) {
1832         QString section;
1833         QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition());
1834         int slashPos;
1835 
1836         if ((slashPos = key.indexOf(QLatin1Char('/'))) != -1) {
1837             section = key.left(slashPos);
1838             key.remove(0, slashPos + 1);
1839         }
1840 
1841         QSettingsIniSection &iniSection = iniMap[section];
1842 
1843         // -1 means infinity
1844         if (uint(key.position) < uint(iniSection.position))
1845             iniSection.position = key.position;
1846         iniSection.keyMap[key] = j.value();
1847     }
1848 
1849     const int sectionCount = iniMap.size();
1850     QVector<QSettingsIniKey> sections;
1851     sections.reserve(sectionCount);
1852     for (i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
1853         sections.append(QSettingsIniKey(i.key(), i.value().position));
1854     std::sort(sections.begin(), sections.end());
1855 
1856     bool writeError = false;
1857     for (int j = 0; !writeError && j < sectionCount; ++j) {
1858         i = iniMap.constFind(sections.at(j));
1859         Q_ASSERT(i != iniMap.constEnd());
1860 
1861         QByteArray realSection;
1862 
1863         iniEscapedKey(i.key(), realSection);
1864 
1865         if (realSection.isEmpty()) {
1866             realSection = "[General]";
1867         } else if (realSection.compare("general", Qt::CaseInsensitive) == 0) {
1868             realSection = "[%General]";
1869         } else {
1870             realSection.prepend('[');
1871             realSection.append(']');
1872         }
1873 
1874         if (j != 0)
1875             realSection.prepend(eol);
1876         realSection += eol;
1877 
1878         device.write(realSection);
1879 
1880         const IniKeyMap &ents = i.value().keyMap;
1881         for (IniKeyMap::const_iterator j = ents.constBegin(); j != ents.constEnd(); ++j) {
1882             QByteArray block;
1883             iniEscapedKey(j.key(), block);
1884             block += '=';
1885 
1886             const QVariant &value = j.value();
1887 
1888             /*
1889                 The size() != 1 trick is necessary because
1890                 QVariant(QString("foo")).toList() returns an empty
1891                 list, not a list containing "foo".
1892             */
1893             if (value.userType() == QMetaType::QStringList
1894                     || (value.userType() == QMetaType::QVariantList && value.toList().size() != 1)) {
1895                 iniEscapedStringList(variantListToStringList(value.toList()), block, iniCodec);
1896             } else {
1897                 iniEscapedString(variantToString(value), block, iniCodec);
1898             }
1899             block += eol;
1900             if (device.write(block) == -1) {
1901                 writeError = true;
1902                 break;
1903             }
1904         }
1905     }
1906     return !writeError;
1907 }
1908 
ensureAllSectionsParsed(QConfFile * confFile) const1909 void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const
1910 {
1911     UnparsedSettingsMap::const_iterator i = confFile->unparsedIniSections.constBegin();
1912     const UnparsedSettingsMap::const_iterator end = confFile->unparsedIniSections.constEnd();
1913 
1914     for (; i != end; ++i) {
1915         if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec))
1916             setStatus(QSettings::FormatError);
1917     }
1918     confFile->unparsedIniSections.clear();
1919 }
1920 
ensureSectionParsed(QConfFile * confFile,const QSettingsKey & key) const1921 void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
1922                                                    const QSettingsKey &key) const
1923 {
1924     if (confFile->unparsedIniSections.isEmpty())
1925         return;
1926 
1927     UnparsedSettingsMap::iterator i;
1928 
1929     int indexOfSlash = key.indexOf(QLatin1Char('/'));
1930     if (indexOfSlash != -1) {
1931         i = confFile->unparsedIniSections.upperBound(key);
1932         if (i == confFile->unparsedIniSections.begin())
1933             return;
1934         --i;
1935         if (i.key().isEmpty() || !key.startsWith(i.key()))
1936             return;
1937     } else {
1938         i = confFile->unparsedIniSections.begin();
1939         if (i == confFile->unparsedIniSections.end() || !i.key().isEmpty())
1940             return;
1941     }
1942 
1943     if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec))
1944         setStatus(QSettings::FormatError);
1945     confFile->unparsedIniSections.erase(i);
1946 }
1947 
1948 /*!
1949     \class QSettings
1950     \inmodule QtCore
1951     \brief The QSettings class provides persistent platform-independent application settings.
1952 
1953     \ingroup io
1954 
1955     \reentrant
1956 
1957     Users normally expect an application to remember its settings
1958     (window sizes and positions, options, etc.) across sessions. This
1959     information is often stored in the system registry on Windows,
1960     and in property list files on \macos and iOS. On Unix systems, in the
1961     absence of a standard, many applications (including the KDE
1962     applications) use INI text files.
1963 
1964     QSettings is an abstraction around these technologies, enabling
1965     you to save and restore application settings in a portable
1966     manner. It also supports \l{registerFormat()}{custom storage
1967     formats}.
1968 
1969     QSettings's API is based on QVariant, allowing you to save
1970     most value-based types, such as QString, QRect, and QImage,
1971     with the minimum of effort.
1972 
1973     If all you need is a non-persistent memory-based structure,
1974     consider using QMap<QString, QVariant> instead.
1975 
1976     \tableofcontents section1
1977 
1978     \section1 Basic Usage
1979 
1980     When creating a QSettings object, you must pass the name of your
1981     company or organization as well as the name of your application.
1982     For example, if your product is called Star Runner and your
1983     company is called MySoft, you would construct the QSettings
1984     object as follows:
1985 
1986     \snippet settings/settings.cpp 0
1987 
1988     QSettings objects can be created either on the stack or on
1989     the heap (i.e. using \c new). Constructing and destroying a
1990     QSettings object is very fast.
1991 
1992     If you use QSettings from many places in your application, you
1993     might want to specify the organization name and the application
1994     name using QCoreApplication::setOrganizationName() and
1995     QCoreApplication::setApplicationName(), and then use the default
1996     QSettings constructor:
1997 
1998     \snippet settings/settings.cpp 1
1999     \snippet settings/settings.cpp 2
2000     \snippet settings/settings.cpp 3
2001     \dots
2002     \snippet settings/settings.cpp 4
2003 
2004     (Here, we also specify the organization's Internet domain. When
2005     the Internet domain is set, it is used on \macos and iOS instead of the
2006     organization name, since \macos and iOS applications conventionally use
2007     Internet domains to identify themselves. If no domain is set, a
2008     fake domain is derived from the organization name. See the
2009     \l{Platform-Specific Notes} below for details.)
2010 
2011     QSettings stores settings. Each setting consists of a QString
2012     that specifies the setting's name (the \e key) and a QVariant
2013     that stores the data associated with the key. To write a setting,
2014     use setValue(). For example:
2015 
2016     \snippet settings/settings.cpp 5
2017 
2018     If there already exists a setting with the same key, the existing
2019     value is overwritten by the new value. For efficiency, the
2020     changes may not be saved to permanent storage immediately. (You
2021     can always call sync() to commit your changes.)
2022 
2023     You can get a setting's value back using value():
2024 
2025     \snippet settings/settings.cpp 6
2026 
2027     If there is no setting with the specified name, QSettings
2028     returns a null QVariant (which can be converted to the integer 0).
2029     You can specify another default value by passing a second
2030     argument to value():
2031 
2032     \snippet settings/settings.cpp 7
2033 
2034     To test whether a given key exists, call contains(). To remove
2035     the setting associated with a key, call remove(). To obtain the
2036     list of all keys, call allKeys(). To remove all keys, call
2037     clear().
2038 
2039     \section1 QVariant and GUI Types
2040 
2041     Because QVariant is part of the Qt Core module, it cannot provide
2042     conversion functions to data types such as QColor, QImage, and
2043     QPixmap, which are part of Qt GUI. In other words, there is no
2044     \c toColor(), \c toImage(), or \c toPixmap() functions in QVariant.
2045 
2046     Instead, you can use the QVariant::value() template function.
2047     For example:
2048 
2049     \snippet code/src_corelib_io_qsettings.cpp 0
2050 
2051     The inverse conversion (e.g., from QColor to QVariant) is
2052     automatic for all data types supported by QVariant, including
2053     GUI-related types:
2054 
2055     \snippet code/src_corelib_io_qsettings.cpp 1
2056 
2057     Custom types registered using qRegisterMetaType() and
2058     qRegisterMetaTypeStreamOperators() can be stored using QSettings.
2059 
2060     \section1 Section and Key Syntax
2061 
2062     Setting keys can contain any Unicode characters. The Windows
2063     registry and INI files use case-insensitive keys, whereas the
2064     CFPreferences API on \macos and iOS uses case-sensitive keys. To
2065     avoid portability problems, follow these simple rules:
2066 
2067     \list 1
2068     \li Always refer to the same key using the same case. For example,
2069        if you refer to a key as "text fonts" in one place in your
2070        code, don't refer to it as "Text Fonts" somewhere else.
2071 
2072     \li Avoid key names that are identical except for the case. For
2073        example, if you have a key called "MainWindow", don't try to
2074        save another key as "mainwindow".
2075 
2076     \li Do not use slashes ('/' and '\\') in section or key names; the
2077        backslash character is used to separate sub keys (see below). On
2078        windows '\\' are converted by QSettings to '/', which makes
2079        them identical.
2080     \endlist
2081 
2082     You can form hierarchical keys using the '/' character as a
2083     separator, similar to Unix file paths. For example:
2084 
2085     \snippet settings/settings.cpp 8
2086     \snippet settings/settings.cpp 9
2087     \snippet settings/settings.cpp 10
2088 
2089     If you want to save or restore many settings with the same
2090     prefix, you can specify the prefix using beginGroup() and call
2091     endGroup() at the end. Here's the same example again, but this
2092     time using the group mechanism:
2093 
2094     \snippet settings/settings.cpp 11
2095     \codeline
2096     \snippet settings/settings.cpp 12
2097 
2098     If a group is set using beginGroup(), the behavior of most
2099     functions changes consequently. Groups can be set recursively.
2100 
2101     In addition to groups, QSettings also supports an "array"
2102     concept. See beginReadArray() and beginWriteArray() for details.
2103 
2104     \section1 Fallback Mechanism
2105 
2106     Let's assume that you have created a QSettings object with the
2107     organization name MySoft and the application name Star Runner.
2108     When you look up a value, up to four locations are searched in
2109     that order:
2110 
2111     \list 1
2112     \li a user-specific location for the Star Runner application
2113     \li a user-specific location for all applications by MySoft
2114     \li a system-wide location for the Star Runner application
2115     \li a system-wide location for all applications by MySoft
2116     \endlist
2117 
2118     (See \l{Platform-Specific Notes} below for information on what
2119     these locations are on the different platforms supported by Qt.)
2120 
2121     If a key cannot be found in the first location, the search goes
2122     on in the second location, and so on. This enables you to store
2123     system-wide or organization-wide settings and to override them on
2124     a per-user or per-application basis. To turn off this mechanism,
2125     call setFallbacksEnabled(false).
2126 
2127     Although keys from all four locations are available for reading,
2128     only the first file (the user-specific location for the
2129     application at hand) is accessible for writing. To write to any
2130     of the other files, omit the application name and/or specify
2131     QSettings::SystemScope (as opposed to QSettings::UserScope, the
2132     default).
2133 
2134     Let's see with an example:
2135 
2136     \snippet settings/settings.cpp 13
2137     \snippet settings/settings.cpp 14
2138 
2139     The table below summarizes which QSettings objects access
2140     which location. "\b{X}" means that the location is the main
2141     location associated to the QSettings object and is used both
2142     for reading and for writing; "o" means that the location is used
2143     as a fallback when reading.
2144 
2145     \table
2146     \header \li Locations               \li \c{obj1} \li \c{obj2} \li \c{obj3} \li \c{obj4}
2147     \row    \li 1. User, Application    \li \b{X} \li          \li          \li
2148     \row    \li 2. User, Organization   \li o        \li \b{X} \li          \li
2149     \row    \li 3. System, Application  \li o        \li          \li \b{X} \li
2150     \row    \li 4. System, Organization \li o        \li o        \li o        \li \b{X}
2151     \endtable
2152 
2153     The beauty of this mechanism is that it works on all platforms
2154     supported by Qt and that it still gives you a lot of flexibility,
2155     without requiring you to specify any file names or registry
2156     paths.
2157 
2158     If you want to use INI files on all platforms instead of the
2159     native API, you can pass QSettings::IniFormat as the first
2160     argument to the QSettings constructor, followed by the scope, the
2161     organization name, and the application name:
2162 
2163     \snippet settings/settings.cpp 15
2164 
2165     Note that type information is not preserved when reading settings from INI
2166     files; all values will be returned as QString.
2167 
2168     The \l{tools/settingseditor}{Settings Editor} example lets you
2169     experiment with different settings location and with fallbacks
2170     turned on or off.
2171 
2172     \section1 Restoring the State of a GUI Application
2173 
2174     QSettings is often used to store the state of a GUI
2175     application. The following example illustrates how to use QSettings
2176     to save and restore the geometry of an application's main window.
2177 
2178     \snippet settings/settings.cpp 16
2179     \codeline
2180     \snippet settings/settings.cpp 17
2181 
2182     See \l{Window Geometry} for a discussion on why it is better to
2183     call QWidget::resize() and QWidget::move() rather than QWidget::setGeometry()
2184     to restore a window's geometry.
2185 
2186     The \c readSettings() and \c writeSettings() functions must be
2187     called from the main window's constructor and close event handler
2188     as follows:
2189 
2190     \snippet settings/settings.cpp 18
2191     \dots
2192     \snippet settings/settings.cpp 19
2193     \snippet settings/settings.cpp 20
2194     \codeline
2195     \snippet settings/settings.cpp 21
2196 
2197     See the \l{mainwindows/application}{Application} example for a
2198     self-contained example that uses QSettings.
2199 
2200     \section1 Accessing Settings from Multiple Threads or Processes Simultaneously
2201 
2202     QSettings is \l{reentrant}. This means that you can use
2203     distinct QSettings object in different threads
2204     simultaneously. This guarantee stands even when the QSettings
2205     objects refer to the same files on disk (or to the same entries
2206     in the system registry). If a setting is modified through one
2207     QSettings object, the change will immediately be visible in
2208     any other QSettings objects that operate on the same location
2209     and that live in the same process.
2210 
2211     QSettings can safely be used from different processes (which can
2212     be different instances of your application running at the same
2213     time or different applications altogether) to read and write to
2214     the same system locations, provided certain conditions are met. For
2215     QSettings::IniFormat, it uses advisory file locking and a smart merging
2216     algorithm to ensure data integrity. The condition for that to work is that
2217     the writeable configuration file must be a regular file and must reside in
2218     a directory that the current user can create new, temporary files in. If
2219     that is not the case, then one must use setAtomicSyncRequired() to turn the
2220     safety off.
2221 
2222     Note that sync() imports changes made by other processes (in addition to
2223     writing the changes from this QSettings).
2224 
2225     \section1 Platform-Specific Notes
2226 
2227     \section2 Locations Where Application Settings Are Stored
2228 
2229     As mentioned in the \l{Fallback Mechanism} section, QSettings
2230     stores settings for an application in up to four locations,
2231     depending on whether the settings are user-specific or
2232     system-wide and whether the settings are application-specific
2233     or organization-wide. For simplicity, we're assuming the
2234     organization is called MySoft and the application is called Star
2235     Runner.
2236 
2237     On Unix systems, if the file format is NativeFormat, the
2238     following files are used by default:
2239 
2240     \list 1
2241     \li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
2242     \li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
2243     \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
2244     \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
2245     \endlist
2246     \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2247 
2248     On \macos and iOS, if the file format is NativeFormat, these files are used by
2249     default:
2250 
2251     \list 1
2252     \li \c{$HOME/Library/Preferences/com.MySoft.Star Runner.plist}
2253     \li \c{$HOME/Library/Preferences/com.MySoft.plist}
2254     \li \c{/Library/Preferences/com.MySoft.Star Runner.plist}
2255     \li \c{/Library/Preferences/com.MySoft.plist}
2256     \endlist
2257 
2258     On Windows, NativeFormat settings are stored in the following
2259     registry paths:
2260 
2261     \list 1
2262     \li \c{HKEY_CURRENT_USER\Software\MySoft\Star Runner}
2263     \li \c{HKEY_CURRENT_USER\Software\MySoft\OrganizationDefaults}
2264     \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner}
2265     \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\OrganizationDefaults}
2266     \endlist
2267 
2268     \note On Windows, for 32-bit programs running in WOW64 mode, settings are
2269     stored in the following registry path:
2270     \c{HKEY_LOCAL_MACHINE\Software\WOW6432node}.
2271 
2272     If the file format is NativeFormat, this is "Settings/MySoft/Star Runner.conf"
2273     in the application's home directory.
2274 
2275     If the file format is IniFormat, the following files are
2276     used on Unix, \macos, and iOS:
2277 
2278     \list 1
2279     \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
2280     \li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
2281     \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
2282     \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
2283     \endlist
2284     \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2285 
2286     On Windows, the following files are used:
2287 
2288     \list 1
2289     \li \c{FOLDERID_RoamingAppData\MySoft\Star Runner.ini}
2290     \li \c{FOLDERID_RoamingAppData\MySoft.ini}
2291     \li \c{FOLDERID_ProgramData\MySoft\Star Runner.ini}
2292     \li \c{FOLDERID_ProgramData\MySoft.ini}
2293     \endlist
2294 
2295     The identifiers prefixed by \c{FOLDERID_} are special item ID lists to be passed
2296     to the Win32 API function \c{SHGetKnownFolderPath()} to obtain the
2297     corresponding path.
2298 
2299     \c{FOLDERID_RoamingAppData} usually points to \tt{C:\\Users\\\e{User Name}\\AppData\\Roaming},
2300     also shown by the environment variable \c{%APPDATA%}.
2301 
2302     \c{FOLDERID_ProgramData} usually points to \tt{C:\\ProgramData}.
2303 
2304     If the file format is IniFormat, this is "Settings/MySoft/Star Runner.ini"
2305     in the application's home directory.
2306 
2307     The paths for the \c .ini and \c .conf files can be changed using
2308     setPath(). On Unix, \macos, and iOS the user can override them by
2309     setting the \c XDG_CONFIG_HOME environment variable; see
2310     setPath() for details.
2311 
2312     \section2 Accessing INI and .plist Files Directly
2313 
2314     Sometimes you do want to access settings stored in a specific
2315     file or registry path. On all platforms, if you want to read an
2316     INI file directly, you can use the QSettings constructor that
2317     takes a file name as first argument and pass QSettings::IniFormat
2318     as second argument. For example:
2319 
2320     \snippet code/src_corelib_io_qsettings.cpp 2
2321 
2322     You can then use the QSettings object to read and write settings
2323     in the file.
2324 
2325     On \macos and iOS, you can access property list \c .plist files by passing
2326     QSettings::NativeFormat as second argument. For example:
2327 
2328     \snippet code/src_corelib_io_qsettings.cpp 3
2329 
2330     \section2 Accessing the Windows Registry Directly
2331 
2332     On Windows, QSettings lets you access settings that have been
2333     written with QSettings (or settings in a supported format, e.g., string
2334     data) in the system registry. This is done by constructing a QSettings
2335     object with a path in the registry and QSettings::NativeFormat.
2336 
2337     For example:
2338 
2339     \snippet code/src_corelib_io_qsettings.cpp 4
2340 
2341     All the registry entries that appear under the specified path can
2342     be read or written through the QSettings object as usual (using
2343     forward slashes instead of backslashes). For example:
2344 
2345     \snippet code/src_corelib_io_qsettings.cpp 5
2346 
2347     Note that the backslash character is, as mentioned, used by
2348     QSettings to separate subkeys. As a result, you cannot read or
2349     write windows registry entries that contain slashes or
2350     backslashes; you should use a native windows API if you need to do
2351     so.
2352 
2353     \section2 Accessing Common Registry Settings on Windows
2354 
2355     On Windows, it is possible for a key to have both a value and subkeys.
2356     Its default value is accessed by using "Default" or "." in
2357     place of a subkey:
2358 
2359     \snippet code/src_corelib_io_qsettings.cpp 6
2360 
2361     On other platforms than Windows, "Default" and "." would be
2362     treated as regular subkeys.
2363 
2364     \section2 Platform Limitations
2365 
2366     While QSettings attempts to smooth over the differences between
2367     the different supported platforms, there are still a few
2368     differences that you should be aware of when porting your
2369     application:
2370 
2371     \list
2372     \li  The Windows system registry has the following limitations: A
2373         subkey may not exceed 255 characters, an entry's value may
2374         not exceed 16,383 characters, and all the values of a key may
2375         not exceed 65,535 characters. One way to work around these
2376         limitations is to store the settings using the IniFormat
2377         instead of the NativeFormat.
2378 
2379     \li  On Windows, when the Windows system registry is used, QSettings
2380          does not preserve the original type of the value. Therefore,
2381          the type of the value might change when a new value is set. For
2382          example, a value with type \c REG_EXPAND_SZ will change to \c REG_SZ.
2383 
2384     \li  On \macos and iOS, allKeys() will return some extra keys for global
2385         settings that apply to all applications. These keys can be
2386         read using value() but cannot be changed, only shadowed.
2387         Calling setFallbacksEnabled(false) will hide these global
2388         settings.
2389 
2390     \li  On \macos and iOS, the CFPreferences API used by QSettings expects
2391         Internet domain names rather than organization names. To
2392         provide a uniform API, QSettings derives a fake domain name
2393         from the organization name (unless the organization name
2394         already is a domain name, e.g. OpenOffice.org). The algorithm
2395         appends ".com" to the company name and replaces spaces and
2396         other illegal characters with hyphens. If you want to specify
2397         a different domain name, call
2398         QCoreApplication::setOrganizationDomain(),
2399         QCoreApplication::setOrganizationName(), and
2400         QCoreApplication::setApplicationName() in your \c main()
2401         function and then use the default QSettings constructor.
2402         Another solution is to use preprocessor directives, for
2403         example:
2404 
2405         \snippet code/src_corelib_io_qsettings.cpp 7
2406 
2407     \li On \macos, permissions to access settings not belonging to the
2408        current user (i.e. SystemScope) have changed with 10.7 (Lion). Prior to
2409        that version, users having admin rights could access these. For 10.7 and
2410        10.8 (Mountain Lion), only root can. However, 10.9 (Mavericks) changes
2411        that rule again but only for the native format (plist files).
2412 
2413     \endlist
2414 
2415     \sa QVariant, QSessionManager, {Settings Editor Example}, {Application Example}
2416 */
2417 
2418 /*! \enum QSettings::Status
2419 
2420     The following status values are possible:
2421 
2422     \value NoError  No error occurred.
2423     \value AccessError  An access error occurred (e.g. trying to write to a read-only file).
2424     \value FormatError  A format error occurred (e.g. loading a malformed INI file).
2425 
2426     \sa status()
2427 */
2428 
2429 /*! \enum QSettings::Format
2430 
2431     This enum type specifies the storage format used by QSettings.
2432 
2433     \value NativeFormat     Store the settings using the most
2434                             appropriate storage format for the platform.
2435                             On Windows, this means the system registry;
2436                             on \macos and iOS, this means the CFPreferences
2437                             API; on Unix, this means textual
2438                             configuration files in INI format.
2439     \value Registry32Format Windows only: Explicitly access the 32-bit system registry
2440                             from a 64-bit application running on 64-bit Windows.
2441                             On 32-bit Windows or from a 32-bit application on 64-bit Windows,
2442                             this works the same as specifying NativeFormat.
2443                             This enum value was added in Qt 5.7.
2444     \value Registry64Format Windows only: Explicitly access the 64-bit system registry
2445                             from a 32-bit application running on 64-bit Windows.
2446                             On 32-bit Windows or from a 64-bit application on 64-bit Windows,
2447                             this works the same as specifying NativeFormat.
2448                             This enum value was added in Qt 5.7.
2449     \value IniFormat        Store the settings in INI files. Note that type information
2450                             is not preserved when reading settings from INI files;
2451                             all values will be returned as QString.
2452 
2453     \value InvalidFormat    Special value returned by registerFormat().
2454     \omitvalue CustomFormat1
2455     \omitvalue CustomFormat2
2456     \omitvalue CustomFormat3
2457     \omitvalue CustomFormat4
2458     \omitvalue CustomFormat5
2459     \omitvalue CustomFormat6
2460     \omitvalue CustomFormat7
2461     \omitvalue CustomFormat8
2462     \omitvalue CustomFormat9
2463     \omitvalue CustomFormat10
2464     \omitvalue CustomFormat11
2465     \omitvalue CustomFormat12
2466     \omitvalue CustomFormat13
2467     \omitvalue CustomFormat14
2468     \omitvalue CustomFormat15
2469     \omitvalue CustomFormat16
2470 
2471     On Unix, NativeFormat and IniFormat mean the same thing, except
2472     that the file extension is different (\c .conf for NativeFormat,
2473     \c .ini for IniFormat).
2474 
2475     The INI file format is a Windows file format that Qt supports on
2476     all platforms. In the absence of an INI standard, we try to
2477     follow what Microsoft does, with the following exceptions:
2478 
2479     \list
2480     \li  If you store types that QVariant can't convert to QString
2481         (e.g., QPoint, QRect, and QSize), Qt uses an \c{@}-based
2482         syntax to encode the type. For example:
2483 
2484         \snippet code/src_corelib_io_qsettings.cpp 8
2485 
2486         To minimize compatibility issues, any \c @ that doesn't
2487         appear at the first position in the value or that isn't
2488         followed by a Qt type (\c Point, \c Rect, \c Size, etc.) is
2489         treated as a normal character.
2490 
2491     \li  Although backslash is a special character in INI files, most
2492         Windows applications don't escape backslashes (\c{\}) in file
2493         paths:
2494 
2495         \snippet code/src_corelib_io_qsettings.cpp 9
2496 
2497         QSettings always treats backslash as a special character and
2498         provides no API for reading or writing such entries.
2499 
2500     \li  The INI file format has severe restrictions on the syntax of
2501         a key. Qt works around this by using \c % as an escape
2502         character in keys. In addition, if you save a top-level
2503         setting (a key with no slashes in it, e.g., "someKey"), it
2504         will appear in the INI file's "General" section. To avoid
2505         overwriting other keys, if you save something using a key
2506         such as "General/someKey", the key will be located in the
2507         "%General" section, \e not in the "General" section.
2508 
2509     \li  Following the philosophy that we should be liberal in what
2510         we accept and conservative in what we generate, QSettings
2511         will accept Latin-1 encoded INI files, but generate pure
2512         ASCII files, where non-ASCII values are encoded using standard
2513         INI escape sequences. To make the INI files more readable (but
2514         potentially less compatible), call setIniCodec().
2515     \endlist
2516 
2517     \sa registerFormat(), setPath()
2518 */
2519 
2520 /*! \enum QSettings::Scope
2521 
2522     This enum specifies whether settings are user-specific or shared
2523     by all users of the same system.
2524 
2525     \value UserScope  Store settings in a location specific to the
2526                       current user (e.g., in the user's home
2527                       directory).
2528     \value SystemScope  Store settings in a global location, so that
2529                         all users on the same machine access the same
2530                         set of settings.
2531 
2532     \sa setPath()
2533 */
2534 
2535 #ifndef QT_NO_QOBJECT
2536 /*!
2537     Constructs a QSettings object for accessing settings of the
2538     application called \a application from the organization called \a
2539     organization, and with parent \a parent.
2540 
2541     Example:
2542     \snippet code/src_corelib_io_qsettings.cpp 10
2543 
2544     The scope is set to QSettings::UserScope, and the format is
2545     set to QSettings::NativeFormat (i.e. calling setDefaultFormat()
2546     before calling this constructor has no effect).
2547 
2548     \sa setDefaultFormat(), {Fallback Mechanism}
2549 */
QSettings(const QString & organization,const QString & application,QObject * parent)2550 QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2551     : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
2552               parent)
2553 {
2554 }
2555 
2556 /*!
2557     Constructs a QSettings object for accessing settings of the
2558     application called \a application from the organization called \a
2559     organization, and with parent \a parent.
2560 
2561     If \a scope is QSettings::UserScope, the QSettings object searches
2562     user-specific settings first, before it searches system-wide
2563     settings as a fallback. If \a scope is QSettings::SystemScope, the
2564     QSettings object ignores user-specific settings and provides
2565     access to system-wide settings.
2566 
2567     The storage format is set to QSettings::NativeFormat (i.e. calling
2568     setDefaultFormat() before calling this constructor has no effect).
2569 
2570     If no application name is given, the QSettings object will
2571     only access the organization-wide \l{Fallback Mechanism}{locations}.
2572 
2573     \sa setDefaultFormat()
2574 */
QSettings(Scope scope,const QString & organization,const QString & application,QObject * parent)2575 QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2576                      QObject *parent)
2577     : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent)
2578 {
2579 }
2580 
2581 /*!
2582     Constructs a QSettings object for accessing settings of the
2583     application called \a application from the organization called
2584     \a organization, and with parent \a parent.
2585 
2586     If \a scope is QSettings::UserScope, the QSettings object searches
2587     user-specific settings first, before it searches system-wide
2588     settings as a fallback. If \a scope is
2589     QSettings::SystemScope, the QSettings object ignores user-specific
2590     settings and provides access to system-wide settings.
2591 
2592     If \a format is QSettings::NativeFormat, the native API is used for
2593     storing settings. If \a format is QSettings::IniFormat, the INI format
2594     is used.
2595 
2596     If no application name is given, the QSettings object will
2597     only access the organization-wide \l{Fallback Mechanism}{locations}.
2598 */
QSettings(Format format,Scope scope,const QString & organization,const QString & application,QObject * parent)2599 QSettings::QSettings(Format format, Scope scope, const QString &organization,
2600                      const QString &application, QObject *parent)
2601     : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent)
2602 {
2603 }
2604 
2605 /*!
2606     Constructs a QSettings object for accessing the settings
2607     stored in the file called \a fileName, with parent \a parent. If
2608     the file doesn't already exist, it is created.
2609 
2610     If \a format is QSettings::NativeFormat, the meaning of \a
2611     fileName depends on the platform. On Unix, \a fileName is the
2612     name of an INI file. On \macos and iOS, \a fileName is the name of a
2613     \c .plist file. On Windows, \a fileName is a path in the system
2614     registry.
2615 
2616     If \a format is QSettings::IniFormat, \a fileName is the name of an INI
2617     file.
2618 
2619     \warning This function is provided for convenience. It works well for
2620     accessing INI or \c .plist files generated by Qt, but might fail on some
2621     syntaxes found in such files originated by other programs. In particular,
2622     be aware of the following limitations:
2623 
2624     \list
2625     \li QSettings provides no way of reading INI "path" entries, i.e., entries
2626        with unescaped slash characters. (This is because these entries are
2627        ambiguous and cannot be resolved automatically.)
2628     \li In INI files, QSettings uses the \c @ character as a metacharacter in some
2629        contexts, to encode Qt-specific data types (e.g., \c @Rect), and might
2630        therefore misinterpret it when it occurs in pure INI files.
2631     \endlist
2632 
2633     \sa fileName()
2634 */
QSettings(const QString & fileName,Format format,QObject * parent)2635 QSettings::QSettings(const QString &fileName, Format format, QObject *parent)
2636     : QObject(*QSettingsPrivate::create(fileName, format), parent)
2637 {
2638 }
2639 
2640 /*!
2641     Constructs a QSettings object for accessing settings of the
2642     application and organization set previously with a call to
2643     QCoreApplication::setOrganizationName(),
2644     QCoreApplication::setOrganizationDomain(), and
2645     QCoreApplication::setApplicationName().
2646 
2647     The scope is QSettings::UserScope and the format is
2648     defaultFormat() (QSettings::NativeFormat by default).
2649     Use setDefaultFormat() before calling this constructor
2650     to change the default format used by this constructor.
2651 
2652     The code
2653 
2654     \snippet code/src_corelib_io_qsettings.cpp 11
2655 
2656     is equivalent to
2657 
2658     \snippet code/src_corelib_io_qsettings.cpp 12
2659 
2660     If QCoreApplication::setOrganizationName() and
2661     QCoreApplication::setApplicationName() has not been previously
2662     called, the QSettings object will not be able to read or write
2663     any settings, and status() will return AccessError.
2664 
2665     You should supply both the domain (used by default on \macos and iOS) and
2666     the name (used by default elsewhere), although the code will cope if you
2667     supply only one, which will then be used (on all platforms), at odds with
2668     the usual naming of the file on platforms for which it isn't the default.
2669 
2670     \sa QCoreApplication::setOrganizationName(),
2671         QCoreApplication::setOrganizationDomain(),
2672         QCoreApplication::setApplicationName(),
2673         setDefaultFormat()
2674 */
QSettings(QObject * parent)2675 QSettings::QSettings(QObject *parent)
2676     : QSettings(UserScope, parent)
2677 {
2678 }
2679 
2680 /*!
2681     \since 5.13
2682 
2683     Constructs a QSettings object in the same way as
2684     QSettings(QObject *parent) but with the given \a scope.
2685 
2686     \sa QSettings(QObject *parent)
2687 */
QSettings(Scope scope,QObject * parent)2688 QSettings::QSettings(Scope scope, QObject *parent)
2689     : QObject(*QSettingsPrivate::create(globalDefaultFormat, scope,
2690 #ifdef Q_OS_DARWIN
2691                                         QCoreApplication::organizationDomain().isEmpty()
2692                                             ? QCoreApplication::organizationName()
2693                                             : QCoreApplication::organizationDomain()
2694 #else
2695                                         QCoreApplication::organizationName().isEmpty()
2696                                             ? QCoreApplication::organizationDomain()
2697                                             : QCoreApplication::organizationName()
2698 #endif
2699                                         , QCoreApplication::applicationName()),
2700               parent)
2701 {
2702 }
2703 
2704 #else
QSettings(const QString & organization,const QString & application)2705 QSettings::QSettings(const QString &organization, const QString &application)
2706     : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application))
2707 {
2708     d_ptr->q_ptr = this;
2709 }
2710 
QSettings(Scope scope,const QString & organization,const QString & application)2711 QSettings::QSettings(Scope scope, const QString &organization, const QString &application)
2712     : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application))
2713 {
2714     d_ptr->q_ptr = this;
2715 }
2716 
QSettings(Format format,Scope scope,const QString & organization,const QString & application)2717 QSettings::QSettings(Format format, Scope scope, const QString &organization,
2718                      const QString &application)
2719     : d_ptr(QSettingsPrivate::create(format, scope, organization, application))
2720 {
2721     d_ptr->q_ptr = this;
2722 }
2723 
QSettings(const QString & fileName,Format format)2724 QSettings::QSettings(const QString &fileName, Format format)
2725     : d_ptr(QSettingsPrivate::create(fileName, format))
2726 {
2727     d_ptr->q_ptr = this;
2728 }
2729 
2730 # ifndef QT_BUILD_QMAKE
QSettings(Scope scope)2731 QSettings::QSettings(Scope scope)
2732     : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope,
2733 #  ifdef Q_OS_DARWIN
2734                                      QCoreApplication::organizationDomain().isEmpty()
2735                                          ? QCoreApplication::organizationName()
2736                                          : QCoreApplication::organizationDomain()
2737 #  else
2738                                      QCoreApplication::organizationName().isEmpty()
2739                                          ? QCoreApplication::organizationDomain()
2740                                          : QCoreApplication::organizationName()
2741 #  endif
2742                                      , QCoreApplication::applicationName())
2743               )
2744 {
2745     d_ptr->q_ptr = this;
2746 }
2747 # endif
2748 #endif
2749 
2750 /*!
2751     Destroys the QSettings object.
2752 
2753     Any unsaved changes will eventually be written to permanent
2754     storage.
2755 
2756     \sa sync()
2757 */
~QSettings()2758 QSettings::~QSettings()
2759 {
2760     Q_D(QSettings);
2761     if (d->pendingChanges) {
2762         QT_TRY {
2763             d->flush();
2764         } QT_CATCH(...) {
2765             ; // ok. then don't flush but at least don't throw in the destructor
2766         }
2767     }
2768 }
2769 
2770 /*!
2771     Removes all entries in the primary location associated to this
2772     QSettings object.
2773 
2774     Entries in fallback locations are not removed.
2775 
2776     If you only want to remove the entries in the current group(),
2777     use remove("") instead.
2778 
2779     \sa remove(), setFallbacksEnabled()
2780 */
clear()2781 void QSettings::clear()
2782 {
2783     Q_D(QSettings);
2784     d->clear();
2785     d->requestUpdate();
2786 }
2787 
2788 /*!
2789     Writes any unsaved changes to permanent storage, and reloads any
2790     settings that have been changed in the meantime by another
2791     application.
2792 
2793     This function is called automatically from QSettings's destructor and
2794     by the event loop at regular intervals, so you normally don't need to
2795     call it yourself.
2796 
2797     \sa status()
2798 */
sync()2799 void QSettings::sync()
2800 {
2801     Q_D(QSettings);
2802     d->sync();
2803     d->pendingChanges = false;
2804 }
2805 
2806 /*!
2807     Returns the path where settings written using this QSettings
2808     object are stored.
2809 
2810     On Windows, if the format is QSettings::NativeFormat, the return value
2811     is a system registry path, not a file path.
2812 
2813     \sa isWritable(), format()
2814 */
fileName() const2815 QString QSettings::fileName() const
2816 {
2817     Q_D(const QSettings);
2818     return d->fileName();
2819 }
2820 
2821 /*!
2822     \since 4.4
2823 
2824     Returns the format used for storing the settings.
2825 
2826     \sa defaultFormat(), fileName(), scope(), organizationName(), applicationName()
2827 */
format() const2828 QSettings::Format QSettings::format() const
2829 {
2830     Q_D(const QSettings);
2831     return d->format;
2832 }
2833 
2834 /*!
2835     \since 4.4
2836 
2837     Returns the scope used for storing the settings.
2838 
2839     \sa format(), organizationName(), applicationName()
2840 */
scope() const2841 QSettings::Scope QSettings::scope() const
2842 {
2843     Q_D(const QSettings);
2844     return d->scope;
2845 }
2846 
2847 /*!
2848     \since 4.4
2849 
2850     Returns the organization name used for storing the settings.
2851 
2852     \sa QCoreApplication::organizationName(), format(), scope(), applicationName()
2853 */
organizationName() const2854 QString QSettings::organizationName() const
2855 {
2856     Q_D(const QSettings);
2857     return d->organizationName;
2858 }
2859 
2860 /*!
2861     \since 4.4
2862 
2863     Returns the application name used for storing the settings.
2864 
2865     \sa QCoreApplication::applicationName(), format(), scope(), organizationName()
2866 */
applicationName() const2867 QString QSettings::applicationName() const
2868 {
2869     Q_D(const QSettings);
2870     return d->applicationName;
2871 }
2872 
2873 #if QT_CONFIG(textcodec)
2874 
2875 /*!
2876     \since 4.5
2877 
2878     Sets the codec for accessing INI files (including \c .conf files on Unix)
2879     to \a codec. The codec is used for decoding any data that is read from
2880     the INI file, and for encoding any data that is written to the file. By
2881     default, no codec is used, and non-ASCII characters are encoded using
2882     standard INI escape sequences.
2883 
2884     \warning The codec must be set immediately after creating the QSettings
2885     object, before accessing any data.
2886 
2887     \sa iniCodec()
2888 */
setIniCodec(QTextCodec * codec)2889 void QSettings::setIniCodec(QTextCodec *codec)
2890 {
2891     Q_D(QSettings);
2892     d->iniCodec = codec;
2893 }
2894 
2895 /*!
2896     \since 4.5
2897     \overload
2898 
2899     Sets the codec for accessing INI files (including \c .conf files on Unix)
2900     to the QTextCodec for the encoding specified by \a codecName. Common
2901     values for \c codecName include "ISO 8859-1", "UTF-8", and "UTF-16".
2902     If the encoding isn't recognized, nothing happens.
2903 
2904     \sa QTextCodec::codecForName()
2905 */
setIniCodec(const char * codecName)2906 void QSettings::setIniCodec(const char *codecName)
2907 {
2908     Q_D(QSettings);
2909     if (QTextCodec *codec = QTextCodec::codecForName(codecName))
2910         d->iniCodec = codec;
2911 }
2912 
2913 /*!
2914     \since 4.5
2915 
2916     Returns the codec that is used for accessing INI files. By default,
2917     no codec is used, so \nullptr is returned.
2918 */
2919 
iniCodec() const2920 QTextCodec *QSettings::iniCodec() const
2921 {
2922     Q_D(const QSettings);
2923     return d->iniCodec;
2924 }
2925 
2926 #endif // textcodec
2927 
2928 /*!
2929     Returns a status code indicating the first error that was met by
2930     QSettings, or QSettings::NoError if no error occurred.
2931 
2932     Be aware that QSettings delays performing some operations. For this
2933     reason, you might want to call sync() to ensure that the data stored
2934     in QSettings is written to disk before calling status().
2935 
2936     \sa sync()
2937 */
status() const2938 QSettings::Status QSettings::status() const
2939 {
2940     Q_D(const QSettings);
2941     return d->status;
2942 }
2943 
2944 /*!
2945     \since 5.10
2946 
2947     Returns \c true if QSettings is only allowed to perform atomic saving and
2948     reloading (synchronization) of the settings. Returns \c false if it is
2949     allowed to save the settings contents directly to the configuration file.
2950 
2951     The default is \c true.
2952 
2953     \sa setAtomicSyncRequired(), QSaveFile
2954 */
isAtomicSyncRequired() const2955 bool QSettings::isAtomicSyncRequired() const
2956 {
2957     Q_D(const QSettings);
2958     return d->atomicSyncOnly;
2959 }
2960 
2961 /*!
2962     \since 5.10
2963 
2964     Configures whether QSettings is required to perform atomic saving and
2965     reloading (synchronization) of the settings. If the \a enable argument is
2966     \c true (the default), sync() will only perform synchronization operations
2967     that are atomic. If this is not possible, sync() will fail and status()
2968     will be an error condition.
2969 
2970     Setting this property to \c false will allow QSettings to write directly to
2971     the configuration file and ignore any errors trying to lock it against
2972     other processes trying to write at the same time. Because of the potential
2973     for corruption, this option should be used with care, but is required in
2974     certain conditions, like a QSettings::IniFormat configuration file that
2975     exists in an otherwise non-writeable directory or NTFS Alternate Data
2976     Streams.
2977 
2978     See \l QSaveFile for more information on the feature.
2979 
2980     \sa isAtomicSyncRequired(), QSaveFile
2981 */
setAtomicSyncRequired(bool enable)2982 void QSettings::setAtomicSyncRequired(bool enable)
2983 {
2984     Q_D(QSettings);
2985     d->atomicSyncOnly = enable;
2986 }
2987 
2988 /*!
2989     Appends \a prefix to the current group.
2990 
2991     The current group is automatically prepended to all keys
2992     specified to QSettings. In addition, query functions such as
2993     childGroups(), childKeys(), and allKeys() are based on the group.
2994     By default, no group is set.
2995 
2996     Groups are useful to avoid typing in the same setting paths over
2997     and over. For example:
2998 
2999     \snippet code/src_corelib_io_qsettings.cpp 13
3000 
3001     This will set the value of three settings:
3002 
3003     \list
3004     \li \c mainwindow/size
3005     \li \c mainwindow/fullScreen
3006     \li \c outputpanel/visible
3007     \endlist
3008 
3009     Call endGroup() to reset the current group to what it was before
3010     the corresponding beginGroup() call. Groups can be nested.
3011 
3012     \sa endGroup(), group()
3013 */
beginGroup(const QString & prefix)3014 void QSettings::beginGroup(const QString &prefix)
3015 {
3016     Q_D(QSettings);
3017     d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
3018 }
3019 
3020 /*!
3021     Resets the group to what it was before the corresponding
3022     beginGroup() call.
3023 
3024     Example:
3025 
3026     \snippet code/src_corelib_io_qsettings.cpp 14
3027 
3028     \sa beginGroup(), group()
3029 */
endGroup()3030 void QSettings::endGroup()
3031 {
3032     Q_D(QSettings);
3033     if (d->groupStack.isEmpty()) {
3034         qWarning("QSettings::endGroup: No matching beginGroup()");
3035         return;
3036     }
3037 
3038     QSettingsGroup group = d->groupStack.pop();
3039     int len = group.toString().size();
3040     if (len > 0)
3041         d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3042 
3043     if (group.isArray())
3044         qWarning("QSettings::endGroup: Expected endArray() instead");
3045 }
3046 
3047 /*!
3048     Returns the current group.
3049 
3050     \sa beginGroup(), endGroup()
3051 */
group() const3052 QString QSettings::group() const
3053 {
3054     Q_D(const QSettings);
3055     return d->groupPrefix.left(d->groupPrefix.size() - 1);
3056 }
3057 
3058 /*!
3059     Adds \a prefix to the current group and starts reading from an
3060     array. Returns the size of the array.
3061 
3062     Example:
3063 
3064     \snippet code/src_corelib_io_qsettings.cpp 15
3065 
3066     Use beginWriteArray() to write the array in the first place.
3067 
3068     \sa beginWriteArray(), endArray(), setArrayIndex()
3069 */
beginReadArray(const QString & prefix)3070 int QSettings::beginReadArray(const QString &prefix)
3071 {
3072     Q_D(QSettings);
3073     d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
3074     return value(QLatin1String("size")).toInt();
3075 }
3076 
3077 /*!
3078     Adds \a prefix to the current group and starts writing an array
3079     of size \a size. If \a size is -1 (the default), it is automatically
3080     determined based on the indexes of the entries written.
3081 
3082     If you have many occurrences of a certain set of keys, you can
3083     use arrays to make your life easier. For example, let's suppose
3084     that you want to save a variable-length list of user names and
3085     passwords. You could then write:
3086 
3087     \snippet code/src_corelib_io_qsettings.cpp 16
3088 
3089     The generated keys will have the form
3090 
3091     \list
3092     \li \c logins/size
3093     \li \c logins/1/userName
3094     \li \c logins/1/password
3095     \li \c logins/2/userName
3096     \li \c logins/2/password
3097     \li \c logins/3/userName
3098     \li \c logins/3/password
3099     \li ...
3100     \endlist
3101 
3102     To read back an array, use beginReadArray().
3103 
3104     \sa beginReadArray(), endArray(), setArrayIndex()
3105 */
beginWriteArray(const QString & prefix,int size)3106 void QSettings::beginWriteArray(const QString &prefix, int size)
3107 {
3108     Q_D(QSettings);
3109     d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
3110 
3111     if (size < 0)
3112         remove(QLatin1String("size"));
3113     else
3114         setValue(QLatin1String("size"), size);
3115 }
3116 
3117 /*!
3118     Closes the array that was started using beginReadArray() or
3119     beginWriteArray().
3120 
3121     \sa beginReadArray(), beginWriteArray()
3122 */
endArray()3123 void QSettings::endArray()
3124 {
3125     Q_D(QSettings);
3126     if (d->groupStack.isEmpty()) {
3127         qWarning("QSettings::endArray: No matching beginArray()");
3128         return;
3129     }
3130 
3131     QSettingsGroup group = d->groupStack.top();
3132     int len = group.toString().size();
3133     d->groupStack.pop();
3134     if (len > 0)
3135         d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3136 
3137     if (group.arraySizeGuess() != -1)
3138         setValue(group.name() + QLatin1String("/size"), group.arraySizeGuess());
3139 
3140     if (!group.isArray())
3141         qWarning("QSettings::endArray: Expected endGroup() instead");
3142 }
3143 
3144 /*!
3145     Sets the current array index to \a i. Calls to functions such as
3146     setValue(), value(), remove(), and contains() will operate on the
3147     array entry at that index.
3148 
3149     You must call beginReadArray() or beginWriteArray() before you
3150     can call this function.
3151 */
setArrayIndex(int i)3152 void QSettings::setArrayIndex(int i)
3153 {
3154     Q_D(QSettings);
3155     if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3156         qWarning("QSettings::setArrayIndex: Missing beginArray()");
3157         return;
3158     }
3159 
3160     QSettingsGroup &top = d->groupStack.top();
3161     int len = top.toString().size();
3162     top.setArrayIndex(qMax(i, 0));
3163     d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
3164 }
3165 
3166 /*!
3167     Returns a list of all keys, including subkeys, that can be read
3168     using the QSettings object.
3169 
3170     Example:
3171 
3172     \snippet code/src_corelib_io_qsettings.cpp 17
3173 
3174     If a group is set using beginGroup(), only the keys in the group
3175     are returned, without the group prefix:
3176 
3177     \snippet code/src_corelib_io_qsettings.cpp 18
3178 
3179     \sa childGroups(), childKeys()
3180 */
allKeys() const3181 QStringList QSettings::allKeys() const
3182 {
3183     Q_D(const QSettings);
3184     return d->children(d->groupPrefix, QSettingsPrivate::AllKeys);
3185 }
3186 
3187 /*!
3188     Returns a list of all top-level keys that can be read using the
3189     QSettings object.
3190 
3191     Example:
3192 
3193     \snippet code/src_corelib_io_qsettings.cpp 19
3194 
3195     If a group is set using beginGroup(), the top-level keys in that
3196     group are returned, without the group prefix:
3197 
3198     \snippet code/src_corelib_io_qsettings.cpp 20
3199 
3200     You can navigate through the entire setting hierarchy using
3201     childKeys() and childGroups() recursively.
3202 
3203     \sa childGroups(), allKeys()
3204 */
childKeys() const3205 QStringList QSettings::childKeys() const
3206 {
3207     Q_D(const QSettings);
3208     return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys);
3209 }
3210 
3211 /*!
3212     Returns a list of all key top-level groups that contain keys that
3213     can be read using the QSettings object.
3214 
3215     Example:
3216 
3217     \snippet code/src_corelib_io_qsettings.cpp 21
3218 
3219     If a group is set using beginGroup(), the first-level keys in
3220     that group are returned, without the group prefix.
3221 
3222     \snippet code/src_corelib_io_qsettings.cpp 22
3223 
3224     You can navigate through the entire setting hierarchy using
3225     childKeys() and childGroups() recursively.
3226 
3227     \sa childKeys(), allKeys()
3228 */
childGroups() const3229 QStringList QSettings::childGroups() const
3230 {
3231     Q_D(const QSettings);
3232     return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups);
3233 }
3234 
3235 /*!
3236     Returns \c true if settings can be written using this QSettings
3237     object; returns \c false otherwise.
3238 
3239     One reason why isWritable() might return false is if
3240     QSettings operates on a read-only file.
3241 
3242     \warning This function is not perfectly reliable, because the
3243     file permissions can change at any time.
3244 
3245     \sa fileName(), status(), sync()
3246 */
isWritable() const3247 bool QSettings::isWritable() const
3248 {
3249     Q_D(const QSettings);
3250     return d->isWritable();
3251 }
3252 
3253 /*!
3254 
3255   Sets the value of setting \a key to \a value. If the \a key already
3256   exists, the previous value is overwritten.
3257 
3258   Note that the Windows registry and INI files use case-insensitive
3259   keys, whereas the CFPreferences API on \macos and iOS uses
3260   case-sensitive keys. To avoid portability problems, see the
3261   \l{Section and Key Syntax} rules.
3262 
3263   Example:
3264 
3265   \snippet code/src_corelib_io_qsettings.cpp 23
3266 
3267   \sa value(), remove(), contains()
3268 */
setValue(const QString & key,const QVariant & value)3269 void QSettings::setValue(const QString &key, const QVariant &value)
3270 {
3271     Q_D(QSettings);
3272     if (key.isEmpty()) {
3273         qWarning("QSettings::setValue: Empty key passed");
3274         return;
3275     }
3276     QString k = d->actualKey(key);
3277     d->set(k, value);
3278     d->requestUpdate();
3279 }
3280 
3281 /*!
3282     Removes the setting \a key and any sub-settings of \a key.
3283 
3284     Example:
3285 
3286     \snippet code/src_corelib_io_qsettings.cpp 24
3287 
3288     Be aware that if one of the fallback locations contains a setting
3289     with the same key, that setting will be visible after calling
3290     remove().
3291 
3292     If \a key is an empty string, all keys in the current group() are
3293     removed. For example:
3294 
3295     \snippet code/src_corelib_io_qsettings.cpp 25
3296 
3297     Note that the Windows registry and INI files use case-insensitive
3298     keys, whereas the CFPreferences API on \macos and iOS uses
3299     case-sensitive keys. To avoid portability problems, see the
3300     \l{Section and Key Syntax} rules.
3301 
3302     \sa setValue(), value(), contains()
3303 */
remove(const QString & key)3304 void QSettings::remove(const QString &key)
3305 {
3306     Q_D(QSettings);
3307     /*
3308         We cannot use actualKey(), because remove() supports empty
3309         keys. The code is also tricky because of slash handling.
3310     */
3311     QString theKey = d->normalizedKey(key);
3312     if (theKey.isEmpty())
3313         theKey = group();
3314     else
3315         theKey.prepend(d->groupPrefix);
3316 
3317     if (theKey.isEmpty()) {
3318         d->clear();
3319     } else {
3320         d->remove(theKey);
3321     }
3322     d->requestUpdate();
3323 }
3324 
3325 /*!
3326     Returns \c true if there exists a setting called \a key; returns
3327     false otherwise.
3328 
3329     If a group is set using beginGroup(), \a key is taken to be
3330     relative to that group.
3331 
3332     Note that the Windows registry and INI files use case-insensitive
3333     keys, whereas the CFPreferences API on \macos and iOS uses
3334     case-sensitive keys. To avoid portability problems, see the
3335     \l{Section and Key Syntax} rules.
3336 
3337     \sa value(), setValue()
3338 */
contains(const QString & key) const3339 bool QSettings::contains(const QString &key) const
3340 {
3341     Q_D(const QSettings);
3342     QString k = d->actualKey(key);
3343     return d->get(k, nullptr);
3344 }
3345 
3346 /*!
3347     Sets whether fallbacks are enabled to \a b.
3348 
3349     By default, fallbacks are enabled.
3350 
3351     \sa fallbacksEnabled()
3352 */
setFallbacksEnabled(bool b)3353 void QSettings::setFallbacksEnabled(bool b)
3354 {
3355     Q_D(QSettings);
3356     d->fallbacks = !!b;
3357 }
3358 
3359 /*!
3360     Returns \c true if fallbacks are enabled; returns \c false otherwise.
3361 
3362     By default, fallbacks are enabled.
3363 
3364     \sa setFallbacksEnabled()
3365 */
fallbacksEnabled() const3366 bool QSettings::fallbacksEnabled() const
3367 {
3368     Q_D(const QSettings);
3369     return d->fallbacks;
3370 }
3371 
3372 #ifndef QT_NO_QOBJECT
3373 /*!
3374     \reimp
3375 */
event(QEvent * event)3376 bool QSettings::event(QEvent *event)
3377 {
3378     Q_D(QSettings);
3379     if (event->type() == QEvent::UpdateRequest) {
3380         d->update();
3381         return true;
3382     }
3383     return QObject::event(event);
3384 }
3385 #endif
3386 
3387 /*!
3388     Returns the value for setting \a key. If the setting doesn't
3389     exist, returns \a defaultValue.
3390 
3391     If no default value is specified, a default QVariant is
3392     returned.
3393 
3394     Note that the Windows registry and INI files use case-insensitive
3395     keys, whereas the CFPreferences API on \macos and iOS uses
3396     case-sensitive keys. To avoid portability problems, see the
3397     \l{Section and Key Syntax} rules.
3398 
3399     Example:
3400 
3401     \snippet code/src_corelib_io_qsettings.cpp 26
3402 
3403     \sa setValue(), contains(), remove()
3404 */
value(const QString & key,const QVariant & defaultValue) const3405 QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
3406 {
3407     Q_D(const QSettings);
3408     if (key.isEmpty()) {
3409         qWarning("QSettings::value: Empty key passed");
3410         return QVariant();
3411     }
3412     QVariant result = defaultValue;
3413     QString k = d->actualKey(key);
3414     d->get(k, &result);
3415     return result;
3416 }
3417 
3418 /*!
3419     \since 4.4
3420 
3421     Sets the default file format to the given \a format, which is used
3422     for storing settings for the QSettings(QObject *) constructor.
3423 
3424     If no default format is set, QSettings::NativeFormat is used. See
3425     the documentation for the QSettings constructor you are using to
3426     see if that constructor will ignore this function.
3427 
3428     \sa format()
3429 */
setDefaultFormat(Format format)3430 void QSettings::setDefaultFormat(Format format)
3431 {
3432     globalDefaultFormat = format;
3433 }
3434 
3435 /*!
3436     \since 4.4
3437 
3438     Returns default file format used for storing settings for the QSettings(QObject *) constructor.
3439     If no default format is set, QSettings::NativeFormat is used.
3440 
3441     \sa format()
3442 */
defaultFormat()3443 QSettings::Format QSettings::defaultFormat()
3444 {
3445     return globalDefaultFormat;
3446 }
3447 
3448 #if QT_DEPRECATED_SINCE(5, 13)
3449 /*!
3450     \obsolete
3451 
3452     Use setPath() instead.
3453 
3454     \oldcode
3455         setSystemIniPath(path);
3456     \newcode
3457         setPath(QSettings::NativeFormat, QSettings::SystemScope, path);
3458         setPath(QSettings::IniFormat, QSettings::SystemScope, path);
3459     \endcode
3460 */
setSystemIniPath(const QString & dir)3461 void QSettings::setSystemIniPath(const QString &dir)
3462 {
3463     setPath(IniFormat, SystemScope, dir);
3464 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3465     setPath(NativeFormat, SystemScope, dir);
3466 #endif
3467 }
3468 
3469 /*!
3470     \obsolete
3471 
3472     Use setPath() instead.
3473 */
3474 
setUserIniPath(const QString & dir)3475 void QSettings::setUserIniPath(const QString &dir)
3476 {
3477     setPath(IniFormat, UserScope, dir);
3478 #if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3479     setPath(NativeFormat, UserScope, dir);
3480 #endif
3481 }
3482 #endif
3483 /*!
3484     \since 4.1
3485 
3486     Sets the path used for storing settings for the given \a format
3487     and \a scope, to \a path. The \a format can be a custom format.
3488 
3489     The table below summarizes the default values:
3490 
3491     \table
3492     \header \li Platform         \li Format                       \li Scope       \li Path
3493     \row    \li{1,2} Windows     \li{1,2} IniFormat               \li UserScope   \li \c FOLDERID_RoamingAppData
3494     \row                                                        \li SystemScope \li \c FOLDERID_ProgramData
3495     \row    \li{1,2} Unix        \li{1,2} NativeFormat, IniFormat \li UserScope   \li \c $HOME/.config
3496     \row                                                        \li SystemScope \li \c /etc/xdg
3497     \row    \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope   \li \c $HOME/Settings
3498     \row                                                        \li SystemScope \li \c /etc/xdg
3499     \row    \li{1,2} \macos and iOS   \li{1,2} IniFormat               \li UserScope   \li \c $HOME/.config
3500     \row                                                        \li SystemScope \li \c /etc/xdg
3501     \endtable
3502 
3503     The default UserScope paths on Unix, \macos, and iOS (\c
3504     $HOME/.config or $HOME/Settings) can be overridden by the user by setting the
3505     \c XDG_CONFIG_HOME environment variable. The default SystemScope
3506     paths on Unix, \macos, and iOS (\c /etc/xdg) can be overridden when
3507     building the Qt library using the \c configure script's \c
3508     -sysconfdir flag (see QLibraryInfo for details).
3509 
3510     Setting the NativeFormat paths on Windows, \macos, and iOS has no
3511     effect.
3512 
3513     \warning This function doesn't affect existing QSettings objects.
3514 
3515     \sa registerFormat()
3516 */
setPath(Format format,Scope scope,const QString & path)3517 void QSettings::setPath(Format format, Scope scope, const QString &path)
3518 {
3519     auto locker = qt_unique_lock(settingsGlobalMutex);
3520     PathHash *pathHash = pathHashFunc();
3521     if (pathHash->isEmpty())
3522         locker = initDefaultPaths(std::move(locker));
3523     pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
3524 }
3525 
3526 /*!
3527     \typedef QSettings::SettingsMap
3528 
3529     Typedef for QMap<QString, QVariant>.
3530 
3531     \sa registerFormat()
3532 */
3533 
3534 /*!
3535     \typedef QSettings::ReadFunc
3536 
3537     Typedef for a pointer to a function with the following signature:
3538 
3539     \snippet code/src_corelib_io_qsettings.cpp 27
3540 
3541     \c ReadFunc is used in \c registerFormat() as a pointer to a function
3542     that reads a set of key/value pairs. \c ReadFunc should read all the
3543     options in one pass, and return all the settings in the \c SettingsMap
3544     container, which is initially empty.
3545 
3546     \sa WriteFunc, registerFormat()
3547 */
3548 
3549 /*!
3550     \typedef QSettings::WriteFunc
3551 
3552     Typedef for a pointer to a function with the following signature:
3553 
3554     \snippet code/src_corelib_io_qsettings.cpp 28
3555 
3556     \c WriteFunc is used in \c registerFormat() as a pointer to a function
3557     that writes a set of key/value pairs. \c WriteFunc is only called once,
3558     so you need to output the settings in one go.
3559 
3560     \sa ReadFunc, registerFormat()
3561 */
3562 
3563 /*!
3564     \since 4.1
3565     \threadsafe
3566 
3567     Registers a custom storage format. On success, returns a special
3568     Format value that can then be passed to the QSettings constructor.
3569     On failure, returns InvalidFormat.
3570 
3571     The \a extension is the file
3572     extension associated to the format (without the '.').
3573 
3574     The \a readFunc and \a writeFunc parameters are pointers to
3575     functions that read and write a set of key/value pairs. The
3576     QIODevice parameter to the read and write functions is always
3577     opened in binary mode (i.e., without the QIODevice::Text flag).
3578 
3579     The \a caseSensitivity parameter specifies whether keys are case
3580     sensitive or not. This makes a difference when looking up values
3581     using QSettings. The default is case sensitive.
3582 
3583     By default, if you use one of the constructors that work in terms
3584     of an organization name and an application name, the file system
3585     locations used are the same as for IniFormat. Use setPath() to
3586     specify other locations.
3587 
3588     Example:
3589 
3590     \snippet code/src_corelib_io_qsettings.cpp 29
3591 
3592     \sa setPath()
3593 */
registerFormat(const QString & extension,ReadFunc readFunc,WriteFunc writeFunc,Qt::CaseSensitivity caseSensitivity)3594 QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc,
3595                                             WriteFunc writeFunc,
3596                                             Qt::CaseSensitivity caseSensitivity)
3597 {
3598 #ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
3599     Q_ASSERT(caseSensitivity == Qt::CaseSensitive);
3600 #endif
3601 
3602     const auto locker = qt_scoped_lock(settingsGlobalMutex);
3603     CustomFormatVector *customFormatVector = customFormatVectorFunc();
3604     int index = customFormatVector->size();
3605     if (index == 16) // the QSettings::Format enum has room for 16 custom formats
3606         return QSettings::InvalidFormat;
3607 
3608     QConfFileCustomFormat info;
3609     info.extension = QLatin1Char('.') + extension;
3610     info.readFunc = readFunc;
3611     info.writeFunc = writeFunc;
3612     info.caseSensitivity = caseSensitivity;
3613     customFormatVector->append(info);
3614 
3615     return QSettings::Format((int)QSettings::CustomFormat1 + index);
3616 }
3617 
3618 QT_END_NAMESPACE
3619 
3620 #ifndef QT_BOOTSTRAPPED
3621 #include "moc_qsettings.cpp"
3622 #endif
3623