summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qabstractfileengine.cpp11
-rw-r--r--src/corelib/io/qabstractfileengine_p.h2
-rw-r--r--src/corelib/io/qbuffer.cpp4
-rw-r--r--src/corelib/io/qdebug.cpp20
-rw-r--r--src/corelib/io/qdebug.h4
-rw-r--r--src/corelib/io/qdebug_p.h2
-rw-r--r--src/corelib/io/qdir.cpp136
-rw-r--r--src/corelib/io/qdiriterator.cpp2
-rw-r--r--src/corelib/io/qfile.cpp11
-rw-r--r--src/corelib/io/qfiledevice.cpp5
-rw-r--r--src/corelib/io/qfileinfo.cpp22
-rw-r--r--src/corelib/io/qfileselector.cpp2
-rw-r--r--src/corelib/io/qfilesystemengine.cpp6
-rw-r--r--src/corelib/io/qfilesystemengine_unix.cpp8
-rw-r--r--src/corelib/io/qfilesystemwatcher_inotify.cpp2
-rw-r--r--src/corelib/io/qfilesystemwatcher_kqueue.cpp2
-rw-r--r--src/corelib/io/qfilesystemwatcher_win.cpp24
-rw-r--r--src/corelib/io/qfilesystemwatcher_win_p.h5
-rw-r--r--src/corelib/io/qfsfileengine.cpp4
-rw-r--r--src/corelib/io/qfsfileengine_unix.cpp22
-rw-r--r--src/corelib/io/qfsfileengine_win.cpp4
-rw-r--r--src/corelib/io/qipaddress.cpp12
-rw-r--r--src/corelib/io/qlockfile.h6
-rw-r--r--src/corelib/io/qloggingcategory.cpp3
-rw-r--r--src/corelib/io/qresource.cpp20
-rw-r--r--src/corelib/io/qsettings.cpp34
-rw-r--r--src/corelib/io/qsettings.h6
-rw-r--r--src/corelib/io/qsettings_p.h6
-rw-r--r--src/corelib/io/qsettings_wasm.cpp294
-rw-r--r--src/corelib/io/qstandardpaths.cpp17
-rw-r--r--src/corelib/io/qstandardpaths_android.cpp161
-rw-r--r--src/corelib/io/qstandardpaths_unix.cpp99
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp33
-rw-r--r--src/corelib/io/qtemporaryfile.cpp8
-rw-r--r--src/corelib/io/qurl.cpp91
-rw-r--r--src/corelib/io/qurlidna.cpp12
-rw-r--r--src/corelib/io/qurlquery.cpp12
37 files changed, 706 insertions, 406 deletions
diff --git a/src/corelib/io/qabstractfileengine.cpp b/src/corelib/io/qabstractfileengine.cpp
index c8f21c5b4c..7eed16d9dd 100644
--- a/src/corelib/io/qabstractfileengine.cpp
+++ b/src/corelib/io/qabstractfileengine.cpp
@@ -123,20 +123,17 @@ QAbstractFileEngineHandler::~QAbstractFileEngineHandler()
*/
QAbstractFileEngine *qt_custom_file_engine_handler_create(const QString &path)
{
- QAbstractFileEngine *engine = nullptr;
-
if (qt_file_engine_handlers_in_use.loadRelaxed()) {
QReadLocker locker(fileEngineHandlerMutex());
// check for registered handlers that can load the file
- QAbstractFileEngineHandlerList *handlers = fileEngineHandlers();
- for (int i = 0; i < handlers->size(); i++) {
- if ((engine = handlers->at(i)->create(path)))
- break;
+ for (QAbstractFileEngineHandler *handler : std::as_const(*fileEngineHandlers())) {
+ if (QAbstractFileEngine *engine = handler->create(path))
+ return engine;
}
}
- return engine;
+ return nullptr;
}
/*!
diff --git a/src/corelib/io/qabstractfileengine_p.h b/src/corelib/io/qabstractfileengine_p.h
index 9982568725..04ad782763 100644
--- a/src/corelib/io/qabstractfileengine_p.h
+++ b/src/corelib/io/qabstractfileengine_p.h
@@ -206,7 +206,7 @@ public:
virtual QString currentFileName() const = 0;
virtual QFileInfo currentFileInfo() const;
- QString currentFilePath() const;
+ virtual QString currentFilePath() const;
protected:
enum EntryInfoType {
diff --git a/src/corelib/io/qbuffer.cpp b/src/corelib/io/qbuffer.cpp
index c244dacab3..36d51822df 100644
--- a/src/corelib/io/qbuffer.cpp
+++ b/src/corelib/io/qbuffer.cpp
@@ -277,6 +277,10 @@ void QBuffer::setData(const QByteArray &data)
/*!
\reimp
+
+ Unlike QFile, opening a QBuffer QIODevice::WriteOnly does not truncate it.
+ However, pos() is set to 0. Use QIODevice::Append or QIODevice::Truncate to
+ change either behavior.
*/
bool QBuffer::open(OpenMode flags)
{
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 524a04456a..0afbb374fa 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -24,15 +24,16 @@ using QtMiscUtils::fromHex;
/*
Returns a human readable representation of the first \a maxSize
- characters in \a data.
+ characters in \a data. The size, \a len, is a 64-bit quantity to
+ avoid truncation due to implicit conversions in callers.
*/
-QByteArray QtDebugUtils::toPrintable(const char *data, int len, int maxSize)
+QByteArray QtDebugUtils::toPrintable(const char *data, qint64 len, qsizetype maxSize)
{
if (!data)
return "(null)";
QByteArray out;
- for (int i = 0; i < qMin(len, maxSize); ++i) {
+ for (qsizetype i = 0; i < qMin(len, maxSize); ++i) {
char c = data[i];
if (isprint(c)) {
out += c;
@@ -202,7 +203,7 @@ static inline bool isPrintable(uchar c)
{ return c >= ' ' && c < 0x7f; }
template <typename Char>
-static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, int length, bool isUnicode = true)
+static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, size_t length, bool isUnicode = true)
{
QChar quote(u'"');
d->write(&quote, 1);
@@ -222,7 +223,7 @@ static inline void putEscapedString(QTextStreamPrivate *d, const Char *begin, in
if (sizeof(Char) == sizeof(QChar)) {
// Surrogate characters are category Cs (Other_Surrogate), so isPrintable = false for them
- int runLength = 0;
+ qsizetype runLength = 0;
while (p + runLength != end &&
isPrintable(p[runLength]) && p[runLength] != '\\' && p[runLength] != '"')
++runLength;
@@ -319,12 +320,12 @@ void QDebug::putString(const QChar *begin, size_t length)
if (stream->noQuotes) {
// no quotes, write the string directly too (no pretty-printing)
// this respects the QTextStream state, though
- stream->ts.d_ptr->putString(begin, int(length));
+ stream->ts.d_ptr->putString(begin, qsizetype(length));
} else {
// we'll reset the QTextStream formatting mechanisms, so save the state
QDebugStateSaver saver(*this);
stream->ts.d_ptr->params.reset();
- putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const ushort *>(begin), int(length));
+ putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const ushort *>(begin), length);
}
}
@@ -337,14 +338,15 @@ void QDebug::putByteArray(const char *begin, size_t length, Latin1Content conten
if (stream->noQuotes) {
// no quotes, write the string directly too (no pretty-printing)
// this respects the QTextStream state, though
- QString string = content == ContainsLatin1 ? QString::fromLatin1(begin, int(length)) : QString::fromUtf8(begin, int(length));
+ QString string = content == ContainsLatin1 ? QString::fromLatin1(begin, qsizetype(length))
+ : QString::fromUtf8(begin, qsizetype(length));
stream->ts.d_ptr->putString(string);
} else {
// we'll reset the QTextStream formatting mechanisms, so save the state
QDebugStateSaver saver(*this);
stream->ts.d_ptr->params.reset();
putEscapedString(stream->ts.d_ptr.data(), reinterpret_cast<const uchar *>(begin),
- int(length), content == ContainsLatin1);
+ length, content == ContainsLatin1);
}
}
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 62999d8011..ad01a3dcd8 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -106,7 +106,7 @@ public:
inline QDebug &operator<<(double t) { stream->ts << t; return maybeSpace(); }
inline QDebug &operator<<(const char* t) { stream->ts << QString::fromUtf8(t); return maybeSpace(); }
inline QDebug &operator<<(const char16_t *t) { stream->ts << QStringView(t); return maybeSpace(); }
- inline QDebug &operator<<(const QString & t) { putString(t.constData(), uint(t.length())); return maybeSpace(); }
+ inline QDebug &operator<<(const QString & t) { putString(t.constData(), size_t(t.size())); return maybeSpace(); }
inline QDebug &operator<<(QStringView s) { putString(s.data(), size_t(s.size())); return maybeSpace(); }
inline QDebug &operator<<(QUtf8StringView s) { putByteArray(reinterpret_cast<const char*>(s.data()), s.size(), ContainsBinary); return maybeSpace(); }
inline QDebug &operator<<(QLatin1StringView t) { putByteArray(t.latin1(), t.size(), ContainsLatin1); return maybeSpace(); }
@@ -292,7 +292,7 @@ inline QDebugIfHasDebugStream<T> operator<<(QDebug debug, const QContiguousCache
{
const QDebugStateSaver saver(debug);
debug.nospace() << "QContiguousCache(";
- for (int i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
+ for (qsizetype i = cache.firstIndex(); i <= cache.lastIndex(); ++i) {
debug << cache[i];
if (i != cache.lastIndex())
debug << ", ";
diff --git a/src/corelib/io/qdebug_p.h b/src/corelib/io/qdebug_p.h
index 1dead0f47d..810fc3b4b6 100644
--- a/src/corelib/io/qdebug_p.h
+++ b/src/corelib/io/qdebug_p.h
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE
namespace QtDebugUtils {
-Q_CORE_EXPORT QByteArray toPrintable(const char *data, int len, int maxSize);
+Q_CORE_EXPORT QByteArray toPrintable(const char *data, qint64 len, qsizetype maxSize);
// inline helpers for formatting basic classes.
diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp
index 09315f9afe..eb55696ccf 100644
--- a/src/corelib/io/qdir.cpp
+++ b/src/corelib/io/qdir.cpp
@@ -57,13 +57,13 @@ enum {
};
// Return the length of the root part of an absolute path, for use by cleanPath(), cd().
-static int rootLength(const QString &name, bool allowUncPaths)
+static qsizetype rootLength(QStringView name, bool allowUncPaths)
{
- const int len = name.length();
+ const qsizetype len = name.size();
// starts with double slash
if (allowUncPaths && name.startsWith("//"_L1)) {
// Server name '//server/path' is part of the prefix.
- const int nextSlash = name.indexOf(u'/', 2);
+ const qsizetype nextSlash = name.indexOf(u'/', 2);
return nextSlash >= 0 ? nextSlash + 1 : len;
}
#if defined(Q_OS_WIN)
@@ -132,7 +132,7 @@ bool QDirPrivate::exists() const
inline QChar QDirPrivate::getFilterSepChar(const QString &nameFilter)
{
QChar sep(u';');
- int i = nameFilter.indexOf(sep, 0);
+ qsizetype i = nameFilter.indexOf(sep, 0);
if (i == -1 && nameFilter.indexOf(u' ', 0) != -1)
sep = QChar(u' ');
return sep;
@@ -153,12 +153,12 @@ inline void QDirPrivate::setPath(const QString &path)
{
QString p = QDir::fromNativeSeparators(path);
if (p.endsWith(u'/')
- && p.length() > 1
+ && p.size() > 1
#if defined(Q_OS_WIN)
&& (!(p.length() == 3 && p.at(1).unicode() == ':' && p.at(0).isLetter()))
#endif
) {
- p.truncate(p.length() - 1);
+ p.truncate(p.size() - 1);
}
dirEntry = QFileSystemEntry(p, QFileSystemEntry::FromInternalPath());
@@ -288,7 +288,7 @@ inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l,
QStringList *names, QFileInfoList *infos)
{
// names and infos are always empty lists or 0 here
- int n = l.size();
+ qsizetype n = l.size();
if (n > 0) {
if (n == 1 || (sort & QDir::SortByMask) == QDir::Unsorted) {
if (infos)
@@ -299,16 +299,16 @@ inline void QDirPrivate::sortFileList(QDir::SortFlags sort, QFileInfoList &l,
}
} else {
QScopedArrayPointer<QDirSortItem> si(new QDirSortItem[n]);
- for (int i = 0; i < n; ++i)
+ for (qsizetype i = 0; i < n; ++i)
si[i].item = l.at(i);
std::sort(si.data(), si.data() + n, QDirSortItemComparator(sort));
// put them back in the list(s)
if (infos) {
- for (int i = 0; i < n; ++i)
+ for (qsizetype i = 0; i < n; ++i)
infos->append(si[i].item);
}
if (names) {
- for (int i = 0; i < n; ++i)
+ for (qsizetype i = 0; i < n; ++i)
names->append(si[i].item.fileName());
}
}
@@ -507,6 +507,10 @@ inline void QDirPrivate::initFileEngine()
\snippet qdir-listfiles/main.cpp 0
+ \section1 Platform Specific Issues
+
+ \include android-content-uri-limitations.qdocinc
+
\sa QFileInfo, QFile, QFileDialog, QCoreApplication::applicationDirPath(), {Find Files Example}
*/
@@ -611,7 +615,7 @@ void QDir::setPath(const QString &path)
*/
QString QDir::path() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->dirEntry.filePath();
}
@@ -625,9 +629,13 @@ QString QDir::path() const
*/
QString QDir::absolutePath() const
{
- const QDirPrivate* d = d_ptr.constData();
- d->resolveAbsoluteEntry();
- return d->absoluteDirEntry.filePath();
+ Q_D(const QDir);
+ if (!d->fileEngine) {
+ d->resolveAbsoluteEntry();
+ return d->absoluteDirEntry.filePath();
+ }
+
+ return d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
}
/*!
@@ -648,7 +656,7 @@ QString QDir::absolutePath() const
*/
QString QDir::canonicalPath() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (!d->fileEngine) {
QFileSystemEntry answer = QFileSystemEngine::canonicalName(d->dirEntry, d->metaData);
return answer.filePath();
@@ -669,17 +677,19 @@ QString QDir::canonicalPath() const
*/
QString QDir::dirName() const
{
- const QDirPrivate* d = d_ptr.constData();
- return d->dirEntry.fileName();
+ Q_D(const QDir);
+ if (!d_ptr->fileEngine)
+ return d->dirEntry.fileName();
+ return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
}
#ifdef Q_OS_WIN
-static int drivePrefixLength(const QString &path)
+static qsizetype drivePrefixLength(QStringView path)
{
// Used to extract path's drive for use as prefix for an "absolute except for drive" path
- const int size = path.length();
- int drive = 2; // length of drive prefix
+ const qsizetype size = path.size();
+ qsizetype drive = 2; // length of drive prefix
if (size > 1 && path.at(1).unicode() == ':') {
if (Q_UNLIKELY(!path.at(0).isLetter()))
return 0;
@@ -691,7 +701,7 @@ static int drivePrefixLength(const QString &path)
drive++;
if (drive >= size) {
qWarning("Base directory starts with neither a drive nor a UNC share: %s",
- qUtf8Printable(QDir::toNativeSeparators(path)));
+ qUtf8Printable(QDir::toNativeSeparators(path.toString())));
return 0;
}
while (drive < size && path.at(drive).unicode() != '/')
@@ -733,7 +743,7 @@ QString QDir::filePath(const QString &fileName) const
if (treatAsAbsolute(fileName))
return fileName;
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
QString ret = d->dirEntry.filePath();
if (fileName.isEmpty())
return ret;
@@ -741,7 +751,7 @@ QString QDir::filePath(const QString &fileName) const
#ifdef Q_OS_WIN
if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
// Handle the "absolute except for drive" case (i.e. \blah not c:\blah):
- const int drive = drivePrefixLength(ret);
+ const qsizetype drive = drivePrefixLength(ret);
return drive > 0 ? QStringView{ret}.left(drive) % fileName : fileName;
}
#endif // Q_OS_WIN
@@ -764,7 +774,7 @@ QString QDir::absoluteFilePath(const QString &fileName) const
if (treatAsAbsolute(fileName))
return fileName;
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
d->resolveAbsoluteEntry();
const QString absoluteDirPath = d->absoluteDirEntry.filePath();
if (fileName.isEmpty())
@@ -773,7 +783,7 @@ QString QDir::absoluteFilePath(const QString &fileName) const
// Handle the "absolute except for drive" case (i.e. \blah not c:\blah):
if (fileName.startsWith(u'/') || fileName.startsWith(u'\\')) {
// Combine absoluteDirPath's drive with fileName
- const int drive = drivePrefixLength(absoluteDirPath);
+ const qsizetype drive = drivePrefixLength(absoluteDirPath);
if (Q_LIKELY(drive))
return QStringView{absoluteDirPath}.left(drive) % fileName;
@@ -883,7 +893,7 @@ QString QDir::relativeFilePath(const QString &fileName) const
QString QDir::toNativeSeparators(const QString &pathName)
{
#if defined(Q_OS_WIN)
- int i = pathName.indexOf(u'/');
+ qsizetype i = pathName.indexOf(u'/');
if (i != -1) {
QString n(pathName);
@@ -988,6 +998,9 @@ bool QDir::cd(const QString &dirName)
otherwise returns \c false. Note that the logical cdUp() operation is
not performed if the new directory does not exist.
+ \note On Android, this is not supported for content URIs. For more information,
+ see \l {Android: DocumentFile.getParentFile()}{DocumentFile.getParentFile()}.
+
\sa cd(), isReadable(), exists(), path()
*/
bool QDir::cdUp()
@@ -1000,7 +1013,7 @@ bool QDir::cdUp()
*/
QStringList QDir::nameFilters() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->nameFilters;
}
@@ -1021,7 +1034,7 @@ QStringList QDir::nameFilters() const
*/
void QDir::setNameFilters(const QStringList &nameFilters)
{
- QDirPrivate* d = d_ptr.data();
+ Q_D(QDir);
d->initFileEngine();
d->clearFileLists();
@@ -1051,12 +1064,12 @@ void QDir::setNameFilters(const QStringList &nameFilters)
*/
void QDir::setSearchPaths(const QString &prefix, const QStringList &searchPaths)
{
- if (prefix.length() < 2) {
+ if (prefix.size() < 2) {
qWarning("QDir::setSearchPaths: Prefix must be longer than 1 character");
return;
}
- for (int i = 0; i < prefix.length(); ++i) {
+ for (int i = 0; i < prefix.size(); ++i) {
if (!prefix.at(i).isLetterOrNumber()) {
qWarning("QDir::setSearchPaths: Prefix can only contain letters or numbers");
return;
@@ -1108,7 +1121,7 @@ QStringList QDir::searchPaths(const QString &prefix)
*/
QDir::Filters QDir::filter() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->filters;
}
@@ -1187,7 +1200,7 @@ QDir::Filters QDir::filter() const
*/
void QDir::setFilter(Filters filters)
{
- QDirPrivate* d = d_ptr.data();
+ Q_D(QDir);
d->initFileEngine();
d->clearFileLists();
@@ -1201,7 +1214,7 @@ void QDir::setFilter(Filters filters)
*/
QDir::SortFlags QDir::sorting() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return d->sort;
}
@@ -1244,7 +1257,7 @@ QDir::SortFlags QDir::sorting() const
*/
void QDir::setSorting(SortFlags sort)
{
- QDirPrivate* d = d_ptr.data();
+ Q_D(QDir);
d->initFileEngine();
d->clearFileLists();
@@ -1260,9 +1273,9 @@ void QDir::setSorting(SortFlags sort)
*/
uint QDir::count() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
d->initFileLists(*this);
- return d->files.count();
+ return d->files.size();
}
/*!
@@ -1274,7 +1287,7 @@ uint QDir::count() const
*/
QString QDir::operator[](int pos) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
d->initFileLists(*this);
return d->files[pos];
}
@@ -1300,7 +1313,7 @@ QString QDir::operator[](int pos) const
*/
QStringList QDir::entryList(Filters filters, SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return entryList(d->nameFilters, filters, sort);
}
@@ -1323,7 +1336,7 @@ QStringList QDir::entryList(Filters filters, SortFlags sort) const
*/
QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
return entryInfoList(d->nameFilters, filters, sort);
}
@@ -1346,7 +1359,7 @@ QFileInfoList QDir::entryInfoList(Filters filters, SortFlags sort) const
QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (filters == NoFilter)
filters = d->filters;
@@ -1386,7 +1399,7 @@ QStringList QDir::entryList(const QStringList &nameFilters, Filters filters,
QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filters,
SortFlags sort) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (filters == NoFilter)
filters = d->filters;
@@ -1429,7 +1442,7 @@ QFileInfoList QDir::entryInfoList(const QStringList &nameFilters, Filters filter
*/
bool QDir::mkdir(const QString &dirName, QFile::Permissions permissions) const
{
- const QDirPrivate *d = d_ptr.constData();
+ Q_D(const QDir);
if (dirName.isEmpty()) {
qWarning("QDir::mkdir: Empty or null file name");
@@ -1451,7 +1464,7 @@ bool QDir::mkdir(const QString &dirName, QFile::Permissions permissions) const
*/
bool QDir::mkdir(const QString &dirName) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirName.isEmpty()) {
qWarning("QDir::mkdir: Empty or null file name");
@@ -1475,7 +1488,7 @@ bool QDir::mkdir(const QString &dirName) const
*/
bool QDir::rmdir(const QString &dirName) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirName.isEmpty()) {
qWarning("QDir::rmdir: Empty or null file name");
@@ -1503,7 +1516,7 @@ bool QDir::rmdir(const QString &dirName) const
*/
bool QDir::mkpath(const QString &dirPath) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirPath.isEmpty()) {
qWarning("QDir::mkpath: Empty or null file name");
@@ -1529,7 +1542,7 @@ bool QDir::mkpath(const QString &dirPath) const
*/
bool QDir::rmpath(const QString &dirPath) const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (dirPath.isEmpty()) {
qWarning("QDir::rmpath: Empty or null file name");
@@ -1607,7 +1620,7 @@ bool QDir::removeRecursively()
*/
bool QDir::isReadable() const
{
- const QDirPrivate* d = d_ptr.constData();
+ Q_D(const QDir);
if (!d->fileEngine) {
if (!d->metaData.hasFlags(QFileSystemMetaData::UserReadPermission))
@@ -1710,7 +1723,7 @@ bool QDir::isRelative() const
*/
bool QDir::makeAbsolute()
{
- const QDirPrivate *d = d_ptr.constData();
+ Q_D(const QDir);
std::unique_ptr<QDirPrivate> dir;
if (!!d->fileEngine) {
QString absolutePath = d->fileEngine->fileName(QAbstractFileEngine::AbsoluteName);
@@ -1739,7 +1752,7 @@ bool QDir::makeAbsolute()
*/
bool QDir::operator==(const QDir &dir) const
{
- const QDirPrivate *d = d_ptr.constData();
+ Q_D(const QDir);
const QDirPrivate *other = dir.d_ptr.constData();
if (d == other)
@@ -1889,7 +1902,7 @@ bool QDir::exists(const QString &name) const
*/
bool QDir::isEmpty(Filters filters) const
{
- const auto d = d_ptr.constData();
+ Q_D(const QDir);
QDirIterator it(d->dirEntry.filePath(), d->nameFilters, filters);
return !it.hasNext();
}
@@ -1898,7 +1911,8 @@ bool QDir::isEmpty(Filters filters) const
Returns a list of the root directories on this system.
On Windows this returns a list of QFileInfo objects containing "C:/",
- "D:/", etc. On other operating systems, it returns a list containing
+ "D:/", etc. This does not return drives with ejectable media that are empty.
+ On other operating systems, it returns a list containing
just one root directory (i.e. "/").
\sa root(), rootPath()
@@ -2127,7 +2141,7 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
{
const bool allowUncPaths = flags.testAnyFlag(QDirPrivate::AllowUncPaths);
const bool isRemote = flags.testAnyFlag(QDirPrivate::RemotePath);
- const int len = name.length();
+ const qsizetype len = name.size();
if (ok)
*ok = false;
@@ -2135,15 +2149,15 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
if (len == 0)
return name;
- int i = len - 1;
+ qsizetype i = len - 1;
QVarLengthArray<char16_t> outVector(len);
- int used = len;
+ qsizetype used = len;
char16_t *out = outVector.data();
const ushort *p = reinterpret_cast<const ushort *>(name.data());
const ushort *prefix = p;
- int up = 0;
+ qsizetype up = 0;
- const int prefixLength = rootLength(name, allowUncPaths);
+ const qsizetype prefixLength = rootLength(name, allowUncPaths);
p += prefixLength;
i -= prefixLength;
@@ -2154,10 +2168,10 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
--i;
}
- auto isDot = [](const ushort *p, int i) {
+ auto isDot = [](const ushort *p, qsizetype i) {
return i > 1 && p[i - 1] == '.' && p[i - 2] == '/';
};
- auto isDotDot = [](const ushort *p, int i) {
+ auto isDotDot = [](const ushort *p, qsizetype i) {
return i > 2 && p[i - 1] == '.' && p[i - 2] == '.' && p[i - 3] == '/';
};
@@ -2260,7 +2274,7 @@ QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormaliza
// string only consists of a prefix followed by one or more slashes. Just skip the slash.
++used;
}
- for (int i = prefixLength - 1; i >= 0; --i)
+ for (qsizetype i = prefixLength - 1; i >= 0; --i)
out[--used] = prefix[i];
} else {
if (isEmpty) {
@@ -2292,7 +2306,7 @@ static QString qt_cleanPath(const QString &path, bool *ok)
QString ret = qt_normalizePathSegments(name, OSSupportsUncPaths ? QDirPrivate::AllowUncPaths : QDirPrivate::DefaultNormalization, ok);
// Strip away last slash except for root directories
- if (ret.length() > 1 && ret.endsWith(u'/')) {
+ if (ret.size() > 1 && ret.endsWith(u'/')) {
#if defined (Q_OS_WIN)
if (!(ret.length() == 3 && ret.at(1) == u':'))
#endif
@@ -2338,7 +2352,7 @@ bool QDir::isRelativePath(const QString &path)
*/
void QDir::refresh() const
{
- QDirPrivate *d = const_cast<QDir*>(this)->d_ptr.data();
+ QDirPrivate *d = const_cast<QDir *>(this)->d_func();
d->metaData.clear();
d->initFileEngine();
d->clearFileLists();
diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp
index 258bb631da..101c8fd2e7 100644
--- a/src/corelib/io/qdiriterator.cpp
+++ b/src/corelib/io/qdiriterator.cpp
@@ -294,7 +294,7 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf
return false;
// filter . and ..?
- const int fileNameSize = fileName.size();
+ const qsizetype fileNameSize = fileName.size();
const bool dotOrDotDot = fileName[0] == u'.'
&& ((fileNameSize == 1)
||(fileNameSize == 2 && fileName[1] == u'.'));
diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp
index b1115ad15c..f23b9f77fa 100644
--- a/src/corelib/io/qfile.cpp
+++ b/src/corelib/io/qfile.cpp
@@ -192,6 +192,8 @@ QAbstractFileEngine *QFilePrivate::engine() const
function mostly useless for NTFS volumes. It may still be of use for USB
sticks that use VFAT file systems. POSIX ACLs are not manipulated, either.
+ \include android-content-uri-limitations.qdocinc
+
\sa QTextStream, QDataStream, QFileInfo, QDir, {The Qt Resource System}
*/
@@ -725,6 +727,9 @@ QFile::link(const QString &fileName, const QString &linkName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa setFileName()
*/
@@ -835,6 +840,9 @@ QFile::copy(const QString &newName)
\include qfile-copy.qdocinc
+ \note On Android, this operation is not yet supported for \c content
+ scheme URIs.
+
\sa rename()
*/
@@ -857,6 +865,9 @@ QFile::copy(const QString &fileName, const QString &newName)
will try to create a new file before opening it. The file will be
created with mode 0666 masked by the umask on POSIX systems, and
with permissions inherited from the parent directory on Windows.
+ On Android, it's expected to have access permission to the parent
+ of the file name, otherwise, it won't be possible to create this
+ non-existing file.
\sa QIODevice::OpenMode, setFileName()
*/
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index 4e508e6597..90b67a22e3 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -109,6 +109,11 @@ void QFileDevicePrivate::setError(QFileDevice::FileError err, int errNum)
decrementing \c qt_ntfs_permission_lookup by 1.
\snippet ntfsp.cpp 1
+
+ \note Since this is a non-atomic global variable, it is only safe
+ to increment or decrement \c qt_ntfs_permission_lookup before any
+ threads other than the main thread have started or after every thread
+ other than the main thread has ended.
*/
//************* QFileDevice
diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp
index 963a936d3a..1fbd1e5708 100644
--- a/src/corelib/io/qfileinfo.cpp
+++ b/src/corelib/io/qfileinfo.cpp
@@ -265,6 +265,11 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
\snippet ntfsp.cpp 1
+ \note Since this is a non-atomic global variable, it is only safe
+ to increment or decrement \c qt_ntfs_permission_lookup before any
+ threads other than the main thread have started or after every thread
+ other than the main thread has ended.
+
\section1 Performance Issues
Some of QFileInfo's functions query the file system, but for
@@ -285,6 +290,10 @@ QDateTime &QFileInfoPrivate::getFileTime(QAbstractFileEngine::FileTime request)
If you want to make sure that all information is read from the
file system, use stat().
+ \section1 Platform Specific Issues
+
+ \include android-content-uri-limitations.qdocinc
+
\sa QDir, QFile
*/
@@ -739,7 +748,9 @@ QString QFileInfo::fileName() const
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return ""_L1;
- return d->fileEntry.fileName();
+ if (!d->fileEngine)
+ return d->fileEntry.fileName();
+ return d->fileEngine->fileName(QAbstractFileEngine::BaseName);
}
/*!
@@ -783,7 +794,9 @@ QString QFileInfo::baseName() const
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return ""_L1;
- return d->fileEntry.baseName();
+ if (!d->fileEngine)
+ return d->fileEntry.baseName();
+ return QFileSystemEntry(d->fileEngine->fileName(QAbstractFileEngine::BaseName)).baseName();
}
/*!
@@ -802,7 +815,10 @@ QString QFileInfo::completeBaseName() const
Q_D(const QFileInfo);
if (d->isDefaultConstructed)
return ""_L1;
- return d->fileEntry.completeBaseName();
+ if (!d->fileEngine)
+ return d->fileEntry.completeBaseName();
+ const QString fileEngineBaseName = d->fileEngine->fileName(QAbstractFileEngine::BaseName);
+ return QFileSystemEntry(fileEngineBaseName).completeBaseName();
}
/*!
diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp
index e622f3af0d..7f5480c274 100644
--- a/src/corelib/io/qfileselector.cpp
+++ b/src/corelib/io/qfileselector.cpp
@@ -295,7 +295,7 @@ void QFileSelectorPrivate::updateSelectors()
QLatin1Char pathSep(',');
QStringList envSelectors = QString::fromLatin1(qgetenv("QT_FILE_SELECTORS"))
.split(pathSep, Qt::SkipEmptyParts);
- if (envSelectors.count())
+ if (envSelectors.size())
sharedData->staticSelectors << envSelectors;
if (!qEnvironmentVariableIsEmpty(env_override))
diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp
index 3edaf1ce1d..fba1063e9e 100644
--- a/src/corelib/io/qfilesystemengine.cpp
+++ b/src/corelib/io/qfilesystemengine.cpp
@@ -27,7 +27,7 @@ QString QFileSystemEngine::slowCanonicalized(const QString &path)
QFileInfo fi;
const QChar slash(u'/');
QString tmpPath = path;
- int separatorPos = 0;
+ qsizetype separatorPos = 0;
QSet<QString> nonSymlinks;
QDuplicateTracker<QString> known;
@@ -104,7 +104,7 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent
return _q_checkEntry(engine, resolvingEntry);
#if defined(QT_BUILD_CORE_LIB)
- for (int prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
+ for (qsizetype prefixSeparator = 0; prefixSeparator < filePath.size(); ++prefixSeparator) {
QChar const ch = filePath[prefixSeparator];
if (ch == u'/')
break;
@@ -119,7 +119,7 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent
break;
const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator));
- for (int i = 0; i < paths.count(); i++) {
+ for (qsizetype i = 0; i < paths.size(); i++) {
entry = QFileSystemEntry(QDir::cleanPath(
paths.at(i) % u'/' % QStringView{filePath}.mid(prefixSeparator + 1)));
// Recurse!
diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp
index 9036608e7d..0645952091 100644
--- a/src/corelib/io/qfilesystemengine_unix.cpp
+++ b/src/corelib/io/qfilesystemengine_unix.cpp
@@ -591,7 +591,7 @@ QFileSystemEntry QFileSystemEngine::getLinkTarget(const QFileSystemEntry &link,
Q_CHECK_FILE_NAME(link, link);
QByteArray s = qt_readlink(link.nativeFilePath().constData());
- if (s.length() > 0) {
+ if (s.size() > 0) {
QString ret;
if (!data.hasFlags(QFileSystemMetaData::DirectoryType))
fillMetaData(link, data, QFileSystemMetaData::DirectoryType);
@@ -713,13 +713,13 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry)
QFileSystemEntry cur(currentPath());
result = cur.nativeFilePath();
}
- if (!orig.isEmpty() && !(orig.length() == 1 && orig[0] == '.')) {
+ if (!orig.isEmpty() && !(orig.size() == 1 && orig[0] == '.')) {
if (!result.isEmpty() && !result.endsWith('/'))
result.append('/');
result.append(orig);
}
- if (result.length() == 1 && result[0] == '/')
+ if (result.size() == 1 && result[0] == '/')
return QFileSystemEntry(result, QFileSystemEntry::FromNativePath());
const bool isDir = result.endsWith('/');
@@ -1152,7 +1152,7 @@ bool QFileSystemEngine::removeDirectory(const QFileSystemEntry &entry, bool remo
if (removeEmptyParents) {
QString dirName = QDir::cleanPath(entry.filePath());
- for (int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) {
+ for (int oldslash = 0, slash=dirName.size(); slash > 0; oldslash = slash) {
const QByteArray chunk = QFile::encodeName(dirName.left(slash));
QT_STATBUF st;
if (QT_STAT(chunk.constData(), &st) != -1) {
diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp
index eef21b2fd4..3b53b490f5 100644
--- a/src/corelib/io/qfilesystemwatcher_inotify.cpp
+++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp
@@ -223,7 +223,7 @@ QInotifyFileSystemWatcherEngine::QInotifyFileSystemWatcherEngine(int fd, QObject
QInotifyFileSystemWatcherEngine::~QInotifyFileSystemWatcherEngine()
{
notifier.setEnabled(false);
- for (int id : qAsConst(pathToID))
+ for (int id : std::as_const(pathToID))
inotify_rm_watch(inotifyFd, id < 0 ? -id : id);
::close(inotifyFd);
diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
index 2cd650a296..40d4c1f150 100644
--- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp
+++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp
@@ -51,7 +51,7 @@ QKqueueFileSystemWatcherEngine::~QKqueueFileSystemWatcherEngine()
notifier.setEnabled(false);
close(kqfd);
- for (int id : qAsConst(pathToID))
+ for (int id : std::as_const(pathToID))
::close(id < 0 ? -id : id);
}
diff --git a/src/corelib/io/qfilesystemwatcher_win.cpp b/src/corelib/io/qfilesystemwatcher_win.cpp
index 4c53e4faac..a0b2b006d6 100644
--- a/src/corelib/io/qfilesystemwatcher_win.cpp
+++ b/src/corelib/io/qfilesystemwatcher_win.cpp
@@ -317,9 +317,9 @@ QWindowsFileSystemWatcherEngine::QWindowsFileSystemWatcherEngine(QObject *parent
QWindowsFileSystemWatcherEngine::~QWindowsFileSystemWatcherEngine()
{
- for (auto *thread : qAsConst(threads))
+ for (auto *thread : std::as_const(threads))
thread->stop();
- for (auto *thread : qAsConst(threads))
+ for (auto *thread : std::as_const(threads))
thread->wait();
qDeleteAll(threads);
}
@@ -332,12 +332,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&] { unhandled.push_back(path); });
- QString normalPath = path;
- if ((normalPath.endsWith(u'/') && !normalPath.endsWith(":/"_L1))
- || (normalPath.endsWith(u'\\') && !normalPath.endsWith(":\\"_L1))) {
- normalPath.chop(1);
- }
- QFileInfo fileInfo(normalPath);
+ QFileInfo fileInfo(path);
fileInfo.stat();
if (!fileInfo.exists())
continue;
@@ -351,7 +346,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
continue;
}
- DEBUG() << "Looking for a thread/handle for" << normalPath;
+ DEBUG() << "Looking for a thread/handle for" << fileInfo.path();
const QString absolutePath = isDir ? fileInfo.absoluteFilePath() : fileInfo.absolutePath();
const uint flags = isDir
@@ -433,7 +428,7 @@ QStringList QWindowsFileSystemWatcherEngine::addPaths(const QStringList &paths,
// now look for a thread to insert
bool found = false;
- for (QWindowsFileSystemWatcherEngineThread *thread : qAsConst(threads)) {
+ for (QWindowsFileSystemWatcherEngineThread *thread : std::as_const(threads)) {
const auto locker = qt_scoped_lock(thread->mutex);
if (thread->handles.count() < MAXIMUM_WAIT_OBJECTS) {
DEBUG() << "Added handle" << handle.handle << "for" << absolutePath << "to watch" << fileInfo.absoluteFilePath()
@@ -495,11 +490,8 @@ QStringList QWindowsFileSystemWatcherEngine::removePaths(const QStringList &path
QStringList unhandled;
for (const QString &path : paths) {
auto sg = qScopeGuard([&] { unhandled.push_back(path); });
- QString normalPath = path;
- if (normalPath.endsWith(u'/') || normalPath.endsWith(u'\\'))
- normalPath.chop(1);
- QFileInfo fileInfo(normalPath);
- DEBUG() << "removing" << normalPath;
+ QFileInfo fileInfo(path);
+ DEBUG() << "removing" << fileInfo.path();
QString absolutePath = fileInfo.absoluteFilePath();
QList<QWindowsFileSystemWatcherEngineThread *>::iterator jt, end;
end = threads.end();
@@ -586,7 +578,7 @@ QWindowsFileSystemWatcherEngineThread::~QWindowsFileSystemWatcherEngineThread()
CloseHandle(handles.at(0));
handles[0] = INVALID_HANDLE_VALUE;
- for (HANDLE h : qAsConst(handles)) {
+ for (HANDLE h : std::as_const(handles)) {
if (h == INVALID_HANDLE_VALUE)
continue;
FindCloseChangeNotification(h);
diff --git a/src/corelib/io/qfilesystemwatcher_win_p.h b/src/corelib/io/qfilesystemwatcher_win_p.h
index 3678043351..79cec00c39 100644
--- a/src/corelib/io/qfilesystemwatcher_win_p.h
+++ b/src/corelib/io/qfilesystemwatcher_win_p.h
@@ -104,7 +104,10 @@ public:
Q_DECLARE_TYPEINFO(QFileSystemWatcherPathKey, Q_RELOCATABLE_TYPE);
-inline size_t qHash(const QFileSystemWatcherPathKey &key) { return qHash(key.toCaseFolded()); }
+inline size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed = 0)
+{
+ return qHash(key.toCaseFolded(), seed);
+}
class QWindowsFileSystemWatcherEngineThread : public QThread
{
diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp
index 23698930c0..ffc4878e0d 100644
--- a/src/corelib/io/qfsfileengine.cpp
+++ b/src/corelib/io/qfsfileengine.cpp
@@ -328,7 +328,7 @@ bool QFSFileEnginePrivate::openFd(QIODevice::OpenMode openMode, int fd)
// Seek to the end when in Append mode.
if (openMode & QFile::Append) {
- int ret;
+ QT_OFF_T ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
@@ -468,7 +468,7 @@ void QFSFileEnginePrivate::unmapAll()
{
if (!maps.isEmpty()) {
const QList<uchar*> keys = maps.keys(); // Make a copy since unmap() modifies the map.
- for (int i = 0; i < keys.count(); ++i)
+ for (int i = 0; i < keys.size(); ++i)
unmap(keys.at(i));
}
}
diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp
index a127b76fcc..fb08385c91 100644
--- a/src/corelib/io/qfsfileengine_unix.cpp
+++ b/src/corelib/io/qfsfileengine_unix.cpp
@@ -115,14 +115,14 @@ bool QFSFileEnginePrivate::nativeOpenImpl(QIODevice::OpenMode openMode, mode_t m
// Seek to the end when in Append mode.
if (flags & QFile::Append) {
- int ret;
+ QT_OFF_T ret;
do {
ret = QT_LSEEK(fd, 0, SEEK_END);
} while (ret == -1 && errno == EINTR);
if (ret == -1) {
q->setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError,
- qt_error_string(int(errno)));
+ qt_error_string(errno));
return false;
}
}
@@ -221,7 +221,7 @@ qint64 QFSFileEnginePrivate::nativeRead(char *data, qint64 len)
}
if (readBytes == 0 && !feof(fh)) {
// if we didn't read anything and we're not at EOF, it must be an error
- q->setError(QFile::ReadError, qt_error_string(int(errno)));
+ q->setError(QFile::ReadError, qt_error_string(errno));
return -1;
}
return readBytes;
@@ -489,6 +489,10 @@ bool QFSFileEngine::setPermissions(uint perms)
Q_D(QFSFileEngine);
QSystemError error;
bool ok;
+
+ // clear cached state (if any)
+ d->metaData.clearFlags(QFileSystemMetaData::Permissions);
+
if (d->fd != -1)
ok = QFileSystemEngine::setPermissions(d->fd, QFile::Permissions(perms), error);
else
@@ -550,13 +554,13 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
Q_Q(QFSFileEngine);
if (openMode == QIODevice::NotOpen) {
- q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
+ q->setError(QFile::PermissionsError, qt_error_string(EACCES));
return nullptr;
}
if (offset < 0 || offset > maxFileOffset
|| size < 0 || quint64(size) > quint64(size_t(-1))) {
- q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
+ q->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
return nullptr;
}
@@ -584,7 +588,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
int extra = offset % pageSize;
if (quint64(size + extra) > quint64((size_t)-1)) {
- q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL)));
+ q->setError(QFile::UnspecifiedError, qt_error_string(EINVAL));
return nullptr;
}
@@ -602,16 +606,16 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla
switch(errno) {
case EBADF:
- q->setError(QFile::PermissionsError, qt_error_string(int(EACCES)));
+ q->setError(QFile::PermissionsError, qt_error_string(EACCES));
break;
case ENFILE:
case ENOMEM:
- q->setError(QFile::ResourceError, qt_error_string(int(errno)));
+ q->setError(QFile::ResourceError, qt_error_string(errno));
break;
case EINVAL:
// size are out of bounds
default:
- q->setError(QFile::UnspecifiedError, qt_error_string(int(errno)));
+ q->setError(QFile::UnspecifiedError, qt_error_string(errno));
break;
}
return nullptr;
diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp
index ae59cf9e55..1030c55937 100644
--- a/src/corelib/io/qfsfileengine_win.cpp
+++ b/src/corelib/io/qfsfileengine_win.cpp
@@ -655,6 +655,10 @@ bool QFSFileEngine::setPermissions(uint perms)
{
Q_D(QFSFileEngine);
QSystemError error;
+
+ // clear cached state (if any)
+ d->metaData.clearFlags(QFileSystemMetaData::Permissions);
+
bool ret = QFileSystemEngine::setPermissions(d->fileEntry, QFile::Permissions(perms), error);
if (!ret)
setError(QFile::PermissionsError, error.toString());
diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp
index eeb3d79b06..feed38bef6 100644
--- a/src/corelib/io/qipaddress.cpp
+++ b/src/corelib/io/qipaddress.cpp
@@ -60,11 +60,9 @@ static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptL
ptr[1] != '.' && ptr[1] != '\0')
return false;
- const char *endptr;
- bool ok;
- quint64 ll = qstrntoull(ptr, stop - ptr, &endptr, 0, &ok);
+ auto [ll, endptr] = qstrntoull(ptr, stop - ptr, 0);
quint32 x = ll;
- if (!ok || endptr == ptr || ll != x)
+ if (!endptr || endptr == ptr || ll != x)
return false;
if (*endptr == '.' || dotCount == 3) {
@@ -176,15 +174,13 @@ const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end
continue;
}
- const char *endptr;
- bool ok;
- quint64 ll = qstrntoull(ptr, stop - ptr, &endptr, 16, &ok);
+ auto [ll, endptr] = qstrntoull(ptr, stop - ptr, 16);
quint16 x = ll;
// Reject malformed fields:
// - failed to parse
// - too many hex digits
- if (!ok || endptr > ptr + 4)
+ if (!endptr || endptr > ptr + 4)
return begin + (ptr - buffer.data());
if (*endptr == '.') {
diff --git a/src/corelib/io/qlockfile.h b/src/corelib/io/qlockfile.h
index bc704ea28f..b63194dcd3 100644
--- a/src/corelib/io/qlockfile.h
+++ b/src/corelib/io/qlockfile.h
@@ -7,9 +7,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qscopedpointer.h>
-#if __has_include(<chrono>)
-# include <chrono>
-#endif
+#include <chrono>
QT_BEGIN_NAMESPACE
@@ -30,7 +28,6 @@ public:
void setStaleLockTime(int);
int staleLockTime() const;
-#if __has_include(<chrono>)
bool tryLock(std::chrono::milliseconds timeout) { return tryLock(int(timeout.count())); }
void setStaleLockTime(std::chrono::milliseconds value) { setStaleLockTime(int(value.count())); }
@@ -39,7 +36,6 @@ public:
{
return std::chrono::milliseconds(staleLockTime());
}
-#endif
bool isLocked() const;
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const;
diff --git a/src/corelib/io/qloggingcategory.cpp b/src/corelib/io/qloggingcategory.cpp
index 8136b5f545..425eb40eb3 100644
--- a/src/corelib/io/qloggingcategory.cpp
+++ b/src/corelib/io/qloggingcategory.cpp
@@ -595,8 +595,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
with a specific name. The implicitly-defined QLoggingCategory object is
created on first use, in a thread-safe manner.
- This macro must be used outside of a class or method. It is only defined
- if variadic macros are supported.
+ This macro must be used outside of a class or method.
*/
QT_END_NAMESPACE
diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp
index 7eac497cea..3fd5a55637 100644
--- a/src/corelib/io/qresource.cpp
+++ b/src/corelib/io/qresource.cpp
@@ -167,7 +167,6 @@ struct QResourceGlobalData
{
QRecursiveMutex resourceMutex;
ResourceList resourceList;
- QStringList resourceSearchPaths;
};
Q_GLOBAL_STATIC(QResourceGlobalData, resourceGlobalData)
@@ -177,9 +176,6 @@ static inline QRecursiveMutex &resourceMutex()
static inline ResourceList *resourceList()
{ return &resourceGlobalData->resourceList; }
-static inline QStringList *resourceSearchPaths()
-{ return &resourceGlobalData->resourceSearchPaths; }
-
/*!
\class QResource
\inmodule QtCore
@@ -360,16 +356,10 @@ void QResourcePrivate::ensureInitialized() const
if (path.startsWith(u'/')) {
that->load(path.toString());
} else {
- const auto locker = qt_scoped_lock(resourceMutex());
- QStringList searchPaths = *resourceSearchPaths();
- searchPaths << ""_L1;
- for (int i = 0; i < searchPaths.size(); ++i) {
- const QString searchPath(searchPaths.at(i) + u'/' + path);
- if (that->load(searchPath)) {
- that->absoluteFilePath = u':' + searchPath;
- break;
- }
- }
+ // Should we search QDir::searchPath() before falling back to root ?
+ const QString searchPath(u'/' + path);
+ if (that->load(searchPath))
+ that->absoluteFilePath = u':' + searchPath;
}
}
@@ -779,7 +769,7 @@ int QResourceRoot::findNode(const QString &_path, const QLocale &locale) const
if (!root.endsWith(u'/'))
root += u'/';
if (path.size() >= root.size() && path.startsWith(root))
- path = path.mid(root.length() - 1);
+ path = path.mid(root.size() - 1);
if (path.isEmpty())
path = u'/';
}
diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp
index 60622e3aaa..d7185e0c01 100644
--- a/src/corelib/io/qsettings.cpp
+++ b/src/corelib/io/qsettings.cpp
@@ -343,7 +343,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;
@@ -356,9 +356,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;
@@ -511,7 +511,7 @@ 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();
@@ -540,7 +540,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) {
@@ -735,7 +735,7 @@ StSkipSpaces:
// fallthrough
StNormal:
- qsizetype chopLimit = stringResult.length();
+ qsizetype chopLimit = stringResult.size();
while (i < str.size()) {
switch (str.at(i)) {
case '\\':
@@ -773,7 +773,7 @@ StNormal:
} else {
// the character is skipped
}
- chopLimit = stringResult.length();
+ chopLimit = stringResult.size();
break;
case '"':
++i;
@@ -860,7 +860,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')');
@@ -1085,16 +1085,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
@@ -1127,7 +1127,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;
@@ -1201,7 +1201,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()) {
@@ -1230,7 +1230,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())
@@ -1281,7 +1281,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);
}
@@ -1515,7 +1515,7 @@ bool QConfFileSettingsPrivate::readIniLine(QByteArrayView data, qsizetype &dataP
qsizetype &lineStart, qsizetype &lineLen,
qsizetype &equalsPos)
{
- qsizetype dataLen = data.length();
+ qsizetype dataLen = data.size();
bool inQuotes = false;
equalsPos = -1;
@@ -1643,7 +1643,7 @@ bool QConfFileSettingsPrivate::readIniFile(QByteArrayView data,
++position;
}
- Q_ASSERT(lineStart == data.length());
+ Q_ASSERT(lineStart == data.size());
FLUSH_CURRENT_SECTION();
return ok;
diff --git a/src/corelib/io/qsettings.h b/src/corelib/io/qsettings.h
index b8fba349ca..5d2c330728 100644
--- a/src/corelib/io/qsettings.h
+++ b/src/corelib/io/qsettings.h
@@ -54,6 +54,12 @@ public:
Registry64Format,
#endif
+#if defined(Q_OS_WASM)
+ // FIXME: add public API in next minor release.
+ // WebLocalStorageFormat (IniFormat + 1)
+ // WebIDBSFormat (IniFormat + 2)
+#endif
+
InvalidFormat = 16,
CustomFormat1,
CustomFormat2,
diff --git a/src/corelib/io/qsettings_p.h b/src/corelib/io/qsettings_p.h
index d1ea37ea0c..2429820242 100644
--- a/src/corelib/io/qsettings_p.h
+++ b/src/corelib/io/qsettings_p.h
@@ -216,10 +216,6 @@ protected:
mutable QSettings::Status status;
};
-#ifdef Q_OS_WASM
-class QWasmSettingsPrivate;
-#endif
-
class QConfFileSettingsPrivate : public QSettingsPrivate
{
public:
@@ -266,7 +262,7 @@ private:
Qt::CaseSensitivity caseSensitivity;
qsizetype nextPosition;
#ifdef Q_OS_WASM
- friend class QWasmSettingsPrivate;
+ friend class QWasmIDBSettingsPrivate;
#endif
};
diff --git a/src/corelib/io/qsettings_wasm.cpp b/src/corelib/io/qsettings_wasm.cpp
index 5c15e6d89b..15ab688abe 100644
--- a/src/corelib/io/qsettings_wasm.cpp
+++ b/src/corelib/io/qsettings_wasm.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2019 The Qt Company Ltd.
+// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qsettings.h"
@@ -16,20 +16,168 @@
#include <QList>
#include <emscripten.h>
+#include <emscripten/val.h>
QT_BEGIN_NAMESPACE
+using emscripten::val;
using namespace Qt::StringLiterals;
-static bool isReadReady = false;
+//
+// Native settings implementation for WebAssembly using window.localStorage
+// as the storage backend. localStorage is a key-value store with a synchronous
+// API and a 5MB storage limit.
+//
+class QWasmLocalStorageSettingsPrivate final : public QSettingsPrivate
+{
+public:
+ QWasmLocalStorageSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application);
+
+ void remove(const QString &key) final;
+ void set(const QString &key, const QVariant &value) final;
+ std::optional<QVariant> get(const QString &key) const final;
+ QStringList children(const QString &prefix, ChildSpec spec) const final;
+ void clear() final;
+ void sync() final;
+ void flush() final;
+ bool isWritable() const final;
+ QString fileName() const final;
+
+private:
+ QString prependStoragePrefix(const QString &key) const;
+ QStringView removeStoragePrefix(QStringView key) const;
+ val m_localStorage = val::global("window")["localStorage"];
+ QString m_keyPrefix;
+};
+
+QWasmLocalStorageSettingsPrivate::QWasmLocalStorageSettingsPrivate(QSettings::Scope scope,
+ const QString &organization,
+ const QString &application)
+ : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
+{
+ // The key prefix contians "qt" to separate Qt keys from other keys on localStorage, a
+ // version tag to allow for making changes to the key format in the future, the org
+ // and app names.
+ //
+ // User code could could create separate settings object with different org and app names,
+ // and would expect them to have separate settings. Also, different webassembly instanaces
+ // on the page could write to the same window.localStorage. Add the org and app name
+ // to the key prefix to differentiate, even if that leads to keys with redundant sectons
+ // for the common case of a single org and app name.
+ const QLatin1String separator("-");
+ const QLatin1String doubleSeparator("--");
+ const QString escapedOrganization = QString(organization).replace(separator, doubleSeparator);
+ const QString escapedApplication = QString(application).replace(separator, doubleSeparator);
+ const QLatin1String prefix("qt-v0-");
+ m_keyPrefix.reserve(prefix.length() + escapedOrganization.length() +
+ escapedApplication.length() + separator.length() * 2);
+ m_keyPrefix = prefix + escapedOrganization + separator + escapedApplication + separator;
+}
+
+void QWasmLocalStorageSettingsPrivate::remove(const QString &key)
+{
+ const std::string keyString = prependStoragePrefix(key).toStdString();
+ m_localStorage.call<val>("removeItem", keyString);
+}
+
+void QWasmLocalStorageSettingsPrivate::set(const QString &key, const QVariant &value)
+{
+ const std::string keyString = prependStoragePrefix(key).toStdString();
+ const std::string valueString = QSettingsPrivate::variantToString(value).toStdString();
+ m_localStorage.call<void>("setItem", keyString, valueString);
+}
-class QWasmSettingsPrivate : public QConfFileSettingsPrivate
+std::optional<QVariant> QWasmLocalStorageSettingsPrivate::get(const QString &key) const
+{
+ const std::string keyString = prependStoragePrefix(key).toStdString();
+ const emscripten::val value = m_localStorage.call<val>("getItem", keyString);
+ if (value.isNull())
+ return std::nullopt;
+ const QString valueString = QString::fromStdString(value.as<std::string>());
+ return QSettingsPrivate::stringToVariant(valueString);
+}
+
+QStringList QWasmLocalStorageSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
+{
+ // Loop through all keys on window.localStorage, return Qt keys belonging to
+ // this application, with the correct prefix, and according to ChildSpec.
+ QStringList children;
+ const int length = m_localStorage["length"].as<int>();
+ for (int i = 0; i < length; ++i) {
+ const QString keyString =
+ QString::fromStdString(m_localStorage.call<val>("key", i).as<std::string>());
+
+ const QStringView key = removeStoragePrefix(QStringView(keyString));
+ if (key.isEmpty())
+ continue;
+ if (!key.startsWith(prefix))
+ continue;
+
+ QSettingsPrivate::processChild(key.sliced(prefix.length()), spec, children);
+ }
+
+ return children;
+}
+
+void QWasmLocalStorageSettingsPrivate::clear()
+{
+ // Get all Qt keys from window.localStorage
+ const int length = m_localStorage["length"].as<int>();
+ std::vector<std::string> keys;
+ keys.reserve(length);
+ for (int i = 0; i < length; ++i) {
+ std::string key = (m_localStorage.call<val>("key", i).as<std::string>());
+ keys.push_back(std::move(key));
+ }
+
+ // Remove all Qt keys. Note that localStorage does not guarantee a stable
+ // iteration order when the storage is mutated, which is why removal is done
+ // in a second step after getting all keys.
+ for (std::string key: keys) {
+ if (removeStoragePrefix(QString::fromStdString(key)).isEmpty() == false)
+ m_localStorage.call<val>("removeItem", key);
+ }
+}
+
+void QWasmLocalStorageSettingsPrivate::sync() { }
+
+void QWasmLocalStorageSettingsPrivate::flush() { }
+
+bool QWasmLocalStorageSettingsPrivate::isWritable() const
+{
+ return true;
+}
+
+QString QWasmLocalStorageSettingsPrivate::fileName() const
+{
+ return QString();
+}
+
+QString QWasmLocalStorageSettingsPrivate::prependStoragePrefix(const QString &key) const
+{
+ return m_keyPrefix + key;
+}
+
+QStringView QWasmLocalStorageSettingsPrivate::removeStoragePrefix(QStringView key) const
+{
+ // Return the key slice after m_keyPrefix, or an empty string view if no match
+ if (!key.startsWith(m_keyPrefix))
+ return QStringView();
+ return key.sliced(m_keyPrefix.length());
+}
+
+//
+// Native settings implementation for WebAssembly using the indexed database as
+// the storage backend
+//
+class QWasmIDBSettingsPrivate : public QConfFileSettingsPrivate
{
public:
- QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
- const QString &application);
- ~QWasmSettingsPrivate();
- static QWasmSettingsPrivate *get(void *userData);
+ QWasmIDBSettingsPrivate(QSettings::Scope scope, const QString &organization,
+ const QString &application);
+ ~QWasmIDBSettingsPrivate();
+ static QWasmIDBSettingsPrivate *get(void *userData);
std::optional<QVariant> get(const QString &key) const override;
QStringList children(const QString &prefix, ChildSpec spec) const override;
@@ -46,14 +194,15 @@ public:
private:
QString databaseName;
QString id;
- static QList<QWasmSettingsPrivate *> liveSettings;
+ static QList<QWasmIDBSettingsPrivate *> liveSettings;
};
-QList<QWasmSettingsPrivate *> QWasmSettingsPrivate::liveSettings;
+QList<QWasmIDBSettingsPrivate *> QWasmIDBSettingsPrivate::liveSettings;
+static bool isReadReady = false;
-static void QWasmSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
+static void QWasmIDBSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
{
- QWasmSettingsPrivate *settings = QWasmSettingsPrivate::get(userData);
+ QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData);
if (!settings)
return;
@@ -70,21 +219,21 @@ static void QWasmSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
}
}
-static void QWasmSettingsPrivate_onError(void *userData)
+static void QWasmIDBSettingsPrivate_onError(void *userData)
{
- if (QWasmSettingsPrivate *settings = QWasmSettingsPrivate::get(userData))
+ if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData))
settings->setStatus(QSettings::AccessError);
}
-static void QWasmSettingsPrivate_onStore(void *userData)
+static void QWasmIDBSettingsPrivate_onStore(void *userData)
{
- if (QWasmSettingsPrivate *settings = QWasmSettingsPrivate::get(userData))
+ if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData))
settings->setStatus(QSettings::NoError);
}
-static void QWasmSettingsPrivate_onCheck(void *userData, int exists)
+static void QWasmIDBSettingsPrivate_onCheck(void *userData, int exists)
{
- if (QWasmSettingsPrivate *settings = QWasmSettingsPrivate::get(userData)) {
+ if (QWasmIDBSettingsPrivate *settings = QWasmIDBSettingsPrivate::get(userData)) {
if (exists)
settings->loadLocal(settings->fileName().toLocal8Bit());
else
@@ -92,31 +241,9 @@ static void QWasmSettingsPrivate_onCheck(void *userData, int exists)
}
}
-QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format,
- QSettings::Scope scope,
- const QString &organization,
- const QString &application)
-{
- Q_UNUSED(format);
- if (organization == "Qt"_L1)
- {
- QString organizationDomain = QCoreApplication::organizationDomain();
- QString applicationName = QCoreApplication::applicationName();
-
- QSettingsPrivate *newSettings;
- newSettings = new QWasmSettingsPrivate(scope, organizationDomain, applicationName);
-
- newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(organization)));
- if (!application.isEmpty())
- newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(application)));
-
- return newSettings;
- }
- return new QWasmSettingsPrivate(scope, organization, application);
-}
-
-QWasmSettingsPrivate::QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
- const QString &application)
+QWasmIDBSettingsPrivate::QWasmIDBSettingsPrivate(QSettings::Scope scope,
+ const QString &organization,
+ const QString &application)
: QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
{
liveSettings.push_back(this);
@@ -128,29 +255,29 @@ QWasmSettingsPrivate::QWasmSettingsPrivate(QSettings::Scope scope, const QString
emscripten_idb_async_exists("/home/web_user",
fileName().toLocal8Bit(),
reinterpret_cast<void*>(this),
- QWasmSettingsPrivate_onCheck,
- QWasmSettingsPrivate_onError);
+ QWasmIDBSettingsPrivate_onCheck,
+ QWasmIDBSettingsPrivate_onError);
}
-QWasmSettingsPrivate::~QWasmSettingsPrivate()
+QWasmIDBSettingsPrivate::~QWasmIDBSettingsPrivate()
{
liveSettings.removeAll(this);
}
-QWasmSettingsPrivate *QWasmSettingsPrivate::get(void *userData)
+QWasmIDBSettingsPrivate *QWasmIDBSettingsPrivate::get(void *userData)
{
- if (QWasmSettingsPrivate::liveSettings.contains(userData))
- return reinterpret_cast<QWasmSettingsPrivate *>(userData);
+ if (QWasmIDBSettingsPrivate::liveSettings.contains(userData))
+ return reinterpret_cast<QWasmIDBSettingsPrivate *>(userData);
return nullptr;
}
- void QWasmSettingsPrivate::initAccess()
+void QWasmIDBSettingsPrivate::initAccess()
{
if (isReadReady)
QConfFileSettingsPrivate::initAccess();
}
-std::optional<QVariant> QWasmSettingsPrivate::get(const QString &key) const
+std::optional<QVariant> QWasmIDBSettingsPrivate::get(const QString &key) const
{
if (isReadReady)
return QConfFileSettingsPrivate::get(key);
@@ -158,22 +285,22 @@ std::optional<QVariant> QWasmSettingsPrivate::get(const QString &key) const
return std::nullopt;
}
-QStringList QWasmSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
+QStringList QWasmIDBSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
{
return QConfFileSettingsPrivate::children(prefix, spec);
}
-void QWasmSettingsPrivate::clear()
+void QWasmIDBSettingsPrivate::clear()
{
QConfFileSettingsPrivate::clear();
emscripten_idb_async_delete("/home/web_user",
fileName().toLocal8Bit(),
reinterpret_cast<void*>(this),
- QWasmSettingsPrivate_onStore,
- QWasmSettingsPrivate_onError);
+ QWasmIDBSettingsPrivate_onStore,
+ QWasmIDBSettingsPrivate_onError);
}
-void QWasmSettingsPrivate::sync()
+void QWasmIDBSettingsPrivate::sync()
{
QConfFileSettingsPrivate::sync();
@@ -186,22 +313,22 @@ void QWasmSettingsPrivate::sync()
reinterpret_cast<void *>(dataPointer.data()),
dataPointer.length(),
reinterpret_cast<void*>(this),
- QWasmSettingsPrivate_onStore,
- QWasmSettingsPrivate_onError);
+ QWasmIDBSettingsPrivate_onStore,
+ QWasmIDBSettingsPrivate_onError);
}
}
-void QWasmSettingsPrivate::flush()
+void QWasmIDBSettingsPrivate::flush()
{
sync();
}
-bool QWasmSettingsPrivate::isWritable() const
+bool QWasmIDBSettingsPrivate::isWritable() const
{
return isReadReady && QConfFileSettingsPrivate::isWritable();
}
-void QWasmSettingsPrivate::syncToLocal(const char *data, int size)
+void QWasmIDBSettingsPrivate::syncToLocal(const char *data, int size)
{
QFile file(fileName());
@@ -214,27 +341,62 @@ void QWasmSettingsPrivate::syncToLocal(const char *data, int size)
reinterpret_cast<void *>(data.data()),
data.length(),
reinterpret_cast<void*>(this),
- QWasmSettingsPrivate_onStore,
- QWasmSettingsPrivate_onError);
+ QWasmIDBSettingsPrivate_onStore,
+ QWasmIDBSettingsPrivate_onError);
setReady();
}
}
-void QWasmSettingsPrivate::loadLocal(const QByteArray &filename)
+void QWasmIDBSettingsPrivate::loadLocal(const QByteArray &filename)
{
emscripten_idb_async_load("/home/web_user",
filename.data(),
reinterpret_cast<void*>(this),
- QWasmSettingsPrivate_onLoad,
- QWasmSettingsPrivate_onError);
+ QWasmIDBSettingsPrivate_onLoad,
+ QWasmIDBSettingsPrivate_onError);
}
-void QWasmSettingsPrivate::setReady()
+void QWasmIDBSettingsPrivate::setReady()
{
isReadReady = true;
setStatus(QSettings::NoError);
QConfFileSettingsPrivate::initAccess();
}
+QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
+ const QString &organization, const QString &application)
+{
+ const auto WebLocalStorageFormat = QSettings::IniFormat + 1;
+ const auto WebIdbFormat = QSettings::IniFormat + 2;
+
+ // Make WebLocalStorageFormat the default native format
+ if (format == QSettings::NativeFormat)
+ format = QSettings::Format(WebLocalStorageFormat);
+
+ // Check if cookies are enabled (required for using persistent storage)
+ const bool cookiesEnabled = val::global("navigator")["cookieEnabled"].as<bool>();
+ constexpr QLatin1StringView cookiesWarningMessage
+ ("QSettings::%1 requires cookies, falling back to IniFormat with temporary file");
+ if (format == WebLocalStorageFormat && !cookiesEnabled) {
+ qWarning() << cookiesWarningMessage.arg("WebLocalStorageFormat");
+ format = QSettings::IniFormat;
+ } else if (format == WebIdbFormat && !cookiesEnabled) {
+ qWarning() << cookiesWarningMessage.arg("WebIdbFormat");
+ format = QSettings::IniFormat;
+ }
+
+ // Create settings backend according to selected format
+ if (format == WebLocalStorageFormat) {
+ return new QWasmLocalStorageSettingsPrivate(scope, organization, application);
+ } else if (format == WebIdbFormat) {
+ return new QWasmIDBSettingsPrivate(scope, organization, application);
+ } else if (format == QSettings::IniFormat) {
+ return new QConfFileSettingsPrivate(format, scope, organization, application);
+ }
+
+ qWarning() << "Unsupported settings format" << format;
+ return nullptr;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_SETTINGS
diff --git a/src/corelib/io/qstandardpaths.cpp b/src/corelib/io/qstandardpaths.cpp
index ec8e6899e4..a20c50e096 100644
--- a/src/corelib/io/qstandardpaths.cpp
+++ b/src/corelib/io/qstandardpaths.cpp
@@ -250,7 +250,7 @@ using namespace Qt::StringLiterals;
\li "<APPROOT>/files"
\li "<APPROOT>/Documents/Desktop"
\row \li DocumentsLocation
- \li "<USER>/Documents", "<USER>/<APPNAME>/Documents"
+ \li "<USER>/Documents" [*], "<USER>/<APPNAME>/Documents"
\li "<APPROOT>/Documents"
\row \li FontsLocation
\li "/system/fonts" (not writable)
@@ -259,13 +259,13 @@ using namespace Qt::StringLiterals;
\li not supported (directory not readable)
\li not supported
\row \li MusicLocation
- \li "<USER>/Music", "<USER>/<APPNAME>/Music"
+ \li "<USER>/Music" [*], "<USER>/<APPNAME>/Music"
\li "<APPROOT>/Documents/Music"
\row \li MoviesLocation
- \li "<USER>/Movies", "<USER>/<APPNAME>/Movies"
+ \li "<USER>/Movies" [*], "<USER>/<APPNAME>/Movies"
\li "<APPROOT>/Documents/Movies"
\row \li PicturesLocation
- \li "<USER>/Pictures", "<USER>/<APPNAME>/Pictures"
+ \li "<USER>/Pictures" [*], "<USER>/<APPNAME>/Pictures"
\li "<APPROOT>/Documents/Pictures", "assets-library://"
\row \li TempLocation
\li "<APPROOT>/cache"
@@ -280,7 +280,7 @@ using namespace Qt::StringLiterals;
\li "<APPROOT>/cache", "<USER>/<APPNAME>/cache"
\li "<APPROOT>/Library/Caches"
\row \li GenericDataLocation
- \li "<USER>"
+ \li "<USER>" [*] or "<USER>/<APPNAME>/files"
\li "<APPROOT>/Library/Application Support"
\row \li RuntimeLocation
\li "<APPROOT>/cache"
@@ -292,7 +292,7 @@ using namespace Qt::StringLiterals;
\li "<APPROOT>/files/settings" (there is no shared settings)
\li "<APPROOT>/Library/Preferences"
\row \li DownloadLocation
- \li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads"
+ \li "<USER>/Downloads" [*], "<USER>/<APPNAME>/Downloads"
\li "<APPROOT>/Documents/Downloads"
\row \li GenericCacheLocation
\li "<APPROOT>/cache" (there is no shared cache)
@@ -328,6 +328,11 @@ using namespace Qt::StringLiterals;
\note On Android, reading/writing to GenericDataLocation needs the READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE permission granted.
+ \note [*] On Android 11 and above, public directories are no longer directly accessible
+ in scoped storage mode. Thus, paths of the form \c "<USER>/DirName" are not returned.
+ Instead, you can use \l QFileDialog which uses the Storage Access Framework (SAF)
+ to access such directories.
+
\note On iOS, if you do pass \c {QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).last()}
as argument to \l{QFileDialog::setDirectory()},
a native image picker dialog will be used for accessing the user's photo album.
diff --git a/src/corelib/io/qstandardpaths_android.cpp b/src/corelib/io/qstandardpaths_android.cpp
index c26a5d30ce..a911087c9c 100644
--- a/src/corelib/io/qstandardpaths_android.cpp
+++ b/src/corelib/io/qstandardpaths_android.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qstandardpaths.h"
@@ -12,6 +12,9 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_JNI_CLASS(Environment, "android/os/Environment");
+Q_DECLARE_JNI_TYPE(File, "Ljava/io/File;");
+
using namespace QNativeInterface;
using namespace Qt::StringLiterals;
@@ -34,6 +37,48 @@ static inline QString getAbsolutePath(const QJniObject &file)
}
/*
+ * The root of the external storage
+ *
+ */
+static QString getExternalStorageDirectory()
+{
+ QString &path = (*androidDirCache)[QStringLiteral("EXT_ROOT")];
+ if (!path.isEmpty())
+ return path;
+
+ QJniObject file = QJniObject::callStaticMethod<QtJniTypes::File>("android/os/Environment",
+ "getExternalStorageDirectory");
+ if (!file.isValid())
+ return QString();
+
+ return (path = getAbsolutePath(file));
+}
+
+/*
+ * Locations where applications can place user files shared by all apps (public).
+ * E.g., /storage/Music
+ */
+static QString getExternalStoragePublicDirectory(const char *directoryField)
+{
+ QString &path = (*androidDirCache)[QLatin1String(directoryField)];
+ if (!path.isEmpty())
+ return path;
+
+ QJniObject dirField = QJniObject::getStaticField<jstring>("android/os/Environment",
+ directoryField);
+ if (!dirField.isValid())
+ return QString();
+
+ QJniObject file = QJniObject::callStaticMethod<QtJniTypes::File>("android/os/Environment",
+ "getExternalStoragePublicDirectory",
+ dirField.object<jstring>());
+ if (!file.isValid())
+ return QString();
+
+ return (path = getAbsolutePath(file));
+}
+
+/*
* Locations where applications can place persistent files it owns.
* E.g., /storage/org.app/Music
*/
@@ -132,25 +177,35 @@ static QString getFilesDir()
return (path = getAbsolutePath(file));
}
+static QString getSdkBasedExternalDir(const char *directoryField = nullptr)
+{
+ return (QNativeInterface::QAndroidApplication::sdkVersion() >= 30)
+ ? getExternalFilesDir(directoryField)
+ : getExternalStoragePublicDirectory(directoryField);
+}
+
QString QStandardPaths::writableLocation(StandardLocation type)
{
switch (type) {
case QStandardPaths::MusicLocation:
- return getExternalFilesDir("DIRECTORY_MUSIC");
+ return getSdkBasedExternalDir("DIRECTORY_MUSIC");
case QStandardPaths::MoviesLocation:
- return getExternalFilesDir("DIRECTORY_MOVIES");
+ return getSdkBasedExternalDir("DIRECTORY_MOVIES");
case QStandardPaths::PicturesLocation:
- return getExternalFilesDir("DIRECTORY_PICTURES");
+ return getSdkBasedExternalDir("DIRECTORY_PICTURES");
case QStandardPaths::DocumentsLocation:
- return getExternalFilesDir("DIRECTORY_DOCUMENTS");
+ return getSdkBasedExternalDir("DIRECTORY_DOCUMENTS");
case QStandardPaths::DownloadLocation:
- return getExternalFilesDir("DIRECTORY_DOWNLOADS");
+ return getSdkBasedExternalDir("DIRECTORY_DOWNLOADS");
case QStandardPaths::GenericConfigLocation:
case QStandardPaths::ConfigLocation:
case QStandardPaths::AppConfigLocation:
return getFilesDir() + testDir() + "/settings"_L1;
case QStandardPaths::GenericDataLocation:
- return getExternalFilesDir() + testDir();
+ {
+ return QAndroidApplication::sdkVersion() >= 30 ?
+ getExternalFilesDir() + testDir() : getExternalStorageDirectory() + testDir();
+ }
case QStandardPaths::AppDataLocation:
case QStandardPaths::AppLocalDataLocation:
return getFilesDir() + testDir();
@@ -175,59 +230,53 @@ QString QStandardPaths::writableLocation(StandardLocation type)
QStringList QStandardPaths::standardLocations(StandardLocation type)
{
- if (type == MusicLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_MUSIC")
- << getExternalFilesDir("DIRECTORY_PODCASTS")
- << getExternalFilesDir("DIRECTORY_NOTIFICATIONS")
- << getExternalFilesDir("DIRECTORY_ALARMS");
- }
-
- if (type == MoviesLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_MOVIES");
- }
-
- if (type == PicturesLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_PICTURES");
- }
+ QStringList locations;
- if (type == DocumentsLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_DOCUMENTS");
- }
-
- if (type == DownloadLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir("DIRECTORY_DOWNLOADS");
- }
-
- if (type == AppDataLocation || type == AppLocalDataLocation) {
- return QStringList() << writableLocation(type)
- << getExternalFilesDir();
- }
-
- if (type == CacheLocation) {
- return QStringList() << writableLocation(type)
- << getExternalCacheDir();
- }
-
- if (type == FontsLocation) {
+ if (type == MusicLocation) {
+ locations << getExternalFilesDir("DIRECTORY_MUSIC");
+ // Place the public dirs before the app own dirs
+ if (QNativeInterface::QAndroidApplication::sdkVersion() < 30) {
+ locations << getExternalStoragePublicDirectory("DIRECTORY_PODCASTS")
+ << getExternalStoragePublicDirectory("DIRECTORY_NOTIFICATIONS")
+ << getExternalStoragePublicDirectory("DIRECTORY_ALARMS");
+ }
+ locations << getExternalFilesDir("DIRECTORY_PODCASTS")
+ << getExternalFilesDir("DIRECTORY_NOTIFICATIONS")
+ << getExternalFilesDir("DIRECTORY_ALARMS");
+ } else if (type == MoviesLocation) {
+ locations << getExternalFilesDir("DIRECTORY_MOVIES");
+ } else if (type == PicturesLocation) {
+ locations << getExternalFilesDir("DIRECTORY_PICTURES");
+ } else if (type == DocumentsLocation) {
+ locations << getExternalFilesDir("DIRECTORY_DOCUMENTS");
+ } else if (type == DownloadLocation) {
+ locations << getExternalFilesDir("DIRECTORY_DOWNLOADS");
+ } else if (type == AppDataLocation || type == AppLocalDataLocation) {
+ locations << getExternalFilesDir();
+ } else if (type == CacheLocation) {
+ locations << getExternalCacheDir();
+ } else if (type == FontsLocation) {
QString &fontLocation = (*androidDirCache)[QStringLiteral("FONT_LOCATION")];
- if (!fontLocation.isEmpty())
- return QStringList(fontLocation);
-
- const QByteArray ba = qgetenv("QT_ANDROID_FONT_LOCATION");
- if (!ba.isEmpty())
- return QStringList((fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba))));
-
- // Don't cache the fallback, as we might just have been called before
- // QT_ANDROID_FONT_LOCATION has been set.
- return QStringList("/system/fonts"_L1);
+ if (!fontLocation.isEmpty()) {
+ locations << fontLocation;
+ } else {
+ const QByteArray ba = qgetenv("QT_ANDROID_FONT_LOCATION");
+ if (!ba.isEmpty()) {
+ locations << (fontLocation = QDir::cleanPath(QString::fromLocal8Bit(ba)));
+ } else {
+ // Don't cache the fallback, as we might just have been called before
+ // QT_ANDROID_FONT_LOCATION has been set.
+ locations << "/system/fonts"_L1;
+ }
+ }
}
- return QStringList(writableLocation(type));
+ const QString writable = writableLocation(type);
+ if (!writable.isEmpty())
+ locations.prepend(writable);
+
+ locations.removeDuplicates();
+ return locations;
}
QT_END_NAMESPACE
diff --git a/src/corelib/io/qstandardpaths_unix.cpp b/src/corelib/io/qstandardpaths_unix.cpp
index e5122ff3b6..55150f9e93 100644
--- a/src/corelib/io/qstandardpaths_unix.cpp
+++ b/src/corelib/io/qstandardpaths_unix.cpp
@@ -180,10 +180,14 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case CacheLocation:
case GenericCacheLocation:
{
+ if (isTestModeEnabled())
+ return QDir::homePath() + "/.qttest/cache"_L1;
+
// http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
QString xdgCacheHome = QFile::decodeName(qgetenv("XDG_CACHE_HOME"));
- if (isTestModeEnabled())
- xdgCacheHome = QDir::homePath() + "/.qttest/cache"_L1;
+ if (!xdgCacheHome.startsWith(u'/'))
+ xdgCacheHome.clear(); // spec says relative paths should be ignored
+
if (xdgCacheHome.isEmpty())
xdgCacheHome = QDir::homePath() + "/.cache"_L1;
if (type == QStandardPaths::CacheLocation)
@@ -194,9 +198,13 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case AppLocalDataLocation:
case GenericDataLocation:
{
- QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
if (isTestModeEnabled())
- xdgDataHome = QDir::homePath() + "/.qttest/share"_L1;
+ return QDir::homePath() + "/.qttest/share"_L1;
+
+ QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
+ if (!xdgDataHome.startsWith(u'/'))
+ xdgDataHome.clear(); // spec says relative paths should be ignored
+
if (xdgDataHome.isEmpty())
xdgDataHome = QDir::homePath() + "/.local/share"_L1;
if (type == AppDataLocation || type == AppLocalDataLocation)
@@ -207,10 +215,14 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case GenericConfigLocation:
case AppConfigLocation:
{
+ if (isTestModeEnabled())
+ return QDir::homePath() + "/.qttest/config"_L1;
+
// http://standards.freedesktop.org/basedir-spec/latest/
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
- if (isTestModeEnabled())
- xdgConfigHome = QDir::homePath() + "/.qttest/config"_L1;
+ if (!xdgConfigHome.startsWith(u'/'))
+ xdgConfigHome.clear(); // spec says relative paths should be ignored
+
if (xdgConfigHome.isEmpty())
xdgConfigHome = QDir::homePath() + "/.config"_L1;
if (type == AppConfigLocation)
@@ -220,6 +232,9 @@ QString QStandardPaths::writableLocation(StandardLocation type)
case RuntimeLocation:
{
QString xdgRuntimeDir = QFile::decodeName(qgetenv("XDG_RUNTIME_DIR"));
+ if (!xdgRuntimeDir.startsWith(u'/'))
+ xdgRuntimeDir.clear(); // spec says relative paths should be ignored
+
bool fromEnv = !xdgRuntimeDir.isEmpty();
if (xdgRuntimeDir.isEmpty() || !checkXdgRuntimeDir(xdgRuntimeDir)) {
// environment variable not set or is set to something unsuitable
@@ -246,6 +261,9 @@ QString QStandardPaths::writableLocation(StandardLocation type)
#if QT_CONFIG(regularexpression)
// http://www.freedesktop.org/wiki/Software/xdg-user-dirs
QString xdgConfigHome = QFile::decodeName(qgetenv("XDG_CONFIG_HOME"));
+ if (!xdgConfigHome.startsWith(u'/'))
+ xdgConfigHome.clear(); // spec says relative paths should be ignored
+
if (xdgConfigHome.isEmpty())
xdgConfigHome = QDir::homePath() + "/.config"_L1;
QFile file(xdgConfigHome + "/user-dirs.dirs"_L1);
@@ -253,23 +271,23 @@ QString QStandardPaths::writableLocation(StandardLocation type)
if (!key.isEmpty() && !isTestModeEnabled() && file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
// Only look for lines like: XDG_DESKTOP_DIR="$HOME/Desktop"
- QRegularExpression exp("^XDG_(.*)_DIR=(.*)$"_L1);
+ static const QRegularExpression exp(u"^XDG_(.*)_DIR=(.*)$"_s);
QString result;
while (!stream.atEnd()) {
const QString &line = stream.readLine();
QRegularExpressionMatch match = exp.match(line);
if (match.hasMatch() && match.capturedView(1) == key) {
QStringView value = match.capturedView(2);
- if (value.length() > 2
+ if (value.size() > 2
&& value.startsWith(u'\"')
&& value.endsWith(u'\"'))
- value = value.mid(1, value.length() - 2);
+ value = value.mid(1, value.size() - 2);
// value can start with $HOME
if (value.startsWith("$HOME"_L1))
result = QDir::homePath() + value.mid(5);
else
result = value.toString();
- if (result.length() > 1 && result.endsWith(u'/'))
+ if (result.size() > 1 && result.endsWith(u'/'))
result.chop(1);
}
}
@@ -323,41 +341,48 @@ QString QStandardPaths::writableLocation(StandardLocation type)
return path;
}
-static QStringList xdgDataDirs()
+static QStringList dirsList(const QString &xdgEnvVar)
{
QStringList dirs;
// http://standards.freedesktop.org/basedir-spec/latest/
+ // Normalize paths, skip relative paths (the spec says relative paths
+ // should be ignored)
+ for (const auto dir : qTokenize(xdgEnvVar, u':'))
+ if (dir.startsWith(u'/'))
+ dirs.push_back(QDir::cleanPath(dir.toString()));
+
+ // Remove duplicates from the list, there's no use for duplicated
+ // paths in XDG_DATA_DIRS - if it's not found in the given
+ // directory the first time, it won't be there the second time.
+ // Plus duplicate paths causes problems for example for mimetypes,
+ // where duplicate paths here lead to duplicated mime types returned
+ // for a file, eg "text/plain,text/plain" instead of "text/plain"
+ dirs.removeDuplicates();
+
+ return dirs;
+}
+
+static QStringList xdgDataDirs()
+{
+ // http://standards.freedesktop.org/basedir-spec/latest/
QString xdgDataDirsEnv = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
- if (xdgDataDirsEnv.isEmpty()) {
- dirs.append(QString::fromLatin1("/usr/local/share"));
- dirs.append(QString::fromLatin1("/usr/share"));
- } else {
- // Normalize paths, skip relative paths
- for (const auto dir : qTokenize(xdgDataDirsEnv, u':')) {
- if (dir.startsWith(u'/'))
- dirs.push_back(QDir::cleanPath(dir.toString()));
- }
- // Remove duplicates from the list, there's no use for duplicated
- // paths in XDG_DATA_DIRS - if it's not found in the given
- // directory the first time, it won't be there the second time.
- // Plus duplicate paths causes problems for example for mimetypes,
- // where duplicate paths here lead to duplicated mime types returned
- // for a file, eg "text/plain,text/plain" instead of "text/plain"
- dirs.removeDuplicates();
- }
+ QStringList dirs = dirsList(xdgDataDirsEnv);
+ if (dirs.isEmpty())
+ dirs = QStringList{u"/usr/local/share"_s, u"/usr/share"_s};
+
return dirs;
}
static QStringList xdgConfigDirs()
{
- QStringList dirs;
// http://standards.freedesktop.org/basedir-spec/latest/
const QString xdgConfigDirs = QFile::decodeName(qgetenv("XDG_CONFIG_DIRS"));
- if (xdgConfigDirs.isEmpty())
- dirs.append(QString::fromLatin1("/etc/xdg"));
- else
- dirs = xdgConfigDirs.split(u':');
+
+ QStringList dirs = dirsList(xdgConfigDirs);
+ if (dirs.isEmpty())
+ dirs.push_back(u"/etc/xdg"_s);
+
return dirs;
}
@@ -371,7 +396,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
break;
case AppConfigLocation:
dirs = xdgConfigDirs();
- for (int i = 0; i < dirs.count(); ++i)
+ for (int i = 0; i < dirs.size(); ++i)
appendOrganizationAndApp(dirs[i]);
break;
case GenericDataLocation:
@@ -379,19 +404,19 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
break;
case ApplicationsLocation:
dirs = xdgDataDirs();
- for (int i = 0; i < dirs.count(); ++i)
+ for (int i = 0; i < dirs.size(); ++i)
dirs[i].append("/applications"_L1);
break;
case AppDataLocation:
case AppLocalDataLocation:
dirs = xdgDataDirs();
- for (int i = 0; i < dirs.count(); ++i)
+ for (int i = 0; i < dirs.size(); ++i)
appendOrganizationAndApp(dirs[i]);
break;
case FontsLocation:
dirs += QDir::homePath() + "/.fonts"_L1;
dirs += xdgDataDirs();
- for (int i = 1; i < dirs.count(); ++i)
+ for (int i = 1; i < dirs.size(); ++i)
dirs[i].append("/fonts"_L1);
break;
default:
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 89b6dfea9d..be3bf0252d 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -451,32 +451,35 @@ inline bool QStorageIterator::next()
const char *const stop = ptr + len - 1;
// parse the line
- bool ok;
mnt.mnt_freq = 0;
mnt.mnt_passno = 0;
- mnt.mount_id = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
+ auto r = qstrntoll(ptr, stop - ptr, 10);
+ if (!r.ok())
return false;
+ mnt.mount_id = r.result;
- int parent_id = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- Q_UNUSED(parent_id);
- if (!ok)
+ r = qstrntoll(r.endptr, stop - r.endptr, 10);
+ if (!r.ok())
return false;
+ int parent_id = r.result;
+ Q_UNUSED(parent_id);
- int rdevmajor = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
+ r = qstrntoll(r.endptr, stop - r.endptr, 10);
+ if (!r.ok())
return false;
- if (*ptr != ':')
+ if (*r.endptr != ':')
return false;
- int rdevminor = qstrntoll(ptr + 1, stop - ptr - 1, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
+ int rdevmajor = r.result;
+ r = qstrntoll(r.endptr + 1, stop - r.endptr - 1, 10);
+ if (!r.ok())
return false;
- mnt.rdev = makedev(rdevmajor, rdevminor);
+ mnt.rdev = makedev(rdevmajor, r.result);
- if (*ptr != ' ')
+ if (*r.endptr != ' ')
return false;
+ ptr = const_cast<char *>(r.endptr);
mnt.subvolume = ++ptr;
ptr = parseMangledPath(ptr);
if (!ptr)
@@ -711,8 +714,8 @@ void QStorageInfoPrivate::initRootPath()
const QString mountDir = it.rootPath();
const QByteArray fsName = it.fileSystemType();
// we try to find most suitable entry
- if (isParentOf(mountDir, oldRootPath) && maxLength < mountDir.length()) {
- maxLength = mountDir.length();
+ if (isParentOf(mountDir, oldRootPath) && maxLength < mountDir.size()) {
+ maxLength = mountDir.size();
rootPath = mountDir;
device = it.device();
fileSystemType = fsName;
diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp
index 44c45a1cad..86ad1439e3 100644
--- a/src/corelib/io/qtemporaryfile.cpp
+++ b/src/corelib/io/qtemporaryfile.cpp
@@ -45,7 +45,7 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
{
// Ensure there is a placeholder mask
QString qfilename = QDir::fromNativeSeparators(templateName);
- uint phPos = qfilename.length();
+ uint phPos = qfilename.size();
uint phLength = 0;
while (phPos != 0) {
@@ -75,7 +75,7 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
.nativeFilePath();
// Find mask in native path
- phPos = filename.length();
+ phPos = filename.size();
phLength = 0;
while (phPos != 0) {
--phPos;
@@ -109,8 +109,8 @@ QTemporaryFileName::QTemporaryFileName(const QString &templateName)
QFileSystemEntry::NativePath QTemporaryFileName::generateNext()
{
Q_ASSERT(length != 0);
- Q_ASSERT(pos < path.length());
- Q_ASSERT(length <= path.length() - pos);
+ Q_ASSERT(pos < path.size());
+ Q_ASSERT(length <= path.size() - pos);
Char *const placeholderStart = (Char *)path.data() + pos;
Char *const placeholderEnd = placeholderStart + length;
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index c3122e27f2..9cfa217e50 100644
--- a/src/corelib/io/qurl.cpp
+++ b/src/corelib/io/qurl.cpp
@@ -14,14 +14,16 @@
\ingroup network
\ingroup shared
-
It can parse and construct URLs in both encoded and unencoded
form. QUrl also has support for internationalized domain names
(IDNs).
- The most common way to use QUrl is to initialize it via the
- constructor by passing a QString. Otherwise, setUrl() can also
- be used.
+ The most common way to use QUrl is to initialize it via the constructor by
+ passing a QString containing a full URL. QUrl objects can also be created
+ from a QByteArray containing a full URL using QUrl::fromEncoded(), or
+ heuristically from incomplete URLs using QUrl::fromUserInput(). The URL
+ representation can be obtained from a QUrl using either QUrl::toString() or
+ QUrl::toEncoded().
URLs can be represented in two forms: encoded or unencoded. The
unencoded representation is suitable for showing to users, but
@@ -510,7 +512,7 @@ public:
ErrorCode validityError(QString *source = nullptr, qsizetype *position = nullptr) const;
bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end);
bool validateComponent(Section section, const QString &input)
- { return validateComponent(section, input, 0, input.length()); }
+ { return validateComponent(section, input, 0, input.size()); }
// no QString scheme() const;
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
@@ -819,14 +821,16 @@ recodeFromUser(const QString &input, const ushort *actions, qsizetype from, qsiz
static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
const ushort *actions)
{
- // Test ComponentFormattingOptions, ignore FormattingOptions.
- if ((options & 0xFFFF0000) == QUrl::PrettyDecoded) {
+ // The stored value is already QUrl::PrettyDecoded, so there's nothing to
+ // do if that's what the user asked for (test only
+ // ComponentFormattingOptions, ignore FormattingOptions).
+ if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
+ !qt_urlRecode(appendTo, value, options, actions))
appendTo += value;
- return;
- }
- if (!qt_urlRecode(appendTo, value, options, actions))
- appendTo += value;
+ // copy nullness, if necessary, because QString::operator+=(QStringView) doesn't
+ if (appendTo.isNull() && !value.isNull())
+ appendTo.detach();
}
inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
@@ -918,7 +922,7 @@ inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions o
}
// check if we need to remove trailing slashes
if (options & QUrl::StripTrailingSlash) {
- while (thePathView.length() > 1 && thePathView.endsWith(u'/'))
+ while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
thePathView.chop(1);
}
@@ -1191,7 +1195,7 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar
// uppercase the version, if necessary
if (begin[2].unicode() >= 'a')
- host[host.length() - 2] = QChar{begin[2].unicode() - 0x20};
+ host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
begin += 4;
--end;
@@ -1341,7 +1345,7 @@ QUrlPrivate::setHost(const QString &value, qsizetype from, qsizetype iend, QUrl:
}
// recurse
- return setHost(s, 0, s.length(), QUrl::StrictMode);
+ return setHost(s, 0, s.size(), QUrl::StrictMode);
}
s = qt_ACE_do(value.mid(from, iend - from), NormalizeAce, ForbidLeadingDot, {});
@@ -1377,7 +1381,7 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode
qsizetype colon = -1;
qsizetype question = -1;
qsizetype hash = -1;
- const qsizetype len = url.length();
+ const qsizetype len = url.size();
const QChar *const begin = url.constData();
const ushort *const data = reinterpret_cast<const ushort *>(begin);
@@ -1628,7 +1632,7 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, qsizet
if (path.isEmpty())
return NoError;
if (path.at(0) == u'/') {
- if (hasAuthority() || path.length() == 1 || path.at(1) != u'/')
+ if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
return NoError;
if (source) {
*source = path;
@@ -1648,7 +1652,7 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, qsizet
return NoError;
// check for a path of "text:text/"
- for (qsizetype i = 0; i < path.length(); ++i) {
+ for (qsizetype i = 0; i < path.size(); ++i) {
ushort c = path.at(i).unicode();
if (c == '/') {
// found the slash before the colon
@@ -1792,7 +1796,20 @@ inline void QUrlPrivate::validate() const
/*!
- Constructs a URL by parsing \a url. QUrl will automatically percent encode
+ Constructs a URL by parsing \a url. Note this constructor expects a proper
+ URL or URL-Reference and will not attempt to guess intent. For example, the
+ following declaration:
+
+ \snippet code/src_corelib_io_qurl.cpp constructor-url-reference
+
+ Will construct a valid URL but it may not be what one expects, as the
+ scheme() part of the input is missing. For a string like the above,
+ applications may want to use fromUserInput(). For this constructor or
+ setUrl(), the following is probably what was intended:
+
+ \snippet code/src_corelib_io_qurl.cpp constructor-url
+
+ QUrl will automatically percent encode
all characters that are not allowed in a URL and decode the percent-encoded
sequences that represent an unreserved character (letters, digits, hyphens,
underscores, dots and tildes). All other characters are left in their
@@ -1956,7 +1973,7 @@ void QUrl::setScheme(const QString &scheme)
d->flags &= ~QUrlPrivate::IsLocalFile;
d->scheme.clear();
} else {
- d->setScheme(scheme, scheme.length(), /* do set error */ true);
+ d->setScheme(scheme, scheme.size(), /* do set error */ true);
}
}
@@ -2016,7 +2033,7 @@ void QUrl::setAuthority(const QString &authority, ParsingMode mode)
return;
}
- d->setAuthority(authority, 0, authority.length(), mode);
+ d->setAuthority(authority, 0, authority.size(), mode);
if (authority.isNull()) {
// QUrlPrivate::setAuthority cleared almost everything
// but it leaves the Host bit set
@@ -2087,7 +2104,7 @@ void QUrl::setUserInfo(const QString &userInfo, ParsingMode mode)
return;
}
- d->setUserInfo(trimmed, 0, trimmed.length());
+ d->setUserInfo(trimmed, 0, trimmed.size());
if (userInfo.isNull()) {
// QUrlPrivate::setUserInfo cleared almost everything
// but it leaves the UserName bit set
@@ -2159,7 +2176,7 @@ void QUrl::setUserName(const QString &userName, ParsingMode mode)
mode = TolerantMode;
}
- d->setUserName(data, 0, data.length());
+ d->setUserName(data, 0, data.size());
if (userName.isNull())
d->sectionIsPresent &= ~QUrlPrivate::UserName;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
@@ -2222,7 +2239,7 @@ void QUrl::setPassword(const QString &password, ParsingMode mode)
mode = TolerantMode;
}
- d->setPassword(data, 0, data.length());
+ d->setPassword(data, 0, data.size());
if (password.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Password;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
@@ -2284,7 +2301,7 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
mode = TolerantMode;
}
- if (d->setHost(data, 0, data.length(), mode)) {
+ if (d->setHost(data, 0, data.size(), mode)) {
if (host.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Host;
} else if (!data.startsWith(u'[')) {
@@ -2293,7 +2310,7 @@ void QUrl::setHost(const QString &host, ParsingMode mode)
data.prepend(u'[');
data.append(u']');
- if (!d->setHost(data, 0, data.length(), mode)) {
+ if (!d->setHost(data, 0, data.size(), mode)) {
// failed again
if (data.contains(u':')) {
// source data contains ':', so it's an IPv6 error
@@ -2330,7 +2347,7 @@ QString QUrl::host(ComponentFormattingOptions options) const
if (d) {
d->appendHost(result, options);
if (result.startsWith(u'['))
- result = result.mid(1, result.length() - 2);
+ result = result.mid(1, result.size() - 2);
}
return result;
}
@@ -2409,7 +2426,7 @@ void QUrl::setPath(const QString &path, ParsingMode mode)
mode = TolerantMode;
}
- d->setPath(data, 0, data.length());
+ d->setPath(data, 0, data.size());
// optimized out, since there is no path delimiter
// if (path.isNull())
@@ -2545,7 +2562,7 @@ void QUrl::setQuery(const QString &query, ParsingMode mode)
mode = TolerantMode;
}
- d->setQuery(data, 0, data.length());
+ d->setQuery(data, 0, data.size());
if (query.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Query;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
@@ -2643,7 +2660,7 @@ void QUrl::setFragment(const QString &fragment, ParsingMode mode)
mode = TolerantMode;
}
- d->setFragment(data, 0, data.length());
+ d->setFragment(data, 0, data.size());
if (fragment.isNull())
d->sectionIsPresent &= ~QUrlPrivate::Fragment;
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
@@ -2937,7 +2954,7 @@ QUrl QUrl::adjusted(QUrl::FormattingOptions options) const
that.detach();
QString path;
d->appendPath(path, options | FullyEncoded, QUrlPrivate::Path);
- that.d->setPath(path, 0, path.length());
+ that.d->setPath(path, 0, path.size());
}
return that;
}
@@ -3346,7 +3363,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
QString deslashified = fromNativeSeparators(localFile);
// magic for drives on windows
- if (deslashified.length() > 1 && deslashified.at(1) == u':' && deslashified.at(0) != u'/') {
+ if (deslashified.size() > 1 && deslashified.at(1) == u':' && deslashified.at(0) != u'/') {
deslashified.prepend(u'/');
} else if (deslashified.startsWith("//"_L1)) {
// magic for shared drive on windows
@@ -3367,7 +3384,7 @@ QUrl QUrl::fromLocalFile(const QString &localFile)
// Path hostname is not a valid URL host, so set it entirely in the path
// (by leaving deslashified unchanged)
} else if (indexOfPath > 2) {
- deslashified = deslashified.right(deslashified.length() - indexOfPath);
+ deslashified = deslashified.right(deslashified.size() - indexOfPath);
} else {
deslashified.clear();
}
@@ -3431,16 +3448,16 @@ bool QUrl::isParentOf(const QUrl &childUrl) const
if (!d)
return ((childUrl.scheme().isEmpty())
&& (childUrl.authority().isEmpty())
- && childPath.length() > 0 && childPath.at(0) == u'/');
+ && childPath.size() > 0 && childPath.at(0) == u'/');
QString ourPath = path();
return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
&& (childUrl.authority().isEmpty() || authority() == childUrl.authority())
&& childPath.startsWith(ourPath)
- && ((ourPath.endsWith(u'/') && childPath.length() > ourPath.length())
- || (!ourPath.endsWith(u'/') && childPath.length() > ourPath.length()
- && childPath.at(ourPath.length()) == u'/')));
+ && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
+ || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
+ && childPath.at(ourPath.size()) == u'/')));
}
@@ -3488,7 +3505,7 @@ QDebug operator<<(QDebug d, const QUrl &url)
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
{
- QChar c = size_t(errorPosition) < size_t(errorSource.length()) ?
+ QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
errorSource.at(errorPosition) : QChar(QChar::Null);
switch (errorCode) {
diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp
index 04b9a25886..5fc6006ef4 100644
--- a/src/corelib/io/qurlidna.cpp
+++ b/src/corelib/io/qurlidna.cpp
@@ -73,11 +73,11 @@ Q_AUTOTEST_EXPORT void qt_punycodeEncoder(QStringView in, QString *output)
// Do not try to encode strings that certainly will result in output
// that is longer than allowable domain name label length. Note that
// non-BMP codepoints are encoded as two QChars.
- if (in.length() > MaxDomainLabelLength * 2)
+ if (in.size() > MaxDomainLabelLength * 2)
return;
- int outLen = output->length();
- output->resize(outLen + in.length());
+ int outLen = output->size();
+ output->resize(outLen + in.size());
QChar *d = output->data() + outLen;
bool skipped = false;
@@ -177,7 +177,7 @@ Q_AUTOTEST_EXPORT QString qt_punycodeDecoder(const QString &pc)
// Do not try to decode strings longer than allowable for a domain label.
// Non-ASCII strings are not allowed here anyway, so there is no need
// to account for surrogates.
- if (pc.length() > MaxDomainLabelLength)
+ if (pc.size() > MaxDomainLabelLength)
return QString();
// strip any ACE prefix
@@ -468,7 +468,7 @@ static QString mapDomainName(const QString &in, QUrl::AceProcessingOptions optio
*/
static bool validateAsciiLabel(QStringView label)
{
- if (label.length() > MaxDomainLabelLength)
+ if (label.size() > MaxDomainLabelLength)
return false;
if (label.first() == u'-' || label.last() == u'-')
@@ -709,7 +709,7 @@ bool DomainValidityChecker::checkLabel(const QString &label, QUrl::AceProcessing
if (label != label.normalized(QString::NormalizationForm_C))
return false;
- if (label.length() >= 4) {
+ if (label.size() >= 4) {
// This assumes that the first two characters are in BMP, but that's ok
// because non-BMP characters are unlikely to be used for specifying
// future extensions.
diff --git a/src/corelib/io/qurlquery.cpp b/src/corelib/io/qurlquery.cpp
index ce8ed6414d..3cf2b1e5eb 100644
--- a/src/corelib/io/qurlquery.cpp
+++ b/src/corelib/io/qurlquery.cpp
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
improperly-encoded strings are passed to the setter or query methods,
QUrlQuery will attempt to recover instead of failing. That is to say, all
functions in this class parse their string arguments as if the
- {{QUrl::TolerantMode}} decoding mode was specified.
+ QUrl::TolerantMode decoding mode was specified.
Application code should strive to always ensure proper encoding and not rely
on TolerantMode parsing fixing the strings. Notably, all user input must be
@@ -401,7 +401,11 @@ bool QUrlQuery::operator ==(const QUrlQuery &other) const
return d->valueDelimiter == other.d->valueDelimiter &&
d->pairDelimiter == other.d->pairDelimiter &&
d->itemList == other.d->itemList;
- return false;
+
+ const QUrlQueryPrivate *x = d ? d.data() : other.d.data();
+ return x->valueDelimiter == defaultQueryValueDelimiter() &&
+ x->pairDelimiter == defaultQueryPairDelimiter() &&
+ x->itemList.isEmpty();
}
/*!
@@ -515,7 +519,7 @@ QString QUrlQuery::query(QUrl::ComponentFormattingOptions encoding) const
{
int size = 0;
for ( ; it != end; ++it)
- size += it->first.length() + 1 + it->second.length() + 1;
+ size += it->first.size() + 1 + it->second.size() + 1;
result.reserve(size + size / 4);
}
@@ -630,7 +634,7 @@ QList<QPair<QString, QString> > QUrlQuery::queryItems(QUrl::ComponentFormattingO
QList<QPair<QString, QString> > result;
Map::const_iterator it = d->itemList.constBegin();
Map::const_iterator end = d->itemList.constEnd();
- result.reserve(d->itemList.count());
+ result.reserve(d->itemList.size());
for ( ; it != end; ++it)
result << qMakePair(d->recodeToUser(it->first, encoding),
d->recodeToUser(it->second, encoding));