diff options
Diffstat (limited to 'src/corelib/io/qsettings.cpp')
-rw-r--r-- | src/corelib/io/qsettings.cpp | 288 |
1 files changed, 169 insertions, 119 deletions
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 88768f9511..6934ca4404 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -44,12 +44,13 @@ # include <shlobj.h> #endif -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID) +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) #define Q_XDG_PLATFORM #endif -#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT)) -#define QSETTINGS_USE_QSTANDARDPATHS +#if !defined(QT_NO_STANDARDPATHS) \ + && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID)) +# define QSETTINGS_USE_QSTANDARDPATHS #endif // ************************************************************************ @@ -65,6 +66,7 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +using namespace QtMiscUtils; struct QConfFileCustomFormat { @@ -127,12 +129,12 @@ bool QConfFile::isWritable() const { QFileInfo fileInfo(name); -#ifndef QT_NO_TEMPORARYFILE +#if QT_CONFIG(temporaryfile) if (fileInfo.exists()) { #endif QFile file(name); return file.open(QFile::ReadWrite); -#ifndef QT_NO_TEMPORARYFILE +#if QT_CONFIG(temporaryfile) } else { // Create the directories to the file. QDir dir(fileInfo.absolutePath()); @@ -210,9 +212,7 @@ namespace { } QChar *write(QChar *out, QLatin1StringView v) { - for (char ch : v) - *out++ = QLatin1Char(ch); - return out; + return QLatin1::convertToUnicode(out, v); } QChar *write(QChar *out, QStringView v) { @@ -270,7 +270,7 @@ QString QSettingsPrivate::normalizedKey(QAnyStringView key) // see also qsettings_win.cpp and qsettings_mac.cpp -#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_WASM) +#if !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN) && !defined(Q_OS_WASM) QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application) { @@ -342,7 +342,7 @@ void QSettingsPrivate::requestUpdate() QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l) { QStringList result; - result.reserve(l.count()); + result.reserve(l.size()); for (auto v : l) result.append(variantToString(v)); return result; @@ -355,9 +355,9 @@ QVariant QSettingsPrivate::stringListToVariantList(const QStringList &l) const QString &str = outStringList.at(i); if (str.startsWith(u'@')) { - if (str.length() < 2 || str.at(1) != u'@') { + if (str.size() < 2 || str.at(1) != u'@') { QVariantList variantList; - variantList.reserve(l.count()); + variantList.reserve(l.size()); for (const auto &s : l) variantList.append(stringToVariant(s)); return variantList; @@ -379,9 +379,7 @@ QString QSettingsPrivate::variantToString(const QVariant &v) case QMetaType::QByteArray: { QByteArray a = v.toByteArray(); - result = "@ByteArray("_L1 - + QLatin1StringView(a.constData(), a.size()) - + u')'; + result = "@ByteArray("_L1 + QLatin1StringView(a) + u')'; break; } @@ -510,14 +508,13 @@ QVariant QSettingsPrivate::stringToVariant(const QString &s) void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result) { - result.reserve(result.length() + key.length() * 3 / 2); + result.reserve(result.size() + key.size() * 3 / 2); for (qsizetype i = 0; i < key.size(); ++i) { uint ch = key.at(i).unicode(); if (ch == '/') { result += '\\'; - } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') - || ch == '_' || ch == '-' || ch == '.') { + } else if (isAsciiLetterOrNumber(ch) || ch == '_' || ch == '-' || ch == '.') { result += (char)ch; } else if (ch <= 0xFF) { result += '%'; @@ -539,7 +536,7 @@ bool QSettingsPrivate::iniUnescapedKey(QByteArrayView key, QString &result) { const QString decoded = QString::fromUtf8(key); const qsizetype size = decoded.size(); - result.reserve(result.length() + size); + result.reserve(result.size() + size); qsizetype i = 0; bool lowercaseOnly = true; while (i < size) { @@ -561,7 +558,7 @@ bool QSettingsPrivate::iniUnescapedKey(QByteArrayView key, QString &result) } int numDigits = 2; - int firstDigitPos = i + 1; + qsizetype firstDigitPos = i + 1; ch = decoded.at(i + 1).unicode(); if (ch == 'U') { @@ -596,25 +593,20 @@ void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result) { bool needsQuotes = false; bool escapeNextIfDigit = false; - bool useCodec = !str.startsWith("@ByteArray("_L1) - && !str.startsWith("@Variant("_L1) - && !str.startsWith("@DateTime("_L1); + const bool useCodec = !(str.startsWith("@ByteArray("_L1) + || str.startsWith("@Variant("_L1) + || str.startsWith("@DateTime("_L1)); + const qsizetype startPos = result.size(); QStringEncoder toUtf8(QStringEncoder::Utf8); - qsizetype startPos = result.size(); result.reserve(startPos + str.size() * 3 / 2); - - const QChar *unicode = str.unicode(); - for (qsizetype i = 0; i < str.size(); ++i) { - uint ch = unicode[i].unicode(); + for (QChar qch : str) { + uint ch = qch.unicode(); if (ch == ';' || ch == ',' || ch == '=') needsQuotes = true; - if (escapeNextIfDigit - && ((ch >= '0' && ch <= '9') - || (ch >= 'a' && ch <= 'f') - || (ch >= 'A' && ch <= 'F'))) { + if (escapeNextIfDigit && isHexDigit(ch)) { result += "\\x" + QByteArray::number(ch, 16); continue; } @@ -658,7 +650,7 @@ void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result) escapeNextIfDigit = true; } else if (useCodec) { // slow - result += toUtf8(unicode[i]); + result += toUtf8(qch); } else { result += (char)ch; } @@ -734,7 +726,7 @@ StSkipSpaces: // fallthrough StNormal: - qsizetype chopLimit = stringResult.length(); + qsizetype chopLimit = stringResult.size(); while (i < str.size()) { switch (str.at(i)) { case '\\': @@ -757,10 +749,10 @@ StNormal: goto end; ch = str.at(i); - if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) + if (isHexDigit(ch)) goto StHexEscape; - } else if (ch >= '0' && ch <= '7') { - escapeVal = ch - '0'; + } else if (const int o = fromOct(ch); o != -1) { + escapeVal = o; goto StOctEscape; } else if (ch == '\n' || ch == '\r') { if (i < str.size()) { @@ -772,7 +764,7 @@ StNormal: } else { // the character is skipped } - chopLimit = stringResult.length(); + chopLimit = stringResult.size(); break; case '"': ++i; @@ -822,11 +814,9 @@ StHexEscape: } ch = str.at(i); - if (ch >= 'a') - ch -= 'a' - 'A'; - if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) { + if (const int h = fromHex(ch); h != -1) { escapeVal <<= 4; - escapeVal += QtMiscUtils::fromHex(ch); + escapeVal += h; ++i; goto StHexEscape; } else { @@ -841,9 +831,9 @@ StOctEscape: } ch = str.at(i); - if (ch >= '0' && ch <= '7') { + if (const int o = fromOct(ch); o != -1) { escapeVal <<= 3; - escapeVal += ch - '0'; + escapeVal += o; ++i; goto StOctEscape; } else { @@ -859,7 +849,7 @@ end: QStringList QSettingsPrivate::splitArgs(const QString &s, qsizetype idx) { - qsizetype l = s.length(); + qsizetype l = s.size(); Q_ASSERT(l > 0); Q_ASSERT(s.at(idx) == u'('); Q_ASSERT(s.at(l - 1) == u')'); @@ -888,16 +878,26 @@ QStringList QSettingsPrivate::splitArgs(const QString &s, qsizetype idx) void QConfFileSettingsPrivate::initFormat() { +#if defined(Q_OS_WASM) + extension = (format == QSettings::NativeFormat || format == QSettings::WebIndexedDBFormat) + ? ".conf"_L1 + : ".ini"_L1; +#else extension = (format == QSettings::NativeFormat) ? ".conf"_L1 : ".ini"_L1; +#endif readFunc = nullptr; writeFunc = nullptr; -#if defined(Q_OS_MAC) +#if defined(Q_OS_DARWIN) caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity; #else caseSensitivity = IniCaseSensitivity; #endif +#if defined Q_OS_WASM + if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) { +#else if (format > QSettings::IniFormat) { +#endif const auto locker = qt_scoped_lock(settingsGlobalMutex); const CustomFormatVector *customFormatVector = customFormatVectorFunc(); @@ -915,7 +915,11 @@ void QConfFileSettingsPrivate::initFormat() void QConfFileSettingsPrivate::initAccess() { if (!confFiles.isEmpty()) { +#if defined Q_OS_WASM + if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat) { +#else if (format > QSettings::IniFormat) { +#endif if (!readFunc) setStatus(QSettings::AccessError); } @@ -953,26 +957,43 @@ static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope) } #ifndef Q_OS_WIN -static QString make_user_path() +static constexpr QChar sep = u'/'; + +#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID) +static QString make_user_path_without_qstandard_paths() { - static constexpr QChar sep = u'/'; -#ifndef QSETTINGS_USE_QSTANDARDPATHS - // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously - // for some time now. Moving away from that would require migrating existing settings. QByteArray env = qgetenv("XDG_CONFIG_HOME"); if (env.isEmpty()) { return QDir::homePath() + "/.config/"_L1; } else if (env.startsWith('/')) { return QFile::decodeName(env) + sep; - } else { - return QDir::homePath() + sep + QFile::decodeName(env) + sep; } + + return QDir::homePath() + sep + QFile::decodeName(env) + sep; +} +#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID + +static QString make_user_path() +{ +#ifndef QSETTINGS_USE_QSTANDARDPATHS + // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously + // for some time now. Moving away from that would require migrating existing settings. + // The migration has already been done for Android. + return make_user_path_without_qstandard_paths(); #else - // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code; - // it makes the use of test mode from unit tests possible. + +#ifdef Q_OS_ANDROID + // If an old settings path exists, use it instead of creating a new one + QString ret = make_user_path_without_qstandard_paths(); + if (QFile(ret).exists()) + return ret; +#endif // Q_OS_ANDROID + + // When using a proper XDG platform or Android platform, use QStandardPaths rather than the + // above hand-written code. It makes the use of test mode from unit tests possible. // Ideally all platforms should use this, but see above for the migration issue. return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep; -#endif +#endif // !QSETTINGS_USE_QSTANDARDPATHS } #endif // !Q_OS_WIN @@ -1008,7 +1029,7 @@ static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMut const QString userPath = make_user_path(); pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false)); pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false)); -#ifndef Q_OS_MAC +#ifndef Q_OS_DARWIN pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false)); pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false)); #endif @@ -1084,16 +1105,16 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, QStringList paths; if (!application.isEmpty()) { paths.reserve(dirs.size() * 2); - for (const auto &dir : qAsConst(dirs)) + for (const auto &dir : std::as_const(dirs)) paths.append(dir + u'/' + appFile); } else { paths.reserve(dirs.size()); } - for (const auto &dir : qAsConst(dirs)) + for (const auto &dir : std::as_const(dirs)) paths.append(dir + u'/' + orgFile); // Note: No check for existence of files is done intentionally. - for (const auto &path : qAsConst(paths)) + for (const auto &path : std::as_const(paths)) confFiles.append(QConfFile::fromName(path, false)); } else #endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS @@ -1103,9 +1124,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format, confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false)); } -#ifndef Q_OS_WASM // wasm needs to delay access until after file sync initAccess(); -#endif } QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName, @@ -1126,7 +1145,7 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate() ConfFileHash *usedHash = usedHashFunc(); ConfFileCache *unusedCache = unusedCacheFunc(); - for (auto conf_file : qAsConst(confFiles)) { + for (auto conf_file : std::as_const(confFiles)) { if (!conf_file->ref.deref()) { if (conf_file->size == 0) { delete conf_file; @@ -1200,7 +1219,7 @@ std::optional<QVariant> QConfFileSettingsPrivate::get(const QString &key) const ParsedSettingsMap::const_iterator j; bool found = false; - for (auto confFile : qAsConst(confFiles)) { + for (auto confFile : std::as_const(confFiles)) { const auto locker = qt_scoped_lock(confFile->mutex); if (!confFile->addedKeys.isEmpty()) { @@ -1229,7 +1248,7 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec QSettingsKey thePrefix(prefix, caseSensitivity); qsizetype startPos = prefix.size(); - for (auto confFile : qAsConst(confFiles)) { + for (auto confFile : std::as_const(confFiles)) { const auto locker = qt_scoped_lock(confFile->mutex); if (thePrefix.isEmpty()) @@ -1237,17 +1256,17 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec else ensureSectionParsed(confFile, thePrefix); - auto j = const_cast<const ParsedSettingsMap *>( - &confFile->originalKeys)->lowerBound( thePrefix); - while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) { - if (!confFile->removedKeys.contains(j.key())) - processChild(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result); - ++j; + const auto &originalKeys = confFile->originalKeys; + auto i = originalKeys.lowerBound(thePrefix); + while (i != originalKeys.end() && i.key().startsWith(thePrefix)) { + if (!confFile->removedKeys.contains(i.key())) + processChild(QStringView{i.key().originalCaseKey()}.sliced(startPos), spec, result); + ++i; } - j = const_cast<const ParsedSettingsMap *>( - &confFile->addedKeys)->lowerBound(thePrefix); - while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) { + const auto &addedKeys = confFile->addedKeys; + auto j = addedKeys.lowerBound(thePrefix); + while (j != addedKeys.end() && j.key().startsWith(thePrefix)) { processChild(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result); ++j; } @@ -1280,7 +1299,7 @@ void QConfFileSettingsPrivate::sync() // people probably won't be checking the status a whole lot, so in case of // error we just try to go on and make the best of it - for (auto confFile : qAsConst(confFiles)) { + for (auto confFile : std::as_const(confFiles)) { const auto locker = qt_scoped_lock(confFile->mutex); syncConfFile(confFile); } @@ -1302,7 +1321,11 @@ QString QConfFileSettingsPrivate::fileName() const bool QConfFileSettingsPrivate::isWritable() const { +#if defined(Q_OS_WASM) + if (format > QSettings::IniFormat && format != QSettings::WebIndexedDBFormat && !writeFunc) +#else if (format > QSettings::IniFormat && !writeFunc) +#endif return false; if (confFiles.isEmpty()) @@ -1315,13 +1338,13 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) { bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty(); + QFileInfo fileInfo(confFile->name); /* We can often optimize the read-only case, if the file on disk hasn't changed. */ if (readOnly && confFile->size > 0) { - QFileInfo fileInfo(confFile->name); - if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified()) + if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified(QTimeZone::UTC)) return; } @@ -1331,6 +1354,14 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) } #ifndef QT_BOOTSTRAPPED + QString lockFileName = confFile->name + ".lock"_L1; + +# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS) + // On android and if it is a content URL put the lock file in a + // writable location to prevent permissions issues and invalid paths. + if (confFile->name.startsWith("content:"_L1)) + lockFileName = make_user_path() + QFileInfo(lockFileName).fileName(); +# endif /* Use a lockfile in order to protect us against other QSettings instances trying to write the same settings at the same time. @@ -1338,7 +1369,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) We only need to lock if we are actually writing as only concurrent writes are a problem. Concurrent read and write are not a problem because the writing operation is atomic. */ - QLockFile lockFile(confFile->name + ".lock"_L1); + QLockFile lockFile(lockFileName); if (!readOnly && !lockFile.lock() && atomicSyncOnly) { setStatus(QSettings::AccessError); return; @@ -1349,13 +1380,13 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) We hold the lock. Let's reread the file if it has changed since last time we read it. */ - QFileInfo fileInfo(confFile->name); + fileInfo.refresh(); bool mustReadFile = true; bool createFile = !fileInfo.exists(); if (!readOnly) mustReadFile = (confFile->size != fileInfo.size() - || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified())); + || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified(QTimeZone::UTC))); if (mustReadFile) { confFile->unparsedIniSections.clear(); @@ -1373,7 +1404,14 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) */ if (file.isReadable() && file.size() != 0) { bool ok = false; -#ifdef Q_OS_MAC + +#ifdef Q_OS_WASM + if (format == QSettings::WebIndexedDBFormat) { + QByteArray data = file.readAll(); + ok = readIniFile(data, &confFile->unparsedIniSections); + } else +#endif +#ifdef Q_OS_DARWIN if (format == QSettings::NativeFormat) { QByteArray data = file.readAll(); ok = readPlistFile(data, &confFile->originalKeys); @@ -1401,7 +1439,7 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) } confFile->size = fileInfo.size(); - confFile->timeStamp = fileInfo.lastModified(); + confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC); } /* @@ -1416,6 +1454,11 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) #if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile) QSaveFile sf(confFile->name); sf.setDirectWriteFallback(!atomicSyncOnly); +# ifdef Q_OS_ANDROID + // QSaveFile requires direct write when using content scheme URL in Android + if (confFile->name.startsWith("content:"_L1)) + sf.setDirectWriteFallback(true); +# endif #else QFile sf(confFile->name); #endif @@ -1424,7 +1467,12 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) return; } -#ifdef Q_OS_MAC +#ifdef Q_OS_WASM + if (format == QSettings::WebIndexedDBFormat) { + ok = writeIniFile(sf, mergedKeys); + } else +#endif +#ifdef Q_OS_DARWIN if (format == QSettings::NativeFormat) { ok = writePlistFile(sf, mergedKeys); } else @@ -1453,9 +1501,9 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) confFile->addedKeys.clear(); confFile->removedKeys.clear(); - QFileInfo fileInfo(confFile->name); + fileInfo.refresh(); confFile->size = fileInfo.size(); - confFile->timeStamp = fileInfo.lastModified(); + confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC); // If we have created the file, apply the file perms if (createFile) { @@ -1470,6 +1518,8 @@ void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile) } } +namespace SettingsImpl { + enum { Space = 0x1, Special = 0x2 }; static const char charTraits[256] = @@ -1496,11 +1546,16 @@ static const char charTraits[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +} // namespace SettingsImpl + +using SettingsImpl::charTraits; + bool QConfFileSettingsPrivate::readIniLine(QByteArrayView data, qsizetype &dataPos, qsizetype &lineStart, qsizetype &lineLen, qsizetype &equalsPos) { - qsizetype dataLen = data.length(); + using namespace SettingsImpl; + qsizetype dataLen = data.size(); bool inQuotes = false; equalsPos = -1; @@ -1592,10 +1647,9 @@ bool QConfFileSettingsPrivate::readIniFile(QByteArrayView data, qsizetype sectionPosition = 0; bool ok = true; - // skip potential utf8 BOM - const uchar *dd = (const uchar *)data.constData(); - if (data.size() >= 3 && dd[0] == 0xef && dd[1] == 0xbb && dd[2] == 0xbf) - dataPos = 3; + // Skip possible UTF-8 BOM: + if (data.startsWith("\xef\xbb\xbf")) + data = data.sliced(3); while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) { QByteArrayView line = data.sliced(lineStart, lineLen); @@ -1616,7 +1670,7 @@ bool QConfFileSettingsPrivate::readIniFile(QByteArrayView data, currentSection.clear(); } else { if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) { - currentSection = QLatin1StringView(iniSection.constData() + 1); + currentSection = QLatin1StringView(iniSection.constData() + 1, iniSection.size() - 1); } else { currentSection.clear(); iniUnescapedKey(iniSection, currentSection); @@ -1628,7 +1682,7 @@ bool QConfFileSettingsPrivate::readIniFile(QByteArrayView data, ++position; } - Q_ASSERT(lineStart == data.length()); + Q_ASSERT(lineStart == data.size()); FLUSH_CURRENT_SECTION(); return ok; @@ -1667,27 +1721,22 @@ bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey §ion, QByte QByteArrayView value = line.sliced(equalsPos + 1); QString strKey = section.originalCaseKey(); - bool keyIsLowercase = iniUnescapedKey(key, strKey) && sectionIsLowercase; + const Qt::CaseSensitivity casing = iniUnescapedKey(key, strKey) && sectionIsLowercase + ? Qt::CaseSensitive + : IniCaseSensitivity; QString strValue; strValue.reserve(value.size()); - bool isStringList = iniUnescapedStringList(value, strValue, strListValue); - QVariant variant; - if (isStringList) { - variant = stringListToVariantList(strListValue); - } else { - variant = stringToVariant(strValue); - } + QVariant variant = iniUnescapedStringList(value, strValue, strListValue) + ? stringListToVariantList(strListValue) + : stringToVariant(strValue); /* We try to avoid the expensive toLower() call in QSettingsKey by passing Qt::CaseSensitive when the key is already in lowercase. */ - settingsMap->insert(QSettingsKey(strKey, keyIsLowercase ? Qt::CaseSensitive - : IniCaseSensitivity, - position), - variant); + settingsMap->insert(QSettingsKey(strKey, casing, position), std::move(variant)); ++position; } @@ -2079,10 +2128,6 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, as QString. The numeric value can be recovered using \l QString::toInt(), \l QString::toDouble() and related functions. - The \l{tools/settingseditor}{Settings Editor} example lets you - experiment with different settings location and with fallbacks - turned on or off. - \section1 Restoring the State of a GUI Application QSettings is often used to store the state of a GUI @@ -2108,9 +2153,6 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \codeline \snippet settings/settings.cpp 21 - See the \l{mainwindows/application}{Application} example for a - self-contained example that uses QSettings. - \section1 Accessing Settings from Multiple Threads or Processes Simultaneously QSettings is \l{reentrant}. This means that you can use @@ -2152,8 +2194,8 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, following files are used by default: \list 1 - \li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf}) - \li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf}) + \li \c{$HOME/.config/MySoft/Star Runner.conf} + \li \c{$HOME/.config/MySoft.conf} \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf} \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf} \endlist @@ -2190,8 +2232,8 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, used on Unix, \macos, and iOS: \list 1 - \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini}) - \li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini}) + \li \c{$HOME/.config/MySoft/Star Runner.ini} + \li \c{$HOME/.config/MySoft.ini} \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini} \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini} \endlist @@ -2326,7 +2368,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \endlist - \sa QVariant, QSessionManager, {Settings Editor Example}, {Qt Widgets - Application Example} + \sa QVariant, QSessionManager */ /*! \enum QSettings::Status @@ -2364,6 +2406,16 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, lose the distinction between numeric data and the strings used to encode them, so values written as numbers shall be read back as QString. + \value WebLocalStorageFormat + WASM only: Store the settings in window.localStorage for the current + origin. If cookies are not allowed, this falls back to the INI format. + This provides up to 5MiB storage per origin, but access to it is + synchronous and JSPI is not required. + \value WebIndexedDBFormat + WASM only: Store the settings in an Indexed DB for the current + origin. If cookies are not allowed, this falls back to the INI format. + This requires JSPI, but provides more storage than + WebLocalStorageFormat. \value InvalidFormat Special value returned by registerFormat(). \omitvalue CustomFormat1 @@ -2433,7 +2485,7 @@ void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile, \section2 Compatibility with older Qt versions Please note that this behavior is different to how QSettings behaved - in versions of Qt prior to Qt 6. INI files written with Qt 5 or earlier aree + in versions of Qt prior to Qt 6. INI files written with Qt 5 or earlier are however fully readable by a Qt 6 based application (unless a ini codec different from utf8 had been set). But INI files written with Qt 6 will only be readable by older Qt versions if you set the "iniCodec" to @@ -3362,8 +3414,6 @@ QSettings::Format QSettings::defaultFormat() \row \li SystemScope \li \c FOLDERID_ProgramData \row \li{1,2} Unix \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/.config \row \li SystemScope \li \c /etc/xdg - \row \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/Settings - \row \li SystemScope \li \c /etc/xdg \row \li{1,2} \macos and iOS \li{1,2} IniFormat \li UserScope \li \c $HOME/.config \row \li SystemScope \li \c /etc/xdg \endtable |