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