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>
93using namespace Microsoft::WRL;
94using namespace Microsoft::WRL::Wrappers;
95using namespace ABI::Windows::Foundation;
96using 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
117QT_BEGIN_NAMESPACE
118
119struct QConfFileCustomFormat
120{
121 QString extension;
122 QSettings::ReadFunc readFunc;
123 QSettings::WriteFunc writeFunc;
124 Qt::CaseSensitivity caseSensitivity;
125};
126Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
127
128typedef QHash<QString, QConfFile *> ConfFileHash;
129typedef QCache<QString, QConfFile> ConfFileCache;
130namespace {
131 struct Path
132 {
133 // Note: Defining constructors explicitly because of buggy C++11
134 // implementation in MSVC (uniform initialization).
135 Path() {}
136 Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
137 QString path;
138 bool userDefined; //!< true - user defined, overridden by setPath
139 };
140}
141typedef QHash<int, Path> PathHash;
142typedef QVector<QConfFileCustomFormat> CustomFormatVector;
143
144Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
145Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)
146Q_GLOBAL_STATIC(PathHash, pathHashFunc)
147Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
148
149static QBasicMutex settingsGlobalMutex;
150
151static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
152
153QConfFile::QConfFile(const QString &fileName, bool _userPerms)
154 : name(fileName), size(0), ref(1), userPerms(_userPerms)
155{
156 usedHashFunc()->insert(akey: name, avalue: this);
157}
158
159QConfFile::~QConfFile()
160{
161 if (usedHashFunc())
162 usedHashFunc()->remove(akey: name);
163}
164
165ParsedSettingsMap 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(akey: i.key());
172 for (i = addedKeys.begin(); i != addedKeys.end(); ++i)
173 result.insert(akey: i.key(), avalue: i.value());
174 return result;
175}
176
177bool 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(flags: 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(dirPath: 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
202QConfFile *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(mutex&: settingsGlobalMutex);
211
212 if (!(confFile = usedHash->value(akey: absPath))) {
213 if ((confFile = unusedCache->take(key: absPath)))
214 usedHash->insert(akey: absPath, avalue: confFile);
215 }
216 if (confFile) {
217 confFile->ref.ref();
218 return confFile;
219 }
220 return new QConfFile(absPath, _userPerms);
221}
222
223void QConfFile::clearCache()
224{
225 const auto locker = qt_scoped_lock(mutex&: settingsGlobalMutex);
226 unusedCacheFunc()->clear();
227}
228
229// ************************************************************************
230// QSettingsPrivate
231
232QSettingsPrivate::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
238QSettingsPrivate::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
245QSettingsPrivate::~QSettingsPrivate()
246{
247}
248
249QString 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*/
267QString 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, len: 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
286after_loop:
287 if (!result.isEmpty())
288 result.truncate(pos: 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)
295QSettingsPrivate *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)
303QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
304{
305 return new QConfFileSettingsPrivate(fileName, format);
306}
307#endif
308
309void QSettingsPrivate::processChild(QStringRef key, ChildSpec spec, QStringList &result)
310{
311 if (spec != AllKeys) {
312 int slashPos = key.indexOf(ch: QLatin1Char('/'));
313 if (slashPos == -1) {
314 if (spec != ChildKeys)
315 return;
316 } else {
317 if (spec != ChildGroups)
318 return;
319 key.truncate(pos: slashPos);
320 }
321 }
322 result.append(t: key.toString());
323}
324
325void QSettingsPrivate::beginGroupOrArray(const QSettingsGroup &group)
326{
327 groupStack.push(t: 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
338void QSettingsPrivate::setStatus(QSettings::Status status) const
339{
340 if (status == QSettings::NoError || this->status == QSettings::NoError)
341 this->status = status;
342}
343
344void QSettingsPrivate::update()
345{
346 flush();
347 pendingChanges = false;
348}
349
350void QSettingsPrivate::requestUpdate()
351{
352 if (!pendingChanges) {
353 pendingChanges = true;
354#ifndef QT_NO_QOBJECT
355 Q_Q(QSettings);
356 QCoreApplication::postEvent(receiver: q, event: new QEvent(QEvent::UpdateRequest));
357#else
358 update();
359#endif
360 }
361}
362
363QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l)
364{
365 QStringList result;
366 result.reserve(alloc: l.count());
367 QVariantList::const_iterator it = l.constBegin();
368 for (; it != l.constEnd(); ++it)
369 result.append(t: variantToString(v: *it));
370 return result;
371}
372
373QVariant 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(c: QLatin1Char('@'))) {
380 if (str.length() >= 2 && str.at(i: 1) == QLatin1Char('@')) {
381 outStringList[i].remove(i: 0, len: 1);
382 } else {
383 QVariantList variantList;
384 const int stringCount = l.count();
385 variantList.reserve(alloc: stringCount);
386 for (int j = 0; j < stringCount; ++j)
387 variantList.append(t: stringToVariant(s: l.at(i: j)));
388 return variantList;
389 }
390 }
391 }
392 return outStringList;
393}
394
395QString 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(c: QChar::Null))
422 result = QLatin1String("@String(") + result + QLatin1Char(')');
423 else if (result.startsWith(c: QLatin1Char('@')))
424 result.prepend(c: 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(format: "@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(format: "@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(format: "@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
477QVariant QSettingsPrivate::stringToVariant(const QString &s)
478{
479 if (s.startsWith(c: QLatin1Char('@'))) {
480 if (s.endsWith(c: QLatin1Char(')'))) {
481 if (s.startsWith(s: QLatin1String("@ByteArray("))) {
482 return QVariant(s.midRef(position: 11, n: s.size() - 12).toLatin1());
483 } else if (s.startsWith(s: QLatin1String("@String("))) {
484 return QVariant(s.midRef(position: 8, n: s.size() - 9).toString());
485 } else if (s.startsWith(s: QLatin1String("@Variant("))
486 || s.startsWith(s: QLatin1String("@DateTime("))) {
487#ifndef QT_NO_DATASTREAM
488 QDataStream::Version version;
489 int offset;
490 if (s.at(i: 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(position: 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(s: QLatin1String("@Rect("))) {
508 QStringList args = QSettingsPrivate::splitArgs(s, idx: 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(s: QLatin1String("@Size("))) {
512 QStringList args = QSettingsPrivate::splitArgs(s, idx: 5);
513 if (args.size() == 2)
514 return QVariant(QSize(args[0].toInt(), args[1].toInt()));
515 } else if (s.startsWith(s: QLatin1String("@Point("))) {
516 QStringList args = QSettingsPrivate::splitArgs(s, idx: 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(s: QLatin1String("@@")))
526 return QVariant(s.mid(position: 1));
527 }
528
529 return QVariant(s);
530}
531
532static const char hexDigits[] = "0123456789ABCDEF";
533
534void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result)
535{
536 result.reserve(asize: 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(c: hexDigits[ch % 16]);
554 ch >>= 4;
555 }
556 result += hexCode;
557 }
558 }
559}
560
561bool QSettingsPrivate::iniUnescapedKey(const QByteArray &key, int from, int to, QString &result)
562{
563 bool lowercaseOnly = true;
564 int i = from;
565 result.reserve(asize: 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: 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(index: firstDigitPos, len: numDigits).toInt(ok: &ok, base: 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
617void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec)
618{
619 bool needsQuotes = false;
620 bool escapeNextIfDigit = false;
621 bool useCodec = codec && !str.startsWith(s: QLatin1String("@ByteArray("))
622 && !str.startsWith(s: QLatin1String("@Variant("));
623
624 int i;
625 int startPos = result.size();
626
627 result.reserve(asize: 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, base: 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, base: 16);
678 escapeNextIfDigit = true;
679#if QT_CONFIG(textcodec)
680 } else if (useCodec) {
681 // slow
682 result += codec->fromUnicode(in: &unicode[i], length: 1);
683#endif
684 } else {
685 result += (char)ch;
686 }
687 }
688 }
689
690 if (needsQuotes
691 || (startPos < result.size() && (result.at(i: startPos) == ' '
692 || result.at(i: result.size() - 1) == ' '))) {
693 result.insert(i: startPos, c: '"');
694 result += '"';
695 }
696}
697
698inline static void iniChopTrailingSpaces(QString &str, int limit)
699{
700 int n = str.size() - 1;
701 QChar ch;
702 while (n >= limit && ((ch = str.at(i: n)) == QLatin1Char(' ') || ch == QLatin1Char('\t')))
703 str.truncate(pos: n--);
704}
705
706void 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(str: strs.at(i), result, codec);
723 }
724 }
725}
726
727bool 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
753StSkipSpaces:
754 while (i < to && ((ch = str.at(i)) == ' ' || ch == '\t'))
755 ++i;
756 // fallthrough
757
758StNormal:
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: 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(str&: stringResult, limit: chopLimit);
810 if (!isStringList) {
811 isStringList = true;
812 stringListResult.clear();
813 stringResult.squeeze();
814 }
815 stringListResult.append(t: 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(i: 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(in: str.constData() + i, length: j - i);
836 } else
837#endif
838 {
839 int n = stringResult.size();
840 stringResult.resize(size: n + (j - i));
841 QChar *resultData = stringResult.data() + n;
842 for (int k = i; k < j; ++k)
843 *resultData++ = QLatin1Char(str.at(i: k));
844 }
845 i = j;
846 }
847 }
848 }
849 if (!currentValueIsQuoted)
850 iniChopTrailingSpaces(str&: stringResult, limit: chopLimit);
851 goto end;
852
853StHexEscape:
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(s: hexDigits, c: ch) - hexDigits;
865 ++i;
866 goto StHexEscape;
867 } else {
868 stringResult += QChar(escapeVal);
869 goto StNormal;
870 }
871
872StOctEscape:
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
889end:
890 if (isStringList)
891 stringListResult.append(t: stringResult);
892 return isStringList;
893}
894
895QStringList 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(i: idx);
907 if (c == QLatin1Char(')')) {
908 Q_ASSERT(idx == l - 1);
909 result.append(t: item);
910 } else if (c == QLatin1Char(' ')) {
911 result.append(t: item);
912 item.clear();
913 } else {
914 item.append(c);
915 }
916 }
917
918 return result;
919}
920
921// ************************************************************************
922// QConfFileSettingsPrivate
923
924void 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(mutex&: 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
950void 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)
963static 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
985enum ConfigPathType {
986 ConfigPath_CommonAppData,
987 ConfigPath_UserAppData
988};
989
990static 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
1022static 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
1028static 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(type: QStandardPaths::GenericConfigLocation) + sep;
1047#endif
1048}
1049#endif // !Q_OS_WIN
1050
1051static 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(akey: pathHashKey(format: QSettings::IniFormat, scope: QSettings::UserScope), avalue: Path(userPath, false));
1088 pathHash->insert(akey: pathHashKey(format: QSettings::IniFormat, scope: QSettings::SystemScope), avalue: Path(systemPath, false));
1089#ifndef Q_OS_MAC
1090 pathHash->insert(akey: pathHashKey(format: QSettings::NativeFormat, scope: QSettings::UserScope), avalue: Path(userPath, false));
1091 pathHash->insert(akey: pathHashKey(format: QSettings::NativeFormat, scope: QSettings::SystemScope), avalue: Path(systemPath, false));
1092#endif
1093#endif // Q_OS_WIN
1094 }
1095
1096 return locker;
1097}
1098
1099static 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(mutex&: settingsGlobalMutex);
1105 PathHash *pathHash = pathHashFunc();
1106 if (pathHash->isEmpty())
1107 locker = initDefaultPaths(locker: std::move(locker));
1108
1109 Path result = pathHash->value(akey: pathHashKey(format, scope));
1110 if (!result.path.isEmpty())
1111 return result;
1112
1113 // fall back on INI path
1114 return pathHash->value(akey: pathHashKey(format: 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.
1119void Q_AUTOTEST_EXPORT clearDefaultPaths()
1120{
1121 const auto locker = qt_scoped_lock(mutex&: settingsGlobalMutex);
1122 pathHashFunc()->clear();
1123}
1124#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1125
1126QConfFileSettingsPrivate::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, scope: QSettings::UserScope);
1146 if (!application.isEmpty())
1147 confFiles.append(t: QConfFile::fromName(fileName: userPath.path + appFile, userPerms: true));
1148 confFiles.append(t: QConfFile::fromName(fileName: userPath.path + orgFile, userPerms: true));
1149 }
1150
1151 Path systemPath = getPath(format, scope: 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(type: 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(alloc: dirs.size() * 2);
1165 for (const auto &dir : qAsConst(t&: dirs))
1166 paths.append(t: dir + QLatin1Char('/') + appFile);
1167 } else {
1168 paths.reserve(alloc: dirs.size());
1169 }
1170 for (const auto &dir : qAsConst(t&: dirs))
1171 paths.append(t: dir + QLatin1Char('/') + orgFile);
1172
1173 // Note: No check for existence of files is done intentionaly.
1174 for (const auto &path : qAsConst(t&: paths))
1175 confFiles.append(t: QConfFile::fromName(fileName: path, userPerms: false));
1176 } else
1177#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1178 {
1179 if (!application.isEmpty())
1180 confFiles.append(t: QConfFile::fromName(fileName: systemPath.path + appFile, userPerms: false));
1181 confFiles.append(t: QConfFile::fromName(fileName: systemPath.path + orgFile, userPerms: false));
1182 }
1183
1184#ifndef Q_OS_WASM // wasm needs to delay access until after file sync
1185 initAccess();
1186#endif
1187}
1188
1189QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
1190 QSettings::Format format)
1191 : QSettingsPrivate(format),
1192 nextPosition(0x40000000) // big positive number
1193{
1194 initFormat();
1195
1196 confFiles.append(t: QConfFile::fromName(fileName, userPerms: true));
1197
1198 initAccess();
1199}
1200
1201QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
1202{
1203 const auto locker = qt_scoped_lock(mutex&: settingsGlobalMutex);
1204 ConfFileHash *usedHash = usedHashFunc();
1205 ConfFileCache *unusedCache = unusedCacheFunc();
1206
1207 for (auto conf_file : qAsConst(t&: 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(akey: conf_file->name);
1214 if (unusedCache) {
1215 QT_TRY {
1216 // compute a better size?
1217 unusedCache->insert(akey: conf_file->name, aobject: conf_file,
1218 acost: 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
1232void 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(i: 0);
1239
1240 QSettingsKey theKey(key, caseSensitivity);
1241 QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
1242 const auto locker = qt_scoped_lock(mutex&: confFile->mutex);
1243
1244 ensureSectionParsed(confFile, key: theKey);
1245 ensureSectionParsed(confFile, key: prefix);
1246
1247 ParsedSettingsMap::iterator i = confFile->addedKeys.lowerBound(akey: prefix);
1248 while (i != confFile->addedKeys.end() && i.key().startsWith(s: prefix))
1249 i = confFile->addedKeys.erase(it: i);
1250 confFile->addedKeys.remove(akey: theKey);
1251
1252 ParsedSettingsMap::const_iterator j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(akey: prefix);
1253 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(s: prefix)) {
1254 confFile->removedKeys.insert(akey: j.key(), avalue: QVariant());
1255 ++j;
1256 }
1257 if (confFile->originalKeys.contains(akey: theKey))
1258 confFile->removedKeys.insert(akey: theKey, avalue: QVariant());
1259}
1260
1261void 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(i: 0);
1268
1269 QSettingsKey theKey(key, caseSensitivity, nextPosition++);
1270 const auto locker = qt_scoped_lock(mutex&: confFile->mutex);
1271 confFile->removedKeys.remove(akey: theKey);
1272 confFile->addedKeys.insert(akey: theKey, avalue: value);
1273}
1274
1275bool 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(t: confFiles)) {
1282 const auto locker = qt_scoped_lock(mutex&: confFile->mutex);
1283
1284 if (!confFile->addedKeys.isEmpty()) {
1285 j = confFile->addedKeys.constFind(akey: theKey);
1286 found = (j != confFile->addedKeys.constEnd());
1287 }
1288 if (!found) {
1289 ensureSectionParsed(confFile, key: theKey);
1290 j = confFile->originalKeys.constFind(akey: theKey);
1291 found = (j != confFile->originalKeys.constEnd()
1292 && !confFile->removedKeys.contains(akey: 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
1306QStringList 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(t: confFiles)) {
1315 const auto locker = qt_scoped_lock(mutex&: confFile->mutex);
1316
1317 if (thePrefix.isEmpty())
1318 ensureAllSectionsParsed(confFile);
1319 else
1320 ensureSectionParsed(confFile, key: thePrefix);
1321
1322 j = const_cast<const ParsedSettingsMap *>(
1323 &confFile->originalKeys)->lowerBound( akey: thePrefix);
1324 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(s: thePrefix)) {
1325 if (!confFile->removedKeys.contains(akey: j.key()))
1326 processChild(key: j.key().originalCaseKey().midRef(position: startPos), spec, result);
1327 ++j;
1328 }
1329
1330 j = const_cast<const ParsedSettingsMap *>(
1331 &confFile->addedKeys)->lowerBound(akey: thePrefix);
1332 while (j != confFile->addedKeys.constEnd() && j.key().startsWith(s: thePrefix)) {
1333 processChild(key: j.key().originalCaseKey().midRef(position: startPos), spec, result);
1334 ++j;
1335 }
1336
1337 if (!fallbacks)
1338 break;
1339 }
1340 std::sort(first: result.begin(), last: result.end());
1341 result.erase(afirst: std::unique(first: result.begin(), last: result.end()),
1342 alast: result.end());
1343 return result;
1344}
1345
1346void 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(i: 0);
1353
1354 const auto locker = qt_scoped_lock(mutex&: confFile->mutex);
1355 ensureAllSectionsParsed(confFile);
1356 confFile->addedKeys.clear();
1357 confFile->removedKeys = confFile->originalKeys;
1358}
1359
1360void 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(t&: confFiles)) {
1366 const auto locker = qt_scoped_lock(mutex&: confFile->mutex);
1367 syncConfFile(confFile);
1368 }
1369}
1370
1371void QConfFileSettingsPrivate::flush()
1372{
1373 sync();
1374}
1375
1376QString 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(i: 0)->name;
1383}
1384
1385bool 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(i: 0)->isWritable();
1394}
1395
1396void 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(flags: 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, unparsedIniSections: &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(akey: QSettingsKey(i.key(), caseSensitivity),
1475 avalue: 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(flags: 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(device&: sf, map: 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(akey: i.key(), avalue: 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
1555enum { Space = 0x1, Special = 0x2 };
1556
1557static 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
1581bool 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(i: 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: 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
1641break_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*/
1652bool 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(name: "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(i: lineStart);
1689 if (ch == '[') {
1690 FLUSH_CURRENT_SECTION();
1691
1692 // this is a section
1693 QByteArray iniSection;
1694 int idx = data.indexOf(c: ']', from: lineStart);
1695 if (idx == -1 || idx >= lineStart + lineLen) {
1696 ok = false;
1697 iniSection = data.mid(index: lineStart + 1, len: lineLen - 1);
1698 } else {
1699 iniSection = data.mid(index: lineStart + 1, len: idx - lineStart - 1);
1700 }
1701
1702 iniSection = iniSection.trimmed();
1703
1704 if (iniSection.compare(c: "general", cs: Qt::CaseInsensitive) == 0) {
1705 currentSection.clear();
1706 } else {
1707 if (iniSection.compare(c: "%general", cs: Qt::CaseInsensitive) == 0) {
1708 currentSection = QLatin1String(iniSection.constData() + 1);
1709 } else {
1710 currentSection.clear();
1711 iniUnescapedKey(key: iniSection, from: 0, to: iniSection.size(), result&: 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
1728bool 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(i: 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(i: keyEnd - 1)) == ' ' || ch == '\t'))
1753 --keyEnd;
1754 int valueStart = equalsPos + 1;
1755
1756 QString key = section.originalCaseKey();
1757 bool keyIsLowercase = (iniUnescapedKey(key: data, from: lineStart, to: keyEnd, result&: key) && sectionIsLowercase);
1758
1759 QString strValue;
1760 strValue.reserve(asize: lineLen - (valueStart - lineStart));
1761 bool isStringList = iniUnescapedStringList(str: data, from: valueStart, to: lineStart + lineLen,
1762 stringResult&: strValue, stringListResult&: strListValue, codec);
1763 QVariant variant;
1764 if (isStringList) {
1765 variant = stringListToVariantList(l: strListValue);
1766 } else {
1767 variant = stringToVariant(s: 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(akey: QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive
1776 : IniCaseSensitivity,
1777 position),
1778 avalue: variant);
1779 ++position;
1780 }
1781
1782 return ok;
1783}
1784
1785class QSettingsIniKey : public QString
1786{
1787public:
1788 inline QSettingsIniKey() : position(-1) {}
1789 inline QSettingsIniKey(const QString &str, int pos = -1) : QString(str), position(pos) {}
1790
1791 int position;
1792};
1793Q_DECLARE_TYPEINFO(QSettingsIniKey, Q_MOVABLE_TYPE);
1794
1795static 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
1802typedef QMap<QSettingsIniKey, QVariant> IniKeyMap;
1803
1804struct QSettingsIniSection
1805{
1806 int position;
1807 IniKeyMap keyMap;
1808
1809 inline QSettingsIniSection() : position(-1) {}
1810};
1811
1812Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE);
1813
1814typedef 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*/
1820bool 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(c: QLatin1Char('/'))) != -1) {
1837 section = key.left(n: slashPos);
1838 key.remove(i: 0, len: 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(asize: sectionCount);
1852 for (i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
1853 sections.append(t: QSettingsIniKey(i.key(), i.value().position));
1854 std::sort(first: sections.begin(), last: sections.end());
1855
1856 bool writeError = false;
1857 for (int j = 0; !writeError && j < sectionCount; ++j) {
1858 i = iniMap.constFind(akey: sections.at(i: j));
1859 Q_ASSERT(i != iniMap.constEnd());
1860
1861 QByteArray realSection;
1862
1863 iniEscapedKey(key: i.key(), result&: realSection);
1864
1865 if (realSection.isEmpty()) {
1866 realSection = "[General]";
1867 } else if (realSection.compare(c: "general", cs: Qt::CaseInsensitive) == 0) {
1868 realSection = "[%General]";
1869 } else {
1870 realSection.prepend(c: '[');
1871 realSection.append(c: ']');
1872 }
1873
1874 if (j != 0)
1875 realSection.prepend(c: eol);
1876 realSection += eol;
1877
1878 device.write(data: 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(key: j.key(), result&: 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(strs: variantListToStringList(l: value.toList()), result&: block, codec: iniCodec);
1896 } else {
1897 iniEscapedString(str: variantToString(v: value), result&: block, codec: iniCodec);
1898 }
1899 block += eol;
1900 if (device.write(data: block) == -1) {
1901 writeError = true;
1902 break;
1903 }
1904 }
1905 }
1906 return !writeError;
1907}
1908
1909void 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(section: i.key(), data: i.value(), settingsMap: &confFile->originalKeys, codec: iniCodec))
1916 setStatus(QSettings::FormatError);
1917 }
1918 confFile->unparsedIniSections.clear();
1919}
1920
1921void 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(c: QLatin1Char('/'));
1930 if (indexOfSlash != -1) {
1931 i = confFile->unparsedIniSections.upperBound(akey: key);
1932 if (i == confFile->unparsedIniSections.begin())
1933 return;
1934 --i;
1935 if (i.key().isEmpty() || !key.startsWith(s: 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(section: i.key(), data: i.value(), settingsMap: &confFile->originalKeys, codec: iniCodec))
1944 setStatus(QSettings::FormatError);
1945 confFile->unparsedIniSections.erase(it: 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*/
2550QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2551 : QObject(*QSettingsPrivate::create(format: NativeFormat, scope: 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*/
2575QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2576 QObject *parent)
2577 : QObject(*QSettingsPrivate::create(format: 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*/
2599QSettings::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*/
2635QSettings::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*/
2675QSettings::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*/
2688QSettings::QSettings(Scope scope, QObject *parent)
2689 : QObject(*QSettingsPrivate::create(format: globalDefaultFormat, scope,
2690#ifdef Q_OS_DARWIN
2691 QCoreApplication::organizationDomain().isEmpty()
2692 ? QCoreApplication::organizationName()
2693 : QCoreApplication::organizationDomain()
2694#else
2695 organization: QCoreApplication::organizationName().isEmpty()
2696 ? QCoreApplication::organizationDomain()
2697 : QCoreApplication::organizationName()
2698#endif
2699 , application: QCoreApplication::applicationName()),
2700 parent)
2701{
2702}
2703
2704#else
2705QSettings::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
2711QSettings::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
2717QSettings::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
2724QSettings::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
2731QSettings::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*/
2758QSettings::~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*/
2781void 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*/
2799void 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*/
2815QString 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*/
2828QSettings::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*/
2841QSettings::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*/
2854QString 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*/
2867QString 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*/
2889void 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*/
2906void QSettings::setIniCodec(const char *codecName)
2907{
2908 Q_D(QSettings);
2909 if (QTextCodec *codec = QTextCodec::codecForName(name: 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
2920QTextCodec *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*/
2938QSettings::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*/
2955bool 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*/
2982void 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*/
3014void QSettings::beginGroup(const QString &prefix)
3015{
3016 Q_D(QSettings);
3017 d->beginGroupOrArray(group: QSettingsGroup(d->normalizedKey(key: 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*/
3030void QSettings::endGroup()
3031{
3032 Q_D(QSettings);
3033 if (d->groupStack.isEmpty()) {
3034 qWarning(msg: "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(pos: d->groupPrefix.size() - (len + 1));
3042
3043 if (group.isArray())
3044 qWarning(msg: "QSettings::endGroup: Expected endArray() instead");
3045}
3046
3047/*!
3048 Returns the current group.
3049
3050 \sa beginGroup(), endGroup()
3051*/
3052QString QSettings::group() const
3053{
3054 Q_D(const QSettings);
3055 return d->groupPrefix.left(n: 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*/
3070int QSettings::beginReadArray(const QString &prefix)
3071{
3072 Q_D(QSettings);
3073 d->beginGroupOrArray(group: QSettingsGroup(d->normalizedKey(key: prefix), false));
3074 return value(key: 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*/
3106void QSettings::beginWriteArray(const QString &prefix, int size)
3107{
3108 Q_D(QSettings);
3109 d->beginGroupOrArray(group: QSettingsGroup(d->normalizedKey(key: prefix), size < 0));
3110
3111 if (size < 0)
3112 remove(key: QLatin1String("size"));
3113 else
3114 setValue(key: QLatin1String("size"), value: size);
3115}
3116
3117/*!
3118 Closes the array that was started using beginReadArray() or
3119 beginWriteArray().
3120
3121 \sa beginReadArray(), beginWriteArray()
3122*/
3123void QSettings::endArray()
3124{
3125 Q_D(QSettings);
3126 if (d->groupStack.isEmpty()) {
3127 qWarning(msg: "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(pos: d->groupPrefix.size() - (len + 1));
3136
3137 if (group.arraySizeGuess() != -1)
3138 setValue(key: group.name() + QLatin1String("/size"), value: group.arraySizeGuess());
3139
3140 if (!group.isArray())
3141 qWarning(msg: "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*/
3152void QSettings::setArrayIndex(int i)
3153{
3154 Q_D(QSettings);
3155 if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3156 qWarning(msg: "QSettings::setArrayIndex: Missing beginArray()");
3157 return;
3158 }
3159
3160 QSettingsGroup &top = d->groupStack.top();
3161 int len = top.toString().size();
3162 top.setArrayIndex(qMax(a: i, b: 0));
3163 d->groupPrefix.replace(i: d->groupPrefix.size() - len - 1, len, after: 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*/
3181QStringList QSettings::allKeys() const
3182{
3183 Q_D(const QSettings);
3184 return d->children(prefix: d->groupPrefix, spec: 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*/
3205QStringList QSettings::childKeys() const
3206{
3207 Q_D(const QSettings);
3208 return d->children(prefix: d->groupPrefix, spec: 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*/
3229QStringList QSettings::childGroups() const
3230{
3231 Q_D(const QSettings);
3232 return d->children(prefix: d->groupPrefix, spec: 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*/
3247bool 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*/
3269void QSettings::setValue(const QString &key, const QVariant &value)
3270{
3271 Q_D(QSettings);
3272 if (key.isEmpty()) {
3273 qWarning(msg: "QSettings::setValue: Empty key passed");
3274 return;
3275 }
3276 QString k = d->actualKey(key);
3277 d->set(key: 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*/
3304void 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(s: d->groupPrefix);
3316
3317 if (theKey.isEmpty()) {
3318 d->clear();
3319 } else {
3320 d->remove(key: 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*/
3339bool QSettings::contains(const QString &key) const
3340{
3341 Q_D(const QSettings);
3342 QString k = d->actualKey(key);
3343 return d->get(key: k, value: 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*/
3353void 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*/
3366bool QSettings::fallbacksEnabled() const
3367{
3368 Q_D(const QSettings);
3369 return d->fallbacks;
3370}
3371
3372#ifndef QT_NO_QOBJECT
3373/*!
3374 \reimp
3375*/
3376bool 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*/
3405QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
3406{
3407 Q_D(const QSettings);
3408 if (key.isEmpty()) {
3409 qWarning(msg: "QSettings::value: Empty key passed");
3410 return QVariant();
3411 }
3412 QVariant result = defaultValue;
3413 QString k = d->actualKey(key);
3414 d->get(key: k, value: &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*/
3430void 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*/
3443QSettings::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*/
3461void QSettings::setSystemIniPath(const QString &dir)
3462{
3463 setPath(format: IniFormat, scope: SystemScope, path: dir);
3464#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3465 setPath(format: NativeFormat, scope: SystemScope, path: dir);
3466#endif
3467}
3468
3469/*!
3470 \obsolete
3471
3472 Use setPath() instead.
3473*/
3474
3475void QSettings::setUserIniPath(const QString &dir)
3476{
3477 setPath(format: IniFormat, scope: UserScope, path: dir);
3478#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3479 setPath(format: NativeFormat, scope: UserScope, path: 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*/
3517void QSettings::setPath(Format format, Scope scope, const QString &path)
3518{
3519 auto locker = qt_unique_lock(mutex&: settingsGlobalMutex);
3520 PathHash *pathHash = pathHashFunc();
3521 if (pathHash->isEmpty())
3522 locker = initDefaultPaths(locker: std::move(locker));
3523 pathHash->insert(akey: pathHashKey(format, scope), avalue: 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*/
3594QSettings::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(mutex&: 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(t: info);
3614
3615 return QSettings::Format((int)QSettings::CustomFormat1 + index);
3616}
3617
3618QT_END_NAMESPACE
3619
3620#ifndef QT_BOOTSTRAPPED
3621#include "moc_qsettings.cpp"
3622#endif
3623

source code of qtbase/src/corelib/io/qsettings.cpp