QFileSystemIterator/Unix: use QStringDecoder
The end result is a QFileInfo constructed from the QFileSystemEntry; QFileSystemEntry's API will at some point convert the NativePath (QBA on Unix) to a QString, e.g. when it calls findLastSeparator(). So instead of converting the parent dir path from Utf8 to Utf16 multiple times, store the dir path as a QString once in the constructor. Use QStringDecoder to convert the dirent->d_name to Utf16 and check the decoder's hasError(); which as Thiago pointed out, is more efficient than using isValidUtf8(), throwing away the results, then converting to unicode anyway later on in QDirIteratorPrivate::advance(). (Ironically) `QFileSystemEntry::NativePath nativePath` is still used on Windows. Change-Id: Icd2b130103640b502862d210d64926b99c499a01 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>bb10
parent
74722411d3
commit
83f7125ac8
|
|
@ -26,6 +26,10 @@
|
|||
#include <QtCore/private/qfilesystementry_p.h>
|
||||
#include <QtCore/private/qfilesystemmetadata_p.h>
|
||||
|
||||
#if !defined(Q_OS_WIN)
|
||||
#include <private/qstringconverter_p.h>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -39,11 +43,11 @@ public:
|
|||
bool advance(QFileSystemEntry &fileEntry, QFileSystemMetaData &metaData);
|
||||
|
||||
private:
|
||||
QFileSystemEntry::NativePath nativePath;
|
||||
QString dirPath;
|
||||
|
||||
// Platform-specific data
|
||||
#if defined(Q_OS_WIN)
|
||||
QString dirPath;
|
||||
QFileSystemEntry::NativePath nativePath;
|
||||
HANDLE findFileHandle;
|
||||
QStringList uncShares;
|
||||
bool uncFallback;
|
||||
|
|
@ -58,6 +62,7 @@ private:
|
|||
|
||||
QT_DIRENT *dirEntry = nullptr;
|
||||
int lastError = 0;
|
||||
QStringDecoder toUtf16;
|
||||
#endif
|
||||
|
||||
Q_DISABLE_COPY_MOVE(QFileSystemIterator)
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
#include "qplatformdefs.h"
|
||||
#include "qfilesystemiterator_p.h"
|
||||
|
||||
#include <private/qstringconverter_p.h>
|
||||
|
||||
#ifndef QT_NO_FILESYSTEMITERATOR
|
||||
|
||||
#include <qvarlengtharray.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
|
@ -15,20 +15,13 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
static bool checkNameDecodable(const char *d_name, qsizetype len)
|
||||
{
|
||||
// This function is called in a loop from advance() below, but the loop is
|
||||
// usually run only once.
|
||||
|
||||
return QUtf8::isValidUtf8(QByteArrayView(d_name, len)).isValidUtf8;
|
||||
}
|
||||
|
||||
/*
|
||||
Native filesystem iterator, which uses ::opendir()/readdir()/dirent from the system
|
||||
libraries to iterate over the directory represented by \a entry.
|
||||
*/
|
||||
QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters)
|
||||
: nativePath(entry.nativeFilePath())
|
||||
: dirPath(entry.filePath()),
|
||||
toUtf16(QStringDecoder::Utf8)
|
||||
{
|
||||
Q_UNUSED(filters);
|
||||
|
||||
|
|
@ -36,8 +29,8 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Fi
|
|||
if (!dir) {
|
||||
lastError = errno;
|
||||
} else {
|
||||
if (!nativePath.endsWith('/'))
|
||||
nativePath.append('/');
|
||||
if (!dirPath.endsWith(u'/'))
|
||||
dirPath.append(u'/');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,9 +51,18 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
|
|||
dirEntry = QT_READDIR(dir.get());
|
||||
|
||||
if (dirEntry) {
|
||||
qsizetype len = strlen(dirEntry->d_name);
|
||||
if (checkNameDecodable(dirEntry->d_name, len)) {
|
||||
fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name, len), QFileSystemEntry::FromNativePath());
|
||||
// POSIX allows readdir() to return a file name in struct dirent that
|
||||
// extends past the end of the d_name array (it's a char[1] array on QNX, for
|
||||
// example). Therefore, we *must* call strlen() on it to get the actual length
|
||||
// of the file name. See:
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html#tag_13_07_05
|
||||
QByteArrayView name(dirEntry->d_name, strlen(dirEntry->d_name));
|
||||
// name.size() is sufficient here, see QUtf8::convertToUnicode() for details
|
||||
QVarLengthArray<char16_t> buffer(name.size());
|
||||
auto *end = toUtf16.appendToBuffer(buffer.data(), name);
|
||||
buffer.resize(end - buffer.constData());
|
||||
if (!toUtf16.hasError()) {
|
||||
fileEntry = {dirPath + QStringView(buffer), QFileSystemEntry::FromInternalPath()};
|
||||
metaData.fillFromDirEnt(*dirEntry);
|
||||
return true;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ using namespace Qt::StringLiterals;
|
|||
bool done = true;
|
||||
|
||||
QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters)
|
||||
: nativePath(entry.nativeFilePath())
|
||||
, dirPath(entry.filePath())
|
||||
: dirPath(entry.filePath())
|
||||
, nativePath(entry.nativeFilePath())
|
||||
, findFileHandle(INVALID_HANDLE_VALUE)
|
||||
, uncFallback(false)
|
||||
, uncShareIndex(0)
|
||||
|
|
|
|||
Loading…
Reference in New Issue