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
261
262
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
362
363
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
408
409
410
411
412
413
414
417
418
419
420
421
422
426#include "qplatformdefs.h"
432#include "private/qipaddress_p.h"
434#include "private/qdir_p.h"
435#include <private/qtools_p.h>
439using namespace Qt::StringLiterals;
440using namespace QtMiscUtils;
445 return isAsciiDigit(c) || (c >=
'a' && c <=
'f');
534 void parse(
const QString &url, QUrl::ParsingMode parsingMode);
536 {
return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
551 void appendHost(QString &appendTo, QUrl::FormattingOptions options)
const;
557 bool setScheme(
const QString &value, qsizetype len,
bool doSetError);
558 void setAuthority(
const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
559 template <
typename String>
void setUserInfo(String &&value, QUrl::ParsingMode mode);
560 template <
typename String>
void setUserName(String &&value, QUrl::ParsingMode mode);
561 template <
typename String>
void setPassword(String &&value, QUrl::ParsingMode mode);
562 bool setHost(
const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode);
563 template <
typename String>
void setPath(String &&value, QUrl::ParsingMode mode);
564 template <
typename String>
void setQuery(String &&value, QUrl::ParsingMode mode);
565 template <
typename String>
void setFragment(String &&value, QUrl::ParsingMode mode);
569 uint s = sectionIsPresent;
584 inline bool hasScheme()
const {
return sectionIsPresent & Scheme; }
585 inline bool hasAuthority()
const {
return sectionIsPresent & Authority; }
586 inline bool hasUserInfo()
const {
return sectionIsPresent & UserInfo; }
587 inline bool hasUserName()
const {
return sectionIsPresent & UserName; }
588 inline bool hasPassword()
const {
return sectionIsPresent & Password; }
589 inline bool hasHost()
const {
return sectionIsPresent & Host; }
591 inline bool hasPath()
const {
return !path.isEmpty(); }
592 inline bool hasQuery()
const {
return sectionIsPresent & Query; }
593 inline bool hasFragment()
const {
return sectionIsPresent & Fragment; }
600 QDirPrivate::PathNormalizations mode = QDirPrivate::UrlNormalizationMode;
602 mode |= QDirPrivate::RemotePath;
603 return qt_normalizePathSegments(path, mode);
610 scheme = userName = password = host = path = query = fragment = QString();
612 sectionIsPresent = 0;
667 return error ? std::make_unique<Error>(*error) :
nullptr;
681 error = std::make_unique<Error>();
682 error->code = errorCode;
683 error->source = source;
684 error->position = supplement;
777template <
typename T>
constexpr ushort decode(T x)
noexcept {
return ushort(x); }
778template <
typename T>
constexpr ushort leave(T x)
noexcept {
return ushort(0x100 | x); }
779template <
typename T>
constexpr ushort encode(T x)
noexcept {
return ushort(0x200 | x); }
866recodeFromUser(QString &output,
const QString &input,
const ushort *actions, QUrl::ParsingMode mode)
870 if (mode == QUrl::DecodedMode)
871 appended = qt_encodeFromUser(output, input, actions);
873 appended = qt_urlRecode(output, input, {}, actions);
879recodeFromUser(QString &output, QStringView input,
const ushort *actions, QUrl::ParsingMode mode)
881 Q_ASSERT_X(mode != QUrl::DecodedMode,
"recodeFromUser",
882 "This function should only be called when parsing encoded components");
885 if (qt_urlRecode(output, input, {}, actions))
887 output.append(input);
892static inline bool appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
893 const ushort *actions)
898 if ((options & 0xFFFF0000) == QUrl::PrettyDecoded) {
901 qsizetype recoded = qt_urlRecode(appendTo, value, options, actions);
909 if (appendTo.isNull() && !value.isNull())
916 if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
917 appendUserInfo(appendTo, options, appendingTo);
920 if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
923 appendHost(appendTo, options);
924 if (!(options & QUrl::RemovePort) && port != -1)
925 appendTo += u':' + QString::number(port);
933 const ushort *userNameActions;
934 const ushort *passwordActions;
935 if (options & QUrl::EncodeDelimiters) {
939 switch (appendingTo) {
962 if (!qt_urlRecode(appendTo, userName, options, userNameActions))
963 appendTo += userName;
964 if (options & QUrl::RemovePassword || !hasPassword()) {
968 if (!qt_urlRecode(appendTo, password, options, passwordActions))
969 appendTo += password;
976 appendToUser(appendTo, userName, options,
977 options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation);
985 appendToUser(appendTo, password, options,
986 options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation);
991 QString thePath = path;
992 if (options & QUrl::NormalizePathSegments)
995 QStringView thePathView(thePath);
996 if (options & QUrl::RemoveFilename) {
997 const qsizetype slash = thePathView.lastIndexOf(u'/');
1000 thePathView = thePathView.left(slash + 1);
1003 if (options & QUrl::StripTrailingSlash) {
1004 while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
1005 thePathView.chop(1);
1008 const ushort *actions = appendingTo == FullUrl || options & QUrl::EncodeDelimiters
1009 ? pathInUrl : pathInIsolation;
1010 return appendToUser(appendTo, thePathView, options, actions);
1015 appendToUser(appendTo, fragment, options,
1016 options & QUrl::EncodeDelimiters ? fragmentInUrl :
1017 appendingTo == FullUrl ?
nullptr : fragmentInIsolation);
1022 appendToUser(appendTo, query, options,
1023 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
1041 sectionIsPresent |= Scheme;
1044 qsizetype needsLowercasing = -1;
1045 const ushort *p =
reinterpret_cast<
const ushort *>(value.data());
1046 for (qsizetype i = 0; i < len; ++i) {
1047 if (isAsciiLower(p[i]))
1049 if (isAsciiUpper(p[i])) {
1050 needsLowercasing = i;
1054 if (isAsciiDigit(p[i]))
1056 if (p[i] ==
'+' || p[i] ==
'-' || p[i] ==
'.')
1064 setError(InvalidSchemeError, value, i);
1068 scheme = value.left(len);
1070 if (needsLowercasing != -1) {
1072 QChar *schemeData = scheme.data();
1073 for (qsizetype i = needsLowercasing; i >= 0; --i) {
1074 ushort c = schemeData[i].unicode();
1075 if (isAsciiUpper(c))
1076 schemeData[i] = QChar(c + 0x20);
1081 if (scheme == fileScheme()
1083 || scheme == webDavScheme()
1086 flags |= IsLocalFile;
1088 flags &= ~IsLocalFile;
1095 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setAuthority",
1096 "This function should only be called when parsing encoded components");
1097 sectionIsPresent &= ~Authority;
1099 if (from == end && !auth.isNull())
1100 sectionIsPresent |= Host;
1103 while (from != end) {
1104 qsizetype userInfoIndex = auth.indexOf(u'@', from);
1105 if (size_t(userInfoIndex) < size_t(end)) {
1106 setUserInfo(QStringView(auth).sliced(from, userInfoIndex - from), mode);
1107 if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1109 from = userInfoIndex + 1;
1112 qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
1113 if (colonIndex < from)
1116 if (size_t(colonIndex) < size_t(end)) {
1117 if (auth.at(from).unicode() ==
'[') {
1119 qsizetype closingBracket = auth.indexOf(u']', from);
1120 if (size_t(closingBracket) > size_t(colonIndex))
1125 if (size_t(colonIndex) < size_t(end) - 1) {
1127 unsigned long x = 0;
1128 for (qsizetype i = colonIndex + 1; i < end; ++i) {
1129 ushort c = auth.at(i).unicode();
1130 if (isAsciiDigit(c)) {
1138 if (x == ushort(x)) {
1141 setError(InvalidPortError, auth, colonIndex + 1);
1142 if (mode == QUrl::StrictMode)
1147 setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
1148 if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
1150 sectionIsPresent &= ~Authority;
1158 sectionIsPresent &= ~Authority | Host;
1167 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1168 "This function should only be called when parsing encoded components");
1169 qsizetype delimIndex = value.indexOf(u':');
1170 if (delimIndex < 0) {
1172 setUserName(
std::move(value), mode);
1174 sectionIsPresent &= ~Password;
1176 setUserName(value.first(delimIndex), mode);
1177 setPassword(value.sliced(delimIndex + 1), mode);
1183 sectionIsPresent |= UserName;
1189 sectionIsPresent |= Password;
1201 sectionIsPresent |= Fragment;
1207 sectionIsPresent |= Query;
1243 if (host.isEmpty()) {
1244 if ((sectionIsPresent & Host) && appendTo.isNull())
1248 if (host.at(0).unicode() ==
'[') {
1251 if (qt_urlRecode(appendTo, host, options,
nullptr))
1257 if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1266static const QChar *
parseIpFuture(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1269 static const char acceptable[] =
1275 const QChar *
const origBegin = begin;
1276 if (begin[3].unicode() !=
'.')
1278 if (isHexDigit(begin[2].unicode())) {
1281 host += QStringView(begin, 4);
1284 if (begin[2].unicode() >=
'a')
1285 host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
1291 if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, QStringView{begin, end}, QUrl::FullyDecoded,
nullptr)) {
1292 begin = decoded.constBegin();
1293 end = decoded.constEnd();
1296 for ( ; begin != end; ++begin) {
1297 if (isAsciiLetterOrNumber(begin->unicode()))
1299 else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) !=
nullptr)
1302 return decoded.isEmpty() ? begin : &origBegin[2];
1307 return &origBegin[2];
1311static const QChar *
parseIp6(QString &host,
const QChar *begin,
const QChar *end, QUrl::ParsingMode mode)
1313 QStringView decoded(begin, end);
1314 QString decodedBuffer;
1315 if (mode == QUrl::TolerantMode) {
1317 const ushort decodeColon[] = { decode(
':'), 0 };
1318 if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1319 decoded = decodedBuffer;
1322 const QStringView zoneIdIdentifier(u"%25");
1323 QIPAddressUtils::IPv6Address address;
1326 qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1327 if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1328 zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1329 decoded.truncate(zoneIdPosition);
1332 if (zoneId.isEmpty())
1338 if (decoded.isEmpty())
1341 const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1343 return begin + (ret - decoded.constBegin());
1345 host.reserve(host.size() + (end - begin) + 2);
1347 QIPAddressUtils::toString(host, address);
1349 if (!zoneId.isEmpty()) {
1350 host += zoneIdIdentifier;
1360 Q_ASSERT_X(mode != QUrl::DecodedMode,
"setUserInfo",
1361 "This function should only be called when parsing encoded components");
1362 const QChar *begin = value.constData() + from;
1363 const QChar *end = value.constData() + iend;
1365 const qsizetype len = end - begin;
1367 sectionIsPresent &= ~Host;
1368 if (!value.isNull() || (sectionIsPresent & Authority))
1369 sectionIsPresent |= Host;
1373 if (begin[0].unicode() ==
'[') {
1377 if (end[-1].unicode() !=
']') {
1378 setError(HostMissingEndBracket, value);
1382 if (len > 5 && begin[1].unicode() ==
'v') {
1383 const QChar *c = parseIpFuture(host, begin, end, mode);
1385 setError(InvalidIPvFutureError, value, c - value.constData());
1387 }
else if (begin[1].unicode() ==
'v') {
1388 setError(InvalidIPvFutureError, value, from);
1391 const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1396 setError(InvalidIPv6AddressError, value, from);
1398 setError(InvalidCharacterInIPv6Error, value, c - value.constData());
1403 QIPAddressUtils::IPv4Address ip4;
1404 if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1406 QIPAddressUtils::toString(host, ip4);
1425 if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { },
nullptr)) {
1428 qsizetype pos = s.indexOf(QChar(0x25));
1430 setError(InvalidRegNameError, s, pos);
1435 return setHost(s, 0, s.size(), QUrl::StrictMode);
1440 setError(InvalidRegNameError, value);
1445 if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1446 QIPAddressUtils::toString(host, ip4);
1463 Q_ASSERT_X(parsingMode != QUrl::DecodedMode,
"parse",
1464 "This function should only be called when parsing encoded URLs");
1465 Q_ASSERT(sectionIsPresent == 0);
1469 qsizetype colon = -1;
1470 qsizetype question = -1;
1471 qsizetype hash = -1;
1472 const qsizetype len = url.size();
1473 const QChar *
const begin = url.constData();
1474 const ushort *
const data =
reinterpret_cast<
const ushort *>(begin);
1476 for (qsizetype i = 0; i < len; ++i) {
1477 size_t uc = data[i];
1478 if (uc ==
'#' && hash == -1) {
1485 if (question == -1) {
1486 if (uc ==
':' && colon == -1)
1494 qsizetype hierStart;
1495 if (colon != -1 && setScheme(url, colon,
false)) {
1496 hierStart = colon + 1;
1500 sectionIsPresent = 0;
1504 qsizetype pathStart;
1505 qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
1506 if (hierEnd - hierStart >= 2 && data[hierStart] ==
'/' && data[hierStart + 1] ==
'/') {
1508 qsizetype authorityEnd = hierEnd;
1509 for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
1510 if (data[i] ==
'/') {
1516 setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1519 pathStart = authorityEnd;
1520 setPath(QStringView(url).sliced(pathStart, hierEnd - pathStart), parsingMode);
1522 Q_ASSERT(userName.isNull());
1523 Q_ASSERT(password.isNull());
1524 Q_ASSERT(host.isNull());
1525 Q_ASSERT(
port == -1);
1526 pathStart = hierStart;
1528 if (hierStart < hierEnd)
1529 setPath(QStringView(url).sliced(hierStart, hierEnd - hierStart), parsingMode);
1534 Q_ASSERT(query.isNull());
1535 if (size_t(question) < size_t(hash))
1536 setQuery(QStringView(url).sliced(question + 1, qMin<size_t>(hash, len) - question - 1),
1539 Q_ASSERT(fragment.isNull());
1541 setFragment(QStringView(url).sliced(hash + 1, len - hash - 1), parsingMode);
1543 if (error || parsingMode == QUrl::TolerantMode)
1554 if (size_t(question) < size_t(hash) && !
validateComponent(
Query, url, question + 1, qMin<size_t>(hash, len)))
1564 if (!appendPath(ourPath, options | QUrlDecodeForLocalFile, QUrlPrivate::Path))
1568 if (!host.isEmpty()) {
1569 tmp =
"//"_L1 + host;
1571 if (scheme == webDavScheme())
1572 tmp += webDavSslTag();
1574 if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
1581 if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
1589
1590
1591
1592
1593
1594
1595
1601 if (!host.isEmpty() && path.isEmpty())
1602 return u'/' + relativePath;
1610 if (!path.contains(u'/'))
1611 newPath = relativePath;
1613 newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
1623 if (path->isEmpty() || path->at(0) != u'/')
1629 while (i + 1 < path->size() && path->at(i + 1) == u'/')
1637 Q_ASSERT(!source == !position);
1640 *source = error->source;
1641 *position = error->position;
1661 if (path.at(0) == u'/') {
1662 if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
1671 if (sectionIsPresent & QUrlPrivate::Host) {
1678 if (sectionIsPresent & QUrlPrivate::Scheme)
1682 for (qsizetype i = 0; i < path.size(); ++i) {
1683 ushort c = path.at(i).unicode();
1701 qsizetype begin, qsizetype end)
1716 static const char forbidden[] =
"\"<>\\^`{|}\x7F";
1717 static const char forbiddenUserInfo[] =
":/?#[]@";
1721 const ushort *
const data =
reinterpret_cast<
const ushort *>(input.constData());
1722 for (size_t i = size_t(begin); i < size_t(end); ++i) {
1728 if ((uc ==
'%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1729 || uc <= 0x20 || strchr(forbidden, uc)) {
1733 if (section ==
UserInfo && strchr(forbiddenUserInfo + 1, uc))
1735 else if (section !=
UserInfo && strchr(forbiddenUserInfo, uc))
1746 for (size_t j = size_t(begin); j < i; ++j)
1747 if (data[j] ==
':') {
1753 setError(errorCode, input, i);
1762inline void QUrlPrivate::validate()
const
1764 QUrlPrivate *that = (QUrlPrivate *)
this;
1765 that->encodedOriginal = that->toEncoded();
1768 QURL_SETFLAG(that->stateFlags, Validated);
1773 QString auth = authority();
1779 if (scheme ==
"mailto"_L1) {
1780 if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1781 that->isValid =
false;
1782 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"expected empty host, username,"
1783 "port and password"),
1786 }
else if (scheme == ftpScheme() || scheme == httpScheme()) {
1787 if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1788 that->isValid =
false;
1789 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl,
"the host is empty, but not the path"),
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
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
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869QUrl::QUrl(
const QString &url, ParsingMode parsingMode) : d(
nullptr)
1871 setUrl(url, parsingMode);
1875
1876
1877QUrl::QUrl() : d(
nullptr)
1882
1883
1884QUrl::QUrl(
const QUrl &other)
noexcept : d(other.d)
1891
1892
1895 if (d && !d->ref.deref())
1900
1901
1902
1903
1904
1905
1906
1907
1908bool QUrl::isValid()
const
1914 return d->validityError() == QUrlPrivate::NoError;
1918
1919
1920
1921
1922bool QUrl::isEmpty()
const
1924 if (!d)
return true;
1925 return d->isEmpty();
1929
1930
1931
1932
1933
1934
1937 if (d && !d->ref.deref())
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960void QUrl::setUrl(
const QString &url, ParsingMode parsingMode)
1962 if (parsingMode == DecodedMode) {
1963 qWarning(
"QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1966 d->parse(url, parsingMode);
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994void QUrl::setScheme(
const QString &scheme)
1998 if (scheme.isEmpty()) {
2000 d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2001 d->flags &= ~QUrlPrivate::IsLocalFile;
2004 d->setScheme(scheme, scheme.size(),
true);
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018QString QUrl::scheme()
const
2020 if (!d)
return QString();
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055void QUrl::setAuthority(
const QString &authority, ParsingMode mode)
2060 if (mode == DecodedMode) {
2061 qWarning(
"QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2065 d->setAuthority(authority, 0, authority.size(), mode);
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083QString QUrl::authority(ComponentFormattingOptions options)
const
2089 if (options == QUrl::FullyDecoded) {
2090 qWarning(
"QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2094 d->appendAuthority(result, options, QUrlPrivate::Authority);
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121void QUrl::setUserInfo(
const QString &userInfo, ParsingMode mode)
2125 QString trimmed = userInfo.trimmed();
2126 if (mode == DecodedMode) {
2127 qWarning(
"QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2131 d->setUserInfo(std::move(trimmed), mode);
2132 if (userInfo.isNull()) {
2135 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2136 }
else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserInfo, userInfo)) {
2137 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2138 d->userName.clear();
2139 d->password.clear();
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157QString QUrl::userInfo(ComponentFormattingOptions options)
const
2163 if (options == QUrl::FullyDecoded) {
2164 qWarning(
"QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2168 d->appendUserInfo(result, options, QUrlPrivate::UserInfo);
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192void QUrl::setUserName(
const QString &userName, ParsingMode mode)
2197 d->setUserName(userName, mode);
2198 if (userName.isNull())
2199 d->sectionIsPresent &= ~QUrlPrivate::UserName;
2200 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::UserName, userName))
2201 d->userName.clear();
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221QString QUrl::userName(ComponentFormattingOptions options)
const
2225 d->appendUserName(result, options);
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249void QUrl::setPassword(
const QString &password, ParsingMode mode)
2254 d->setPassword(password, mode);
2255 if (password.isNull())
2256 d->sectionIsPresent &= ~QUrlPrivate::Password;
2257 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Password, password))
2258 d->password.clear();
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278QString QUrl::password(ComponentFormattingOptions options)
const
2282 d->appendPassword(result, options);
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305void QUrl::setHost(
const QString &host, ParsingMode mode)
2310 QString data = host;
2311 if (mode == DecodedMode) {
2312 data.replace(u'%',
"%25"_L1);
2313 mode = TolerantMode;
2316 if (d->setHost(data, 0, data.size(), mode)) {
2318 }
else if (!data.startsWith(u'[')) {
2324 if (!d->setHost(data, 0, data.size(), mode)) {
2326 if (data.contains(u':')) {
2328 d->error->code = QUrlPrivate::InvalidIPv6AddressError;
2330 d->sectionIsPresent &= ~QUrlPrivate::Host;
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356QString QUrl::host(ComponentFormattingOptions options)
const
2360 d->appendHost(result, options);
2361 if (result.startsWith(u'['))
2362 result = result.mid(1, result.size() - 2);
2368
2369
2370
2371
2372
2373
2374void QUrl::setPort(
int port)
2379 if (port < -1 || port > 65535) {
2380 d->setError(QUrlPrivate::InvalidPortError, QString::number(port), 0);
2386 d->sectionIsPresent |= QUrlPrivate::Host;
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399int QUrl::port(
int defaultPort)
const
2401 if (!d)
return defaultPort;
2402 return d->port == -1 ? defaultPort : d->port;
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431void QUrl::setPath(
const QString &path, ParsingMode mode)
2436 d->setPath(path, mode);
2442 if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Path, path))
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484QString QUrl::path(ComponentFormattingOptions options)
const
2488 d->appendPath(result, options, QUrlPrivate::Path);
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513QString QUrl::fileName(ComponentFormattingOptions options)
const
2515 const QString ourPath = path(options);
2516 const qsizetype slash = ourPath.lastIndexOf(u'/');
2519 return ourPath.mid(slash + 1);
2523
2524
2525
2526
2527
2528
2529bool QUrl::hasQuery()
const
2531 if (!d)
return false;
2532 return d->hasQuery();
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566void QUrl::setQuery(
const QString &query, ParsingMode mode)
2571 d->setQuery(query, mode);
2573 d->sectionIsPresent &= ~QUrlPrivate::Query;
2574 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Query, query))
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589void QUrl::setQuery(
const QUrlQuery &query)
2595 d->query = query.toString();
2596 if (query.isEmpty())
2597 d->sectionIsPresent &= ~QUrlPrivate::Query;
2599 d->sectionIsPresent |= QUrlPrivate::Query;
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619QString QUrl::query(ComponentFormattingOptions options)
const
2623 d->appendQuery(result, options, QUrlPrivate::Query);
2624 if (d->hasQuery() && result.isNull())
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658void QUrl::setFragment(
const QString &fragment, ParsingMode mode)
2663 d->setFragment(fragment, mode);
2664 if (fragment.isNull())
2665 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2666 else if (mode == StrictMode && !d->validateComponent(QUrlPrivate::Fragment, fragment))
2667 d->fragment.clear();
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686QString QUrl::fragment(ComponentFormattingOptions options)
const
2690 d->appendFragment(result, options, QUrlPrivate::Fragment);
2691 if (d->hasFragment() && result.isNull())
2698
2699
2700
2701
2702
2703
2704bool QUrl::hasFragment()
const
2706 if (!d)
return false;
2707 return d->hasFragment();
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729QUrl QUrl::resolved(
const QUrl &relative)
const
2731 if (!d)
return relative;
2732 if (!relative.d)
return *
this;
2735 if (!relative.d->scheme.isEmpty()) {
2739 if (relative.d->hasAuthority()) {
2743 t.d =
new QUrlPrivate;
2746 t.d->userName = d->userName;
2747 t.d->password = d->password;
2748 t.d->host = d->host;
2749 t.d->port = d->port;
2750 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2752 if (relative.d->path.isEmpty()) {
2753 t.d->path = d->path;
2754 if (relative.d->hasQuery()) {
2755 t.d->query = relative.d->query;
2756 t.d->sectionIsPresent |= QUrlPrivate::Query;
2757 }
else if (d->hasQuery()) {
2758 t.d->query = d->query;
2759 t.d->sectionIsPresent |= QUrlPrivate::Query;
2762 t.d->path = relative.d->path.startsWith(u'/')
2764 : d->mergePaths(relative.d->path);
2765 if (relative.d->hasQuery()) {
2766 t.d->query = relative.d->query;
2767 t.d->sectionIsPresent |= QUrlPrivate::Query;
2771 t.d->scheme = d->scheme;
2773 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2775 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2776 t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2778 t.d->fragment = relative.d->fragment;
2779 if (relative.d->hasFragment())
2780 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2782 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2784 t.d->normalizePathSegments(&t.d->path);
2785 if (!t.d->hasAuthority()) {
2786 if (t.d->isLocalFile() && t.d->path.startsWith(u'/'))
2787 t.d->sectionIsPresent |= QUrlPrivate::Host;
2789 fixupNonAuthorityPath(&t.d->path);
2792#if defined(QURL_DEBUG)
2793 qDebug(
"QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2794 qUtf16Printable(url()),
2795 qUtf16Printable(relative.url()),
2796 qUtf16Printable(t.url()));
2802
2803
2804
2805
2806
2807
2808
2809
2810bool QUrl::isRelative()
const
2812 if (!d)
return true;
2813 return !d->hasScheme();
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827QString QUrl::url(FormattingOptions options)
const
2829 return toString(options);
2833
2834
2835
2836
2837
2838
2839
2840
2841QString QUrl::toString(FormattingOptions options)
const
2848 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2849 qWarning(
"QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2850 options &= ~QUrl::FullyDecoded;
2860 if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2861 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2862 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2864 url = d->toLocalFile(options | QUrl::FullyDecoded);
2865 if (!url.isNull() || !d->hasPath())
2873 if (options & DecodeReserved)
2874 options &= ~EncodeReserved;
2876 options |= EncodeReserved;
2878 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2879 url += d->scheme + u':';
2881 bool pathIsAbsolute = d->path.startsWith(u'/');
2882 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2884 d->appendAuthority(url, options, QUrlPrivate::FullUrl);
2885 }
else if (isLocalFile() && pathIsAbsolute) {
2890 if (!(options & QUrl::RemovePath))
2891 d->appendPath(url, options, QUrlPrivate::FullUrl);
2893 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2895 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2897 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2899 d->appendFragment(url, options, QUrlPrivate::FullUrl);
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2920QString QUrl::toDisplayString(FormattingOptions options)
const
2922 return toString(options | RemovePassword);
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938QUrl QUrl::adjusted(QUrl::FormattingOptions options)
const
2945 if (options & RemoveScheme)
2946 that.setScheme(QString());
2947 if ((options & RemoveAuthority) == RemoveAuthority) {
2948 that.setAuthority(QString());
2950 if ((options & RemoveUserInfo) == RemoveUserInfo)
2951 that.setUserInfo(QString());
2952 else if (options & RemovePassword)
2953 that.setPassword(QString());
2954 if (options & RemovePort)
2957 if (options & RemoveQuery)
2958 that.setQuery(QString());
2959 if (options & RemoveFragment)
2960 that.setFragment(QString());
2961 if (options & RemovePath) {
2962 that.setPath(QString());
2963 }
else if (
auto pathOpts = options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2965 that.d->path.resize(0);
2966 d->appendPath(that.d->path, pathOpts, QUrlPrivate::Path);
2968 if (that.d->isLocalFile() && that.d->path.startsWith(u'/')) {
2971 that.d->sectionIsPresent |= QUrlPrivate::Host;
2977
2978
2979
2980
2981
2982
2983
2984
2985QByteArray QUrl::toEncoded(FormattingOptions options)
const
2987 options &= ~(FullyDecoded | FullyEncoded);
2988 return toString(options | FullyEncoded).toLatin1();
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode)
3008 return QUrl(QString::fromUtf8(input), mode);
3012
3013
3014
3015
3016
3017
3018
3019QString QUrl::fromPercentEncoding(
const QByteArray &input)
3021 QByteArray ba = QByteArray::fromPercentEncoding(input);
3022 return QString::fromUtf8(ba);
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037QByteArray QUrl::toPercentEncoding(
const QString &input,
const QByteArray &exclude,
const QByteArray &include)
3039 return input.toUtf8().toPercentEncoding(exclude, include);
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059QString QUrl::fromAce(
const QByteArray &domain, QUrl::AceProcessingOptions options)
3061 return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3062 ForbidLeadingDot , options);
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082QByteArray QUrl::toAce(
const QString &domain, AceProcessingOptions options)
3084 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot , options)
3089
3090
3091
3092
3093
3094
3095
3099 if (!lhs.d || !rhs.d) {
3100 bool thisIsEmpty = !lhs.d || lhs.d->isEmpty();
3101 bool thatIsEmpty = !rhs.d || rhs.d->isEmpty();
3106 return Qt::weak_ordering::less;
3108 return Qt::weak_ordering::equivalent;
3110 return Qt::weak_ordering::greater;
3115 cmp = lhs.d->scheme.compare(rhs.d->scheme);
3117 return Qt::compareThreeWay(cmp, 0);
3119 cmp = lhs.d->userName.compare(rhs.d->userName);
3121 return Qt::compareThreeWay(cmp, 0);
3123 cmp = lhs.d->password.compare(rhs.d->password);
3125 return Qt::compareThreeWay(cmp, 0);
3127 cmp = lhs.d->host.compare(rhs.d->host);
3129 return Qt::compareThreeWay(cmp, 0);
3131 if (lhs.d->port != rhs.d->port)
3132 return Qt::compareThreeWay(lhs.d->port, rhs.d->port);
3134 cmp = lhs.d->path.compare(rhs.d->path);
3136 return Qt::compareThreeWay(cmp, 0);
3138 if (lhs.d->hasQuery() != rhs.d->hasQuery())
3139 return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3141 cmp = lhs.d->query.compare(rhs.d->query);
3143 return Qt::compareThreeWay(cmp, 0);
3145 if (lhs.d->hasFragment() != rhs.d->hasFragment())
3146 return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater;
3148 cmp = lhs.d->fragment.compare(rhs.d->fragment);
3149 return Qt::compareThreeWay(cmp, 0);
3153
3154
3155
3156
3157
3158
3159
3163 if (!lhs.d && !rhs.d)
3166 return rhs.d->isEmpty();
3168 return lhs.d->isEmpty();
3170 return (lhs.d->presentSections() == rhs.d->presentSections()) &&
3171 lhs.d->scheme == rhs.d->scheme &&
3172 lhs.d->userName == rhs.d->userName &&
3173 lhs.d->password == rhs.d->password &&
3174 lhs.d->host == rhs.d->host &&
3175 lhs.d->port == rhs.d->port &&
3176 lhs.d->path == rhs.d->path &&
3177 lhs.d->query == rhs.d->query &&
3178 lhs.d->fragment == rhs.d->fragment;
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191bool QUrl::matches(
const QUrl &url, FormattingOptions options)
const
3196 return url.d->isEmpty();
3198 return d->isEmpty();
3200 uint mask = d->presentSections();
3202 if (options.testFlag(QUrl::RemoveScheme))
3203 mask &= ~QUrlPrivate::Scheme;
3204 else if (d->scheme != url.d->scheme)
3207 if (options.testFlag(QUrl::RemovePassword))
3208 mask &= ~QUrlPrivate::Password;
3209 else if (d->password != url.d->password)
3212 if (options.testFlag(QUrl::RemoveUserInfo))
3213 mask &= ~QUrlPrivate::UserName;
3214 else if (d->userName != url.d->userName)
3217 if (options.testFlag(QUrl::RemovePort))
3218 mask &= ~QUrlPrivate::Port;
3219 else if (d->port != url.d->port)
3222 if (options.testFlag(QUrl::RemoveAuthority))
3223 mask &= ~QUrlPrivate::Host;
3224 else if (d->host != url.d->host)
3227 if (options.testFlag(QUrl::RemoveQuery))
3228 mask &= ~QUrlPrivate::Query;
3229 else if (d->query != url.d->query)
3232 if (options.testFlag(QUrl::RemoveFragment))
3233 mask &= ~QUrlPrivate::Fragment;
3234 else if (d->fragment != url.d->fragment)
3237 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3240 if (options.testFlag(QUrl::RemovePath))
3245 d->appendPath(path1, options, QUrlPrivate::Path);
3247 url.d->appendPath(path2, options, QUrlPrivate::Path);
3248 return path1 == path2;
3252
3253
3254
3255
3256
3257
3258
3261
3262
3263QUrl &QUrl::operator =(
const QUrl &url)
noexcept
3272 qAtomicAssign(d, url.d);
3280
3281
3282
3283
3284
3285#ifdef QT_NO_URL_CAST_FROM_STRING
3286#error You cannot define QT_NO_URL_CAST_FROM_STRING in QtCore, for ABI reasons
3288QUrl &QUrl::operator =(
const QString &url)
3292 d->parse(url, TolerantMode);
3297
3298
3299
3300
3303
3304
3305
3306
3310 d =
new QUrlPrivate;
3316
3317
3318
3319
3320void QUrl::detachToClear()
3322 if (d && (d->ref.loadAcquire() == 1 || !d->ref.deref())) {
3324 d->ref.storeRelaxed(1);
3327 d =
new QUrlPrivate;
3332
3333
3334bool QUrl::isDetached()
const
3336 return !d || d->ref.loadRelaxed() == 1;
3341#if defined(Q_OS_WIN)
3342 QString result(pathName);
3343 const QChar nativeSeparator = u'\\';
3344 auto i = result.indexOf(nativeSeparator);
3346 QChar *
const data = result.data();
3347 const auto length = result.length();
3348 for (; i < length; ++i) {
3349 if (data[i] == nativeSeparator)
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395QUrl QUrl::fromLocalFile(
const QString &localFile)
3398 QString deslashified = fromNativeSeparators(localFile);
3399 if (deslashified.isEmpty())
3401 QString scheme = fileScheme();
3402 char16_t firstChar = deslashified.at(0).unicode();
3403 char16_t secondChar = deslashified.size() > 1 ? deslashified.at(1).unicode() : u'\0';
3406 if (firstChar != u'/' && secondChar == u':') {
3407 deslashified.prepend(u'/');
3409 }
else if (firstChar == u'/' && secondChar == u'/') {
3411 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3412 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3414 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3415 hostSpec.truncate(hostSpec.size() - 4);
3416 scheme = webDavScheme();
3421 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3422 if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3427 }
else if (indexOfPath > 2) {
3428 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3430 deslashified.clear();
3433 if (firstChar == u'/') {
3436 url.d->sectionIsPresent |= QUrlPrivate::Host;
3439 url.setScheme(scheme);
3440 url.setPath(deslashified, DecodedMode);
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478QString QUrl::toLocalFile()
const
3484 return d->toLocalFile(QUrl::FullyDecoded);
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504bool QUrl::isLocalFile()
const
3506 return d && d->isLocalFile();
3510
3511
3512
3513
3514bool QUrl::isParentOf(
const QUrl &childUrl)
const
3516 QString childPath = childUrl.path();
3519 return ((childUrl.scheme().isEmpty())
3520 && (childUrl.authority().isEmpty())
3521 && childPath.size() > 0 && childPath.at(0) == u'/');
3523 QString ourPath = path();
3525 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3526 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3527 && childPath.startsWith(ourPath)
3528 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3529 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3530 && childPath.at(ourPath.size()) == u'/')));
3534#ifndef QT_NO_DATASTREAM
3536
3537
3538
3539
3540
3541
3542QDataStream &operator<<(QDataStream &out,
const QUrl &url)
3546 u = url.toEncoded();
3552
3553
3554
3555
3556
3557
3562 url.setUrl(QString::fromLatin1(u));
3567#ifndef QT_NO_DEBUG_STREAM
3570 QDebugStateSaver saver(d);
3571 d.nospace() <<
"QUrl(" << url.toDisplayString() <<
')';
3578 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3579 errorSource.at(errorPosition) : QChar(QChar::Null);
3581 switch (errorCode) {
3583 Q_UNREACHABLE_RETURN(QString());
3586 auto msg =
"Invalid scheme (character '%1' not permitted)"_L1;
3590 case QUrlPrivate::InvalidUserNameError:
3591 return "Invalid user name (character '%1' not permitted)"_L1
3594 case QUrlPrivate::InvalidPasswordError:
3595 return "Invalid password (character '%1' not permitted)"_L1
3598 case QUrlPrivate::InvalidRegNameError:
3599 if (errorPosition >= 0)
3600 return "Invalid hostname (character '%1' not permitted)"_L1
3603 return QStringLiteral(
"Invalid hostname (contains invalid characters)");
3606 case QUrlPrivate::InvalidIPv6AddressError:
3608 case QUrlPrivate::InvalidCharacterInIPv6Error:
3609 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3610 case QUrlPrivate::InvalidIPvFutureError:
3611 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3612 case QUrlPrivate::HostMissingEndBracket:
3615 case QUrlPrivate::InvalidPortError:
3616 return QStringLiteral(
"Invalid port or port number out of range");
3617 case QUrlPrivate::PortEmptyError:
3620 case QUrlPrivate::InvalidPathError:
3621 return "Invalid path (character '%1' not permitted)"_L1
3624 case QUrlPrivate::InvalidQueryError:
3625 return "Invalid query (character '%1' not permitted)"_L1
3628 case QUrlPrivate::InvalidFragmentError:
3629 return "Invalid fragment (character '%1' not permitted)"_L1
3632 case QUrlPrivate::AuthorityPresentAndPathIsRelative:
3633 return QStringLiteral(
"Path component is relative and authority is present");
3634 case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
3635 return QStringLiteral(
"Path component starts with '//' and authority is absent");
3636 case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
3637 return QStringLiteral(
"Relative URL's path component contains ':' before any '/'");
3640 Q_UNREACHABLE_RETURN(QString());
3644 const QString &component)
3647 msg += QLatin1StringView(componentName) % u'"' % component %
"\","_L1;
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663QString QUrl::errorString()
const
3669 QString errorSource;
3670 qsizetype errorPosition = 0;
3671 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3672 if (errorCode == QUrlPrivate::NoError)
3675 msg += errorMessage(errorCode, errorSource, errorPosition);
3676 msg +=
"; source was \""_L1;
3679 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3680 " scheme = ", d->scheme);
3681 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3682 " userinfo = ", userInfo());
3683 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3684 " host = ", d->host);
3685 appendComponentIfPresent(msg, d->port != -1,
3686 " port = ", QString::number(d->port));
3687 appendComponentIfPresent(msg, !d->path.isEmpty(),
3688 " path = ", d->path);
3689 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3690 " query = ", d->query);
3691 appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3692 " fragment = ", d->fragment);
3693 if (msg.endsWith(u','))
3699
3700
3701
3702
3703QStringList QUrl::toStringList(
const QList<QUrl> &urls, FormattingOptions options)
3706 lst.reserve(urls.size());
3707 for (
const QUrl &url : urls)
3708 lst.append(url.toString(options));
3714
3715
3716
3717
3718
3719QList<QUrl> QUrl::fromStringList(
const QStringList &urls, ParsingMode mode)
3722 lst.reserve(urls.size());
3723 for (
const QString &str : urls)
3724 lst.append(QUrl(str, mode));
3729
3730
3731
3734
3735
3736
3739
3740
3741
3742
3745 QtPrivate::QHashCombineWithSeed hasher(seed);
3749 return hasher(0, -1);
3750 size_t state = hasher(0, url.d->port);
3752 if (url.d->hasScheme())
3753 state = hasher(state, url.d->scheme);
3754 if (url.d->hasUserInfo()) {
3756 state = hasher(state, url.d->userName);
3757 state = hasher(state, url.d->password);
3759 if (url.d->hasHost() || url.d->isLocalFile())
3760 state = hasher(state, url.d->host);
3761 if (url.d->hasPath())
3762 state = hasher(state, url.d->path);
3763 if (url.d->hasQuery())
3764 state = hasher(state, url.d->query);
3765 if (url.d->hasFragment())
3766 state = hasher(state, url.d->fragment);
3772 if (url.scheme() == ftpScheme()) {
3773 QString path = url.path(QUrl::PrettyDecoded);
3774 if (path.startsWith(
"//"_L1))
3775 url.setPath(
"/%2F"_L1 + QStringView{path}.mid(2), QUrl::TolerantMode);
3782 QIPAddressUtils::IPv6Address address;
3783 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) ==
nullptr;
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826QUrl QUrl::fromUserInput(
const QString &userInput,
const QString &workingDirectory,
3827 UserInputResolutionOptions options)
3829 QString trimmedString = userInput.trimmed();
3831 if (trimmedString.isEmpty())
3836 if (isIp6(trimmedString)) {
3838 url.setHost(trimmedString);
3843 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3846 if (!workingDirectory.isEmpty()) {
3847 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3848 if (fileInfo.exists())
3849 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3852 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3853 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3857 if (QDir::isAbsolutePath(trimmedString))
3858 return QUrl::fromLocalFile(trimmedString);
3860 QUrl urlPrepended = QUrl(
"http://"_L1 + trimmedString, QUrl::TolerantMode);
3866 && !url.scheme().isEmpty()
3867 && urlPrepended.port() == -1)
3868 return adjustFtpPath(url);
3871 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3872 qsizetype dotIndex = trimmedString.indexOf(u'.');
3873 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3874 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3875 urlPrepended.setScheme(ftpScheme());
3876 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)
bool appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
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
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 bool 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)