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