summaryrefslogtreecommitdiffstats
path: root/src/corelib/io/qurl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io/qurl.cpp')
-rw-r--r--src/corelib/io/qurl.cpp620
1 files changed, 317 insertions, 303 deletions
diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp
index 1e198ebdd3..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
@@ -390,6 +358,25 @@
*/
/*!
+ \enum QUrl::AceProcessingOption
+ \since 6.3
+
+ The ACE processing options control the way URLs are transformed to and from
+ ASCII-Compatible Encoding.
+
+ \value IgnoreIDNWhitelist Ignore the IDN whitelist when converting URLs
+ to Unicode.
+ \value AceTransitionalProcessing Use transitional processing described in UTS #46.
+ This allows better compatibility with IDNA 2003
+ specification.
+
+ The default is to use nontransitional processing and to allow non-ASCII
+ characters only inside URLs whose top-level domains are listed in the IDN whitelist.
+
+ \sa toAce(), fromAce(), idnWhitelist()
+*/
+
+/*!
\fn QUrl::QUrl(QUrl &&other)
Move-constructs a QUrl instance, making it point at the same
@@ -417,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()
@@ -507,8 +495,8 @@ public:
struct Error {
QString source;
+ qsizetype position;
ErrorCode code;
- int position;
};
QUrlPrivate();
@@ -521,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;
@@ -538,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; }
@@ -623,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
@@ -814,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;
@@ -834,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
@@ -851,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
@@ -897,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;
}
@@ -926,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);
}
@@ -956,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 / "+" / "-" / "." )
@@ -972,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;
@@ -1001,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);
}
}
@@ -1021,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;
@@ -1029,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 {
@@ -1072,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;
@@ -1090,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 {
@@ -1103,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);
@@ -1177,7 +1167,7 @@ inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions o
// this is either an IPv4Address or a reg-name
// if it is a reg-name, it is already stored in Unicode form
if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
- appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot);
+ appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot, {});
else
appendTo += host;
}
@@ -1197,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;
@@ -1218,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];
@@ -1251,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);
@@ -1271,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)
@@ -1339,7 +1324,7 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl:
// Unicode encoding (some non-ASCII characters case-fold to digits
// when nameprepping is done)
//
- // The qt_ACE_do function below applies nameprepping and the STD3 check.
+ // The qt_ACE_do function below does IDNA normalization and the STD3 check.
// That means a Unicode string may become an IPv4 address, but it cannot
// produce a '[' or a '%'.
@@ -1348,17 +1333,17 @@ 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(QStringView(begin, len), NormalizeAce, ForbidLeadingDot);
+ s = qt_ACE_do(value.mid(from, iend - from), NormalizeAce, ForbidLeadingDot, {});
if (s.isEmpty()) {
setError(InvalidRegNameError, value);
return false;
@@ -1388,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;
@@ -1413,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 {
@@ -1423,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;
@@ -1453,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);
@@ -1470,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);
@@ -1484,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
}
@@ -1517,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
@@ -1525,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;
}
@@ -1574,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;
}
@@ -1615,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) {
@@ -1641,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;
@@ -1662,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
@@ -1681,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
@@ -1702,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;
@@ -1726,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;
@@ -1759,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,"
@@ -1788,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
@@ -1800,10 +1791,23 @@ 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,
- undercores, dots and tildes). All other characters are left in their
+ underscores, dots and tildes). All other characters are left in their
original forms.
Parses the \a url using the parser mode \a parsingMode. In TolerantMode
@@ -1845,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();
@@ -1907,7 +1911,7 @@ void QUrl::clear()
Parses \a url and sets this object to that value. 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, undercores, dots and tildes). All other characters are
+ digits, hyphens, underscores, dots and tildes). All other characters are
left in their original forms.
Parses the \a url using the parser mode \a parsingMode. In TolerantMode
@@ -1939,7 +1943,7 @@ void QUrl::setUrl(const QString &url, ParsingMode parsingMode)
The scheme describes the type (or protocol) of the URL. It's
represented by one or more ASCII characters at the start the URL.
- A scheme is strictly \l {http://www.ietf.org/rfc/rfc3986.txt} {RFC 3986}-compliant:
+ A scheme is strictly \l {RFC 3986}-compliant:
\tt {scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )}
The following example shows a URL where the scheme is "ftp":
@@ -1964,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);
}
}
@@ -2024,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
@@ -2095,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
@@ -2167,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))
@@ -2230,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))
@@ -2292,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;
}
@@ -2337,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;
}
@@ -2417,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())
@@ -2492,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);
@@ -2553,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))
@@ -2651,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))
@@ -2750,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()) {
@@ -2857,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);
}
@@ -2945,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;
}
@@ -2966,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);
}
/*!
@@ -3013,134 +3021,149 @@ QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclu
}
/*!
- \since 4.2
+ \since 6.3
Returns the Unicode form of the given domain name
\a domain, which is encoded in the ASCII Compatible Encoding (ACE).
+ The output can be customized by passing flags with \a options.
The result of this function is considered equivalent to \a domain.
If the value in \a domain cannot be encoded, it will be converted
to QString and returned.
- The ASCII Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491
- and RFC 3492. It is part of the Internationalizing Domain Names in
- Applications (IDNA) specification, which allows for domain names
- (like \c "example.com") to be written using international
- characters.
+ The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491
+ and RFC 3492 and updated by the Unicode Technical Standard #46. It is part
+ of the Internationalizing Domain Names in Applications (IDNA) specification,
+ which allows for domain names (like \c "example.com") to be written using
+ non-US-ASCII characters.
*/
-QString QUrl::fromAce(const QByteArray &domain)
+QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions options)
{
- QVarLengthArray<char16_t> buffer;
- buffer.resize(domain.size());
- qt_from_latin1(buffer.data(), domain.data(), domain.size());
- return qt_ACE_do(QStringView{buffer.data(), buffer.size()},
- NormalizeAce, ForbidLeadingDot /*FIXME: make configurable*/);
+ return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
+ ForbidLeadingDot /*FIXME: make configurable*/, options);
}
/*!
- \since 4.2
+ \since 6.3
Returns the ASCII Compatible Encoding of the given domain name \a domain.
+ The output can be customized by passing flags with \a options.
The result of this function is considered equivalent to \a domain.
The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491
- and RFC 3492. It is part of the Internationalizing Domain Names in
- Applications (IDNA) specification, which allows for domain names
- (like \c "example.com") to be written using international
- characters.
+ and RFC 3492 and updated by the Unicode Technical Standard #46. It is part
+ of the Internationalizing Domain Names in Applications (IDNA) specification,
+ which allows for domain names (like \c "example.com") to be written using
+ non-US-ASCII characters.
This function returns an empty QByteArray if \a domain is not a valid
hostname. Note, in particular, that IPv6 literals are not valid domain
names.
*/
-QByteArray QUrl::toAce(const QString &domain)
+QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
{
- return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/).toLatin1();
+ return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/, options)
+ .toLatin1();
}
/*!
\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;
}
/*!
@@ -3220,18 +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) {
@@ -3350,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)) {
@@ -3371,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();
}
@@ -3435,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'/')));
}
@@ -3490,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)");
@@ -3526,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");
@@ -3538,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:
@@ -3557,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;
}
/*!
@@ -3593,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,
@@ -3616,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;
}
@@ -3687,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;
}
@@ -3769,15 +3783,15 @@ QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirecto
return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
}
- // Check first for files, since on Windows drive letters can be interpretted as schemes
+ // Check first for files, since on Windows drive letters can be interpreted as schemes
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
- // where the host would be interpretted as the scheme
+ // where the host would be interpreted as the scheme
if (url.isValid()
&& !url.scheme().isEmpty()
&& urlPrepended.port() == -1)
@@ -3785,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());