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