summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qsettings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qsettings.cpp')
-rw-r--r--src/corelib/io/qsettings.cpp288
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 &section, 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