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 (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 */
1002 QString systemPath = QLibraryInfo::path(QLibraryInfo::SettingsPath) + u'/';
1003
1004 locker.lock();
1005 if (pathHash->isEmpty()) {
1006 /*
1007 Lazy initialization of pathHash. We initialize the
1008 IniFormat paths and (on Unix) the NativeFormat paths.
1009 (The NativeFormat paths are not configurable for the
1010 Windows registry and the Mac CFPreferences.)
1011 */
1012#ifdef Q_OS_WIN
1013 const QString roamingAppDataFolder = windowsConfigPath(FOLDERID_RoamingAppData);
1014 const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
1015 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
1016 Path(roamingAppDataFolder + QDir::separator(), false));
1017 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
1018 Path(programDataFolder + QDir::separator(), false));
1019#else
1020 const QString userPath = make_user_path();
1021 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
1022 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
1023#ifndef Q_OS_DARWIN
1024 pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
1025 pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
1026#endif
1027#endif // Q_OS_WIN
1028 }
1029
1030 return locker;
1031}
1032
1033static Path getPath(QSettings::Format format, QSettings::Scope scope)
1034{
1035 Q_ASSERT(int(QSettings::NativeFormat) == 0);
1036 Q_ASSERT(int(QSettings::IniFormat) == 1);
1037
1038 auto locker = qt_unique_lock(settingsGlobalMutex);
1039 PathHash *pathHash = pathHashFunc();
1040 if (pathHash->isEmpty())
1041 locker = initDefaultPaths(std::move(locker));
1042
1043 Path result = pathHash->value(pathHashKey(format, scope));
1044 if (!result.path.isEmpty())
1045 return result;
1046
1047 // fall back on INI path
1048 return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
1049}
1050
1051#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1052// Note: Suitable only for autotests.
1053void Q_AUTOTEST_EXPORT clearDefaultPaths()
1054{
1055 const auto locker = qt_scoped_lock(settingsGlobalMutex);
1056 pathHashFunc()->clear();
1057}
1058#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1059
1060QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
1061 QSettings::Scope scope,
1062 const QString &organization,
1063 const QString &application)
1064 : QSettingsPrivate(format, scope, organization, application),
1065 nextPosition(0x40000000) // big positive number
1066{
1067 initFormat();
1068
1069 QString org = organization;
1070 if (org.isEmpty()) {
1071 setStatus(QSettings::AccessError);
1072 org = "Unknown Organization"_L1;
1073 }
1074
1075 QString appFile = org + QDir::separator() + application + extension;
1076 QString orgFile = org + extension;
1077
1078 if (scope == QSettings::UserScope) {
1079 Path userPath = getPath(format, QSettings::UserScope);
1080 if (!application.isEmpty())
1081 confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
1082 confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
1083 }
1084
1085 Path systemPath = getPath(format, QSettings::SystemScope);
1086#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1087 // check if the systemPath wasn't overridden by QSettings::setPath()
1088 if (!systemPath.userDefined) {
1089 // Note: We can't use QStandardPaths::locateAll() as we need all the
1090 // possible files (not just the existing ones) and there is no way
1091 // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
1092 QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
1093 // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
1094 if (!dirs.isEmpty())
1095 dirs.takeFirst();
1096 QStringList paths;
1097 if (!application.isEmpty()) {
1098 paths.reserve(dirs.size() * 2);
1099 for (const auto &dir : std::as_const(dirs))
1100 paths.append(dir + u'/' + appFile);
1101 } else {
1102 paths.reserve(dirs.size());
1103 }
1104 for (const auto &dir : std::as_const(dirs))
1105 paths.append(dir + u'/' + orgFile);
1106
1107 // Note: No check for existence of files is done intentionally.
1108 for (const auto &path : std::as_const(paths))
1109 confFiles.append(QConfFile::fromName(path, false));
1110 } else
1111#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1112 {
1113 if (!application.isEmpty())
1114 confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
1115 confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
1116 }
1117
1119}
1120
1121QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
1122 QSettings::Format format)
1123 : QSettingsPrivate(format),
1124 nextPosition(0x40000000) // big positive number
1125{
1126 initFormat();
1127
1128 confFiles.append(QConfFile::fromName(fileName, true));
1129
1131}
1132
1134{
1135 const auto locker = qt_scoped_lock(settingsGlobalMutex);
1136 ConfFileHash *usedHash = usedHashFunc();
1137 ConfFileCache *unusedCache = unusedCacheFunc();
1138
1139 for (auto conf_file : std::as_const(confFiles)) {
1140 if (!conf_file->ref.deref()) {
1141 if (conf_file->size == 0) {
1142 delete conf_file;
1143 } else {
1144 if (usedHash)
1145 usedHash->remove(conf_file->name);
1146 if (unusedCache) {
1147 QT_TRY {
1148 // compute a better size?
1149 unusedCache->insert(conf_file->name, conf_file,
1150 10 + (conf_file->originalKeys.size() / 4));
1151 } QT_CATCH(...) {
1152 // out of memory. Do not cache the file.
1153 delete conf_file;
1154 }
1155 } else {
1156 // unusedCache is gone - delete the entry to prevent a memory leak
1157 delete conf_file;
1158 }
1159 }
1160 }
1161 }
1162}
1163
1164void QConfFileSettingsPrivate::remove(const QString &key)
1165{
1166 if (confFiles.isEmpty())
1167 return;
1168
1169 // Note: First config file is always the most specific.
1170 QConfFile *confFile = confFiles.at(0);
1171
1172 QSettingsKey theKey(key, caseSensitivity);
1173 QSettingsKey prefix(key + u'/', caseSensitivity);
1174 const auto locker = qt_scoped_lock(confFile->mutex);
1175
1176 ensureSectionParsed(confFile, theKey);
1177 ensureSectionParsed(confFile, prefix);
1178
1179 auto i = confFile->addedKeys.lowerBound(prefix);
1180 while (i != confFile->addedKeys.end() && i.key().startsWith(prefix))
1181 i = confFile->addedKeys.erase(i);
1182 confFile->addedKeys.remove(theKey);
1183
1184 auto j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
1185 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) {
1186 confFile->removedKeys.insert(j.key(), QVariant());
1187 ++j;
1188 }
1189 if (confFile->originalKeys.contains(theKey))
1190 confFile->removedKeys.insert(theKey, QVariant());
1191}
1192
1193void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
1194{
1195 if (confFiles.isEmpty())
1196 return;
1197
1198 // Note: First config file is always the most specific.
1199 QConfFile *confFile = confFiles.at(0);
1200
1201 QSettingsKey theKey(key, caseSensitivity, nextPosition++);
1202 const auto locker = qt_scoped_lock(confFile->mutex);
1203 confFile->removedKeys.remove(theKey);
1204 confFile->addedKeys.insert(theKey, value);
1205}
1206
1207std::optional<QVariant> QConfFileSettingsPrivate::get(const QString &key) const
1208{
1209 QSettingsKey theKey(key, caseSensitivity);
1210 ParsedSettingsMap::const_iterator j;
1211 bool found = false;
1212
1213 for (auto confFile : std::as_const(confFiles)) {
1214 const auto locker = qt_scoped_lock(confFile->mutex);
1215
1216 if (!confFile->addedKeys.isEmpty()) {
1217 j = confFile->addedKeys.constFind(theKey);
1218 found = (j != confFile->addedKeys.constEnd());
1219 }
1220 if (!found) {
1221 ensureSectionParsed(confFile, theKey);
1222 j = confFile->originalKeys.constFind(theKey);
1223 found = (j != confFile->originalKeys.constEnd()
1224 && !confFile->removedKeys.contains(theKey));
1225 }
1226
1227 if (found)
1228 return *j;
1229 if (!fallbacks)
1230 break;
1231 }
1232 return std::nullopt;
1233}
1234
1235QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
1236{
1237 QStringList result;
1238
1239 QSettingsKey thePrefix(prefix, caseSensitivity);
1240 qsizetype startPos = prefix.size();
1241
1242 for (auto confFile : std::as_const(confFiles)) {
1243 const auto locker = qt_scoped_lock(confFile->mutex);
1244
1245 if (thePrefix.isEmpty())
1246 ensureAllSectionsParsed(confFile);
1247 else
1248 ensureSectionParsed(confFile, thePrefix);
1249
1250 const auto &originalKeys = confFile->originalKeys;
1251 auto i = originalKeys.lowerBound(thePrefix);
1252 while (i != originalKeys.end() && i.key().startsWith(thePrefix)) {
1253 if (!confFile->removedKeys.contains(i.key()))
1254 processChild(QStringView{i.key().originalCaseKey()}.sliced(startPos), spec, result);
1255 ++i;
1256 }
1257
1258 const auto &addedKeys = confFile->addedKeys;
1259 auto j = addedKeys.lowerBound(thePrefix);
1260 while (j != addedKeys.end() && j.key().startsWith(thePrefix)) {
1261 processChild(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result);
1262 ++j;
1263 }
1264
1265 if (!fallbacks)
1266 break;
1267 }
1268 std::sort(result.begin(), result.end());
1269 result.erase(std::unique(result.begin(), result.end()),
1270 result.end());
1271 return result;
1272}
1273
1275{
1276 if (confFiles.isEmpty())
1277 return;
1278
1279 // Note: First config file is always the most specific.
1280 QConfFile *confFile = confFiles.at(0);
1281
1282 const auto locker = qt_scoped_lock(confFile->mutex);
1283 ensureAllSectionsParsed(confFile);
1284 confFile->addedKeys.clear();
1285 confFile->removedKeys = confFile->originalKeys;
1286}
1287
1289{
1290 // people probably won't be checking the status a whole lot, so in case of
1291 // error we just try to go on and make the best of it
1292
1293 for (auto confFile : std::as_const(confFiles)) {
1294 const auto locker = qt_scoped_lock(confFile->mutex);
1295 syncConfFile(confFile);
1296 }
1297}
1298
1300{
1301 sync();
1302}
1303
1305{
1306 if (confFiles.isEmpty())
1307 return QString();
1308
1309 // Note: First config file is always the most specific.
1310 return confFiles.at(0)->name;
1311}
1312
1314{
1315#if defined(Q_OS_WASM)
1316 if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat && !writeFunc)
1317#else
1318 if (format > QSettings::IniFormat && !writeFunc)
1319#endif
1320 return false;
1321
1322 if (confFiles.isEmpty())
1323 return false;
1324
1325 return confFiles.at(0)->isWritable();
1326}
1327
1328void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
1329{
1330 bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
1331
1332 QFileInfo fileInfo(confFile->name);
1333 /*
1334 We can often optimize the read-only case, if the file on disk
1335 hasn't changed.
1336 */
1337 if (readOnly && confFile->size > 0) {
1338 if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified(QTimeZone::UTC))
1339 return;
1340 }
1341
1342 if (!readOnly && !confFile->isWritable()) {
1343 setStatus(QSettings::AccessError);
1344 return;
1345 }
1346
1347#ifndef QT_BOOTSTRAPPED
1348 QString lockFileName = confFile->name + ".lock"_L1;
1349
1350# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS)
1351 // On android and if it is a content URL put the lock file in a
1352 // writable location to prevent permissions issues and invalid paths.
1353 if (confFile->name.startsWith("content:"_L1))
1354 lockFileName = make_user_path() + QFileInfo(lockFileName).fileName();
1355# endif
1356 /*
1357 Use a lockfile in order to protect us against other QSettings instances
1358 trying to write the same settings at the same time.
1359
1360 We only need to lock if we are actually writing as only concurrent writes are a problem.
1361 Concurrent read and write are not a problem because the writing operation is atomic.
1362 */
1363 QLockFile lockFile(lockFileName);
1364 if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
1365 setStatus(QSettings::AccessError);
1366 return;
1367 }
1368#endif
1369
1370 /*
1371 We hold the lock. Let's reread the file if it has changed
1372 since last time we read it.
1373 */
1374 fileInfo.refresh();
1375 bool mustReadFile = true;
1376 bool createFile = !fileInfo.exists();
1377
1378 if (!readOnly)
1379 mustReadFile = (confFile->size != fileInfo.size()
1380 || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified(QTimeZone::UTC)));
1381
1382 if (mustReadFile) {
1383 confFile->unparsedIniSections.clear();
1384 confFile->originalKeys.clear();
1385
1386 QFile file(confFile->name);
1387 if (!createFile && !file.open(QFile::ReadOnly)) {
1388 setStatus(QSettings::AccessError);
1389 return;
1390 }
1391
1392 /*
1393 Files that we can't read (because of permissions or
1394 because they don't exist) are treated as empty files.
1395 */
1396 if (file.isReadable() && file.size() != 0) {
1397 bool ok = false;
1398
1399#ifdef Q_OS_WASM
1400 if (format == QSettings::WebIndexedDBFormat) {
1401 QByteArray data = file.readAll();
1402 ok = readIniFile(data, &confFile->unparsedIniSections);
1403 } else
1404#endif
1405#ifdef Q_OS_DARWIN
1406 if (format == QSettings::NativeFormat) {
1407 QByteArray data = file.readAll();
1408 ok = readPlistFile(data, &confFile->originalKeys);
1409 } else
1410#endif
1411 if (format <= QSettings::IniFormat) {
1412 QByteArray data = file.readAll();
1413 ok = readIniFile(data, &confFile->unparsedIniSections);
1414 } else if (readFunc) {
1415 QSettings::SettingsMap tempNewKeys;
1416 ok = readFunc(file, tempNewKeys);
1417
1418 if (ok) {
1419 auto i = tempNewKeys.constBegin();
1420 while (i != tempNewKeys.constEnd()) {
1421 confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
1422 i.value());
1423 ++i;
1424 }
1425 }
1426 }
1427
1428 for (const auto &section : confFile->unparsedIniSections.keys()) {
1429 if (section.count(u'/') > 1) {
1430 setStatus(QSettings::FormatError);
1431 break;
1432 }
1433 }
1434
1435 if (!ok)
1436 setStatus(QSettings::FormatError);
1437 }
1438
1439 confFile->size = fileInfo.size();
1440 confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC);
1441 }
1442
1443 /*
1444 We also need to save the file. We still hold the file lock,
1445 so everything is under control.
1446 */
1447 if (!readOnly) {
1448 bool ok = false;
1449 ensureAllSectionsParsed(confFile);
1450 ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
1451
1452#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1453 QSaveFile sf(confFile->name);
1454 sf.setDirectWriteFallback(!atomicSyncOnly);
1455# ifdef Q_OS_ANDROID
1456 // QSaveFile requires direct write when using content scheme URL in Android
1457 if (confFile->name.startsWith("content:"_L1))
1458 sf.setDirectWriteFallback(true);
1459# endif
1460#else
1461 QFile sf(confFile->name);
1462#endif
1463 if (!sf.open(QIODevice::WriteOnly)) {
1464 setStatus(QSettings::AccessError);
1465 return;
1466 }
1467
1468#ifdef Q_OS_WASM
1469 if (format == QSettings::WebIndexedDBFormat) {
1470 ok = writeIniFile(sf, mergedKeys);
1471 } else
1472#endif
1473#ifdef Q_OS_DARWIN
1474 if (format == QSettings::NativeFormat) {
1475 ok = writePlistFile(sf, mergedKeys);
1476 } else
1477#endif
1478 if (format <= QSettings::IniFormat) {
1479 ok = writeIniFile(sf, mergedKeys);
1480 } else if (writeFunc) {
1481 QSettings::SettingsMap tempOriginalKeys;
1482
1483 auto i = mergedKeys.constBegin();
1484 while (i != mergedKeys.constEnd()) {
1485 tempOriginalKeys.insert(i.key(), i.value());
1486 ++i;
1487 }
1488 ok = writeFunc(sf, tempOriginalKeys);
1489 }
1490
1491#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1492 if (ok)
1493 ok = sf.commit();
1494#endif
1495
1496 if (ok) {
1497 confFile->unparsedIniSections.clear();
1498 confFile->originalKeys = mergedKeys;
1499 confFile->addedKeys.clear();
1500 confFile->removedKeys.clear();
1501
1502 fileInfo.refresh();
1503 confFile->size = fileInfo.size();
1504 confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC);
1505
1506 // If we have created the file, apply the file perms
1507 if (createFile) {
1508 QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
1509 if (!confFile->userPerms)
1510 perms |= QFile::ReadGroup | QFile::ReadOther;
1511 QFile(confFile->name).setPermissions(perms);
1512 }
1513 } else {
1514 setStatus(QSettings::AccessError);
1515 }
1516 }
1517}
1518
1519namespace SettingsImpl {
1520
1521enum { Space = 0x1, Special = 0x2 };
1522
1523static const char charTraits[256] =
1524{
1525 // Space: '\t', '\n', '\r', ' '
1526 // Special: '\n', '\r', '"', ';', '=', '\\'
1527
1528 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0,
1529 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1530 Space, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1531 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0,
1532 0, 0, 0, 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, 0, Special, 0, 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, 0, 0, 0, 0,
1536
1537 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1538 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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};
1546
1547} // namespace SettingsImpl
1548
1549using SettingsImpl::charTraits;
1550
1551bool QConfFileSettingsPrivate::readIniLine(QByteArrayView data, qsizetype &dataPos,
1552 qsizetype &lineStart, qsizetype &lineLen,
1553 qsizetype &equalsPos)
1554{
1555 constexpr auto Space = SettingsImpl::Space;
1556 constexpr auto Special = SettingsImpl::Special;
1557 qsizetype dataLen = data.size();
1558 bool inQuotes = false;
1559
1560 equalsPos = -1;
1561
1562 lineStart = dataPos;
1563 while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space))
1564 ++lineStart;
1565
1566 qsizetype i = lineStart;
1567 while (i < dataLen) {
1568 char ch = data.at(i);
1569 while (!(charTraits[uchar(ch)] & Special)) {
1570 if (++i == dataLen)
1571 goto break_out_of_outer_loop;
1572 ch = data.at(i);
1573 }
1574
1575 ++i;
1576 if (ch == '=') {
1577 if (!inQuotes && equalsPos == -1)
1578 equalsPos = i - 1;
1579 } else if (ch == '\n' || ch == '\r') {
1580 if (i == lineStart + 1) {
1581 ++lineStart;
1582 } else if (!inQuotes) {
1583 --i;
1584 goto break_out_of_outer_loop;
1585 }
1586 } else if (ch == '\\') {
1587 if (i < dataLen) {
1588 char ch = data.at(i++);
1589 if (i < dataLen) {
1590 char ch2 = data.at(i);
1591 // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
1592 if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n'))
1593 ++i;
1594 }
1595 }
1596 } else if (ch == '"') {
1597 inQuotes = !inQuotes;
1598 } else {
1599 Q_ASSERT(ch == ';');
1600
1601 if (i == lineStart + 1) {
1602 while (i < dataLen && (((ch = data.at(i)) != '\n') && ch != '\r'))
1603 ++i;
1604 while (i < dataLen && charTraits[uchar(data.at(i))] & Space)
1605 ++i;
1606 lineStart = i;
1607 } else if (!inQuotes) {
1608 --i;
1609 goto break_out_of_outer_loop;
1610 }
1611 }
1612 }
1613
1614break_out_of_outer_loop:
1615 dataPos = i;
1616 lineLen = i - lineStart;
1617 return lineLen > 0;
1618}
1619
1620/*
1621 Returns \c false on parse error. However, as many keys are read as
1622 possible, so if the user doesn't check the status he will get the
1623 most out of the file anyway.
1624*/
1625bool QConfFileSettingsPrivate::readIniFile(QByteArrayView data,
1626 UnparsedSettingsMap *unparsedIniSections)
1627{
1628#define FLUSH_CURRENT_SECTION()
1629 {
1630 QByteArray &sectionData = (*unparsedIniSections)[QSettingsKey(currentSection,
1631 IniCaseSensitivity,
1632 sectionPosition)];
1633 if (!sectionData.isEmpty())
1634 sectionData.append('\n');
1635 sectionData += data.first(lineStart).sliced(currentSectionStart);
1636 sectionPosition = ++position;
1637 }
1638
1639 QString currentSection;
1640 qsizetype currentSectionStart = 0;
1641 qsizetype dataPos = 0;
1642 qsizetype lineStart;
1643 qsizetype lineLen;
1644 qsizetype equalsPos;
1645 qsizetype position = 0;
1646 qsizetype sectionPosition = 0;
1647 bool ok = true;
1648
1649 // Skip possible UTF-8 BOM:
1650 if (data.startsWith("\xef\xbb\xbf"))
1651 data = data.sliced(3);
1652
1653 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1654 QByteArrayView line = data.sliced(lineStart, lineLen);
1655 if (line.startsWith('[')) {
1657
1658 // This starts a new section.
1659 qsizetype idx = line.indexOf(']');
1660 Q_ASSERT(idx == -1 || idx > 0); // line[0] is '[', not ']'.
1661 Q_ASSERT(idx < lineLen); // (including -1 < lineLen, if no ']' present.)
1662 if (idx < 0) {
1663 ok = false;
1664 idx = lineLen; // so line.first(idx) is just line
1665 }
1666 QByteArrayView iniSection = line.first(idx).sliced(1).trimmed();
1667
1668 if (iniSection.compare("general", Qt::CaseInsensitive) == 0) {
1669 currentSection.clear();
1670 } else {
1671 if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) {
1672 currentSection = QLatin1StringView(iniSection.constData() + 1, iniSection.size() - 1);
1673 } else {
1674 currentSection.clear();
1675 iniUnescapedKey(iniSection, currentSection);
1676 }
1677 currentSection += u'/';
1678 }
1679 currentSectionStart = dataPos;
1680 }
1681 ++position;
1682 }
1683
1684 Q_ASSERT(lineStart == data.size());
1686
1687 return ok;
1688
1689#undef FLUSH_CURRENT_SECTION
1690}
1691
1692bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey &section, QByteArrayView data,
1693 ParsedSettingsMap *settingsMap)
1694{
1695 QStringList strListValue;
1696 bool sectionIsLowercase = (section == section.originalCaseKey());
1697 qsizetype equalsPos;
1698
1699 bool ok = true;
1700 qsizetype dataPos = 0;
1701 qsizetype lineStart;
1702 qsizetype lineLen;
1703 qsizetype position = section.originalKeyPosition();
1704
1705 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1706 QByteArrayView line = data.sliced(lineStart, lineLen);
1707 Q_ASSERT(!line.startsWith('['));
1708
1709 if (equalsPos == -1) {
1710 if (!line.startsWith(';'))
1711 ok = false;
1712 continue;
1713 }
1714 // Shift equalPos indexing to be within line, rather than data:
1715 equalsPos -= lineStart;
1716 // Assured by readIniLine:
1717 Q_ASSERT(equalsPos >= 0 && equalsPos < lineLen);
1718
1719 QByteArrayView key = line.first(equalsPos).trimmed();
1720 QByteArrayView value = line.sliced(equalsPos + 1);
1721
1722 QString strKey = section.originalCaseKey();
1723 const Qt::CaseSensitivity casing = iniUnescapedKey(key, strKey) && sectionIsLowercase
1724 ? Qt::CaseSensitive
1725 : IniCaseSensitivity;
1726
1727 QString strValue;
1728 strValue.reserve(value.size());
1729 QVariant variant = iniUnescapedStringList(value, strValue, strListValue)
1730 ? stringListToVariantList(strListValue)
1731 : stringToVariant(strValue);
1732
1733 /*
1734 We try to avoid the expensive toLower() call in
1735 QSettingsKey by passing Qt::CaseSensitive when the
1736 key is already in lowercase.
1737 */
1738 settingsMap->insert(QSettingsKey(strKey, casing, position), std::move(variant));
1739 ++position;
1740 }
1741
1742 return ok;
1743}
1744
1746{
1747public:
1748 inline QSettingsIniKey() : position(-1) {}
1749 inline QSettingsIniKey(const QString &str, qsizetype pos = -1) : QString(str), position(pos) {}
1750
1752};
1754
1755static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2)
1756{
1757 if (k1.position != k2.position)
1758 return k1.position < k2.position;
1759 return static_cast<const QString &>(k1) < static_cast<const QString &>(k2);
1760}
1761
1763
1771
1773
1775
1776/*
1777 This would be more straightforward if we didn't try to remember the original
1778 key order in the .ini file, but we do.
1779*/
1780bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map)
1781{
1782 IniMap iniMap;
1783
1784#ifdef Q_OS_WIN
1785 const char * const eol = "\r\n";
1786#else
1787 const char eol = '\n';
1788#endif
1789
1790 for (auto j = map.constBegin(); j != map.constEnd(); ++j) {
1791 QString section;
1792 QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition());
1793 qsizetype slashPos;
1794
1795 if ((slashPos = key.indexOf(u'/')) != -1) {
1796 section = key.left(slashPos);
1797 key.remove(0, slashPos + 1);
1798 }
1799
1800 QSettingsIniSection &iniSection = iniMap[section];
1801
1802 // -1 means infinity
1803 if (size_t(key.position) < size_t(iniSection.position))
1804 iniSection.position = key.position;
1805 iniSection.keyMap[key] = j.value();
1806 }
1807
1808 const qsizetype sectionCount = iniMap.size();
1809 QList<QSettingsIniKey> sections;
1810 sections.reserve(sectionCount);
1811 for (auto i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
1812 sections.append(QSettingsIniKey(i.key(), i.value().position));
1813 std::sort(sections.begin(), sections.end());
1814
1815 bool writeError = false;
1816 for (qsizetype j = 0; !writeError && j < sectionCount; ++j) {
1817 auto i = iniMap.constFind(sections.at(j));
1818 Q_ASSERT(i != iniMap.constEnd());
1819
1820 QByteArray realSection;
1821
1822 iniEscapedKey(i.key(), realSection);
1823
1824 if (realSection.isEmpty()) {
1825 realSection = "[General]";
1826 } else if (realSection.compare("general", Qt::CaseInsensitive) == 0) {
1827 realSection = "[%General]";
1828 } else {
1829 realSection.prepend('[');
1830 realSection.append(']');
1831 }
1832
1833 if (j != 0)
1834 realSection.prepend(eol);
1835 realSection += eol;
1836
1837 device.write(realSection);
1838
1839 const IniKeyMap &ents = i.value().keyMap;
1840 for (auto j = ents.constBegin(); j != ents.constEnd(); ++j) {
1841 QByteArray block;
1842 iniEscapedKey(j.key(), block);
1843 block += '=';
1844
1845 const QVariant &value = j.value();
1846
1847 /*
1848 The size() != 1 trick is necessary because
1849 QVariant(QString("foo")).toList() returns an empty
1850 list, not a list containing "foo".
1851 */
1852 if (value.metaType().id() == QMetaType::QStringList
1853 || (value.metaType().id() == QMetaType::QVariantList && value.toList().size() != 1)) {
1854 iniEscapedStringList(variantListToStringList(value.toList()), block);
1855 } else {
1856 iniEscapedString(variantToString(value), block);
1857 }
1858 block += eol;
1859 if (device.write(block) == -1) {
1860 writeError = true;
1861 break;
1862 }
1863 }
1864 }
1865 return !writeError;
1866}
1867
1868void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const
1869{
1870 auto i = confFile->unparsedIniSections.constBegin();
1871 const auto end = confFile->unparsedIniSections.constEnd();
1872
1873 for (; i != end; ++i) {
1874 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys))
1875 setStatus(QSettings::FormatError);
1876 }
1877 confFile->unparsedIniSections.clear();
1878}
1879
1880void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
1881 const QSettingsKey &key) const
1882{
1883 if (confFile->unparsedIniSections.isEmpty())
1884 return;
1885
1886 UnparsedSettingsMap::iterator i;
1887
1888 qsizetype indexOfSlash = key.indexOf(u'/');
1889 if (indexOfSlash != -1) {
1890 i = confFile->unparsedIniSections.upperBound(key);
1891 if (i == confFile->unparsedIniSections.begin())
1892 return;
1893 --i;
1894 if (i.key().isEmpty() || !key.startsWith(i.key()))
1895 return;
1896 } else {
1897 i = confFile->unparsedIniSections.begin();
1898 if (i == confFile->unparsedIniSections.end() || !i.key().isEmpty())
1899 return;
1900 }
1901
1902 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys))
1903 setStatus(QSettings::FormatError);
1904 confFile->unparsedIniSections.erase(i);
1905}
1906
1907/*!
1908 \class QSettings
1909 \inmodule QtCore
1910 \brief The QSettings class provides persistent platform-independent application settings.
1911
1912 \ingroup io
1913
1914 \reentrant
1915
1916 Users normally expect an application to remember its settings
1917 (window sizes and positions, options, etc.) across sessions. This
1918 information is often stored in the system registry on Windows,
1919 and in property list files on \macos and iOS. On Unix systems, in the
1920 absence of a standard, many applications (including the KDE
1921 applications) use INI text files.
1922
1923 QSettings is an abstraction around these technologies, enabling
1924 you to save and restore application settings in a portable
1925 manner. It also supports \l{registerFormat()}{custom storage
1926 formats}.
1927
1928 QSettings's API is based on QVariant, allowing you to save
1929 most value-based types, such as QString, QRect, and QImage,
1930 with the minimum of effort.
1931
1932 If all you need is a non-persistent memory-based structure,
1933 consider using QMap<QString, QVariant> instead.
1934
1935 \section1 Basic Usage
1936
1937 When creating a QSettings object, you must pass the name of your
1938 company or organization as well as the name of your application.
1939 For example, if your product is called Star Runner and your
1940 company is called MySoft, you would construct the QSettings
1941 object as follows:
1942
1943 \snippet settings/settings.cpp 0
1944
1945 QSettings objects can be created either on the stack or on
1946 the heap (i.e. using \c new). Constructing and destroying a
1947 QSettings object is very fast.
1948
1949 If you use QSettings from many places in your application, you
1950 might want to specify the organization name and the application
1951 name using QCoreApplication::setOrganizationName() and
1952 QCoreApplication::setApplicationName(), and then use the default
1953 QSettings constructor:
1954
1955 \snippet settings/settings.cpp 1
1956 \snippet settings/settings.cpp 2
1957 \snippet settings/settings.cpp 3
1958 \dots
1959 \snippet settings/settings.cpp 4
1960
1961 (Here, we also specify the organization's Internet domain. When
1962 the Internet domain is set, it is used on \macos and iOS instead of the
1963 organization name, since \macos and iOS applications conventionally use
1964 Internet domains to identify themselves. If no domain is set, a
1965 fake domain is derived from the organization name. See the
1966 \l{Platform-Specific Notes} below for details.)
1967
1968 QSettings stores settings. Each setting consists of a QString
1969 that specifies the setting's name (the \e key) and a QVariant
1970 that stores the data associated with the key. To write a setting,
1971 use setValue(). For example:
1972
1973 \snippet settings/settings.cpp 5
1974
1975 If there already exists a setting with the same key, the existing
1976 value is overwritten by the new value. For efficiency, the
1977 changes may not be saved to permanent storage immediately. (You
1978 can always call sync() to commit your changes.)
1979
1980 You can get a setting's value back using value():
1981
1982 \snippet settings/settings.cpp 6
1983
1984 If there is no setting with the specified name, QSettings
1985 returns a null QVariant (which can be converted to the integer 0).
1986 You can specify another default value by passing a second
1987 argument to value():
1988
1989 \snippet settings/settings.cpp 7
1990
1991 To test whether a given key exists, call contains(). To remove
1992 the setting associated with a key, call remove(). To obtain the
1993 list of all keys, call allKeys(). To remove all keys, call
1994 clear().
1995
1996 \section1 QVariant and GUI Types
1997
1998 Because QVariant is part of the Qt Core module, it cannot provide
1999 conversion functions to data types such as QColor, QImage, and
2000 QPixmap, which are part of Qt GUI. In other words, there is no
2001 \c toColor(), \c toImage(), or \c toPixmap() functions in QVariant.
2002
2003 Instead, you can use the QVariant::value() template function.
2004 For example:
2005
2006 \snippet code/src_corelib_io_qsettings.cpp 0
2007
2008 The inverse conversion (e.g., from QColor to QVariant) is
2009 automatic for all data types supported by QVariant, including
2010 GUI-related types:
2011
2012 \snippet code/src_corelib_io_qsettings.cpp 1
2013
2014 Custom types registered using qRegisterMetaType() that have
2015 operators for streaming to and from a QDataStream can be stored
2016 using QSettings.
2017
2018 \section1 Section and Key Syntax
2019
2020 Setting keys can contain any Unicode characters. The file format and
2021 operating system will determine if they are sensitive to case or not. On
2022 Windows, the registry and INI files will use case-insensitive keys, while
2023 user-specified formats registered with registerFormat() may be either. On
2024 Unix systems, keys are always case-sensitive.
2025
2026 To avoid portability problems, follow these simple rules:
2027
2028 \list 1
2029 \li Always refer to the same key using the same case. For example,
2030 if you refer to a key as "text fonts" in one place in your
2031 code, don't refer to it as "Text Fonts" somewhere else.
2032
2033 \li Avoid key names that are identical except for the case. For
2034 example, if you have a key called "MainWindow", don't try to
2035 save another key as "mainwindow".
2036
2037 \li Do not use slashes ('/' and '\\') in section or key names; the
2038 backslash character is used to separate sub keys (see below). On
2039 windows '\\' are converted by QSettings to '/', which makes
2040 them identical.
2041 \endlist
2042
2043 You can form hierarchical keys using the '/' character as a
2044 separator, similar to Unix file paths. For example:
2045
2046 \snippet settings/settings.cpp 8
2047 \snippet settings/settings.cpp 9
2048 \snippet settings/settings.cpp 10
2049
2050 If you want to save or restore many settings with the same
2051 prefix, you can specify the prefix using beginGroup() and call
2052 endGroup() at the end. Here's the same example again, but this
2053 time using the group mechanism:
2054
2055 \snippet settings/settings.cpp 11
2056 \codeline
2057 \snippet settings/settings.cpp 12
2058
2059 If a group is set using beginGroup(), the behavior of most
2060 functions changes consequently. Groups can be set recursively.
2061
2062 In addition to groups, QSettings also supports an "array"
2063 concept. See beginReadArray() and beginWriteArray() for details.
2064
2065 \section1 Fallback Mechanism
2066
2067 Let's assume that you have created a QSettings object with the
2068 organization name MySoft and the application name Star Runner.
2069 When you look up a value, up to four locations are searched in
2070 that order:
2071
2072 \list 1
2073 \li a user-specific location for the Star Runner application
2074 \li a user-specific location for all applications by MySoft
2075 \li a system-wide location for the Star Runner application
2076 \li a system-wide location for all applications by MySoft
2077 \endlist
2078
2079 (See \l{Platform-Specific Notes} below for information on what
2080 these locations are on the different platforms supported by Qt.)
2081
2082 If a key cannot be found in the first location, the search goes
2083 on in the second location, and so on. This enables you to store
2084 system-wide or organization-wide settings and to override them on
2085 a per-user or per-application basis. To turn off this mechanism,
2086 call setFallbacksEnabled(false).
2087
2088 Although keys from all four locations are available for reading,
2089 only the first file (the user-specific location for the
2090 application at hand) is accessible for writing. To write to any
2091 of the other files, omit the application name and/or specify
2092 QSettings::SystemScope (as opposed to QSettings::UserScope, the
2093 default).
2094
2095 Let's see with an example:
2096
2097 \snippet settings/settings.cpp 13
2098 \snippet settings/settings.cpp 14
2099
2100 The table below summarizes which QSettings objects access
2101 which location. "\b{X}" means that the location is the main
2102 location associated to the QSettings object and is used both
2103 for reading and for writing; "o" means that the location is used
2104 as a fallback when reading.
2105
2106 \table
2107 \header \li Locations \li \c{obj1} \li \c{obj2} \li \c{obj3} \li \c{obj4}
2108 \row \li 1. User, Application \li \b{X} \li \li \li
2109 \row \li 2. User, Organization \li o \li \b{X} \li \li
2110 \row \li 3. System, Application \li o \li \li \b{X} \li
2111 \row \li 4. System, Organization \li o \li o \li o \li \b{X}
2112 \endtable
2113
2114 The beauty of this mechanism is that it works on all platforms
2115 supported by Qt and that it still gives you a lot of flexibility,
2116 without requiring you to specify any file names or registry
2117 paths.
2118
2119 If you want to use INI files on all platforms instead of the
2120 native API, you can pass QSettings::IniFormat as the first
2121 argument to the QSettings constructor, followed by the scope, the
2122 organization name, and the application name:
2123
2124 \snippet settings/settings.cpp 15
2125
2126 Note that INI files lose the distinction between numeric data and the
2127 strings used to encode them, so values written as numbers shall be read back
2128 as QString. The numeric value can be recovered using \l QString::toInt(), \l
2129 QString::toDouble() and related functions.
2130
2131 \section1 Restoring the State of a GUI Application
2132
2133 QSettings is often used to store the state of a GUI
2134 application. The following example illustrates how to use QSettings
2135 to save and restore the geometry of an application's main window.
2136
2137 \snippet settings/settings.cpp 16
2138 \codeline
2139 \snippet settings/settings.cpp 17
2140
2141 See \l{Window Geometry} for a discussion on why it is better to
2142 call QWidget::resize() and QWidget::move() rather than QWidget::setGeometry()
2143 to restore a window's geometry.
2144
2145 The \c readSettings() and \c writeSettings() functions must be
2146 called from the main window's constructor and close event handler
2147 as follows:
2148
2149 \snippet settings/settings.cpp 18
2150 \dots
2151 \snippet settings/settings.cpp 19
2152 \snippet settings/settings.cpp 20
2153 \codeline
2154 \snippet settings/settings.cpp 21
2155
2156 \section1 Accessing Settings from Multiple Threads or Processes Simultaneously
2157
2158 QSettings is \l{reentrant}. This means that you can use
2159 distinct QSettings object in different threads
2160 simultaneously. This guarantee stands even when the QSettings
2161 objects refer to the same files on disk (or to the same entries
2162 in the system registry). If a setting is modified through one
2163 QSettings object, the change will immediately be visible in
2164 any other QSettings objects that operate on the same location
2165 and that live in the same process.
2166
2167 QSettings can safely be used from different processes (which can
2168 be different instances of your application running at the same
2169 time or different applications altogether) to read and write to
2170 the same system locations, provided certain conditions are met. For
2171 QSettings::IniFormat, it uses advisory file locking and a smart merging
2172 algorithm to ensure data integrity. The condition for that to work is that
2173 the writeable configuration file must be a regular file and must reside in
2174 a directory that the current user can create new, temporary files in. If
2175 that is not the case, then one must use setAtomicSyncRequired() to turn the
2176 safety off.
2177
2178 Note that sync() imports changes made by other processes (in addition to
2179 writing the changes from this QSettings).
2180
2181 \section1 Platform-Specific Notes
2182
2183 \section2 Locations Where Application Settings Are Stored
2184
2185 As mentioned in the \l{Fallback Mechanism} section, QSettings
2186 stores settings for an application in up to four locations,
2187 depending on whether the settings are user-specific or
2188 system-wide and whether the settings are application-specific
2189 or organization-wide. For simplicity, we're assuming the
2190 organization is called MySoft and the application is called Star
2191 Runner.
2192
2193 On Unix systems, if the file format is NativeFormat, the
2194 following files are used by default:
2195
2196 \list 1
2197 \li \c{$HOME/.config/MySoft/Star Runner.conf}
2198 \li \c{$HOME/.config/MySoft.conf}
2199 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
2200 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
2201 \endlist
2202 \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2203
2204 On \macos and iOS, if the file format is NativeFormat, these files are used by
2205 default:
2206
2207 \list 1
2208 \li \c{$HOME/Library/Preferences/com.MySoft.Star Runner.plist}
2209 \li \c{$HOME/Library/Preferences/com.MySoft.plist}
2210 \li \c{/Library/Preferences/com.MySoft.Star Runner.plist}
2211 \li \c{/Library/Preferences/com.MySoft.plist}
2212 \endlist
2213
2214 On Windows, NativeFormat settings are stored in the following
2215 registry paths:
2216
2217 \list 1
2218 \li \c{HKEY_CURRENT_USER\Software\MySoft\Star Runner}
2219 \li \c{HKEY_CURRENT_USER\Software\MySoft\OrganizationDefaults}
2220 \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner}
2221 \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\OrganizationDefaults}
2222 \endlist
2223
2224 \note On Windows, for 32-bit programs running in WOW64 mode, settings are
2225 stored in the following registry path:
2226 \c{HKEY_LOCAL_MACHINE\Software\WOW6432node}.
2227
2228 If the file format is NativeFormat, this is "Settings/MySoft/Star Runner.conf"
2229 in the application's home directory.
2230
2231 If the file format is IniFormat, the following files are
2232 used on Unix, \macos, and iOS:
2233
2234 \list 1
2235 \li \c{$HOME/.config/MySoft/Star Runner.ini}
2236 \li \c{$HOME/.config/MySoft.ini}
2237 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
2238 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
2239 \endlist
2240 \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2241
2242 On Windows, the following files are used:
2243
2244 \list 1
2245 \li \c{FOLDERID_RoamingAppData\MySoft\Star Runner.ini}
2246 \li \c{FOLDERID_RoamingAppData\MySoft.ini}
2247 \li \c{FOLDERID_ProgramData\MySoft\Star Runner.ini}
2248 \li \c{FOLDERID_ProgramData\MySoft.ini}
2249 \endlist
2250
2251 The identifiers prefixed by \c{FOLDERID_} are special item ID lists to be passed
2252 to the Win32 API function \c{SHGetKnownFolderPath()} to obtain the
2253 corresponding path.
2254
2255 \c{FOLDERID_RoamingAppData} usually points to \tt{C:\\Users\\\e{User Name}\\AppData\\Roaming},
2256 also shown by the environment variable \c{%APPDATA%}.
2257
2258 \c{FOLDERID_ProgramData} usually points to \tt{C:\\ProgramData}.
2259
2260 If the file format is IniFormat, this is "Settings/MySoft/Star Runner.ini"
2261 in the application's home directory.
2262
2263 The paths for the \c .ini and \c .conf files can be changed using
2264 setPath(). On Unix, \macos, and iOS the user can override them by
2265 setting the \c XDG_CONFIG_HOME environment variable; see
2266 setPath() for details.
2267
2268 \section2 Accessing INI and .plist Files Directly
2269
2270 Sometimes you do want to access settings stored in a specific
2271 file or registry path. On all platforms, if you want to read an
2272 INI file directly, you can use the QSettings constructor that
2273 takes a file name as first argument and pass QSettings::IniFormat
2274 as second argument. For example:
2275
2276 \snippet code/src_corelib_io_qsettings.cpp 2
2277
2278 You can then use the QSettings object to read and write settings
2279 in the file.
2280
2281 On \macos and iOS, you can access property list \c .plist files by passing
2282 QSettings::NativeFormat as second argument. For example:
2283
2284 \snippet code/src_corelib_io_qsettings.cpp 3
2285
2286 \section2 Accessing the Windows Registry Directly
2287
2288 On Windows, QSettings lets you access settings that have been
2289 written with QSettings (or settings in a supported format, e.g., string
2290 data) in the system registry. This is done by constructing a QSettings
2291 object with a path in the registry and QSettings::NativeFormat.
2292
2293 For example:
2294
2295 \snippet code/src_corelib_io_qsettings.cpp 4
2296
2297 All the registry entries that appear under the specified path can
2298 be read or written through the QSettings object as usual (using
2299 forward slashes instead of backslashes). For example:
2300
2301 \snippet code/src_corelib_io_qsettings.cpp 5
2302
2303 Note that the backslash character is, as mentioned, used by
2304 QSettings to separate subkeys. As a result, you cannot read or
2305 write windows registry entries that contain slashes or
2306 backslashes; you should use a native windows API if you need to do
2307 so.
2308
2309 \section2 Accessing Common Registry Settings on Windows
2310
2311 On Windows, it is possible for a key to have both a value and subkeys.
2312 Its default value is accessed by using "Default" or "." in
2313 place of a subkey:
2314
2315 \snippet code/src_corelib_io_qsettings.cpp 6
2316
2317 On other platforms than Windows, "Default" and "." would be
2318 treated as regular subkeys.
2319
2320 \section2 Platform Limitations
2321
2322 While QSettings attempts to smooth over the differences between
2323 the different supported platforms, there are still a few
2324 differences that you should be aware of when porting your
2325 application:
2326
2327 \list
2328 \li The Windows system registry has the following limitations: A
2329 subkey may not exceed 255 characters, an entry's value may
2330 not exceed 16,383 characters, and all the values of a key may
2331 not exceed 65,535 characters. One way to work around these
2332 limitations is to store the settings using the IniFormat
2333 instead of the NativeFormat.
2334
2335 \li On Windows, when the Windows system registry is used, QSettings
2336 does not preserve the original type of the value. Therefore,
2337 the type of the value might change when a new value is set. For
2338 example, a value with type \c REG_EXPAND_SZ will change to \c REG_SZ.
2339
2340 \li On \macos and iOS, allKeys() will return some extra keys for global
2341 settings that apply to all applications. These keys can be
2342 read using value() but cannot be changed, only shadowed.
2343 Calling setFallbacksEnabled(false) will hide these global
2344 settings.
2345
2346 \li On \macos and iOS, the CFPreferences API used by QSettings expects
2347 Internet domain names rather than organization names. To
2348 provide a uniform API, QSettings derives a fake domain name
2349 from the organization name (unless the organization name
2350 already is a domain name, e.g. OpenOffice.org). The algorithm
2351 appends ".com" to the company name and replaces spaces and
2352 other illegal characters with hyphens. If you want to specify
2353 a different domain name, call
2354 QCoreApplication::setOrganizationDomain(),
2355 QCoreApplication::setOrganizationName(), and
2356 QCoreApplication::setApplicationName() in your \c main()
2357 function and then use the default QSettings constructor.
2358 Another solution is to use preprocessor directives, for
2359 example:
2360
2361 \snippet code/src_corelib_io_qsettings.cpp 7
2362
2363 \li On \macos, permissions to access settings not belonging to the
2364 current user (i.e. SystemScope) have changed with 10.7 (Lion). Prior to
2365 that version, users having admin rights could access these. For 10.7 and
2366 10.8 (Mountain Lion), only root can. However, 10.9 (Mavericks) changes
2367 that rule again but only for the native format (plist files).
2368
2369 \endlist
2370
2371 \sa QVariant, QSessionManager
2372*/
2373
2374/*! \enum QSettings::Status
2375
2376 The following status values are possible:
2377
2378 \value NoError No error occurred.
2379 \value AccessError An access error occurred (e.g. trying to write to a read-only file).
2380 \value FormatError A format error occurred (e.g. loading a malformed INI file).
2381
2382 \sa status()
2383*/
2384
2385/*! \enum QSettings::Format
2386
2387 This enum type specifies the storage format used by QSettings.
2388
2389 \value NativeFormat Store the settings using the most
2390 appropriate storage format for the platform.
2391 On Windows, this means the system registry;
2392 on \macos and iOS, this means the CFPreferences
2393 API; on Unix, this means textual
2394 configuration files in INI format.
2395 \value Registry32Format Windows only: Explicitly access the 32-bit system registry
2396 from a 64-bit application running on 64-bit Windows.
2397 On 32-bit Windows or from a 32-bit application on 64-bit Windows,
2398 this works the same as specifying NativeFormat.
2399 This enum value was added in Qt 5.7.
2400 \value Registry64Format Windows only: Explicitly access the 64-bit system registry
2401 from a 32-bit application running on 64-bit Windows.
2402 On 32-bit Windows or from a 64-bit application on 64-bit Windows,
2403 this works the same as specifying NativeFormat.
2404 This enum value was added in Qt 5.7.
2405 \value IniFormat Store the settings in INI files. Note that INI files
2406 lose the distinction between numeric data and the
2407 strings used to encode them, so values written as
2408 numbers shall be read back as QString.
2409 \value WebLocalStorageFormat
2410 WASM only: Store the settings in window.localStorage for the current
2411 origin. If cookies are not allowed, this falls back to the INI format.
2412 This provides up to 5MiB storage per origin, but access to it is
2413 synchronous and JSPI is not required.
2414 \value WebIndexedDBFormat
2415 WASM only: Store the settings in an Indexed DB for the current
2416 origin. If cookies are not allowed, this falls back to the INI format.
2417 This requires JSPI, but provides more storage than
2418 WebLocalStorageFormat.
2419
2420 \value InvalidFormat Special value returned by registerFormat().
2421 \omitvalue CustomFormat1
2422 \omitvalue CustomFormat2
2423 \omitvalue CustomFormat3
2424 \omitvalue CustomFormat4
2425 \omitvalue CustomFormat5
2426 \omitvalue CustomFormat6
2427 \omitvalue CustomFormat7
2428 \omitvalue CustomFormat8
2429 \omitvalue CustomFormat9
2430 \omitvalue CustomFormat10
2431 \omitvalue CustomFormat11
2432 \omitvalue CustomFormat12
2433 \omitvalue CustomFormat13
2434 \omitvalue CustomFormat14
2435 \omitvalue CustomFormat15
2436 \omitvalue CustomFormat16
2437
2438 On Unix, NativeFormat and IniFormat mean the same thing, except
2439 that the file extension is different (\c .conf for NativeFormat,
2440 \c .ini for IniFormat).
2441
2442 The INI file format is a Windows file format that Qt supports on
2443 all platforms. In the absence of an INI standard, we try to
2444 follow what Microsoft does, with the following exceptions:
2445
2446 \list
2447 \li If you store types that QVariant can't convert to QString
2448 (e.g., QPoint, QRect, and QSize), Qt uses an \c{@}-based
2449 syntax to encode the type. For example:
2450
2451 \snippet code/src_corelib_io_qsettings.cpp 8
2452
2453 To minimize compatibility issues, any \c @ that doesn't
2454 appear at the first position in the value or that isn't
2455 followed by a Qt type (\c Point, \c Rect, \c Size, etc.) is
2456 treated as a normal character.
2457
2458 \li Although backslash is a special character in INI files, most
2459 Windows applications don't escape backslashes (\c{\}) in file
2460 paths:
2461
2462 \snippet code/src_corelib_io_qsettings.cpp 9
2463
2464 QSettings always treats backslash as a special character and
2465 provides no API for reading or writing such entries.
2466
2467 \li The INI file format has severe restrictions on the syntax of
2468 a key. Qt works around this by using \c % as an escape
2469 character in keys. In addition, if you save a top-level
2470 setting (a key with no slashes in it, e.g., "someKey"), it
2471 will appear in the INI file's "General" section. To avoid
2472 overwriting other keys, if you save something using a key
2473 such as "General/someKey", the key will be located in the
2474 "%General" section, \e not in the "General" section.
2475
2476 \li In line with most implementations today, QSettings will assume that
2477 \e values in the INI file are UTF-8 encoded. This means that \e values
2478 will be decoded as UTF-8 encoded entries and written back as UTF-8.
2479 To retain backward compatibility with older Qt versions, \e keys in the
2480 INI file are written in %-encoded format, but can be read in both
2481 %-encoded and UTF-8 formats.
2482
2483 \endlist
2484
2485 \section2 Compatibility with older Qt versions
2486
2487 Please note that this behavior is different to how QSettings behaved
2488 in versions of Qt prior to Qt 6. INI files written with Qt 5 or earlier are
2489 however fully readable by a Qt 6 based application (unless a ini codec
2490 different from utf8 had been set). But INI files written with Qt 6
2491 will only be readable by older Qt versions if you set the "iniCodec" to
2492 a UTF-8 textcodec.
2493
2494 \sa registerFormat(), setPath()
2495*/
2496
2497/*! \enum QSettings::Scope
2498
2499 This enum specifies whether settings are user-specific or shared
2500 by all users of the same system.
2501
2502 \value UserScope Store settings in a location specific to the
2503 current user (e.g., in the user's home
2504 directory).
2505 \value SystemScope Store settings in a global location, so that
2506 all users on the same machine access the same
2507 set of settings.
2508
2509 \sa setPath()
2510*/
2511
2512#ifndef QT_NO_QOBJECT
2513/*!
2514 Constructs a QSettings object for accessing settings of the
2515 application called \a application from the organization called \a
2516 organization, and with parent \a parent.
2517
2518 Example:
2519 \snippet code/src_corelib_io_qsettings.cpp 10
2520
2521 The scope is set to QSettings::UserScope, and the format is
2522 set to QSettings::NativeFormat (i.e. calling setDefaultFormat()
2523 before calling this constructor has no effect).
2524
2525 \sa setDefaultFormat(), {Fallback Mechanism}
2526*/
2527QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2528 : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
2529 parent)
2530{
2531}
2532
2533/*!
2534 Constructs a QSettings object for accessing settings of the
2535 application called \a application from the organization called \a
2536 organization, and with parent \a parent.
2537
2538 If \a scope is QSettings::UserScope, the QSettings object searches
2539 user-specific settings first, before it searches system-wide
2540 settings as a fallback. If \a scope is QSettings::SystemScope, the
2541 QSettings object ignores user-specific settings and provides
2542 access to system-wide settings.
2543
2544 The storage format is set to QSettings::NativeFormat (i.e. calling
2545 setDefaultFormat() before calling this constructor has no effect).
2546
2547 If no application name is given, the QSettings object will
2548 only access the organization-wide \l{Fallback Mechanism}{locations}.
2549
2550 \sa setDefaultFormat()
2551*/
2552QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2553 QObject *parent)
2554 : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent)
2555{
2556}
2557
2558/*!
2559 Constructs a QSettings object for accessing settings of the
2560 application called \a application from the organization called
2561 \a organization, and with parent \a parent.
2562
2563 If \a scope is QSettings::UserScope, the QSettings object searches
2564 user-specific settings first, before it searches system-wide
2565 settings as a fallback. If \a scope is
2566 QSettings::SystemScope, the QSettings object ignores user-specific
2567 settings and provides access to system-wide settings.
2568
2569 If \a format is QSettings::NativeFormat, the native API is used for
2570 storing settings. If \a format is QSettings::IniFormat, the INI format
2571 is used.
2572
2573 If no application name is given, the QSettings object will
2574 only access the organization-wide \l{Fallback Mechanism}{locations}.
2575*/
2576QSettings::QSettings(Format format, Scope scope, const QString &organization,
2577 const QString &application, QObject *parent)
2578 : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent)
2579{
2580}
2581
2582/*!
2583 Constructs a QSettings object for accessing the settings
2584 stored in the file called \a fileName, with parent \a parent. If
2585 the file doesn't already exist, it is created.
2586
2587 If \a format is QSettings::NativeFormat, the meaning of \a
2588 fileName depends on the platform. On Unix, \a fileName is the
2589 name of an INI file. On \macos and iOS, \a fileName is the name of a
2590 \c .plist file. On Windows, \a fileName is a path in the system
2591 registry.
2592
2593 If \a format is QSettings::IniFormat, \a fileName is the name of an INI
2594 file.
2595
2596 \warning This function is provided for convenience. It works well for
2597 accessing INI or \c .plist files generated by Qt, but might fail on some
2598 syntaxes found in such files originated by other programs. In particular,
2599 be aware of the following limitations:
2600
2601 \list
2602 \li QSettings provides no way of reading INI "path" entries, i.e., entries
2603 with unescaped slash characters. (This is because these entries are
2604 ambiguous and cannot be resolved automatically.)
2605 \li In INI files, QSettings uses the \c @ character as a metacharacter in some
2606 contexts, to encode Qt-specific data types (e.g., \c @Rect), and might
2607 therefore misinterpret it when it occurs in pure INI files.
2608 \endlist
2609
2610 \sa fileName()
2611*/
2612QSettings::QSettings(const QString &fileName, Format format, QObject *parent)
2613 : QObject(*QSettingsPrivate::create(fileName, format), parent)
2614{
2615}
2616
2617/*!
2618 Constructs a QSettings object for accessing settings of the
2619 application and organization set previously with a call to
2620 QCoreApplication::setOrganizationName(),
2621 QCoreApplication::setOrganizationDomain(), and
2622 QCoreApplication::setApplicationName().
2623
2624 The scope is QSettings::UserScope and the format is
2625 defaultFormat() (QSettings::NativeFormat by default).
2626 Use setDefaultFormat() before calling this constructor
2627 to change the default format used by this constructor.
2628
2629 The code
2630
2631 \snippet code/src_corelib_io_qsettings.cpp 11
2632
2633 is equivalent to
2634
2635 \snippet code/src_corelib_io_qsettings.cpp 12
2636
2637 If QCoreApplication::setOrganizationName() and
2638 QCoreApplication::setApplicationName() has not been previously
2639 called, the QSettings object will not be able to read or write
2640 any settings, and status() will return AccessError.
2641
2642 You should supply both the domain (used by default on \macos and iOS) and
2643 the name (used by default elsewhere), although the code will cope if you
2644 supply only one, which will then be used (on all platforms), at odds with
2645 the usual naming of the file on platforms for which it isn't the default.
2646
2647 \sa QCoreApplication::setOrganizationName(),
2648 QCoreApplication::setOrganizationDomain(),
2649 QCoreApplication::setApplicationName(),
2650 setDefaultFormat()
2651*/
2652QSettings::QSettings(QObject *parent)
2653 : QSettings(UserScope, parent)
2654{
2655}
2656
2657/*!
2658 \since 5.13
2659
2660 Constructs a QSettings object in the same way as
2661 QSettings(QObject *parent) but with the given \a scope.
2662
2663 \sa QSettings(QObject *parent)
2664*/
2665QSettings::QSettings(Scope scope, QObject *parent)
2666 : QObject(*QSettingsPrivate::create(globalDefaultFormat, scope,
2667#ifdef Q_OS_DARWIN
2668 QCoreApplication::organizationDomain().isEmpty()
2669 ? QCoreApplication::organizationName()
2670 : QCoreApplication::organizationDomain()
2671#else
2672 QCoreApplication::organizationName().isEmpty()
2673 ? QCoreApplication::organizationDomain()
2674 : QCoreApplication::organizationName()
2675#endif
2676 , QCoreApplication::applicationName()),
2677 parent)
2678{
2679}
2680
2681#else
2682QSettings::QSettings(const QString &organization, const QString &application)
2683 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application))
2684{
2685 d_ptr->q_ptr = this;
2686}
2687
2688QSettings::QSettings(Scope scope, const QString &organization, const QString &application)
2689 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application))
2690{
2691 d_ptr->q_ptr = this;
2692}
2693
2694QSettings::QSettings(Format format, Scope scope, const QString &organization,
2695 const QString &application)
2696 : d_ptr(QSettingsPrivate::create(format, scope, organization, application))
2697{
2698 d_ptr->q_ptr = this;
2699}
2700
2701QSettings::QSettings(const QString &fileName, Format format)
2702 : d_ptr(QSettingsPrivate::create(fileName, format))
2703{
2704 d_ptr->q_ptr = this;
2705}
2706
2707QSettings::QSettings(Scope scope)
2708 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope,
2709# ifdef Q_OS_DARWIN
2710 QCoreApplication::organizationDomain().isEmpty()
2711 ? QCoreApplication::organizationName()
2712 : QCoreApplication::organizationDomain()
2713# else
2714 QCoreApplication::organizationName().isEmpty()
2715 ? QCoreApplication::organizationDomain()
2716 : QCoreApplication::organizationName()
2717# endif
2718 , QCoreApplication::applicationName())
2719 )
2720{
2721 d_ptr->q_ptr = this;
2722}
2723#endif
2724
2725/*!
2726 Destroys the QSettings object.
2727
2728 Any unsaved changes will eventually be written to permanent
2729 storage.
2730
2731 \sa sync()
2732*/
2733QSettings::~QSettings()
2734{
2735 Q_D(QSettings);
2736 if (d->pendingChanges) {
2737 // Don't cause a failing flush() to std::terminate() the whole
2738 // application - dtors are implicitly noexcept!
2739 QT_TRY {
2740 d->flush();
2741 } QT_CATCH(...) {
2742 }
2743 }
2744}
2745
2746/*!
2747 Removes all entries in the primary location associated to this
2748 QSettings object.
2749
2750 Entries in fallback locations are not removed.
2751
2752 If you only want to remove the entries in the current group(),
2753 use remove("") instead.
2754
2755 \sa remove(), setFallbacksEnabled()
2756*/
2757void QSettings::clear()
2758{
2759 Q_D(QSettings);
2760 d->clear();
2761 d->requestUpdate();
2762}
2763
2764/*!
2765 Writes any unsaved changes to permanent storage, and reloads any
2766 settings that have been changed in the meantime by another
2767 application.
2768
2769 This function is called automatically from QSettings's destructor and
2770 by the event loop at regular intervals, so you normally don't need to
2771 call it yourself.
2772
2773 \sa status()
2774*/
2775void QSettings::sync()
2776{
2777 Q_D(QSettings);
2778 d->sync();
2779 d->pendingChanges = false;
2780}
2781
2782/*!
2783 Returns the path where settings written using this QSettings
2784 object are stored.
2785
2786 On Windows, if the format is QSettings::NativeFormat, the return value
2787 is a system registry path, not a file path.
2788
2789 \sa isWritable(), format()
2790*/
2791QString QSettings::fileName() const
2792{
2793 Q_D(const QSettings);
2794 return d->fileName();
2795}
2796
2797/*!
2798 \since 4.4
2799
2800 Returns the format used for storing the settings.
2801
2802 \sa defaultFormat(), fileName(), scope(), organizationName(), applicationName()
2803*/
2804QSettings::Format QSettings::format() const
2805{
2806 Q_D(const QSettings);
2807 return d->format;
2808}
2809
2810/*!
2811 \since 4.4
2812
2813 Returns the scope used for storing the settings.
2814
2815 \sa format(), organizationName(), applicationName()
2816*/
2817QSettings::Scope QSettings::scope() const
2818{
2819 Q_D(const QSettings);
2820 return d->scope;
2821}
2822
2823/*!
2824 \since 4.4
2825
2826 Returns the organization name used for storing the settings.
2827
2828 \sa QCoreApplication::organizationName(), format(), scope(), applicationName()
2829*/
2830QString QSettings::organizationName() const
2831{
2832 Q_D(const QSettings);
2833 return d->organizationName;
2834}
2835
2836/*!
2837 \since 4.4
2838
2839 Returns the application name used for storing the settings.
2840
2841 \sa QCoreApplication::applicationName(), format(), scope(), organizationName()
2842*/
2843QString QSettings::applicationName() const
2844{
2845 Q_D(const QSettings);
2846 return d->applicationName;
2847}
2848
2849/*!
2850 Returns a status code indicating the first error that was met by
2851 QSettings, or QSettings::NoError if no error occurred.
2852
2853 Be aware that QSettings delays performing some operations. For this
2854 reason, you might want to call sync() to ensure that the data stored
2855 in QSettings is written to disk before calling status().
2856
2857 \sa sync()
2858*/
2859QSettings::Status QSettings::status() const
2860{
2861 Q_D(const QSettings);
2862 return d->status;
2863}
2864
2865/*!
2866 \since 5.10
2867
2868 Returns \c true if QSettings is only allowed to perform atomic saving and
2869 reloading (synchronization) of the settings. Returns \c false if it is
2870 allowed to save the settings contents directly to the configuration file.
2871
2872 The default is \c true.
2873
2874 \sa setAtomicSyncRequired(), QSaveFile
2875*/
2876bool QSettings::isAtomicSyncRequired() const
2877{
2878 Q_D(const QSettings);
2879 return d->atomicSyncOnly;
2880}
2881
2882/*!
2883 \since 5.10
2884
2885 Configures whether QSettings is required to perform atomic saving and
2886 reloading (synchronization) of the settings. If the \a enable argument is
2887 \c true (the default), sync() will only perform synchronization operations
2888 that are atomic. If this is not possible, sync() will fail and status()
2889 will be an error condition.
2890
2891 Setting this property to \c false will allow QSettings to write directly to
2892 the configuration file and ignore any errors trying to lock it against
2893 other processes trying to write at the same time. Because of the potential
2894 for corruption, this option should be used with care, but is required in
2895 certain conditions, like a QSettings::IniFormat configuration file that
2896 exists in an otherwise non-writeable directory or NTFS Alternate Data
2897 Streams.
2898
2899 See \l QSaveFile for more information on the feature.
2900
2901 \sa isAtomicSyncRequired(), QSaveFile
2902*/
2903void QSettings::setAtomicSyncRequired(bool enable)
2904{
2905 Q_D(QSettings);
2906 d->atomicSyncOnly = enable;
2907}
2908
2909/*!
2910 Appends \a prefix to the current group.
2911
2912 The current group is automatically prepended to all keys
2913 specified to QSettings. In addition, query functions such as
2914 childGroups(), childKeys(), and allKeys() are based on the group.
2915 By default, no group is set.
2916
2917 Groups are useful to avoid typing in the same setting paths over
2918 and over. For example:
2919
2920 \snippet code/src_corelib_io_qsettings.cpp 13
2921
2922 This will set the value of three settings:
2923
2924 \list
2925 \li \c mainwindow/size
2926 \li \c mainwindow/active
2927 \li \c outputpanel/visible
2928 \endlist
2929
2930 Call endGroup() to reset the current group to what it was before
2931 the corresponding beginGroup() call. Groups can be nested.
2932
2933 \note In Qt versions prior to 6.4, this function took QString, not
2934 QAnyStringView.
2935
2936 \sa endGroup(), group()
2937*/
2938void QSettings::beginGroup(QAnyStringView prefix)
2939{
2940 Q_D(QSettings);
2941 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
2942}
2943
2944/*!
2945 Resets the group to what it was before the corresponding
2946 beginGroup() call.
2947
2948 Example:
2949
2950 \snippet code/src_corelib_io_qsettings.cpp 14
2951
2952 \sa beginGroup(), group()
2953*/
2954void QSettings::endGroup()
2955{
2956 Q_D(QSettings);
2957 if (d->groupStack.isEmpty()) {
2958 qWarning("QSettings::endGroup: No matching beginGroup()");
2959 return;
2960 }
2961
2962 QSettingsGroup group = d->groupStack.pop();
2963 qsizetype len = group.toString().size();
2964 if (len > 0)
2965 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
2966
2967 if (group.isArray())
2968 qWarning("QSettings::endGroup: Expected endArray() instead");
2969}
2970
2971/*!
2972 Returns the current group.
2973
2974 \sa beginGroup(), endGroup()
2975*/
2976QString QSettings::group() const
2977{
2978 Q_D(const QSettings);
2979 return d->groupPrefix.left(d->groupPrefix.size() - 1);
2980}
2981
2982/*!
2983 Adds \a prefix to the current group and starts reading from an
2984 array. Returns the size of the array.
2985
2986 Example:
2987
2988 \snippet code/src_corelib_io_qsettings.cpp 15
2989
2990 Use beginWriteArray() to write the array in the first place.
2991
2992 \note In Qt versions prior to 6.4, this function took QString, not
2993 QAnyStringView.
2994
2995 \sa beginWriteArray(), endArray(), setArrayIndex()
2996*/
2997int QSettings::beginReadArray(QAnyStringView prefix)
2998{
2999 Q_D(QSettings);
3000 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
3001 return value("size"_L1).toInt();
3002}
3003
3004/*!
3005 Adds \a prefix to the current group and starts writing an array
3006 of size \a size. If \a size is -1 (the default), it is automatically
3007 determined based on the indexes of the entries written.
3008
3009 If you have many occurrences of a certain set of keys, you can
3010 use arrays to make your life easier. For example, let's suppose
3011 that you want to save a variable-length list of user names and
3012 passwords. You could then write:
3013
3014 \snippet code/src_corelib_io_qsettings.cpp 16
3015
3016 The generated keys will have the form
3017
3018 \list
3019 \li \c logins/size
3020 \li \c logins/1/userName
3021 \li \c logins/1/password
3022 \li \c logins/2/userName
3023 \li \c logins/2/password
3024 \li \c logins/3/userName
3025 \li \c logins/3/password
3026 \li ...
3027 \endlist
3028
3029 To read back an array, use beginReadArray().
3030
3031 \note In Qt versions prior to 6.4, this function took QString, not
3032 QAnyStringView.
3033
3034 \sa beginReadArray(), endArray(), setArrayIndex()
3035*/
3036void QSettings::beginWriteArray(QAnyStringView prefix, int size)
3037{
3038 Q_D(QSettings);
3039 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
3040
3041 if (size < 0)
3042 remove("size"_L1);
3043 else
3044 setValue("size"_L1, size);
3045}
3046
3047/*!
3048 Closes the array that was started using beginReadArray() or
3049 beginWriteArray().
3050
3051 \sa beginReadArray(), beginWriteArray()
3052*/
3053void QSettings::endArray()
3054{
3055 Q_D(QSettings);
3056 if (d->groupStack.isEmpty()) {
3057 qWarning("QSettings::endArray: No matching beginArray()");
3058 return;
3059 }
3060
3061 QSettingsGroup group = d->groupStack.top();
3062 qsizetype len = group.toString().size();
3063 d->groupStack.pop();
3064 if (len > 0)
3065 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3066
3067 if (group.arraySizeGuess() != -1)
3068 setValue(group.name() + "/size"_L1, group.arraySizeGuess());
3069
3070 if (!group.isArray())
3071 qWarning("QSettings::endArray: Expected endGroup() instead");
3072}
3073
3074/*!
3075 Sets the current array index to \a i. Calls to functions such as
3076 setValue(), value(), remove(), and contains() will operate on the
3077 array entry at that index.
3078
3079 You must call beginReadArray() or beginWriteArray() before you
3080 can call this function.
3081*/
3082void QSettings::setArrayIndex(int i)
3083{
3084 Q_D(QSettings);
3085 if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3086 qWarning("QSettings::setArrayIndex: Missing beginArray()");
3087 return;
3088 }
3089
3090 QSettingsGroup &top = d->groupStack.top();
3091 qsizetype len = top.toString().size();
3092 top.setArrayIndex(qMax(i, 0));
3093 d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
3094}
3095
3096/*!
3097 Returns a list of all keys, including subkeys, that can be read
3098 using the QSettings object.
3099
3100 Example:
3101
3102 \snippet code/src_corelib_io_qsettings.cpp 17
3103
3104 If a group is set using beginGroup(), only the keys in the group
3105 are returned, without the group prefix:
3106
3107 \snippet code/src_corelib_io_qsettings.cpp 18
3108
3109 \sa childGroups(), childKeys()
3110*/
3111QStringList QSettings::allKeys() const
3112{
3113 Q_D(const QSettings);
3114 return d->children(d->groupPrefix, QSettingsPrivate::AllKeys);
3115}
3116
3117/*!
3118 Returns a list of all top-level keys that can be read using the
3119 QSettings object.
3120
3121 Example:
3122
3123 \snippet code/src_corelib_io_qsettings.cpp 19
3124
3125 If a group is set using beginGroup(), the top-level keys in that
3126 group are returned, without the group prefix:
3127
3128 \snippet code/src_corelib_io_qsettings.cpp 20
3129
3130 You can navigate through the entire setting hierarchy using
3131 childKeys() and childGroups() recursively.
3132
3133 \sa childGroups(), allKeys()
3134*/
3135QStringList QSettings::childKeys() const
3136{
3137 Q_D(const QSettings);
3138 return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys);
3139}
3140
3141/*!
3142 Returns a list of all key top-level groups that contain keys that
3143 can be read using the QSettings object.
3144
3145 Example:
3146
3147 \snippet code/src_corelib_io_qsettings.cpp 21
3148
3149 If a group is set using beginGroup(), the first-level keys in
3150 that group are returned, without the group prefix.
3151
3152 \snippet code/src_corelib_io_qsettings.cpp 22
3153
3154 You can navigate through the entire setting hierarchy using
3155 childKeys() and childGroups() recursively.
3156
3157 \sa childKeys(), allKeys()
3158*/
3159QStringList QSettings::childGroups() const
3160{
3161 Q_D(const QSettings);
3162 return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups);
3163}
3164
3165/*!
3166 Returns \c true if settings can be written using this QSettings
3167 object; returns \c false otherwise.
3168
3169 One reason why isWritable() might return false is if
3170 QSettings operates on a read-only file.
3171
3172 \warning This function is not perfectly reliable, because the
3173 file permissions can change at any time.
3174
3175 \sa fileName(), status(), sync()
3176*/
3177bool QSettings::isWritable() const
3178{
3179 Q_D(const QSettings);
3180 return d->isWritable();
3181}
3182
3183/*!
3184
3185 Sets the value of setting \a key to \a value. If the \a key already
3186 exists, the previous value is overwritten.
3187
3188//! [key-case-sensitivity]
3189 Key lookup will either be sensitive or insensitive to case depending on
3190 file format and operating system. To avoid portability problems, see the
3191 \l{Section and Key Syntax} rules.
3192//! [key-case-sensitivity]
3193
3194 Example:
3195
3196 \snippet code/src_corelib_io_qsettings.cpp 23
3197
3198 \note In Qt versions prior to 6.4, this function took QString, not
3199 QAnyStringView.
3200
3201 \sa value(), remove(), contains()
3202*/
3203void QSettings::setValue(QAnyStringView key, const QVariant &value)
3204{
3205 Q_D(QSettings);
3206 if (key.isEmpty()) {
3207 qWarning("QSettings::setValue: Empty key passed");
3208 return;
3209 }
3210 d->set(d->actualKey(key), value);
3211 d->requestUpdate();
3212}
3213
3214/*!
3215 Removes the setting \a key and any sub-settings of \a key.
3216
3217 Example:
3218
3219 \snippet code/src_corelib_io_qsettings.cpp 24
3220
3221 Be aware that if one of the fallback locations contains a setting
3222 with the same key, that setting will be visible after calling
3223 remove().
3224
3225 If \a key is an empty string, all keys in the current group() are
3226 removed. For example:
3227
3228 \snippet code/src_corelib_io_qsettings.cpp 25
3229
3230 \include qsettings.cpp key-case-sensitivity
3231
3232 \note In Qt versions prior to 6.4, this function took QString, not
3233 QAnyStringView.
3234
3235 \sa setValue(), value(), contains()
3236*/
3237void QSettings::remove(QAnyStringView key)
3238{
3239 Q_D(QSettings);
3240 /*
3241 We cannot use actualKey(), because remove() supports empty
3242 keys. The code is also tricky because of slash handling.
3243 */
3244 QString theKey = d->normalizedKey(key);
3245 if (theKey.isEmpty())
3246 theKey = group();
3247 else
3248 theKey.prepend(d->groupPrefix);
3249
3250 if (theKey.isEmpty()) {
3251 d->clear();
3252 } else {
3253 d->remove(theKey);
3254 }
3255 d->requestUpdate();
3256}
3257
3258/*!
3259 Returns \c true if there exists a setting called \a key; returns
3260 false otherwise.
3261
3262 If a group is set using beginGroup(), \a key is taken to be
3263 relative to that group.
3264
3265 \include qsettings.cpp key-case-sensitivity
3266
3267 \note In Qt versions prior to 6.4, this function took QString, not
3268 QAnyStringView.
3269
3270 \sa value(), setValue()
3271*/
3272bool QSettings::contains(QAnyStringView key) const
3273{
3274 Q_D(const QSettings);
3275 return d->get(d->actualKey(key)) != std::nullopt;
3276}
3277
3278/*!
3279 Sets whether fallbacks are enabled to \a b.
3280
3281 By default, fallbacks are enabled.
3282
3283 \sa fallbacksEnabled()
3284*/
3285void QSettings::setFallbacksEnabled(bool b)
3286{
3287 Q_D(QSettings);
3288 d->fallbacks = !!b;
3289}
3290
3291/*!
3292 Returns \c true if fallbacks are enabled; returns \c false otherwise.
3293
3294 By default, fallbacks are enabled.
3295
3296 \sa setFallbacksEnabled()
3297*/
3298bool QSettings::fallbacksEnabled() const
3299{
3300 Q_D(const QSettings);
3301 return d->fallbacks;
3302}
3303
3304#ifndef QT_NO_QOBJECT
3305/*!
3306 \reimp
3307*/
3308bool QSettings::event(QEvent *event)
3309{
3310 Q_D(QSettings);
3311 if (event->type() == QEvent::UpdateRequest) {
3312 d->update();
3313 return true;
3314 }
3315 return QObject::event(event);
3316}
3317#endif
3318
3319/*!
3320 \fn QSettings::value(QAnyStringView key) const
3321 \fn QSettings::value(QAnyStringView key, const QVariant &defaultValue) const
3322
3323 Returns the value for setting \a key. If the setting doesn't
3324 exist, returns \a defaultValue.
3325
3326 If no default value is specified, a default QVariant is
3327 returned.
3328
3329 \include qsettings.cpp key-case-sensitivity
3330
3331 Example:
3332
3333 \snippet code/src_corelib_io_qsettings.cpp 26
3334
3335 \note In Qt versions prior to 6.4, this function took QString, not
3336 QAnyStringView.
3337
3338 \sa setValue(), contains(), remove()
3339*/
3340QVariant QSettings::value(QAnyStringView key) const
3341{
3342 Q_D(const QSettings);
3343 return d->value(key, nullptr);
3344}
3345
3346QVariant QSettings::value(QAnyStringView key, const QVariant &defaultValue) const
3347{
3348 Q_D(const QSettings);
3349 return d->value(key, &defaultValue);
3350}
3351
3352QVariant QSettingsPrivate::value(QAnyStringView key, const QVariant *defaultValue) const
3353{
3354 if (key.isEmpty()) {
3355 qWarning("QSettings::value: Empty key passed");
3356 return QVariant();
3357 }
3358 if (std::optional r = get(actualKey(key)))
3359 return std::move(*r);
3360 if (defaultValue)
3361 return *defaultValue;
3362 return QVariant();
3363}
3364
3365/*!
3366 \since 4.4
3367
3368 Sets the default file format to the given \a format, which is used
3369 for storing settings for the QSettings(QObject *) constructor.
3370
3371 If no default format is set, QSettings::NativeFormat is used. See
3372 the documentation for the QSettings constructor you are using to
3373 see if that constructor will ignore this function.
3374
3375 \sa format()
3376*/
3377void QSettings::setDefaultFormat(Format format)
3378{
3379 globalDefaultFormat = format;
3380}
3381
3382/*!
3383 \since 4.4
3384
3385 Returns default file format used for storing settings for the QSettings(QObject *) constructor.
3386 If no default format is set, QSettings::NativeFormat is used.
3387
3388 \sa format()
3389*/
3390QSettings::Format QSettings::defaultFormat()
3391{
3392 return globalDefaultFormat;
3393}
3394
3395/*!
3396 \since 4.1
3397
3398 Sets the path used for storing settings for the given \a format
3399 and \a scope, to \a path. The \a format can be a custom format.
3400
3401 The table below summarizes the default values:
3402
3403 \table
3404 \header \li Platform \li Format \li Scope \li Path
3405 \row \li{1,2} Windows \li{1,2} IniFormat \li UserScope \li \c FOLDERID_RoamingAppData
3406 \row \li SystemScope \li \c FOLDERID_ProgramData
3407 \row \li{1,2} Unix \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/.config
3408 \row \li SystemScope \li \c /etc/xdg
3409 \row \li{1,2} \macos and iOS \li{1,2} IniFormat \li UserScope \li \c $HOME/.config
3410 \row \li SystemScope \li \c /etc/xdg
3411 \endtable
3412
3413 The default UserScope paths on Unix, \macos, and iOS (\c
3414 $HOME/.config or $HOME/Settings) can be overridden by the user by setting the
3415 \c XDG_CONFIG_HOME environment variable. The default SystemScope
3416 paths on Unix, \macos, and iOS (\c /etc/xdg) can be overridden when
3417 building the Qt library using the \c configure script's \c
3418 -sysconfdir flag (see QLibraryInfo for details).
3419
3420 Setting the NativeFormat paths on Windows, \macos, and iOS has no
3421 effect.
3422
3423 \warning This function doesn't affect existing QSettings objects.
3424
3425 \sa registerFormat()
3426*/
3427void QSettings::setPath(Format format, Scope scope, const QString &path)
3428{
3429 auto locker = qt_unique_lock(settingsGlobalMutex);
3430 PathHash *pathHash = pathHashFunc();
3431 if (pathHash->isEmpty())
3432 locker = initDefaultPaths(std::move(locker));
3433 pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
3434}
3435
3436/*!
3437 \typedef QSettings::SettingsMap
3438
3439 Typedef for QMap<QString, QVariant>.
3440
3441 \sa registerFormat()
3442*/
3443
3444/*!
3445 \typedef QSettings::ReadFunc
3446
3447 Typedef for a pointer to a function with the following signature:
3448
3449 \snippet code/src_corelib_io_qsettings.cpp 27
3450
3451 \c ReadFunc is used in \c registerFormat() as a pointer to a function
3452 that reads a set of key/value pairs. \c ReadFunc should read all the
3453 options in one pass, and return all the settings in the \c SettingsMap
3454 container, which is initially empty.
3455
3456 \sa WriteFunc, registerFormat()
3457*/
3458
3459/*!
3460 \typedef QSettings::WriteFunc
3461
3462 Typedef for a pointer to a function with the following signature:
3463
3464 \snippet code/src_corelib_io_qsettings.cpp 28
3465
3466 \c WriteFunc is used in \c registerFormat() as a pointer to a function
3467 that writes a set of key/value pairs. \c WriteFunc is only called once,
3468 so you need to output the settings in one go.
3469
3470 \sa ReadFunc, registerFormat()
3471*/
3472
3473/*!
3474 \since 4.1
3475 \threadsafe
3476
3477 Registers a custom storage format. On success, returns a special
3478 Format value that can then be passed to the QSettings constructor.
3479 On failure, returns InvalidFormat.
3480
3481 The \a extension is the file
3482 extension associated to the format (without the '.').
3483
3484 The \a readFunc and \a writeFunc parameters are pointers to
3485 functions that read and write a set of key/value pairs. The
3486 QIODevice parameter to the read and write functions is always
3487 opened in binary mode (i.e., without the \l QIODeviceBase::Text flag).
3488
3489 The \a caseSensitivity parameter specifies whether keys are case-sensitive
3490 or not. This makes a difference when looking up values using QSettings. The
3491 default is case-sensitive. The parameter must be \c{Qt::CaseSensitive} on
3492 Unix systems.
3493
3494 By default, if you use one of the constructors that work in terms
3495 of an organization name and an application name, the file system
3496 locations used are the same as for IniFormat. Use setPath() to
3497 specify other locations.
3498
3499 Example:
3500
3501 \snippet code/src_corelib_io_qsettings.cpp 29
3502
3503 \sa setPath()
3504*/
3505QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc,
3506 WriteFunc writeFunc,
3507 Qt::CaseSensitivity caseSensitivity)
3508{
3510 Q_ASSERT(caseSensitivity == Qt::CaseSensitive);
3511#endif
3512
3513 const auto locker = qt_scoped_lock(settingsGlobalMutex);
3514 CustomFormatVector *customFormatVector = customFormatVectorFunc();
3515 qsizetype index = customFormatVector->size();
3516 if (index == 16) // the QSettings::Format enum has room for 16 custom formats
3517 return QSettings::InvalidFormat;
3518
3519 QConfFileCustomFormat info;
3520 info.extension = u'.' + extension;
3521 info.readFunc = readFunc;
3522 info.writeFunc = writeFunc;
3523 info.caseSensitivity = caseSensitivity;
3524 customFormatVector->append(info);
3525
3526 return QSettings::Format(int(QSettings::CustomFormat1) + index);
3527}
3528
3529QT_END_NAMESPACE
3530
3531#ifndef QT_BOOTSTRAPPED
3532#include "moc_qsettings.cpp"
3533#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
\inmodule QtCore
Definition qfile.h:96
\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