diff options
Diffstat (limited to 'src/corelib/io/qurl.cpp')
-rw-r--r-- | src/corelib/io/qurl.cpp | 565 |
1 files changed, 267 insertions, 298 deletions
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 0e7ef68ecb..4360b5b076 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -1,42 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only /*! \class QUrl @@ -50,14 +14,18 @@ \ingroup network \ingroup shared + \compares weak 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 @@ -436,16 +404,17 @@ #include "private/qipaddress_p.h" #include "qurlquery.h" #include "private/qdir_p.h" +#include <private/qtools_p.h> QT_BEGIN_NAMESPACE -// in qstring.cpp: -void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept; +using namespace Qt::StringLiterals; +using namespace QtMiscUtils; inline static bool isHex(char c) { c |= 0x20; - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); + return isAsciiDigit(c) || (c >= 'a' && c <= 'f'); } static inline QString ftpScheme() @@ -526,8 +495,8 @@ public: struct Error { QString source; + qsizetype position; ErrorCode code; - int position; }; QUrlPrivate(); @@ -540,11 +509,11 @@ public: std::unique_ptr<Error> cloneError() const; void clearError(); - void setError(ErrorCode errorCode, const QString &source, int supplement = -1); - ErrorCode validityError(QString *source = nullptr, int *position = nullptr) const; - bool validateComponent(Section section, const QString &input, int begin, int end); + void setError(ErrorCode errorCode, const QString &source, qsizetype supplement = -1); + 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, uint(input.length())); } + { return validateComponent(section, input, 0, input.size()); } // no QString scheme() const; void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; @@ -557,15 +526,15 @@ public: void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; // the "end" parameters are like STL iterators: they point to one past the last valid element - bool setScheme(const QString &value, int len, bool doSetError); - void setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode); - void setUserInfo(const QString &userInfo, int from, int end); - void setUserName(const QString &value, int from, int end); - void setPassword(const QString &value, int from, int end); - bool setHost(const QString &value, int from, int end, QUrl::ParsingMode mode); - void setPath(const QString &value, int from, int end); - void setQuery(const QString &value, int from, int end); - void setFragment(const QString &value, int from, int end); + bool setScheme(const QString &value, qsizetype len, bool doSetError); + void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode); + void setUserInfo(const QString &userInfo, qsizetype from, qsizetype end); + void setUserName(const QString &value, qsizetype from, qsizetype end); + void setPassword(const QString &value, qsizetype from, qsizetype end); + bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode); + void setPath(const QString &value, qsizetype from, qsizetype end); + void setQuery(const QString &value, qsizetype from, qsizetype end); + void setFragment(const QString &value, qsizetype from, qsizetype end); inline bool hasScheme() const { return sectionIsPresent & Scheme; } inline bool hasAuthority() const { return sectionIsPresent & Authority; } @@ -642,7 +611,7 @@ inline void QUrlPrivate::clearError() error.reset(); } -inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, int supplement) +inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, qsizetype supplement) { if (error) { // don't overwrite an error set in a previous section during parsing @@ -833,11 +802,11 @@ static const ushort * const fragmentInUrl = userNameInUrl + 6; static inline void parseDecodedComponent(QString &data) { - data.replace(QLatin1Char('%'), QLatin1String("%25")); + data.replace(u'%', "%25"_L1); } static inline QString -recodeFromUser(const QString &input, const ushort *actions, int from, int to) +recodeFromUser(const QString &input, const ushort *actions, qsizetype from, qsizetype to) { QString output; const QChar *begin = input.constData() + from; @@ -853,14 +822,16 @@ recodeFromUser(const QString &input, const ushort *actions, int from, int to) 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 @@ -870,11 +841,11 @@ inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOpti // add '@' only if we added anything if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0)) - appendTo += QLatin1Char('@'); + appendTo += u'@'; } appendHost(appendTo, options); if (!(options & QUrl::RemovePort) && port != -1) - appendTo += QLatin1Char(':') + QString::number(port); + appendTo += u':' + QString::number(port); } inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const @@ -916,7 +887,7 @@ inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptio if (options & QUrl::RemovePassword || !hasPassword()) { return; } else { - appendTo += QLatin1Char(':'); + appendTo += u':'; if (!qt_urlRecode(appendTo, password, options, passwordActions)) appendTo += password; } @@ -945,14 +916,14 @@ inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions o QStringView thePathView(thePath); if (options & QUrl::RemoveFilename) { - const int slash = path.lastIndexOf(QLatin1Char('/')); + const qsizetype slash = path.lastIndexOf(u'/'); if (slash == -1) return; thePathView = QStringView{path}.left(slash + 1); } // check if we need to remove trailing slashes if (options & QUrl::StripTrailingSlash) { - while (thePathView.length() > 1 && thePathView.endsWith(QLatin1Char('/'))) + while (thePathView.size() > 1 && thePathView.endsWith(u'/')) thePathView.chop(1); } @@ -975,7 +946,7 @@ inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions // setXXX functions -inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetError) +inline bool QUrlPrivate::setScheme(const QString &value, qsizetype len, bool doSetError) { // schemes are strictly RFC-compliant: // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) @@ -991,17 +962,17 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro sectionIsPresent |= Scheme; // validate it: - int needsLowercasing = -1; - const ushort *p = value.utf16(); - for (int i = 0; i < len; ++i) { - if (p[i] >= 'a' && p[i] <= 'z') + qsizetype needsLowercasing = -1; + const ushort *p = reinterpret_cast<const ushort *>(value.data()); + for (qsizetype i = 0; i < len; ++i) { + if (isAsciiLower(p[i])) continue; - if (p[i] >= 'A' && p[i] <= 'Z') { + if (isAsciiUpper(p[i])) { needsLowercasing = i; continue; } if (i) { - if (p[i] >= '0' && p[i] <= '9') + if (isAsciiDigit(p[i])) continue; if (p[i] == '+' || p[i] == '-' || p[i] == '.') continue; @@ -1020,9 +991,9 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro if (needsLowercasing != -1) { // schemes are ASCII only, so we don't need the full Unicode toLower QChar *schemeData = scheme.data(); // force detaching here - for (int i = needsLowercasing; i >= 0; --i) { + for (qsizetype i = needsLowercasing; i >= 0; --i) { ushort c = schemeData[i].unicode(); - if (c >= 'A' && c <= 'Z') + if (isAsciiUpper(c)) schemeData[i] = QChar(c + 0x20); } } @@ -1040,7 +1011,7 @@ inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetErro return true; } -inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode) +inline void QUrlPrivate::setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode) { sectionIsPresent &= ~Authority; sectionIsPresent |= Host; @@ -1048,33 +1019,33 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU // we never actually _loop_ while (from != end) { - int userInfoIndex = auth.indexOf(QLatin1Char('@'), from); - if (uint(userInfoIndex) < uint(end)) { + qsizetype userInfoIndex = auth.indexOf(u'@', from); + if (size_t(userInfoIndex) < size_t(end)) { setUserInfo(auth, from, userInfoIndex); if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex)) break; from = userInfoIndex + 1; } - int colonIndex = auth.lastIndexOf(QLatin1Char(':'), end - 1); + qsizetype colonIndex = auth.lastIndexOf(u':', end - 1); if (colonIndex < from) colonIndex = -1; - if (uint(colonIndex) < uint(end)) { + if (size_t(colonIndex) < size_t(end)) { if (auth.at(from).unicode() == '[') { // check if colonIndex isn't inside the "[...]" part - int closingBracket = auth.indexOf(QLatin1Char(']'), from); - if (uint(closingBracket) > uint(colonIndex)) + qsizetype closingBracket = auth.indexOf(u']', from); + if (size_t(closingBracket) > size_t(colonIndex)) colonIndex = -1; } } - if (uint(colonIndex) < uint(end) - 1) { + if (size_t(colonIndex) < size_t(end) - 1) { // found a colon with digits after it unsigned long x = 0; - for (int i = colonIndex + 1; i < end; ++i) { + for (qsizetype i = colonIndex + 1; i < end; ++i) { ushort c = auth.at(i).unicode(); - if (c >= '0' && c <= '9') { + if (isAsciiDigit(c)) { x *= 10; x += c - '0'; } else { @@ -1091,8 +1062,8 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU } } - setHost(auth, from, qMin<uint>(end, colonIndex), mode); - if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<uint>(end, colonIndex))) { + setHost(auth, from, qMin<size_t>(end, colonIndex), mode); + if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) { // clear host too sectionIsPresent &= ~Authority; break; @@ -1109,12 +1080,12 @@ inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QU port = -1; } -inline void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end) +inline void QUrlPrivate::setUserInfo(const QString &userInfo, qsizetype from, qsizetype end) { - int delimIndex = userInfo.indexOf(QLatin1Char(':'), from); - setUserName(userInfo, from, qMin<uint>(delimIndex, end)); + qsizetype delimIndex = userInfo.indexOf(u':', from); + setUserName(userInfo, from, qMin<size_t>(delimIndex, end)); - if (uint(delimIndex) >= uint(end)) { + if (size_t(delimIndex) >= size_t(end)) { password.clear(); sectionIsPresent &= ~Password; } else { @@ -1122,31 +1093,31 @@ inline void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end) } } -inline void QUrlPrivate::setUserName(const QString &value, int from, int end) +inline void QUrlPrivate::setUserName(const QString &value, qsizetype from, qsizetype end) { sectionIsPresent |= UserName; userName = recodeFromUser(value, userNameInIsolation, from, end); } -inline void QUrlPrivate::setPassword(const QString &value, int from, int end) +inline void QUrlPrivate::setPassword(const QString &value, qsizetype from, qsizetype end) { sectionIsPresent |= Password; password = recodeFromUser(value, passwordInIsolation, from, end); } -inline void QUrlPrivate::setPath(const QString &value, int from, int end) +inline void QUrlPrivate::setPath(const QString &value, qsizetype from, qsizetype end) { // sectionIsPresent |= Path; // not used, save some cycles path = recodeFromUser(value, pathInIsolation, from, end); } -inline void QUrlPrivate::setFragment(const QString &value, int from, int end) +inline void QUrlPrivate::setFragment(const QString &value, qsizetype from, qsizetype end) { sectionIsPresent |= Fragment; fragment = recodeFromUser(value, fragmentInIsolation, from, end); } -inline void QUrlPrivate::setQuery(const QString &value, int from, int iend) +inline void QUrlPrivate::setQuery(const QString &value, qsizetype from, qsizetype iend) { sectionIsPresent |= Query; query = recodeFromUser(value, queryInIsolation, from, iend); @@ -1216,16 +1187,14 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar const QChar *const origBegin = begin; if (begin[3].unicode() != '.') return &begin[3]; - if ((begin[2].unicode() >= 'A' && begin[2].unicode() <= 'F') || - (begin[2].unicode() >= 'a' && begin[2].unicode() <= 'f') || - (begin[2].unicode() >= '0' && begin[2].unicode() <= '9')) { + if (isHexDigit(begin[2].unicode())) { // this is so unlikely that we'll just go down the slow path // decode the whole string, skipping the "[vH." and "]" which we already know to be there host += QStringView(begin, 4); // 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; @@ -1237,18 +1206,14 @@ static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar } for ( ; begin != end; ++begin) { - if (begin->unicode() >= 'A' && begin->unicode() <= 'Z') - host += *begin; - else if (begin->unicode() >= 'a' && begin->unicode() <= 'z') - host += *begin; - else if (begin->unicode() >= '0' && begin->unicode() <= '9') + if (isAsciiLetterOrNumber(begin->unicode())) host += *begin; else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) != nullptr) host += *begin; else return decoded.isEmpty() ? begin : &origBegin[2]; } - host += QLatin1Char(']'); + host += u']'; return nullptr; } return &origBegin[2]; @@ -1270,7 +1235,7 @@ static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end QIPAddressUtils::IPv6Address address; QStringView zoneId; - int zoneIdPosition = decoded.indexOf(zoneIdIdentifier); + qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier); if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) { zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size()); decoded.truncate(zoneIdPosition); @@ -1290,23 +1255,24 @@ static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end return begin + (ret - decoded.constBegin()); host.reserve(host.size() + (end - begin) + 2); // +2 for the brackets - host += QLatin1Char('['); + host += u'['; QIPAddressUtils::toString(host, address); if (!zoneId.isEmpty()) { host += zoneIdIdentifier; host += zoneId; } - host += QLatin1Char(']'); + host += u']'; return nullptr; } -inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl::ParsingMode mode) +inline bool +QUrlPrivate::setHost(const QString &value, qsizetype from, qsizetype iend, QUrl::ParsingMode mode) { const QChar *begin = value.constData() + from; const QChar *end = value.constData() + iend; - const int len = end - begin; + const qsizetype len = end - begin; host.clear(); sectionIsPresent |= Host; if (len == 0) @@ -1367,14 +1333,14 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl: if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { }, nullptr)) { // something was decoded // anything encoded left? - int pos = s.indexOf(QChar(0x25)); // '%' + qsizetype pos = s.indexOf(QChar(0x25)); // '%' if (pos != -1) { setError(InvalidRegNameError, s, pos); return false; } // 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, {}); @@ -1407,15 +1373,15 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode clearError(); // find the important delimiters - int colon = -1; - int question = -1; - int hash = -1; - const int len = url.length(); + qsizetype colon = -1; + qsizetype question = -1; + qsizetype hash = -1; + const qsizetype len = url.size(); const QChar *const begin = url.constData(); const ushort *const data = reinterpret_cast<const ushort *>(begin); - for (int i = 0; i < len; ++i) { - uint uc = data[i]; + for (qsizetype i = 0; i < len; ++i) { + size_t uc = data[i]; if (uc == '#' && hash == -1) { hash = i; @@ -1432,7 +1398,7 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode } // check if we have a scheme - int hierStart; + qsizetype hierStart; if (colon != -1 && setScheme(url, colon, /* don't set error */ false)) { hierStart = colon + 1; } else { @@ -1442,12 +1408,12 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode hierStart = 0; } - int pathStart; - int hierEnd = qMin<uint>(qMin<uint>(question, hash), len); + qsizetype pathStart; + qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len); if (hierEnd - hierStart >= 2 && data[hierStart] == '/' && data[hierStart + 1] == '/') { // we have an authority, it ends at the first slash after these - int authorityEnd = hierEnd; - for (int i = hierStart + 2; i < authorityEnd ; ++i) { + qsizetype authorityEnd = hierEnd; + for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) { if (data[i] == '/') { authorityEnd = i; break; @@ -1472,8 +1438,8 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode path.clear(); } - if (uint(question) < uint(hash)) - setQuery(url, question + 1, qMin<uint>(hash, len)); + if (size_t(question) < size_t(hash)) + setQuery(url, question + 1, qMin<size_t>(hash, len)); if (hash != -1) setFragment(url, hash + 1, len); @@ -1489,7 +1455,7 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode if (!validateComponent(Path, url, pathStart, hierEnd)) return; - if (uint(question) < uint(hash) && !validateComponent(Query, url, question + 1, qMin<uint>(hash, len))) + if (size_t(question) < size_t(hash) && !validateComponent(Query, url, question + 1, qMin<size_t>(hash, len))) return; if (hash != -1) validateComponent(Fragment, url, hash + 1, len); @@ -1503,19 +1469,19 @@ QString QUrlPrivate::toLocalFile(QUrl::FormattingOptions options) const // magic for shared drive on windows if (!host.isEmpty()) { - tmp = QLatin1String("//") + host; + tmp = "//"_L1 + host; #ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only. if (scheme == webDavScheme()) tmp += webDavSslTag(); #endif - if (!ourPath.isEmpty() && !ourPath.startsWith(QLatin1Char('/'))) - tmp += QLatin1Char('/'); + if (!ourPath.isEmpty() && !ourPath.startsWith(u'/')) + tmp += u'/'; tmp += ourPath; } else { tmp = ourPath; #ifdef Q_OS_WIN // magic for drives on windows - if (ourPath.length() > 2 && ourPath.at(0) == QLatin1Char('/') && ourPath.at(2) == QLatin1Char(':')) + if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':') tmp.remove(0, 1); #endif } @@ -1536,7 +1502,7 @@ inline QString QUrlPrivate::mergePaths(const QString &relativePath) const // path, then return a string consisting of "/" concatenated with // the reference's path; otherwise, if (!host.isEmpty() && path.isEmpty()) - return QLatin1Char('/') + relativePath; + return u'/' + relativePath; // Return a string consisting of the reference's path component // appended to all but the last segment of the base URI's path @@ -1544,10 +1510,10 @@ inline QString QUrlPrivate::mergePaths(const QString &relativePath) const // base URI path, or excluding the entire base URI path if it does // not contain any "/" characters). QString newPath; - if (!path.contains(QLatin1Char('/'))) + if (!path.contains(u'/')) newPath = relativePath; else - newPath = QStringView{path}.left(path.lastIndexOf(QLatin1Char('/')) + 1) + relativePath; + newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath; return newPath; } @@ -1593,7 +1559,7 @@ static void removeDotsFromPath(QString *path) in += 2; continue; } else if (in == end - 2 && in[0].unicode() == '/' && in[1].unicode() == '.') { - *out++ = QLatin1Char('/'); + *out++ = u'/'; in += 2; break; } @@ -1634,7 +1600,7 @@ static void removeDotsFromPath(QString *path) path->truncate(out - path->constData()); } -inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *position) const +inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, qsizetype *position) const { Q_ASSERT(!source == !position); if (error) { @@ -1660,8 +1626,8 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p if (path.isEmpty()) return NoError; - if (path.at(0) == QLatin1Char('/')) { - if (hasAuthority() || path.length() == 1 || path.at(1) != QLatin1Char('/')) + if (path.at(0) == u'/') { + if (hasAuthority() || path.size() == 1 || path.at(1) != u'/') return NoError; if (source) { *source = path; @@ -1681,7 +1647,7 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p return NoError; // check for a path of "text:text/" - for (int 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 @@ -1700,7 +1666,7 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p } bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString &input, - int begin, int end) + qsizetype begin, qsizetype end) { // What we need to look out for, that the regular parser tolerates: // - percent signs not followed by two hex digits @@ -1721,13 +1687,13 @@ bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString Q_ASSERT(section != Authority && section != Hierarchy && section != FullUrl); const ushort *const data = reinterpret_cast<const ushort *>(input.constData()); - for (uint i = uint(begin); i < uint(end); ++i) { + for (size_t i = size_t(begin); i < size_t(end); ++i) { uint uc = data[i]; if (uc >= 0x80) continue; bool error = false; - if ((uc == '%' && (uint(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2]))) + if ((uc == '%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2]))) || uc <= 0x20 || strchr(forbidden, uc)) { // found an error error = true; @@ -1745,7 +1711,7 @@ bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString if (section == UserInfo) { // is it the user name or the password? errorCode = InvalidUserNameError; - for (uint j = uint(begin); j < i; ++j) + for (size_t j = size_t(begin); j < i; ++j) if (data[j] == ':') { errorCode = InvalidPasswordError; break; @@ -1778,7 +1744,7 @@ inline void QUrlPrivate::validate() const if (!isHostValid) return; - if (scheme == QLatin1String("mailto")) { + if (scheme == "mailto"_L1) { if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) { that->isValid = false; that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "expected empty host, username," @@ -1807,9 +1773,15 @@ inline void QUrlPrivate::validate() const help avoid missing QUrl::resolved() calls, and other misuses of QString to QUrl conversions. - \oldcode + For example, if you have code like + + \code url = filename; // probably not what you want - \newcode + \endcode + + you can rewrite it as + + \code url = QUrl::fromLocalFile(filename); url = baseurl.resolved(QUrl(filename)); \endcode @@ -1819,7 +1791,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 @@ -1864,7 +1849,7 @@ QUrl::QUrl() : d(nullptr) /*! Constructs a copy of \a other. */ -QUrl::QUrl(const QUrl &other) : d(other.d) +QUrl::QUrl(const QUrl &other) noexcept : d(other.d) { if (d) d->ref.ref(); @@ -1983,7 +1968,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); } } @@ -2043,7 +2028,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 @@ -2114,7 +2099,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 @@ -2186,7 +2171,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)) @@ -2249,7 +2234,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)) @@ -2311,18 +2296,18 @@ 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(QLatin1Char('['))) { + } else if (!data.startsWith(u'[')) { // setHost failed, it might be IPv6 or IPvFuture in need of bracketing Q_ASSERT(d->error); - data.prepend(QLatin1Char('[')); - data.append(QLatin1Char(']')); - if (!d->setHost(data, 0, data.length(), mode)) { + data.prepend(u'['); + data.append(u']'); + if (!d->setHost(data, 0, data.size(), mode)) { // failed again - if (data.contains(QLatin1Char(':'))) { + if (data.contains(u':')) { // source data contains ':', so it's an IPv6 error d->error->code = QUrlPrivate::InvalidIPv6AddressError; } @@ -2356,8 +2341,8 @@ QString QUrl::host(ComponentFormattingOptions options) const QString result; if (d) { d->appendHost(result, options); - if (result.startsWith(QLatin1Char('['))) - result = result.mid(1, result.length() - 2); + if (result.startsWith(u'[')) + result = result.mid(1, result.size() - 2); } return result; } @@ -2436,7 +2421,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()) @@ -2511,7 +2496,7 @@ QString QUrl::path(ComponentFormattingOptions options) const QString QUrl::fileName(ComponentFormattingOptions options) const { const QString ourPath = path(options); - const int slash = ourPath.lastIndexOf(QLatin1Char('/')); + const qsizetype slash = ourPath.lastIndexOf(u'/'); if (slash == -1) return ourPath; return ourPath.mid(slash + 1); @@ -2572,7 +2557,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)) @@ -2670,7 +2655,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)) @@ -2769,7 +2754,7 @@ QUrl QUrl::resolved(const QUrl &relative) const t.d->sectionIsPresent |= QUrlPrivate::Query; } } else { - t.d->path = relative.d->path.startsWith(QLatin1Char('/')) + t.d->path = relative.d->path.startsWith(u'/') ? relative.d->path : d->mergePaths(relative.d->path); if (relative.d->hasQuery()) { @@ -2876,26 +2861,26 @@ QString QUrl::toString(FormattingOptions options) const options |= EncodeReserved; if (!(options & QUrl::RemoveScheme) && d->hasScheme()) - url += d->scheme + QLatin1Char(':'); + url += d->scheme + u':'; - bool pathIsAbsolute = d->path.startsWith(QLatin1Char('/')); + bool pathIsAbsolute = d->path.startsWith(u'/'); if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) { - url += QLatin1String("//"); + url += "//"_L1; d->appendAuthority(url, options, QUrlPrivate::FullUrl); } else if (isLocalFile() && pathIsAbsolute) { // Comply with the XDG file URI spec, which requires triple slashes. - url += QLatin1String("//"); + url += "//"_L1; } if (!(options & QUrl::RemovePath)) d->appendPath(url, options, QUrlPrivate::FullUrl); if (!(options & QUrl::RemoveQuery) && d->hasQuery()) { - url += QLatin1Char('?'); + url += u'?'; d->appendQuery(url, options, QUrlPrivate::FullUrl); } if (!(options & QUrl::RemoveFragment) && d->hasFragment()) { - url += QLatin1Char('#'); + url += u'#'; d->appendFragment(url, options, QUrlPrivate::FullUrl); } @@ -2964,7 +2949,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; } @@ -2985,19 +2970,23 @@ QByteArray QUrl::toEncoded(FormattingOptions options) const } /*! - \fn QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode parsingMode) - Parses \a input and returns the corresponding QUrl. \a input is assumed to be in encoded form, containing only ASCII characters. - Parses the URL using \a parsingMode. See setUrl() for more information on + Parses the URL using \a mode. See setUrl() for more information on this parameter. QUrl::DecodedMode is not permitted in this context. + \note In Qt versions prior to 6.7, this function took a QByteArray, not + QByteArrayView. If you experience compile errors, it's because your code + is passing objects that are implicitly convertible to QByteArray, but not + QByteArrayView. Wrap the corresponding argument in \c{QByteArray{~~~}} to + make the cast explicit. This is backwards-compatible with old Qt versions. + \sa toEncoded(), setUrl() */ -QUrl QUrl::fromEncoded(const QByteArray &input, ParsingMode mode) +QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode) { - return QUrl(QString::fromUtf8(input.constData(), input.size()), mode); + return QUrl(QString::fromUtf8(input), mode); } /*! @@ -3054,17 +3043,6 @@ QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions optio ForbidLeadingDot /*FIXME: make configurable*/, options); } -#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) -/*! - \since 4.2 - \overload -*/ -QString QUrl::fromAce(const QByteArray &domain) -{ - return fromAce(domain, {}); -} -#endif - /*! \since 6.3 @@ -3088,102 +3066,104 @@ QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options) .toLatin1(); } -#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) -/*! - \since 4.2 - \overload -*/ -QByteArray QUrl::toAce(const QString &domain) -{ - return toAce(domain, {}); -} -#endif - /*! \internal - Returns \c true if this URL is "less than" the given \a url. This + \fn bool QUrl::operator<(const QUrl &lhs, const QUrl &rhs) + + Returns \c true if URL \a lhs is "less than" URL \a rhs. This provides a means of ordering URLs. */ -bool QUrl::operator <(const QUrl &url) const + +Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs) { - if (!d || !url.d) { - bool thisIsEmpty = !d || d->isEmpty(); - bool thatIsEmpty = !url.d || url.d->isEmpty(); + if (!lhs.d || !rhs.d) { + bool thisIsEmpty = !lhs.d || lhs.d->isEmpty(); + bool thatIsEmpty = !rhs.d || rhs.d->isEmpty(); // sort an empty URL first - return thisIsEmpty && !thatIsEmpty; + if (thisIsEmpty) { + if (!thatIsEmpty) + return Qt::weak_ordering::less; + else + return Qt::weak_ordering::equivalent; + } else { + return Qt::weak_ordering::greater; + } } int cmp; - cmp = d->scheme.compare(url.d->scheme); + cmp = lhs.d->scheme.compare(rhs.d->scheme); if (cmp != 0) - return cmp < 0; + return Qt::compareThreeWay(cmp, 0); - cmp = d->userName.compare(url.d->userName); + cmp = lhs.d->userName.compare(rhs.d->userName); if (cmp != 0) - return cmp < 0; + return Qt::compareThreeWay(cmp, 0); - cmp = d->password.compare(url.d->password); + cmp = lhs.d->password.compare(rhs.d->password); if (cmp != 0) - return cmp < 0; + return Qt::compareThreeWay(cmp, 0); - cmp = d->host.compare(url.d->host); + cmp = lhs.d->host.compare(rhs.d->host); if (cmp != 0) - return cmp < 0; + return Qt::compareThreeWay(cmp, 0); - if (d->port != url.d->port) - return d->port < url.d->port; + if (lhs.d->port != rhs.d->port) + return Qt::compareThreeWay(lhs.d->port, rhs.d->port); - cmp = d->path.compare(url.d->path); + cmp = lhs.d->path.compare(rhs.d->path); if (cmp != 0) - return cmp < 0; + return Qt::compareThreeWay(cmp, 0); - if (d->hasQuery() != url.d->hasQuery()) - return url.d->hasQuery(); + if (lhs.d->hasQuery() != rhs.d->hasQuery()) + return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater; - cmp = d->query.compare(url.d->query); + cmp = lhs.d->query.compare(rhs.d->query); if (cmp != 0) - return cmp < 0; + return Qt::compareThreeWay(cmp, 0); - if (d->hasFragment() != url.d->hasFragment()) - return url.d->hasFragment(); + if (lhs.d->hasFragment() != rhs.d->hasFragment()) + return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater; - cmp = d->fragment.compare(url.d->fragment); - return cmp < 0; + cmp = lhs.d->fragment.compare(rhs.d->fragment); + return Qt::compareThreeWay(cmp, 0); } /*! - Returns \c true if this URL and the given \a url are equal; + \fn bool QUrl::operator==(const QUrl &lhs, const QUrl &rhs) + + Returns \c true if \a lhs and \a rhs URLs are equivalent; otherwise returns \c false. \sa matches() */ -bool QUrl::operator ==(const QUrl &url) const + +bool comparesEqual(const QUrl &lhs, const QUrl &rhs) { - if (!d && !url.d) + if (!lhs.d && !rhs.d) return true; - if (!d) - return url.d->isEmpty(); - if (!url.d) - return d->isEmpty(); + if (!lhs.d) + return rhs.d->isEmpty(); + if (!rhs.d) + return lhs.d->isEmpty(); // First, compare which sections are present, since it speeds up the // processing considerably. We just have to ignore the host-is-present flag // for local files (the "file" protocol), due to the requirements of the // XDG file URI specification. int mask = QUrlPrivate::FullUrl; - if (isLocalFile()) + if (lhs.isLocalFile()) mask &= ~QUrlPrivate::Host; - return (d->sectionIsPresent & mask) == (url.d->sectionIsPresent & mask) && - d->scheme == url.d->scheme && - d->userName == url.d->userName && - d->password == url.d->password && - d->host == url.d->host && - d->port == url.d->port && - d->path == url.d->path && - d->query == url.d->query && - d->fragment == url.d->fragment; + return (lhs.d->sectionIsPresent & mask) == (rhs.d->sectionIsPresent & mask) && + lhs.d->scheme == rhs.d->scheme && + lhs.d->userName == rhs.d->userName && + lhs.d->password == rhs.d->password && + lhs.d->host == rhs.d->host && + lhs.d->port == rhs.d->port && + lhs.d->path == rhs.d->path && + lhs.d->query == rhs.d->query && + lhs.d->fragment == rhs.d->fragment; } /*! @@ -3263,20 +3243,18 @@ bool QUrl::matches(const QUrl &url, FormattingOptions options) const } /*! - Returns \c true if this URL and the given \a url are not equal; + \fn bool QUrl::operator !=(const QUrl &lhs, const QUrl &rhs) + + Returns \c true if \a lhs and \a rhs URLs are not equal; otherwise returns \c false. \sa matches() */ -bool QUrl::operator !=(const QUrl &url) const -{ - return !(*this == url); -} /*! Assigns the specified \a url to this object. */ -QUrl &QUrl::operator =(const QUrl &url) +QUrl &QUrl::operator =(const QUrl &url) noexcept { if (!d) { if (url.d) { @@ -3395,11 +3373,11 @@ QUrl QUrl::fromLocalFile(const QString &localFile) QString deslashified = fromNativeSeparators(localFile); // magic for drives on windows - if (deslashified.length() > 1 && deslashified.at(1) == QLatin1Char(':') && deslashified.at(0) != QLatin1Char('/')) { - deslashified.prepend(QLatin1Char('/')); - } else if (deslashified.startsWith(QLatin1String("//"))) { + 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 - int indexOfPath = deslashified.indexOf(QLatin1Char('/'), 2); + qsizetype indexOfPath = deslashified.indexOf(u'/', 2); QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2); // Check for Windows-specific WebDAV specification: "//host@SSL/path". if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) { @@ -3416,7 +3394,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(); } @@ -3480,16 +3458,16 @@ bool QUrl::isParentOf(const QUrl &childUrl) const if (!d) return ((childUrl.scheme().isEmpty()) && (childUrl.authority().isEmpty()) - && childPath.length() > 0 && childPath.at(0) == QLatin1Char('/')); + && 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(QLatin1Char('/')) && childPath.length() > ourPath.length()) - || (!ourPath.endsWith(QLatin1Char('/')) - && childPath.length() > ourPath.length() && childPath.at(ourPath.length()) == QLatin1Char('/')))); + && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size()) + || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size() + && childPath.at(ourPath.size()) == u'/'))); } @@ -3535,34 +3513,31 @@ QDebug operator<<(QDebug d, const QUrl &url) } #endif -static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, int errorPosition) +static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition) { - QChar c = uint(errorPosition) < uint(errorSource.length()) ? + QChar c = size_t(errorPosition) < size_t(errorSource.size()) ? errorSource.at(errorPosition) : QChar(QChar::Null); switch (errorCode) { case QUrlPrivate::NoError: - Q_ASSERT_X(false, "QUrl::errorString", - "Impossible: QUrl::errorString should have treated this condition"); - Q_UNREACHABLE(); - return QString(); + Q_UNREACHABLE_RETURN(QString()); // QUrl::errorString should have treated this condition case QUrlPrivate::InvalidSchemeError: { - auto msg = QLatin1String("Invalid scheme (character '%1' not permitted)"); + auto msg = "Invalid scheme (character '%1' not permitted)"_L1; return msg.arg(c); } case QUrlPrivate::InvalidUserNameError: - return QLatin1String("Invalid user name (character '%1' not permitted)") + return "Invalid user name (character '%1' not permitted)"_L1 .arg(c); case QUrlPrivate::InvalidPasswordError: - return QLatin1String("Invalid password (character '%1' not permitted)") + return "Invalid password (character '%1' not permitted)"_L1 .arg(c); case QUrlPrivate::InvalidRegNameError: - if (errorPosition != -1) - return QLatin1String("Invalid hostname (character '%1' not permitted)") + if (errorPosition >= 0) + return "Invalid hostname (character '%1' not permitted)"_L1 .arg(c); else return QStringLiteral("Invalid hostname (contains invalid characters)"); @@ -3571,9 +3546,9 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err case QUrlPrivate::InvalidIPv6AddressError: return QStringLiteral("Invalid IPv6 address"); case QUrlPrivate::InvalidCharacterInIPv6Error: - return QLatin1String("Invalid IPv6 address (character '%1' not permitted)").arg(c); + return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c); case QUrlPrivate::InvalidIPvFutureError: - return QLatin1String("Invalid IPvFuture address (character '%1' not permitted)").arg(c); + return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c); case QUrlPrivate::HostMissingEndBracket: return QStringLiteral("Expected ']' to match '[' in hostname"); @@ -3583,15 +3558,15 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err return QStringLiteral("Port field was empty"); case QUrlPrivate::InvalidPathError: - return QLatin1String("Invalid path (character '%1' not permitted)") + return "Invalid path (character '%1' not permitted)"_L1 .arg(c); case QUrlPrivate::InvalidQueryError: - return QLatin1String("Invalid query (character '%1' not permitted)") + return "Invalid query (character '%1' not permitted)"_L1 .arg(c); case QUrlPrivate::InvalidFragmentError: - return QLatin1String("Invalid fragment (character '%1' not permitted)") + return "Invalid fragment (character '%1' not permitted)"_L1 .arg(c); case QUrlPrivate::AuthorityPresentAndPathIsRelative: @@ -3602,20 +3577,14 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err return QStringLiteral("Relative URL's path component contains ':' before any '/'"); } - Q_ASSERT_X(false, "QUrl::errorString", "Cannot happen, unknown error"); - Q_UNREACHABLE(); - return QString(); + Q_UNREACHABLE_RETURN(QString()); } static inline void appendComponentIfPresent(QString &msg, bool present, const char *componentName, const QString &component) { - if (present) { - msg += QLatin1String(componentName); - msg += QLatin1Char('"'); - msg += component; - msg += QLatin1String("\","); - } + if (present) + msg += QLatin1StringView(componentName) % u'"' % component % "\","_L1; } /*! @@ -3638,15 +3607,15 @@ QString QUrl::errorString() const return msg; QString errorSource; - int errorPosition = 0; + qsizetype errorPosition = 0; QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition); if (errorCode == QUrlPrivate::NoError) return msg; msg += errorMessage(errorCode, errorSource, errorPosition); - msg += QLatin1String("; source was \""); + msg += "; source was \""_L1; msg += errorSource; - msg += QLatin1String("\";"); + msg += "\";"_L1; appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme, " scheme = ", d->scheme); appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo, @@ -3661,7 +3630,7 @@ QString QUrl::errorString() const " query = ", d->query); appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment, " fragment = ", d->fragment); - if (msg.endsWith(QLatin1Char(','))) + if (msg.endsWith(u',')) msg.chop(1); return msg; } @@ -3732,8 +3701,8 @@ static QUrl adjustFtpPath(QUrl url) { if (url.scheme() == ftpScheme()) { QString path = url.path(QUrl::PrettyDecoded); - if (path.startsWith(QLatin1String("//"))) - url.setPath(QLatin1String("/%2F") + QStringView{path}.mid(2), QUrl::TolerantMode); + if (path.startsWith("//"_L1)) + url.setPath("/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode); } return url; } @@ -3818,7 +3787,7 @@ QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirecto if (QDir::isAbsolutePath(trimmedString)) return QUrl::fromLocalFile(trimmedString); - QUrl urlPrepended = QUrl(QLatin1String("http://") + trimmedString, QUrl::TolerantMode); + QUrl urlPrepended = QUrl("http://"_L1 + trimmedString, QUrl::TolerantMode); // Check the most common case of a valid url with a scheme // We check if the port would be valid by adding the scheme to handle the case host:port @@ -3830,7 +3799,7 @@ QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirecto // Else, try the prepended one and adjust the scheme from the host name if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) { - int dotIndex = trimmedString.indexOf(QLatin1Char('.')); + qsizetype dotIndex = trimmedString.indexOf(u'.'); const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex); if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0) urlPrepended.setScheme(ftpScheme()); |