diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index f10e1569473..a7e12eaae35 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -2223,16 +2223,12 @@ bool QDir::match(const QString &filter, const QString &fileName) "a/b/" and "a/b//../.." becomes "a/"), which matches the behavior observed in web browsers. - However, QUrl also uses local path mode for local URLs; with one exception: - Even in local mode we leave one trailing slash for paths ending in "/." if - the KeepLocalTrailingSlash flag is given. This reflects how QUrl needs to - treat local URLs due to compatibility constraints. + As a Qt extension, for local URLs we treat multiple slashes as one slash. */ bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations flags) { const bool allowUncPaths = flags.testAnyFlag(QDirPrivate::AllowUncPaths); const bool isRemote = flags.testAnyFlag(QDirPrivate::RemotePath); - const bool keepLocalTrailingSlash = flags.testAnyFlags(QDirPrivate::KeepLocalTrailingSlash); const qsizetype prefixLength = rootLength(*path, allowUncPaths); // RFC 3986 says: "The input buffer is initialized with the now-appended @@ -2343,27 +2339,12 @@ bool qt_normalizePathSegments(QString *path, QDirPrivate::PathNormalizations fla ++in; // the one dot } - if (out > start) { - // Always backtrack one slash - if (out[-1] == u'/' && in != end) - --out; - - if (!isRemote) { - bool removedAnySlashes = false; - - // Backtrack all slashes ... - while (out > start && out[-1] == u'/') { - --out; - removedAnySlashes = true; - } - - // ... except a trailing one if it exists and flag given - if (removedAnySlashes && keepLocalTrailingSlash && out > start) { - ++out; - break; - } - } - } + // Not at 'end' yet, prepare for the next loop iteration by backtracking one slash. + // E.g.: /a/b/../c >>> /a/b/../c + // ^out ^out + // the next iteration will copy '/c' to the output buffer >>> /a/c + if (in != end && out > start && out[-1] == u'/') + --out; if (out == start) { // We've reached the root. Make sure we don't turn a relative path // to absolute or, in the case of local paths that are already diff --git a/src/corelib/io/qdir_p.h b/src/corelib/io/qdir_p.h index 3641d003bec..36a20c64723 100644 --- a/src/corelib/io/qdir_p.h +++ b/src/corelib/io/qdir_p.h @@ -31,7 +31,6 @@ public: DefaultNormalization = 0x00, AllowUncPaths = 0x01, RemotePath = 0x02, - KeepLocalTrailingSlash = 0x04, }; Q_DECLARE_FLAGS(PathNormalizations, PathNormalization) Q_FLAGS(PathNormalizations) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 2b34c6b8bcb..7bd2288b8af 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -913,7 +913,7 @@ inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions o if (options & QUrl::NormalizePathSegments) { qt_normalizePathSegments( &thePath, - isLocalFile() ? QDirPrivate::KeepLocalTrailingSlash : QDirPrivate::RemotePath); + isLocalFile() ? QDirPrivate::DefaultNormalization : QDirPrivate::RemotePath); } QStringView thePathView(thePath); @@ -2716,7 +2716,7 @@ QUrl QUrl::resolved(const QUrl &relative) const qt_normalizePathSegments( &t.d->path, - isLocalFile() ? QDirPrivate::KeepLocalTrailingSlash : QDirPrivate::RemotePath); + isLocalFile() ? QDirPrivate::DefaultNormalization : QDirPrivate::RemotePath); if (!t.d->hasAuthority()) fixupNonAuthorityPath(&t.d->path); diff --git a/tests/auto/corelib/io/qdir/tst_qdir.cpp b/tests/auto/corelib/io/qdir/tst_qdir.cpp index da83ca898a0..bc9bd8411b3 100644 --- a/tests/auto/corelib/io/qdir/tst_qdir.cpp +++ b/tests/auto/corelib/io/qdir/tst_qdir.cpp @@ -1384,8 +1384,14 @@ void tst_QDir::normalizePathSegments_data() QTest::addColumn("uncHandling"); QTest::addColumn("expected"); - QTest::newRow("data0") << "/Users/sam/troll/qt4.0//.." << HandleUnc << "/Users/sam/troll"; - QTest::newRow("data1") << "/Users/sam////troll/qt4.0//.." << HandleUnc << "/Users/sam/troll"; + QTest::newRow("data0") << "/Users/sam/troll/qt4.0//.." << HandleUnc << "/Users/sam/troll/"; + QTest::newRow("data1") << "/Users/sam////troll/qt4.0//.." << HandleUnc << "/Users/sam/troll/"; + QTest::newRow("data53") <<"/b//." << HandleUnc << "/b/"; + QTest::newRow("data54") <<"/b//./" << HandleUnc << "/b/"; + QTest::newRow("data55") <<"/b/." << HandleUnc << "/b/"; + QTest::newRow("data56") <<"/b/./" << HandleUnc << "/b/"; + QTest::newRow("data57") <<"/b" << HandleUnc << "/b"; + QTest::newRow("data2") << "/" << HandleUnc << "/"; QTest::newRow("data3") << "//" << HandleUnc << "//"; QTest::newRow("data4") << "//" << IgnoreUnc << "/"; @@ -1426,12 +1432,11 @@ void tst_QDir::normalizePathSegments_data() QTest::newRow("data34") << "c://foo" << HandleUnc << "c:/foo"; QTest::newRow("data35") << "c:" << HandleUnc << "c:"; QTest::newRow("data36") << "c:foo/bar" << IgnoreUnc << "c:foo/bar"; -#if defined Q_OS_WIN QTest::newRow("data37") << "c:/." << HandleUnc << "c:/"; +#if defined Q_OS_WIN QTest::newRow("data38") << "c:/.." << HandleUnc << "c:/.."; QTest::newRow("data39") << "c:/../" << HandleUnc << "c:/../"; #else - QTest::newRow("data37") << "c:/." << HandleUnc << "c:"; QTest::newRow("data38") << "c:/.." << HandleUnc << "."; QTest::newRow("data39") << "c:/../" << HandleUnc << "."; #endif @@ -1439,9 +1444,9 @@ void tst_QDir::normalizePathSegments_data() QTest::newRow("data41") << "foo/../foo/.." << HandleUnc << "."; QTest::newRow("data42") << "foo/../foo/../.." << HandleUnc << ".."; QTest::newRow("data43") << "..foo.bar/foo" << HandleUnc << "..foo.bar/foo"; - QTest::newRow("data44") << ".foo./bar/.." << HandleUnc << ".foo."; + QTest::newRow("data44") << ".foo./bar/.." << HandleUnc << ".foo./"; QTest::newRow("data45") << "foo/..bar.." << HandleUnc << "foo/..bar.."; - QTest::newRow("data46") << "foo/.bar./.." << HandleUnc << "foo"; + QTest::newRow("data46") << "foo/.bar./.." << HandleUnc << "foo/"; QTest::newRow("data47") << "//foo//bar" << HandleUnc << "//foo/bar"; QTest::newRow("data48") << "..." << HandleUnc << "..."; QTest::newRow("data49") << "foo/.../bar" << HandleUnc << "foo/.../bar"; diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index ea751b586ee..dcda0ff97ff 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -1487,6 +1487,11 @@ void tst_QUrl::fromLocalFileNormalize_data() QTest::newRow("absolute-path") << QString::fromLatin1("/a.txt") << QString::fromLatin1("file:///a.txt") << QString::fromLatin1("file:///a.txt"); QTest::newRow("relative-path") << QString::fromLatin1("a.txt") << QString::fromLatin1("file:a.txt") << QString::fromLatin1("file:a.txt"); + + QTest::newRow("absolute-path-trailing-slash") << u"/b/"_s << u"file:///b/"_s << u"file:///b/"_s; + QTest::newRow("absolute-path-no-trailing-slash") << u"/b"_s << u"file:///b"_s << u"file:///b"_s; + QTest::newRow("absolute-path-2-trailing-slashes") << u"/b//"_s << u"file:///b//"_s << u"file:///b/"_s; + QTest::newRow("percent") << QString::fromLatin1("/a%.txt") << QString::fromLatin1("file:///a%25.txt") << QString::fromLatin1("file:///a%25.txt"); QTest::newRow("percent25") << QString::fromLatin1("/a%25.txt") << QString::fromLatin1("file:///a%2525.txt")