7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
406
407
408
409
410
411
412
415
416
417
418
419
420
424#include "qplatformdefs.h"
430#include "private/qipaddress_p.h"
432#include "private/qdir_p.h"
433#include <private/qtools_p.h>
437using namespace Qt::StringLiterals;
438using namespace QtMiscUtils;
443 return isAsciiDigit(c) || (c >=
'a' && c <=
'f');
532 void parse(
const QString &url, QUrl::ParsingMode parsingMode);
534 {
return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
549 void appendHost(QString &appendTo, QUrl::FormattingOptions options)
const;
555 bool setScheme(
const QString &value, qsizetype len,
bool doSetError);
556 void setAuthority(
const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
557 template <
typename String>
void setUserInfo(String &&value, QUrl::ParsingMode mode);
558 template <
typename String>
void setUserName(String &&value, QUrl::ParsingMode mode);
559 template <
typename String>
void setPassword(String &&value, QUrl::ParsingMode mode);
560 bool setHost(
const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
561 template <
typename String>
void setPath(String &&value, QUrl::ParsingMode mode);
562 template <
typename String>
void setQuery(String &&value, QUrl::ParsingMode mode);
563 template <
typename String>
void setFragment(String &&value, QUrl::ParsingMode mode);
567 uint s = sectionIsPresent;
582 inline bool hasScheme()
const {
return sectionIsPresent & Scheme; }
583 inline bool hasAuthority()
const {
return sectionIsPresent & Authority; }
584 inline bool hasUserInfo()
const {
return sectionIsPresent & UserInfo; }
585 inline bool hasUserName()
const {
return sectionIsPresent & UserName; }
586 inline bool hasPassword()
const {
return sectionIsPresent & Password; }
587 inline bool hasHost()
const {
return sectionIsPresent & Host; }
589 inline bool hasPath()
const {
return !path.isEmpty(); }
590 inline bool hasQuery()
const {
return sectionIsPresent & Query; }
591 inline bool hasFragment()
const {
return sectionIsPresent & Fragment; }
598 QDirPrivate::PathNormalizations mode = QDirPrivate::UrlNormalizationMode;
600 mode |= QDirPrivate::RemotePath;
601 return qt_normalizePathSegments(path, mode);
608 scheme = userName = password = host = path = query = fragment = QString();
610 sectionIsPresent = 0;
665 return error ? std::make_unique<Error>(*error) :
nullptr;
679 error = std::make_unique<Error>();
680 error->code = errorCode;
681 error->source = source;
682 error->position = supplement;
775template <
typename T>
constexpr ushort decode(T x)
noexcept {
return ushort(x); }
776template <
typename T>
constexpr ushort leave(T x)
noexcept {
return ushort(0x100 | x); }
777template <
typename T>
constexpr ushort encode(T x)
noexcept {
return ushort(0x200 | x); }
864recodeFromUser(QString &output,
const QString &input,
const ushort *actions, QUrl::ParsingMode mode)
868 if (mode == QUrl::DecodedMode)
869 appended = qt_encodeFromUser(output, input, actions);
871 appended = qt_urlRecode(output, input, {}, actions);
877recodeFromUser(QString &output, QStringView input,
const ushort *actions, QUrl::ParsingMode mode)
879 Q_ASSERT_X(mode != QUrl::DecodedMode,
"recodeFromUser",
880 "This function should only be called when parsing encoded components");
883 if (qt_urlRecode(output, input, {}, actions))
885 output.append(input);
890static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
891 const ushort *actions)
896 if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
897 !qt_urlRecode(appendTo, value, options, actions))
901 if (appendTo.isNull() && !value.isNull())
907 if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
908 appendUserInfo(appendTo, options, appendingTo);
911 if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
914 appendHost(appendTo, options);
915 if (!(options & QUrl::RemovePort) && port != -1)
916 appendTo += u':' + QString::number(port);
924 const ushort *userNameActions;
925 const ushort *passwordActions;
926 if (options & QUrl::EncodeDelimiters) {
930 switch (appendingTo) {
953 if (!qt_urlRecode(appendTo, userName, options, userNameActions))
954 appendTo += userName;
955 if (options & QUrl::RemovePassword || !hasPassword()) {
959 if (!qt_urlRecode(appendTo, password, options, passwordActions))
960 appendTo += password;
967 appendToUser(appendTo, userName, options,
968 options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation);
976 appendToUser(appendTo, password, options,
977 options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation);
982 QString thePath = path;
983 if (options & QUrl::NormalizePathSegments)
986 QStringView thePathView(thePath);
987 if (options & QUrl::RemoveFilename) {
988 const qsizetype slash = thePathView.lastIndexOf(u'/');
991 thePathView = thePathView.left(slash + 1);
994 if (options & QUrl::StripTrailingSlash) {
995 while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
999 appendToUser(appendTo, thePathView, options,
1000 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation);
1005 appendToUser(appendTo, fragment, options,
1006 options & QUrl::EncodeDelimiters ? fragmentInUrl :
1007 appendingTo == FullUrl ?
nullptr : fragmentInIsolation);
1012 appendToUser(appendTo, query, options,
1013 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
1031 sectionIsPresent |= Scheme;
1034 qsizetype needsLowercasing = -1;
1035 const ushort *p =
reinterpret_cast<
const ushort *>(value.data());
1036 for (qsizetype i = 0; i < len; ++i) {
1037 if (isAsciiLower(p[i]))
1039 if (isAsciiUpper(p[i])) {
1040 needsLowercasing = i;
1044 if (isAsciiDigit(p[i]))
1046 if (p[i] ==
'+' || p[i] ==
'-' || p[i] ==
'.')
1054 setError(InvalidSchemeError, value, i);
1058 scheme = value.left(len);
1060 if (needsLowercasing != -1) {
1062 QChar *schemeData = scheme.data();
1063 for (qsizetype i = needsLowercasing; i >= 0; --i) {
1064 ushort c = schemeData[i].unicode();
1065 if (isAsciiUpper(c))
1066 schemeData[i] = QChar(c + 0x20);
1071 if (scheme == fileScheme()
1073 || scheme == webDavScheme()
1076 flags |= IsLocalFile;
1078 flags &= ~IsLocalFile;
1085 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setAuthority",
1086 "This function should only be called when parsing encoded components");
1087 sectionIsPresent &= ~Authority;
1089 if (from == end && !auth.isNull())
1090 sectionIsPresent |= Host;
1093 while (from != end) {
1094 qsizetype userInfoIndex = auth.indexOf(u'@', from);
1095 if (size_t(userInfoIndex) < size_t(end)) {
1096 setUserInfo(QStringView(auth).sliced(from, userInfoIndex - from), mode);
1097 if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1099 from = userInfoIndex + 1;
1102 qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
1103 if (colonIndex < from)
1106 if (size_t(colonIndex) < size_t(end)) {
1107 if (auth.at(from).unicode() ==
'[') {
1109 qsizetype closingBracket = auth.indexOf(u']', from);
1110 if (size_t(closingBracket) > size_t(colonIndex))
1115 if (size_t(colonIndex) < size_t(end) - 1) {
1117 unsigned long x = 0;
1118 for (qsizetype i = colonIndex + 1; i < end; ++i) {
1119 ushort c = auth.at(i).unicode();
1120 if (isAsciiDigit(c)) {
1128 if (x == ushort(x)) {
1131 setError(InvalidPortError, auth, colonIndex + 1);
1132 if (mode == QUrl::StrictMode)
1137 setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
1138 if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
1140 sectionIsPresent &= ~Authority;
1148 sectionIsPresent &= ~Authority | Host;
1157 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1158 "This function should only be called when parsing encoded components");
1159 qsizetype delimIndex = value.indexOf(u':');
1160 if (delimIndex < 0) {
1162 setUserName(
std::move(value), mode);
1164 sectionIsPresent &= ~Password;
1166 setUserName(value.first(delimIndex), mode);
1167 setPassword(value.sliced(delimIndex + 1), mode);
1173 sectionIsPresent |= UserName;
1179 sectionIsPresent |= Password;
1191 sectionIsPresent |= Fragment;
1197 sectionIsPresent |= Query;
1233 if (host.isEmpty()) {
1234 if ((sectionIsPresent & Host) && appendTo.isNull())
1238 if (host.at(0).unicode() ==
'[') {
1241 if (qt_urlRecode(appendTo, host, options,
nullptr))
1247 if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1256static const QChar *
parseIpFuture(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1259 static const char acceptable[] =
1265 const QChar *
const origBegin = begin;
1266 if (begin[3].unicode() !=
'.')
1268 if (isHexDigit(begin[2].unicode())) {
1271 host += QStringView(begin, 4);
1274 if (begin[2].unicode() >=
'a')
1275 host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
1281 if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, QStringView{begin, end}, QUrl::FullyDecoded,
nullptr)) {
1282 begin = decoded.constBegin();
1283 end = decoded.constEnd();
1286 for ( ; begin != end; ++begin) {
1287 if (isAsciiLetterOrNumber(begin->unicode()))
1289 else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) !=
nullptr)
1292 return decoded.isEmpty() ? begin : &origBegin[2];
1297 return &origBegin[2];
1301static const QChar *
parseIp6(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1303 QStringView decoded(begin, end);
1304 QString decodedBuffer;
1305 if (mode == QUrl::TolerantMode) {
1307 const ushort decodeColon[] = { decode(
':'), 0 };
1308 if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1309 decoded = decodedBuffer;
1312 const QStringView zoneIdIdentifier(u"%25");
1313 QIPAddressUtils::IPv6Address address;
1316 qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1317 if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1318 zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1319 decoded.truncate(zoneIdPosition);
1322 if (zoneId.isEmpty())
1328 if (decoded.isEmpty())
1331 const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1333 return begin + (ret - decoded.constBegin());
1335 host.reserve(host.size() + (end - begin) + 2);
1337 QIPAddressUtils::toString(host, address);
1339 if (!zoneId.isEmpty()) {
1340 host += zoneIdIdentifier;
1350 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1351 "This function should only be called when parsing encoded components");
1352 const QChar *begin = value.constData() + from;
1353 const QChar *end = value.constData() + iend;
1355 const qsizetype len = end - begin;
1357 sectionIsPresent &= ~Host;
1358 if (!value.isNull() || (sectionIsPresent & Authority))
1359 sectionIsPresent |= Host;
1363 if (begin[0].unicode() ==
'[') {
1367 if (end[-1].unicode() !=
']') {
1368 setError(HostMissingEndBracket, value);
1372 if (len > 5 && begin[1].unicode() ==
'v') {
1373 const QChar *c = parseIpFuture(host, begin, end, mode);
1375 setError(InvalidIPvFutureError, value, c - value.constData());
1377 }
else if (begin[1].unicode() ==
'v') {
1378 setError(InvalidIPvFutureError, value, from);
1381 const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1386 setError(InvalidIPv6AddressError, value, from);
1388 setError(InvalidCharacterInIPv6Error, value, c - value.constData());
1393 QIPAddressUtils::IPv4Address ip4;
1394 if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1396 QIPAddressUtils::toString(host, ip4);
1415 if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { },
nullptr)) {
1418 qsizetype pos = s.indexOf(QChar(0x25));
1420 setError(InvalidRegNameError, s, pos);
1425 return setHost(s, 0, s.size(), QUrl::StrictMode);
1430 setError(InvalidRegNameError, value);
1435 if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1436 QIPAddressUtils::toString(host, ip4);
1453 Q_ASSERT_X(parsingMode != QUrl::DecodedMode,
"parse",
1454 "This function should only be called when parsing encoded URLs");
1455 Q_ASSERT(sectionIsPresent == 0);
1459 qsizetype colon = -1;
1460 qsizetype question = -1;
1461 qsizetype hash = -1;
1462 const qsizetype len = url.size();
1463 const QChar *
const begin = url.constData();
1464 const ushort *
const data =
reinterpret_cast<
const ushort *>(begin);
1466 for (qsizetype i = 0; i < len; ++i) {
1467 size_t uc = data[i];
1468 if (uc ==
'#' && hash == -1) {
1475 if (question == -1) {
1476 if (uc ==
':' && colon == -1)
1484 qsizetype hierStart;
1485 if (colon != -1 && setScheme(url, colon,
false)) {
1486 hierStart = colon + 1;
1490 sectionIsPresent = 0;
1494 qsizetype pathStart;
1495 qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
1496 if (hierEnd - hierStart >= 2 && data[hierStart] ==
'/' && data[hierStart + 1] ==
'/') {
1498 qsizetype authorityEnd = hierEnd;
1499 for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
1500 if (data[i] ==
'/') {
1506 setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1509 pathStart = authorityEnd;
1510 setPath(QStringView(url).sliced(pathStart, hierEnd - pathStart), parsingMode);
1512 Q_ASSERT(userName.isNull());
1513 Q_ASSERT(password.isNull());
1514 Q_ASSERT(host.isNull());
1515 Q_ASSERT(
port == -1);
1516 pathStart = hierStart;
1518 if (hierStart < hierEnd)
1519 setPath(QStringView(url).sliced(hierStart, hierEnd - hierStart), parsingMode);
1524 Q_ASSERT(query.isNull());
1525 if (size_t(question) < size_t(hash))
1526 setQuery(QStringView(url).sliced(question + 1, qMin<size_t>(hash, len) - question - 1),
1529 Q_ASSERT(fragment.isNull());
1531 setFragment(QStringView(url).sliced(hash + 1, len - hash - 1), parsingMode);
1533 if (error || parsingMode == QUrl::TolerantMode)
1544 if (size_t(question) < size_t(hash) && !
validateComponent(
Query, url, question + 1, qMin<size_t>(hash, len)))
1554 appendPath(ourPath, options, QUrlPrivate::Path);
1557 if (!host.isEmpty()) {
1558 tmp =
"//"_L1 + host;
1560 if (scheme == webDavScheme())
1561 tmp += webDavSslTag();
1563 if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
1570 if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
1578
1579
1580
1581
1582
1583
1584
1590 if (!host.isEmpty() && path.isEmpty())
1591 return u'/' + relativePath;
1599 if (!path.contains(u'/'))
1600 newPath = relativePath;
1602 newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
1612 if (path->isEmpty() || path->at(0) != u'/')
1618 while (i + 1 < path->size() && path->at(i + 1) == u'/')
1626 Q_ASSERT(!source == !position);
1629 *source = error->source;
1630 *position = error->position;
1650 if (path.at(0) == u'/') {
1651 if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
1660 if (sectionIsPresent & QUrlPrivate::Host) {
1667 if (sectionIsPresent & QUrlPrivate::Scheme)
1671 for (qsizetype i = 0; i < path.size(); ++i) {
1672 ushort c = path.at(i).unicode();
1690 qsizetype begin, qsizetype end)
1705 static const char forbidden[] =
"\"<>\\^`{|}\x7F";
1706 static const char forbiddenUserInfo[] =
":/?#[]@";
1710 const ushort *
const data =
reinterpret_cast<
const ushort *>(input.constData());
1711 for (size_t i = size_t(begin); i < size_t(end); ++i) {
1717 if ((uc ==
'%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1718 || uc <= 0x20 || strchr(forbidden, uc)) {
1722 if (section ==
UserInfo && strchr(forbiddenUserInfo + 1, uc))
1724 else if (section !=
UserInfo && strchr(forbiddenUserInfo, uc))
1735 for (size_t j = size_t(begin); j < i; ++j)
1736 if (data[j] ==
':') {
1742 setError(errorCode, input, i);
1751inline void QUrlPrivate::validate()
const
1753 QUrlPrivate *that = (QUrlPrivate *)
this;
1754 that->encodedOriginal = that->toEncoded();
1757 QURL_SETFLAG(that->stateFlags, Validated);
1762 QString auth = authority();
1768 if (scheme ==
"mailto"_L1) {
1769 if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1770 that->isValid =
false;
1771 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"expected empty host, username,"
1772 "port and password"),
1775 }
else if (scheme == ftpScheme() || scheme == httpScheme()) {
1776 if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1777 that->isValid =
false;
1778 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"the host is empty, but not the path"),
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858QUrl::QUrl(
const QString &url, ParsingMode parsingMode) : d(
nullptr)
1860 setUrl(url, parsingMode);
1864
1865
1866QUrl::QUrl() : d(
nullptr)
1871
1872
1873QUrl::QUrl(
const QUrl &other)
noexcept : d(other.d)
1880
1881
1884 if (d && !d->ref.deref())
1889
1890
1891
1892
1893
1894
1895
1896
1897bool QUrl::isValid()
const
1903 return d->validityError() == QUrlPrivate::NoError;
1907
1908
1909
1910
1911bool QUrl::isEmpty()
const
1913 if (!d)
return true;
1914 return d->isEmpty();
1918
1919
1920
1921
1922
1923
1926 if (d && !d->ref.deref())
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949void QUrl::setUrl(
const QString &url, ParsingMode parsingMode)
1951 if (parsingMode == DecodedMode) {
1952 qWarning(
"QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1955 d->parse(url, parsingMode);
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983void QUrl::setScheme(
const QString &scheme)
1987 if (scheme.isEmpty()) {
1989 d->sectionIsPresent &= ~QUrlPrivate::Scheme;
1990 d->flags &= ~QUrlPrivate::IsLocalFile;
1993 d->setScheme(scheme, scheme.size(),
true);
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007QString QUrl::scheme()
const
2009 if (!d)
return QString();
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044void QUrl::setAuthority(
const QString &authority, ParsingMode mode)
2049 if (mode == DecodedMode) {
2050 qWarning(
"QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2054 d->setAuthority(authority, 0, authority.size(), mode);
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072QString QUrl::authority(ComponentFormattingOptions options)
const
2078 if (options == QUrl::FullyDecoded) {
2079 qWarning(
"QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2083 d->appendAuthority(result, options, QUrlPrivate::Authority);
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110void QUrl::setUserInfo(
const QString &userInfo, ParsingMode mode)
2114 QString trimmed = userInfo.trimmed();
2115 if (mode == DecodedMode) {
2116 qWarning(
"QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2120 d->setUserInfo(std::move(trimmed), mode);
2121 if (userInfo.isNull()) {
2124 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2125 }
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserInfo, userInfo)) {
2126 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2127 d->userName.clear();
2128 d->password.clear();
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146QString QUrl::userInfo(ComponentFormattingOptions options)
const
2152 if (options == QUrl::FullyDecoded) {
2153 qWarning(
"QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2157 d->appendUserInfo(result, options, QUrlPrivate::UserInfo);
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181void QUrl::setUserName(
const QString &userName, ParsingMode mode)
2186 d->setUserName(userName, mode);
2187 if (userName.isNull())
2188 d->sectionIsPresent &= ~QUrlPrivate::UserName;
2189 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
2190 d->userName.clear();
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210QString QUrl::userName(ComponentFormattingOptions options)
const
2214 d->appendUserName(result, options);
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238void QUrl::setPassword(
const QString &password, ParsingMode mode)
2243 d->setPassword(password, mode);
2244 if (password.isNull())
2245 d->sectionIsPresent &= ~QUrlPrivate::Password;
2246 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
2247 d->password.clear();
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267QString QUrl::password(ComponentFormattingOptions options)
const
2271 d->appendPassword(result, options);
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294void QUrl::setHost(
const QString &host, ParsingMode mode)
2299 QString data = host;
2300 if (mode == DecodedMode) {
2301 data.replace(u'%',
"%25"_L1);
2302 mode = TolerantMode;
2305 if (d->setHost(data, 0, data.size(), mode)) {
2307 }
else if (!data.startsWith(u'[')) {
2313 if (!d->setHost(data, 0, data.size(), mode)) {
2315 if (data.contains(u':')) {
2317 d->error->code = QUrlPrivate::InvalidIPv6AddressError;
2319 d->sectionIsPresent &= ~QUrlPrivate::Host;
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345QString QUrl::host(ComponentFormattingOptions options)
const
2349 d->appendHost(result, options);
2350 if (result.startsWith(u'['))
2351 result = result.mid(1, result.size() - 2);
2357
2358
2359
2360
2361
2362
2363void QUrl::setPort(
int port)
2368 if (port < -1 || port > 65535) {
2369 d->setError(QUrlPrivate::InvalidPortError, QString::number(port), 0);
2375 d->sectionIsPresent |= QUrlPrivate::Host;
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388int QUrl::port(
int defaultPort)
const
2390 if (!d)
return defaultPort;
2391 return d->port == -1 ? defaultPort : d->port;
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420void QUrl::setPath(
const QString &path, ParsingMode mode)
2425 d->setPath(path, mode);
2431 if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Path, path))
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468QString QUrl::path(ComponentFormattingOptions options)
const
2472 d->appendPath(result, options, QUrlPrivate::Path);
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497QString QUrl::fileName(ComponentFormattingOptions options)
const
2499 const QString ourPath = path(options);
2500 const qsizetype slash = ourPath.lastIndexOf(u'/');
2503 return ourPath.mid(slash + 1);
2507
2508
2509
2510
2511
2512
2513bool QUrl::hasQuery()
const
2515 if (!d)
return false;
2516 return d->hasQuery();
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550void QUrl::setQuery(
const QString &query, ParsingMode mode)
2555 d->setQuery(query, mode);
2557 d->sectionIsPresent &= ~QUrlPrivate::Query;
2558 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573void QUrl::setQuery(
const QUrlQuery &query)
2579 d->query = query.toString();
2580 if (query.isEmpty())
2581 d->sectionIsPresent &= ~QUrlPrivate::Query;
2583 d->sectionIsPresent |= QUrlPrivate::Query;
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603QString QUrl::query(ComponentFormattingOptions options)
const
2607 d->appendQuery(result, options, QUrlPrivate::Query);
2608 if (d->hasQuery() && result.isNull())
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642void QUrl::setFragment(
const QString &fragment, ParsingMode mode)
2647 d->setFragment(fragment, mode);
2648 if (fragment.isNull())
2649 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2650 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
2651 d->fragment.clear();
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670QString QUrl::fragment(ComponentFormattingOptions options)
const
2674 d->appendFragment(result, options, QUrlPrivate::Fragment);
2675 if (d->hasFragment() && result.isNull())
2682
2683
2684
2685
2686
2687
2688bool QUrl::hasFragment()
const
2690 if (!d)
return false;
2691 return d->hasFragment();
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713QUrl QUrl::resolved(
const QUrl &relative)
const
2715 if (!d)
return relative;
2716 if (!relative.d)
return *
this;
2719 if (!relative.d->scheme.isEmpty()) {
2723 if (relative.d->hasAuthority()) {
2727 t.d =
new QUrlPrivate;
2730 t.d->userName = d->userName;
2731 t.d->password = d->password;
2732 t.d->host = d->host;
2733 t.d->port = d->port;
2734 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2736 if (relative.d->path.isEmpty()) {
2737 t.d->path = d->path;
2738 if (relative.d->hasQuery()) {
2739 t.d->query = relative.d->query;
2740 t.d->sectionIsPresent |= QUrlPrivate::Query;
2741 }
else if (d->hasQuery()) {
2742 t.d->query = d->query;
2743 t.d->sectionIsPresent |= QUrlPrivate::Query;
2746 t.d->path = relative.d->path.startsWith(u'/')
2748 : d->mergePaths(relative.d->path);
2749 if (relative.d->hasQuery()) {
2750 t.d->query = relative.d->query;
2751 t.d->sectionIsPresent |= QUrlPrivate::Query;
2755 t.d->scheme = d->scheme;
2757 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2759 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2760 t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2762 t.d->fragment = relative.d->fragment;
2763 if (relative.d->hasFragment())
2764 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2766 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2768 t.d->normalizePathSegments(&t.d->path);
2769 if (!t.d->hasAuthority()) {
2770 if (t.d->isLocalFile() && t.d->path.startsWith(u'/'))
2771 t.d->sectionIsPresent |= QUrlPrivate::Host;
2773 fixupNonAuthorityPath(&t.d->path);
2776#if defined(QURL_DEBUG)
2777 qDebug(
"QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2778 qUtf16Printable(url()),
2779 qUtf16Printable(relative.url()),
2780 qUtf16Printable(t.url()));
2786
2787
2788
2789
2790
2791
2792
2793
2794bool QUrl::isRelative()
const
2796 if (!d)
return true;
2797 return !d->hasScheme();
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811QString QUrl::url(FormattingOptions options)
const
2813 return toString(options);
2817
2818
2819
2820
2821
2822
2823
2824
2825QString QUrl::toString(FormattingOptions options)
const
2832 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2833 qWarning(
"QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2834 options &= ~QUrl::FullyDecoded;
2844 if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2845 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2846 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2848 url = d->toLocalFile(options | QUrl::FullyDecoded);
2853 if (options & DecodeReserved)
2854 options &= ~EncodeReserved;
2856 options |= EncodeReserved;
2858 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2859 url += d->scheme + u':';
2861 bool pathIsAbsolute = d->path.startsWith(u'/');
2862 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2864 d->appendAuthority(url, options, QUrlPrivate::FullUrl);
2865 }
else if (isLocalFile() && pathIsAbsolute) {
2870 if (!(options & QUrl::RemovePath))
2871 d->appendPath(url, options, QUrlPrivate::FullUrl);
2873 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2875 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2877 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2879 d->appendFragment(url, options, QUrlPrivate::FullUrl);
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2900QString QUrl::toDisplayString(FormattingOptions options)
const
2902 return toString(options | RemovePassword);
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918QUrl QUrl::adjusted(QUrl::FormattingOptions options)
const
2925 if (options & RemoveScheme)
2926 that.setScheme(QString());
2927 if ((options & RemoveAuthority) == RemoveAuthority) {
2928 that.setAuthority(QString());
2930 if ((options & RemoveUserInfo) == RemoveUserInfo)
2931 that.setUserInfo(QString());
2932 else if (options & RemovePassword)
2933 that.setPassword(QString());
2934 if (options & RemovePort)
2937 if (options & RemoveQuery)
2938 that.setQuery(QString());
2939 if (options & RemoveFragment)
2940 that.setFragment(QString());
2941 if (options & RemovePath) {
2942 that.setPath(QString());
2943 }
else if (
auto pathOpts = options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2945 that.d->path.resize(0);
2946 d->appendPath(that.d->path, pathOpts, QUrlPrivate::Path);
2948 if (that.d->isLocalFile() && that.d->path.startsWith(u'/')) {
2951 that.d->sectionIsPresent |= QUrlPrivate::Host;
2957
2958
2959
2960
2961
2962
2963
2964
2965QByteArray QUrl::toEncoded(FormattingOptions options)
const
2967 options &= ~(FullyDecoded | FullyEncoded);
2968 return toString(options | FullyEncoded).toLatin1();
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
2988 return QUrl(QString::fromUtf8(input), mode);
2992
2993
2994
2995
2996
2997
2998
2999QString QUrl::fromPercentEncoding(
const QByteArray &input)
3001 QByteArray ba = QByteArray::fromPercentEncoding(input);
3002 return QString::fromUtf8(ba);
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017QByteArray QUrl::toPercentEncoding(
const QString &input,
const QByteArray &exclude,
const QByteArray &include)
3019 return input.toUtf8().toPercentEncoding(exclude, include);
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039QString QUrl::fromAce(
const QByteArray &domain, QUrl::AceProcessingOptions options)
3041 return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3042 ForbidLeadingDot , options);
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062QByteArray QUrl::toAce(
const QString &domain, AceProcessingOptions options)
3064 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot , options)
3069
3070
3071
3072
3073
3074
3075
3079 if (!lhs.d || !rhs.d) {
3080 bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
3081 bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
3086 return Qt::weak_ordering::less;
3088 return Qt::weak_ordering::equivalent;
3090 return Qt::weak_ordering::greater;
3095 cmp = lhs.d->scheme.compare(rhs.d->scheme);
3097 return Qt::compareThreeWay(cmp, 0);
3099 cmp = lhs.d->userName.compare(rhs.d->userName);
3101 return Qt::compareThreeWay(cmp, 0);
3103 cmp = lhs.d->password.compare(rhs.d->password);
3105 return Qt::compareThreeWay(cmp, 0);
3107 cmp = lhs.d->host.compare(rhs.d->host);
3109 return Qt::compareThreeWay(cmp, 0);
3111 if (lhs.d->port != rhs.d->port)
3112 return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
3114 cmp = lhs.d->path.compare(rhs.d->path);
3116 return Qt::compareThreeWay(cmp, 0);
3118 if (lhs.d->hasQuery() != rhs.d->hasQuery())
3119 return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3121 cmp = lhs.d->query.compare(rhs.d->query);
3123 return Qt::compareThreeWay(cmp, 0);
3125 if (lhs.d->hasFragment() != rhs.d->hasFragment())
3126 return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3128 cmp = lhs.d->fragment.compare(rhs.d->fragment);
3129 return Qt::compareThreeWay(cmp, 0);
3133
3134
3135
3136
3137
3138
3139
3143 if (!lhs.d && !rhs.d)
3146 return rhs.d->isEmpty();
3148 return lhs.d->isEmpty();
3150 return (lhs.d->presentSections() == rhs.d->presentSections()) &&
3151 lhs.d->scheme == rhs.d->scheme &&
3152 lhs.d->userName == rhs.d->userName &&
3153 lhs.d->password == rhs.d->password &&
3154 lhs.d->host == rhs.d->host &&
3155 lhs.d->port == rhs.d->port &&
3156 lhs.d->path == rhs.d->path &&
3157 lhs.d->query == rhs.d->query &&
3158 lhs.d->fragment == rhs.d->fragment;
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171bool QUrl::matches(
const QUrl &url, FormattingOptions options)
const
3176 return url.d->isEmpty();
3178 return d->isEmpty();
3180 uint mask = d->presentSections();
3182 if (options.testFlag(QUrl::RemoveScheme))
3183 mask &= ~QUrlPrivate::Scheme;
3184 else if (d->scheme != url.d->scheme)
3187 if (options.testFlag(QUrl::RemovePassword))
3188 mask &= ~QUrlPrivate::Password;
3189 else if (d->password != url.d->password)
3192 if (options.testFlag(QUrl::RemoveUserInfo))
3193 mask &= ~QUrlPrivate::UserName;
3194 else if (d->userName != url.d->userName)
3197 if (options.testFlag(QUrl::RemovePort))
3198 mask &= ~QUrlPrivate::Port;
3199 else if (d->port != url.d->port)
3202 if (options.testFlag(QUrl::RemoveAuthority))
3203 mask &= ~QUrlPrivate::Host;
3204 else if (d->host != url.d->host)
3207 if (options.testFlag(QUrl::RemoveQuery))
3208 mask &= ~QUrlPrivate::Query;
3209 else if (d->query != url.d->query)
3212 if (options.testFlag(QUrl::RemoveFragment))
3213 mask &= ~QUrlPrivate::Fragment;
3214 else if (d->fragment != url.d->fragment)
3217 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3220 if (options.testFlag(QUrl::RemovePath))
3225 d->appendPath(path1, options, QUrlPrivate::Path);
3227 url.d->appendPath(path2, options, QUrlPrivate::Path);
3228 return path1 == path2;
3232
3233
3234
3235
3236
3237
3238
3241
3242
3243QUrl &QUrl::operator =(
const QUrl &url)
noexcept
3252 qAtomicAssign(d, url.d);
3260
3261
3262
3263
3264
3265#ifdef QT_NO_URL_CAST_FROM_STRING
3266#error You cannot define QT_NO_URL_CAST_FROM_STRING in QtCore, for ABI reasons
3268QUrl &QUrl::operator =(
const QString &url)
3272 d->parse(url, TolerantMode);
3277
3278
3279
3280
3283
3284
3285
3286
3290 d =
new QUrlPrivate;
3296
3297
3298
3299
3300void QUrl::detachToClear()
3302 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
3304 d->ref.storeRelaxed(1);
3307 d =
new QUrlPrivate;
3312
3313
3314bool QUrl::isDetached()
const
3316 return !d || d->ref.loadRelaxed() == 1;
3321#if defined(Q_OS_WIN)
3322 QString result(pathName);
3323 const QChar nativeSeparator = u'\\';
3324 auto i = result.indexOf(nativeSeparator);
3326 QChar *
const data = result.data();
3327 const auto length = result.length();
3328 for (; i < length; ++i) {
3329 if (data[i] == nativeSeparator)
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370QUrl QUrl::fromLocalFile(
const QString &localFile)
3373 QString deslashified = fromNativeSeparators(localFile);
3374 if (deslashified.isEmpty())
3376 QString scheme = fileScheme();
3377 char16_t firstChar = deslashified.at(0).unicode();
3378 char16_t secondChar = deslashified.size() > 1 ? deslashified.at(1).unicode() : u'\0';
3381 if (firstChar != u'/' && secondChar == u':') {
3382 deslashified.prepend(u'/');
3384 }
else if (firstChar == u'/' && secondChar == u'/') {
3386 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3387 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3389 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3390 hostSpec.truncate(hostSpec.size() - 4);
3391 scheme = webDavScheme();
3396 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3397 if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3402 }
else if (indexOfPath > 2) {
3403 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3405 deslashified.clear();
3408 if (firstChar == u'/') {
3411 url.d->sectionIsPresent |= QUrlPrivate::Host;
3414 url.setScheme(scheme);
3415 url.setPath(deslashified, DecodedMode);
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436QString QUrl::toLocalFile()
const
3442 return d->toLocalFile(QUrl::FullyDecoded);
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456bool QUrl::isLocalFile()
const
3458 return d && d->isLocalFile();
3462
3463
3464
3465
3466bool QUrl::isParentOf(
const QUrl &childUrl)
const
3468 QString childPath = childUrl.path();
3471 return ((childUrl.scheme().isEmpty())
3472 && (childUrl.authority().isEmpty())
3473 && childPath.size() > 0 && childPath.at(0) == u'/');
3475 QString ourPath = path();
3477 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3478 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3479 && childPath.startsWith(ourPath)
3480 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3481 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3482 && childPath.at(ourPath.size()) == u'/')));
3486#ifndef QT_NO_DATASTREAM
3488
3489
3490
3491
3492
3493
3494QDataStream &operator<<(QDataStream &out,
const QUrl &url)
3498 u = url.toEncoded();
3504
3505
3506
3507
3508
3509
3514 url.setUrl(QString::fromLatin1(u));
3519#ifndef QT_NO_DEBUG_STREAM
3522 QDebugStateSaver saver(d);
3523 d.nospace() <<
"QUrl(" << url.toDisplayString() <<
')';
3530 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3531 errorSource.at(errorPosition) : QChar(QChar::Null);
3533 switch (errorCode) {
3535 Q_UNREACHABLE_RETURN(QString());
3538 auto msg =
"Invalid scheme (character '%1' not permitted)"_L1;
3542 case QUrlPrivate::InvalidUserNameError:
3543 return "Invalid user name (character '%1' not permitted)"_L1
3546 case QUrlPrivate::InvalidPasswordError:
3547 return "Invalid password (character '%1' not permitted)"_L1
3550 case QUrlPrivate::InvalidRegNameError:
3551 if (errorPosition >= 0)
3552 return "Invalid hostname (character '%1' not permitted)"_L1
3555 return QStringLiteral(
"Invalid hostname (contains invalid characters)");
3558 case QUrlPrivate::InvalidIPv6AddressError:
3560 case QUrlPrivate::InvalidCharacterInIPv6Error:
3561 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3562 case QUrlPrivate::InvalidIPvFutureError:
3563 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3564 case QUrlPrivate::HostMissingEndBracket:
3567 case QUrlPrivate::InvalidPortError:
3568 return QStringLiteral(
"Invalid port or port number out of range");
3569 case QUrlPrivate::PortEmptyError:
3572 case QUrlPrivate::InvalidPathError:
3573 return "Invalid path (character '%1' not permitted)"_L1
3576 case QUrlPrivate::InvalidQueryError:
3577 return "Invalid query (character '%1' not permitted)"_L1
3580 case QUrlPrivate::InvalidFragmentError:
3581 return "Invalid fragment (character '%1' not permitted)"_L1
3584 case QUrlPrivate::AuthorityPresentAndPathIsRelative:
3585 return QStringLiteral(
"Path component is relative and authority is present");
3586 case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
3587 return QStringLiteral(
"Path component starts with '//' and authority is absent");
3588 case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
3589 return QStringLiteral(
"Relative URL's path component contains ':' before any '/'");
3592 Q_UNREACHABLE_RETURN(QString());
3596 const QString &component)
3599 msg += QLatin1StringView(componentName) % u'"' % component %
"\","_L1;
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615QString QUrl::errorString()
const
3621 QString errorSource;
3622 qsizetype errorPosition = 0;
3623 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3624 if (errorCode == QUrlPrivate::NoError)
3627 msg += errorMessage(errorCode, errorSource, errorPosition);
3628 msg +=
"; source was \""_L1;
3631 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3632 " scheme = ", d->scheme);
3633 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3634 " userinfo = ", userInfo());
3635 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3636 " host = ", d->host);
3637 appendComponentIfPresent(msg, d->port != -1,
3638 " port = ", QString::number(d->port));
3639 appendComponentIfPresent(msg, !d->path.isEmpty(),
3640 " path = ", d->path);
3641 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3642 " query = ", d->query);
3643 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3644 " fragment = ", d->fragment);
3645 if (msg.endsWith(u','))
3651
3652
3653
3654
3655QStringList QUrl::toStringList(
const QList<QUrl> &urls, FormattingOptions options)
3658 lst.reserve(urls.size());
3659 for (
const QUrl &url : urls)
3660 lst.append(url.toString(options));
3666
3667
3668
3669
3670
3671QList<QUrl> QUrl::fromStringList(
const QStringList &urls, ParsingMode mode)
3674 lst.reserve(urls.size());
3675 for (
const QString &str : urls)
3676 lst.append(QUrl(str, mode));
3681
3682
3683
3686
3687
3688
3691
3692
3693
3694
3697 QtPrivate::QHashCombineWithSeed hasher(seed);
3701 return hasher(0, -1);
3702 size_t state = hasher(0, url.d->port);
3704 if (url.d->hasScheme())
3705 state = hasher(state, url.d->scheme);
3706 if (url.d->hasUserInfo()) {
3708 state = hasher(state, url.d->userName);
3709 state = hasher(state, url.d->password);
3711 if (url.d->hasHost() || url.d->isLocalFile())
3712 state = hasher(state, url.d->host);
3713 if (url.d->hasPath())
3714 state = hasher(state, url.d->path);
3715 if (url.d->hasQuery())
3716 state = hasher(state, url.d->query);
3717 if (url.d->hasFragment())
3718 state = hasher(state, url.d->fragment);
3724 if (url.scheme() == ftpScheme()) {
3725 QString path = url.path(QUrl::PrettyDecoded);
3726 if (path.startsWith(
"//"_L1))
3727 url.setPath(
"/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
3734 QIPAddressUtils::IPv6Address address;
3735 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) ==
nullptr;
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778QUrl QUrl::fromUserInput(
const QString &userInput,
const QString &workingDirectory,
3779 UserInputResolutionOptions options)
3781 QString trimmedString = userInput.trimmed();
3783 if (trimmedString.isEmpty())
3788 if (isIp6(trimmedString)) {
3790 url.setHost(trimmedString);
3795 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3798 if (!workingDirectory.isEmpty()) {
3799 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3800 if (fileInfo.exists())
3801 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3804 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3805 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3809 if (QDir::isAbsolutePath(trimmedString))
3810 return QUrl::fromLocalFile(trimmedString);
3812 QUrl urlPrepended = QUrl(
"http://"_L1 + trimmedString, QUrl::TolerantMode);
3818 && !url.scheme().isEmpty()
3819 && urlPrepended.port() == -1)
3820 return adjustFtpPath(url);
3823 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3824 qsizetype dotIndex = trimmedString.indexOf(u'.');
3825 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3826 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3827 urlPrepended.setScheme(ftpScheme());
3828 return adjustFtpPath(urlPrepended);
uint presentSections() const noexcept
void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const
void appendHost(QString &appendTo, QUrl::FormattingOptions options) const
bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end)
std::unique_ptr< Error > cloneError() const
void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
QString toLocalFile(QUrl::FormattingOptions options) const
ErrorCode validityError(QString *source=nullptr, qsizetype *position=nullptr) const
void setFragment(String &&value, QUrl::ParsingMode mode)
QUrlPrivate(const QUrlPrivate ©)
QString mergePaths(const QString &relativePath) const
std::unique_ptr< Error > error
@ AuthorityPresentAndPathIsRelative
@ RelativeUrlPathContainsColonBeforeSlash
@ AuthorityAbsentAndPathIsDoubleSlash
@ InvalidIPv6AddressError
@ InvalidIPv4AddressError
@ InvalidCharacterInIPv6Error
bool setScheme(const QString &value, qsizetype len, bool doSetError)
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const
void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
bool validateComponent(Section section, const QString &input)
bool normalizePathSegments(QString *path) const
void setError(ErrorCode errorCode, const QString &source, qsizetype supplement=-1)
void setUserInfo(String &&value, QUrl::ParsingMode mode)
void setPath(String &&value, QUrl::ParsingMode mode)
void setQuery(String &&value, QUrl::ParsingMode mode)
bool hasAuthority() const
void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
void setPassword(String &&value, QUrl::ParsingMode mode)
void setUserName(String &&value, QUrl::ParsingMode mode)
void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
void parse(const QString &url, QUrl::ParsingMode parsingMode)
QDataStream & operator>>(QDataStream &in, QUrl &url)
Reads a url into url from the stream in and returns a reference to the stream.
#define QStringLiteral(str)
static const ushort userNameInAuthority[]
size_t qHash(const QUrl &url, size_t seed) noexcept
\qhashold{QHash}
QDebug operator<<(QDebug d, const QUrl &url)
static QString fileScheme()
static const QChar * parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
static const ushort *const passwordInAuthority
static void appendComponentIfPresent(QString &msg, bool present, const char *componentName, const QString &component)
static const ushort userNameInUrl[]
static QString webDavSslTag()
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
static const ushort *const fragmentInIsolation
static void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options, const ushort *actions)
static bool isHex(char c)
static void fixupNonAuthorityPath(QString *path)
static const QChar * parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
static const ushort *const pathInUrl
static const ushort *const pathInIsolation
static const ushort *const passwordInUserInfo
static void recodeFromUser(QString &output, QStringView input, const ushort *actions, QUrl::ParsingMode mode)
Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs)
static const ushort userNameInUserInfo[]
static const ushort userNameInIsolation[]
static const ushort *const queryInIsolation
static QUrl adjustFtpPath(QUrl url)
static const ushort *const fragmentInUrl
static QString ftpScheme()
static bool isIp6(const QString &text)
static void recodeFromUser(QString &output, const QString &input, const ushort *actions, QUrl::ParsingMode mode)
static const ushort *const passwordInUrl
static const ushort *const queryInUrl
static const ushort *const passwordInIsolation
bool comparesEqual(const QUrl &lhs, const QUrl &rhs)
static QString webDavScheme()
static QString fromNativeSeparators(const QString &pathName)