Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qurl.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
394#include "qurl.h"
395#include "qurl_p.h"
396#include "qplatformdefs.h"
397#include "qstring.h"
398#include "qstringlist.h"
399#include "qdebug.h"
400#include "qhash.h"
401#include "qdatastream.h"
402#include "private/qipaddress_p.h"
403#include "qurlquery.h"
404#include "private/qdir_p.h"
405#include <private/qtools_p.h>
406
408
409using namespace Qt::StringLiterals;
410using namespace QtMiscUtils;
411
412inline static bool isHex(char c)
413{
414 c |= 0x20;
415 return isAsciiDigit(c) || (c >= 'a' && c <= 'f');
416}
417
418static inline QString ftpScheme()
419{
420 return QStringLiteral("ftp");
421}
422
423static inline QString fileScheme()
424{
425 return QStringLiteral("file");
426}
427
428static inline QString webDavScheme()
429{
430 return QStringLiteral("webdavs");
431}
432
433static inline QString webDavSslTag()
434{
435 return QStringLiteral("@SSL");
436}
437
439{
440public:
441 enum Section : uchar {
442 Scheme = 0x01,
443 UserName = 0x02,
444 Password = 0x04,
446 Host = 0x08,
447 Port = 0x10,
449 Path = 0x20,
451 Query = 0x40,
452 Fragment = 0x80,
453 FullUrl = 0xff
454 };
455
456 enum Flags : uchar {
457 IsLocalFile = 0x01
458 };
459
461 // the high byte of the error code matches the Section
462 // the first item in each value must be the generic "Invalid xxx Error"
464
466
468
475
478
480
482
484
485 // the following three cases are only possible in combination with
486 // presence/absence of the path, authority and scheme. See validityError().
490
491 NoError = 0
492 };
493
494 struct Error {
498 };
499
500 QUrlPrivate();
503
504 void parse(const QString &url, QUrl::ParsingMode parsingMode);
505 bool isEmpty() const
506 { return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
507
508 std::unique_ptr<Error> cloneError() const;
509 void clearError();
510 void setError(ErrorCode errorCode, const QString &source, qsizetype supplement = -1);
511 ErrorCode validityError(QString *source = nullptr, qsizetype *position = nullptr) const;
514 { return validateComponent(section, input, 0, input.size()); }
515
516 // no QString scheme() const;
517 void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
518 void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
519 void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const;
520 void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const;
521 void appendHost(QString &appendTo, QUrl::FormattingOptions options) const;
522 void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
523 void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
524 void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
525
526 // the "end" parameters are like STL iterators: they point to one past the last valid element
527 bool setScheme(const QString &value, qsizetype len, bool doSetError);
529 void setUserInfo(const QString &userInfo, qsizetype from, qsizetype end);
530 void setUserName(const QString &value, qsizetype from, qsizetype end);
531 void setPassword(const QString &value, qsizetype from, qsizetype end);
533 void setPath(const QString &value, qsizetype from, qsizetype end);
534 void setQuery(const QString &value, qsizetype from, qsizetype end);
535 void setFragment(const QString &value, qsizetype from, qsizetype end);
536
537 inline bool hasScheme() const { return sectionIsPresent & Scheme; }
538 inline bool hasAuthority() const { return sectionIsPresent & Authority; }
539 inline bool hasUserInfo() const { return sectionIsPresent & UserInfo; }
540 inline bool hasUserName() const { return sectionIsPresent & UserName; }
541 inline bool hasPassword() const { return sectionIsPresent & Password; }
542 inline bool hasHost() const { return sectionIsPresent & Host; }
543 inline bool hasPort() const { return port != -1; }
544 inline bool hasPath() const { return !path.isEmpty(); }
545 inline bool hasQuery() const { return sectionIsPresent & Query; }
546 inline bool hasFragment() const { return sectionIsPresent & Fragment; }
547
548 inline bool isLocalFile() const { return flags & IsLocalFile; }
550
551 QString mergePaths(const QString &relativePath) const;
552
554 int port;
555
563
564 std::unique_ptr<Error> error;
565
566 // not used for:
567 // - Port (port == -1 means absence)
568 // - Path (there's no path delimiter, so we optimize its use out of existence)
569 // Schemes are never supposed to be empty, but we keep the flag anyway
572
573 // 32-bit: 2 bytes tail padding available
574 // 64-bit: 6 bytes tail padding available
575};
576
578 : ref(1), port(-1),
579 sectionIsPresent(0),
580 flags(0)
581{
582}
583
585 : ref(1), port(copy.port),
586 scheme(copy.scheme),
587 userName(copy.userName),
588 password(copy.password),
589 host(copy.host),
590 path(copy.path),
592 fragment(copy.fragment),
593 error(copy.cloneError()),
594 sectionIsPresent(copy.sectionIsPresent),
596{
597}
598
600 = default;
601
602std::unique_ptr<QUrlPrivate::Error> QUrlPrivate::cloneError() const
603{
604 return error ? std::make_unique<Error>(*error) : nullptr;
605}
606
608{
609 error.reset();
610}
611
612inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, qsizetype supplement)
613{
614 if (error) {
615 // don't overwrite an error set in a previous section during parsing
616 return;
617 }
618 error = std::make_unique<Error>();
619 error->code = errorCode;
620 error->source = source;
621 error->position = supplement;
622}
623
624// From RFC 3986, Appendix A Collected ABNF for URI
625// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
626//[...]
627// scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
628//
629// authority = [ userinfo "@" ] host [ ":" port ]
630// userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
631// host = IP-literal / IPv4address / reg-name
632// port = *DIGIT
633//[...]
634// reg-name = *( unreserved / pct-encoded / sub-delims )
635//[..]
636// pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
637//
638// query = *( pchar / "/" / "?" )
639//
640// fragment = *( pchar / "/" / "?" )
641//
642// pct-encoded = "%" HEXDIG HEXDIG
643//
644// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
645// reserved = gen-delims / sub-delims
646// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
647// sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
648// / "*" / "+" / "," / ";" / "="
649// the path component has a complex ABNF that basically boils down to
650// slash-separated segments of "pchar"
651
652// The above is the strict definition of the URL components and we mostly
653// adhere to it, with few exceptions. QUrl obeys the following behavior:
654// - percent-encoding sequences always use uppercase HEXDIG;
655// - unreserved characters are *always* decoded, no exceptions;
656// - the space character and bytes with the high bit set are controlled by
657// the EncodeSpaces and EncodeUnicode bits;
658// - control characters, the percent sign itself, and bytes with the high
659// bit set that don't form valid UTF-8 sequences are always encoded,
660// except in FullyDecoded mode;
661// - sub-delims are always left alone, except in FullyDecoded mode;
662// - gen-delim change behavior depending on which section of the URL (or
663// the entire URL) we're looking at; see below;
664// - characters not mentioned above, like "<", and ">", are usually
665// decoded in individual sections of the URL, but encoded when the full
666// URL is put together (we can change on subjective definition of
667// "pretty").
668//
669// The behavior for the delimiters bears some explanation. The spec says in
670// section 2.2:
671// URIs that differ in the replacement of a reserved character with its
672// corresponding percent-encoded octet are not equivalent.
673// (note: QUrl API mistakenly uses the "reserved" term, so we will refer to
674// them here as "delimiters").
675//
676// For that reason, we cannot encode delimiters found in decoded form and we
677// cannot decode the ones found in encoded form if that would change the
678// interpretation. Conversely, we *can* perform the transformation if it would
679// not change the interpretation. From the last component of a URL to the first,
680// here are the gen-delims we can unambiguously transform when the field is
681// taken in isolation:
682// - fragment: none, since it's the last
683// - query: "#" is unambiguous
684// - path: "#" and "?" are unambiguous
685// - host: completely special but never ambiguous, see setHost() below.
686// - password: the "#", "?", "/", "[", "]" and "@" characters are unambiguous
687// - username: the "#", "?", "/", "[", "]", "@", and ":" characters are unambiguous
688// - scheme: doesn't accept any delimiter, see setScheme() below.
689//
690// Internally, QUrl stores each component in the format that corresponds to the
691// default mode (PrettyDecoded). It deviates from the "strict" FullyEncoded
692// mode in the following way:
693// - spaces are decoded
694// - valid UTF-8 sequences are decoded
695// - gen-delims that can be unambiguously transformed are decoded
696// - characters controlled by DecodeReserved are often decoded, though this behavior
697// can change depending on the subjective definition of "pretty"
698//
699// Note that the list of gen-delims that we can transform is different for the
700// user info (user name + password) and the authority (user info + host +
701// port).
702
703
704// list the recoding table modifications to be used with the recodeFromUser and
705// appendToUser functions, according to the rules above. Spaces and UTF-8
706// sequences are handled outside the tables.
707
708// the encodedXXX tables are run with the delimiters set to "leave" by default;
709// the decodedXXX tables are run with the delimiters set to "decode" by default
710// (except for the query, which doesn't use these functions)
711
712namespace {
713template <typename T> constexpr ushort decode(T x) noexcept { return ushort(x); }
714template <typename T> constexpr ushort leave(T x) noexcept { return ushort(0x100 | x); }
715template <typename T> constexpr ushort encode(T x) noexcept { return ushort(0x200 | x); }
716}
717
718static const ushort userNameInIsolation[] = {
719 decode(':'), // 0
720 decode('@'), // 1
721 decode(']'), // 2
722 decode('['), // 3
723 decode('/'), // 4
724 decode('?'), // 5
725 decode('#'), // 6
726
727 decode('"'), // 7
728 decode('<'),
729 decode('>'),
730 decode('^'),
731 decode('\\'),
732 decode('|'),
733 decode('{'),
734 decode('}'),
735 0
736};
738static const ushort * const pathInIsolation = userNameInIsolation + 5;
739static const ushort * const queryInIsolation = userNameInIsolation + 6;
741
742static const ushort userNameInUserInfo[] = {
743 encode(':'), // 0
744 decode('@'), // 1
745 decode(']'), // 2
746 decode('['), // 3
747 decode('/'), // 4
748 decode('?'), // 5
749 decode('#'), // 6
750
751 decode('"'), // 7
752 decode('<'),
753 decode('>'),
754 decode('^'),
755 decode('\\'),
756 decode('|'),
757 decode('{'),
758 decode('}'),
759 0
760};
762
763static const ushort userNameInAuthority[] = {
764 encode(':'), // 0
765 encode('@'), // 1
766 encode(']'), // 2
767 encode('['), // 3
768 decode('/'), // 4
769 decode('?'), // 5
770 decode('#'), // 6
771
772 decode('"'), // 7
773 decode('<'),
774 decode('>'),
775 decode('^'),
776 decode('\\'),
777 decode('|'),
778 decode('{'),
779 decode('}'),
780 0
781};
783
784static const ushort userNameInUrl[] = {
785 encode(':'), // 0
786 encode('@'), // 1
787 encode(']'), // 2
788 encode('['), // 3
789 encode('/'), // 4
790 encode('?'), // 5
791 encode('#'), // 6
792
793 // no need to list encode(x) for the other characters
794 0
795};
796static const ushort * const passwordInUrl = userNameInUrl + 1;
797static const ushort * const pathInUrl = userNameInUrl + 5;
798static const ushort * const queryInUrl = userNameInUrl + 6;
799static const ushort * const fragmentInUrl = userNameInUrl + 6;
800
802{
803 data.replace(u'%', "%25"_L1);
804}
805
806static inline QString
807recodeFromUser(const QString &input, const ushort *actions, qsizetype from, qsizetype to)
808{
810 const QChar *begin = input.constData() + from;
811 const QChar *end = input.constData() + to;
812 if (qt_urlRecode(output, QStringView{begin, end}, {}, actions))
813 return output;
814
815 return input.mid(from, to - from);
816}
817
818// appendXXXX functions: copy from the internal form to the external, user form.
819// the internal value is stored in its PrettyDecoded form, so that case is easy.
820static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
821 const ushort *actions)
822{
823 // The stored value is already QUrl::PrettyDecoded, so there's nothing to
824 // do if that's what the user asked for (test only
825 // ComponentFormattingOptions, ignore FormattingOptions).
826 if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
827 !qt_urlRecode(appendTo, value, options, actions))
828 appendTo += value;
829
830 // copy nullness, if necessary, because QString::operator+=(QStringView) doesn't
831 if (appendTo.isNull() && !value.isNull())
832 appendTo.detach();
833}
834
835inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
836{
837 if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
838 appendUserInfo(appendTo, options, appendingTo);
839
840 // add '@' only if we added anything
841 if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
842 appendTo += u'@';
843 }
844 appendHost(appendTo, options);
845 if (!(options & QUrl::RemovePort) && port != -1)
846 appendTo += u':' + QString::number(port);
847}
848
849inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
850{
851 if (Q_LIKELY(!hasUserInfo()))
852 return;
853
854 const ushort *userNameActions;
855 const ushort *passwordActions;
856 if (options & QUrl::EncodeDelimiters) {
857 userNameActions = userNameInUrl;
858 passwordActions = passwordInUrl;
859 } else {
860 switch (appendingTo) {
861 case UserInfo:
862 userNameActions = userNameInUserInfo;
863 passwordActions = passwordInUserInfo;
864 break;
865
866 case Authority:
867 userNameActions = userNameInAuthority;
868 passwordActions = passwordInAuthority;
869 break;
870
871 case FullUrl:
872 userNameActions = userNameInUrl;
873 passwordActions = passwordInUrl;
874 break;
875
876 default:
877 // can't happen
878 Q_UNREACHABLE();
879 break;
880 }
881 }
882
883 if (!qt_urlRecode(appendTo, userName, options, userNameActions))
884 appendTo += userName;
885 if (options & QUrl::RemovePassword || !hasPassword()) {
886 return;
887 } else {
888 appendTo += u':';
889 if (!qt_urlRecode(appendTo, password, options, passwordActions))
890 appendTo += password;
891 }
892}
893
895{
896 // only called from QUrl::userName()
897 appendToUser(appendTo, userName, options,
899}
900
902{
903 // only called from QUrl::password()
904 appendToUser(appendTo, password, options,
906}
907
908inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
909{
910 QString thePath = path;
911 if (options & QUrl::NormalizePathSegments) {
913 }
914
915 QStringView thePathView(thePath);
916 if (options & QUrl::RemoveFilename) {
917 const qsizetype slash = path.lastIndexOf(u'/');
918 if (slash == -1)
919 return;
920 thePathView = QStringView{path}.left(slash + 1);
921 }
922 // check if we need to remove trailing slashes
923 if (options & QUrl::StripTrailingSlash) {
924 while (thePathView.size() > 1 && thePathView.endsWith(u'/'))
925 thePathView.chop(1);
926 }
927
928 appendToUser(appendTo, thePathView, options,
929 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation);
930}
931
932inline void QUrlPrivate::appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
933{
934 appendToUser(appendTo, fragment, options,
936 appendingTo == FullUrl ? nullptr : fragmentInIsolation);
937}
938
939inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
940{
941 appendToUser(appendTo, query, options,
942 appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
943}
944
945// setXXX functions
946
947inline bool QUrlPrivate::setScheme(const QString &value, qsizetype len, bool doSetError)
948{
949 // schemes are strictly RFC-compliant:
950 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
951 // we also lowercase the scheme
952
953 // schemes in URLs are not allowed to be empty, but they can be in
954 // "Relative URIs" which QUrl also supports. QUrl::setScheme does
955 // not call us with len == 0, so this can only be from parse()
956 scheme.clear();
957 if (len == 0)
958 return false;
959
961
962 // validate it:
963 qsizetype needsLowercasing = -1;
964 const ushort *p = reinterpret_cast<const ushort *>(value.data());
965 for (qsizetype i = 0; i < len; ++i) {
966 if (isAsciiLower(p[i]))
967 continue;
968 if (isAsciiUpper(p[i])) {
969 needsLowercasing = i;
970 continue;
971 }
972 if (i) {
973 if (isAsciiDigit(p[i]))
974 continue;
975 if (p[i] == '+' || p[i] == '-' || p[i] == '.')
976 continue;
977 }
978
979 // found something else
980 // don't call setError needlessly:
981 // if we've been called from parse(), it will try to recover
982 if (doSetError)
984 return false;
985 }
986
987 scheme = value.left(len);
988
989 if (needsLowercasing != -1) {
990 // schemes are ASCII only, so we don't need the full Unicode toLower
991 QChar *schemeData = scheme.data(); // force detaching here
992 for (qsizetype i = needsLowercasing; i >= 0; --i) {
993 ushort c = schemeData[i].unicode();
994 if (isAsciiUpper(c))
995 schemeData[i] = QChar(c + 0x20);
996 }
997 }
998
999 // did we set to the file protocol?
1000 if (scheme == fileScheme()
1001#ifdef Q_OS_WIN
1002 || scheme == webDavScheme()
1003#endif
1004 ) {
1005 flags |= IsLocalFile;
1006 } else {
1007 flags &= ~IsLocalFile;
1008 }
1009 return true;
1010}
1011
1013{
1014 sectionIsPresent &= ~Authority;
1016 port = -1;
1017
1018 // we never actually _loop_
1019 while (from != end) {
1020 qsizetype userInfoIndex = auth.indexOf(u'@', from);
1021 if (size_t(userInfoIndex) < size_t(end)) {
1022 setUserInfo(auth, from, userInfoIndex);
1023 if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1024 break;
1025 from = userInfoIndex + 1;
1026 }
1027
1028 qsizetype colonIndex = auth.lastIndexOf(u':', end - 1);
1029 if (colonIndex < from)
1030 colonIndex = -1;
1031
1032 if (size_t(colonIndex) < size_t(end)) {
1033 if (auth.at(from).unicode() == '[') {
1034 // check if colonIndex isn't inside the "[...]" part
1035 qsizetype closingBracket = auth.indexOf(u']', from);
1036 if (size_t(closingBracket) > size_t(colonIndex))
1037 colonIndex = -1;
1038 }
1039 }
1040
1041 if (size_t(colonIndex) < size_t(end) - 1) {
1042 // found a colon with digits after it
1043 unsigned long x = 0;
1044 for (qsizetype i = colonIndex + 1; i < end; ++i) {
1045 ushort c = auth.at(i).unicode();
1046 if (isAsciiDigit(c)) {
1047 x *= 10;
1048 x += c - '0';
1049 } else {
1050 x = ulong(-1); // x != ushort(x)
1051 break;
1052 }
1053 }
1054 if (x == ushort(x)) {
1055 port = ushort(x);
1056 } else {
1057 setError(InvalidPortError, auth, colonIndex + 1);
1058 if (mode == QUrl::StrictMode)
1059 break;
1060 }
1061 }
1062
1063 setHost(auth, from, qMin<size_t>(end, colonIndex), mode);
1064 if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<size_t>(end, colonIndex))) {
1065 // clear host too
1066 sectionIsPresent &= ~Authority;
1067 break;
1068 }
1069
1070 // success
1071 return;
1072 }
1073 // clear all sections but host
1074 sectionIsPresent &= ~Authority | Host;
1075 userName.clear();
1076 password.clear();
1077 host.clear();
1078 port = -1;
1079}
1080
1081inline void QUrlPrivate::setUserInfo(const QString &userInfo, qsizetype from, qsizetype end)
1082{
1083 qsizetype delimIndex = userInfo.indexOf(u':', from);
1084 setUserName(userInfo, from, qMin<size_t>(delimIndex, end));
1085
1086 if (size_t(delimIndex) >= size_t(end)) {
1087 password.clear();
1088 sectionIsPresent &= ~Password;
1089 } else {
1090 setPassword(userInfo, delimIndex + 1, end);
1091 }
1092}
1093
1095{
1098}
1099
1101{
1104}
1105
1107{
1108 // sectionIsPresent |= Path; // not used, save some cycles
1110}
1111
1113{
1116}
1117
1119{
1122}
1123
1124// Host handling
1125// The RFC says the host is:
1126// host = IP-literal / IPv4address / reg-name
1127// IP-literal = "[" ( IPv6address / IPvFuture ) "]"
1128// IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1129// [a strict definition of IPv6Address and IPv4Address]
1130// reg-name = *( unreserved / pct-encoded / sub-delims )
1131//
1132// We deviate from the standard in all but IPvFuture. For IPvFuture we accept
1133// and store only exactly what the RFC says we should. No percent-encoding is
1134// permitted in this field, so Unicode characters and space aren't either.
1135//
1136// For IPv4 addresses, we accept broken addresses like inet_aton does (that is,
1137// less than three dots). However, we correct the address to the proper form
1138// and store the corrected address. After correction, we comply to the RFC and
1139// it's exclusively composed of unreserved characters.
1140//
1141// For IPv6 addresses, we accept addresses including trailing (embedded) IPv4
1142// addresses, the so-called v4-compat and v4-mapped addresses. We also store
1143// those addresses like that in the hostname field, which violates the spec.
1144// IPv6 hosts are stored with the square brackets in the QString. It also
1145// requires no transformation in any way.
1146//
1147// As for registered names, it's the other way around: we accept only valid
1148// hostnames as specified by STD 3 and IDNA. That means everything we accept is
1149// valid in the RFC definition above, but there are many valid reg-names
1150// according to the RFC that we do not accept in the name of security. Since we
1151// do accept IDNA, reg-names are subject to ACE encoding and decoding, which is
1152// specified by the DecodeUnicode flag. The hostname is stored in its Unicode form.
1153
1154inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions options) const
1155{
1156 if (host.isEmpty())
1157 return;
1158 if (host.at(0).unicode() == '[') {
1159 // IPv6 addresses might contain a zone-id which needs to be recoded
1160 if (options != 0)
1161 if (qt_urlRecode(appendTo, host, options, nullptr))
1162 return;
1163 appendTo += host;
1164 } else {
1165 // this is either an IPv4Address or a reg-name
1166 // if it is a reg-name, it is already stored in Unicode form
1167 if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1168 appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot, {});
1169 else
1170 appendTo += host;
1171 }
1172}
1173
1174// the whole IPvFuture is passed and parsed here, including brackets;
1175// returns null if the parsing was successful, or the QChar of the first failure
1176static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
1177{
1178 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1179 static const char acceptable[] =
1180 "!$&'()*+,;=" // sub-delims
1181 ":" // ":"
1182 "-._~"; // unreserved
1183
1184 // the brackets and the "v" have been checked
1185 const QChar *const origBegin = begin;
1186 if (begin[3].unicode() != '.')
1187 return &begin[3];
1188 if (isHexDigit(begin[2].unicode())) {
1189 // this is so unlikely that we'll just go down the slow path
1190 // decode the whole string, skipping the "[vH." and "]" which we already know to be there
1191 host += QStringView(begin, 4);
1192
1193 // uppercase the version, if necessary
1194 if (begin[2].unicode() >= 'a')
1195 host[host.size() - 2] = QChar{begin[2].unicode() - 0x20};
1196
1197 begin += 4;
1198 --end;
1199
1200 QString decoded;
1202 begin = decoded.constBegin();
1203 end = decoded.constEnd();
1204 }
1205
1206 for ( ; begin != end; ++begin) {
1207 if (isAsciiLetterOrNumber(begin->unicode()))
1208 host += *begin;
1209 else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) != nullptr)
1210 host += *begin;
1211 else
1212 return decoded.isEmpty() ? begin : &origBegin[2];
1213 }
1214 host += u']';
1215 return nullptr;
1216 }
1217 return &origBegin[2];
1218}
1219
1220// ONLY the IPv6 address is parsed here, WITHOUT the brackets
1221static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
1222{
1223 QStringView decoded(begin, end);
1224 QString decodedBuffer;
1225 if (mode == QUrl::TolerantMode) {
1226 // this struct is kept in automatic storage because it's only 4 bytes
1227 const ushort decodeColon[] = { decode(':'), 0 };
1228 if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1229 decoded = decodedBuffer;
1230 }
1231
1232 const QStringView zoneIdIdentifier(u"%25");
1234 QStringView zoneId;
1235
1236 qsizetype zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1237 if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1238 zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1239 decoded.truncate(zoneIdPosition);
1240
1241 // was there anything after the zone ID separator?
1242 if (zoneId.isEmpty())
1243 return end;
1244 }
1245
1246 // did the address become empty after removing the zone ID?
1247 // (it might have always been empty)
1248 if (decoded.isEmpty())
1249 return end;
1250
1251 const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1252 if (ret)
1253 return begin + (ret - decoded.constBegin());
1254
1255 host.reserve(host.size() + (end - begin) + 2); // +2 for the brackets
1256 host += u'[';
1258
1259 if (!zoneId.isEmpty()) {
1260 host += zoneIdIdentifier;
1261 host += zoneId;
1262 }
1263 host += u']';
1264 return nullptr;
1265}
1266
1267inline bool
1269{
1270 const QChar *begin = value.constData() + from;
1271 const QChar *end = value.constData() + iend;
1272
1273 const qsizetype len = end - begin;
1274 host.clear();
1276 if (len == 0)
1277 return true;
1278
1279 if (begin[0].unicode() == '[') {
1280 // IPv6Address or IPvFuture
1281 // smallest IPv6 address is "[::]" (len = 4)
1282 // smallest IPvFuture address is "[v7.X]" (len = 6)
1283 if (end[-1].unicode() != ']') {
1285 return false;
1286 }
1287
1288 if (len > 5 && begin[1].unicode() == 'v') {
1289 const QChar *c = parseIpFuture(host, begin, end, mode);
1290 if (c)
1291 setError(InvalidIPvFutureError, value, c - value.constData());
1292 return !c;
1293 } else if (begin[1].unicode() == 'v') {
1295 }
1296
1297 const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1298 if (!c)
1299 return true;
1300
1301 if (c == end - 1)
1303 else
1305 return false;
1306 }
1307
1308 // check if it's an IPv4 address
1310 if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1311 // yes, it was
1313 return true;
1314 }
1315
1316 // This is probably a reg-name.
1317 // But it can also be an encoded string that, when decoded becomes one
1318 // of the types above.
1319 //
1320 // Two types of encoding are possible:
1321 // percent encoding (e.g., "%31%30%2E%30%2E%30%2E%31" -> "10.0.0.1")
1322 // Unicode encoding (some non-ASCII characters case-fold to digits
1323 // when nameprepping is done)
1324 //
1325 // The qt_ACE_do function below does IDNA normalization and the STD3 check.
1326 // That means a Unicode string may become an IPv4 address, but it cannot
1327 // produce a '[' or a '%'.
1328
1329 // check for percent-encoding first
1330 QString s;
1331 if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { }, nullptr)) {
1332 // something was decoded
1333 // anything encoded left?
1334 qsizetype pos = s.indexOf(QChar(0x25)); // '%'
1335 if (pos != -1) {
1337 return false;
1338 }
1339
1340 // recurse
1341 return setHost(s, 0, s.size(), QUrl::StrictMode);
1342 }
1343
1344 s = qt_ACE_do(value.mid(from, iend - from), NormalizeAce, ForbidLeadingDot, {});
1345 if (s.isEmpty()) {
1347 return false;
1348 }
1349
1350 // check IPv4 again
1351 if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1353 } else {
1354 host = s;
1355 }
1356 return true;
1357}
1358
1359inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode)
1360{
1361 // URI-reference = URI / relative-ref
1362 // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
1363 // relative-ref = relative-part [ "?" query ] [ "#" fragment ]
1364 // hier-part = "//" authority path-abempty
1365 // / other path types
1366 // relative-part = "//" authority path-abempty
1367 // / other path types here
1368
1369 sectionIsPresent = 0;
1370 flags = 0;
1371 clearError();
1372
1373 // find the important delimiters
1374 qsizetype colon = -1;
1375 qsizetype question = -1;
1376 qsizetype hash = -1;
1377 const qsizetype len = url.size();
1378 const QChar *const begin = url.constData();
1379 const ushort *const data = reinterpret_cast<const ushort *>(begin);
1380
1381 for (qsizetype i = 0; i < len; ++i) {
1382 size_t uc = data[i];
1383 if (uc == '#' && hash == -1) {
1384 hash = i;
1385
1386 // nothing more to be found
1387 break;
1388 }
1389
1390 if (question == -1) {
1391 if (uc == ':' && colon == -1)
1392 colon = i;
1393 else if (uc == '?')
1394 question = i;
1395 }
1396 }
1397
1398 // check if we have a scheme
1399 qsizetype hierStart;
1400 if (colon != -1 && setScheme(url, colon, /* don't set error */ false)) {
1401 hierStart = colon + 1;
1402 } else {
1403 // recover from a failed scheme: it might not have been a scheme at all
1404 scheme.clear();
1405 sectionIsPresent = 0;
1406 hierStart = 0;
1407 }
1408
1409 qsizetype pathStart;
1410 qsizetype hierEnd = qMin<size_t>(qMin<size_t>(question, hash), len);
1411 if (hierEnd - hierStart >= 2 && data[hierStart] == '/' && data[hierStart + 1] == '/') {
1412 // we have an authority, it ends at the first slash after these
1413 qsizetype authorityEnd = hierEnd;
1414 for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) {
1415 if (data[i] == '/') {
1416 authorityEnd = i;
1417 break;
1418 }
1419 }
1420
1421 setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1422
1423 // even if we failed to set the authority properly, let's try to recover
1424 pathStart = authorityEnd;
1425 setPath(url, pathStart, hierEnd);
1426 } else {
1427 userName.clear();
1428 password.clear();
1429 host.clear();
1430 port = -1;
1431 pathStart = hierStart;
1432
1433 if (hierStart < hierEnd)
1434 setPath(url, hierStart, hierEnd);
1435 else
1436 path.clear();
1437 }
1438
1439 if (size_t(question) < size_t(hash))
1440 setQuery(url, question + 1, qMin<size_t>(hash, len));
1441
1442 if (hash != -1)
1443 setFragment(url, hash + 1, len);
1444
1445 if (error || parsingMode == QUrl::TolerantMode)
1446 return;
1447
1448 // The parsing so far was partially tolerant of errors, except for the
1449 // scheme parser (which is always strict) and the authority (which was
1450 // executed in strict mode).
1451 // If we haven't found any errors so far, continue the strict-mode parsing
1452 // from the path component onwards.
1453
1454 if (!validateComponent(Path, url, pathStart, hierEnd))
1455 return;
1456 if (size_t(question) < size_t(hash) && !validateComponent(Query, url, question + 1, qMin<size_t>(hash, len)))
1457 return;
1458 if (hash != -1)
1460}
1461
1463{
1464 QString tmp;
1465 QString ourPath;
1466 appendPath(ourPath, options, QUrlPrivate::Path);
1467
1468 // magic for shared drive on windows
1469 if (!host.isEmpty()) {
1470 tmp = "//"_L1 + host;
1471#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only.
1472 if (scheme == webDavScheme())
1473 tmp += webDavSslTag();
1474#endif
1475 if (!ourPath.isEmpty() && !ourPath.startsWith(u'/'))
1476 tmp += u'/';
1477 tmp += ourPath;
1478 } else {
1479 tmp = ourPath;
1480#ifdef Q_OS_WIN
1481 // magic for drives on windows
1482 if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':')
1483 tmp.remove(0, 1);
1484#endif
1485 }
1486 return tmp;
1487}
1488
1489/*
1490 From http://www.ietf.org/rfc/rfc3986.txt, 5.2.3: Merge paths
1491
1492 Returns a merge of the current path with the relative path passed
1493 as argument.
1494
1495 Note: \a relativePath is relative (does not start with '/').
1496*/
1497inline QString QUrlPrivate::mergePaths(const QString &relativePath) const
1498{
1499 // If the base URI has a defined authority component and an empty
1500 // path, then return a string consisting of "/" concatenated with
1501 // the reference's path; otherwise,
1502 if (!host.isEmpty() && path.isEmpty())
1503 return u'/' + relativePath;
1504
1505 // Return a string consisting of the reference's path component
1506 // appended to all but the last segment of the base URI's path
1507 // (i.e., excluding any characters after the right-most "/" in the
1508 // base URI path, or excluding the entire base URI path if it does
1509 // not contain any "/" characters).
1510 QString newPath;
1511 if (!path.contains(u'/'))
1512 newPath = relativePath;
1513 else
1514 newPath = QStringView{path}.left(path.lastIndexOf(u'/') + 1) + relativePath;
1515
1516 return newPath;
1517}
1518
1519/*
1520 From http://www.ietf.org/rfc/rfc3986.txt, 5.2.4: Remove dot segments
1521
1522 Removes unnecessary ../ and ./ from the path. Used for normalizing
1523 the URL.
1524*/
1526{
1527 // The input buffer is initialized with the now-appended path
1528 // components and the output buffer is initialized to the empty
1529 // string.
1530 QChar *out = path->data();
1531 const QChar *in = out;
1532 const QChar *end = out + path->size();
1533
1534 // If the input buffer consists only of
1535 // "." or "..", then remove that from the input
1536 // buffer;
1537 if (path->size() == 1 && in[0].unicode() == '.')
1538 ++in;
1539 else if (path->size() == 2 && in[0].unicode() == '.' && in[1].unicode() == '.')
1540 in += 2;
1541 // While the input buffer is not empty, loop:
1542 while (in < end) {
1543
1544 // otherwise, if the input buffer begins with a prefix of "../" or "./",
1545 // then remove that prefix from the input buffer;
1546 if (path->size() >= 2 && in[0].unicode() == '.' && in[1].unicode() == '/')
1547 in += 2;
1548 else if (path->size() >= 3 && in[0].unicode() == '.'
1549 && in[1].unicode() == '.' && in[2].unicode() == '/')
1550 in += 3;
1551
1552 // otherwise, if the input buffer begins with a prefix of
1553 // "/./" or "/.", where "." is a complete path segment,
1554 // then replace that prefix with "/" in the input buffer;
1555 if (in <= end - 3 && in[0].unicode() == '/' && in[1].unicode() == '.'
1556 && in[2].unicode() == '/') {
1557 in += 2;
1558 continue;
1559 } else if (in == end - 2 && in[0].unicode() == '/' && in[1].unicode() == '.') {
1560 *out++ = u'/';
1561 in += 2;
1562 break;
1563 }
1564
1565 // otherwise, if the input buffer begins with a prefix
1566 // of "/../" or "/..", where ".." is a complete path
1567 // segment, then replace that prefix with "/" in the
1568 // input buffer and remove the last //segment and its
1569 // preceding "/" (if any) from the output buffer;
1570 if (in <= end - 4 && in[0].unicode() == '/' && in[1].unicode() == '.'
1571 && in[2].unicode() == '.' && in[3].unicode() == '/') {
1572 while (out > path->constData() && (--out)->unicode() != '/')
1573 ;
1574 if (out == path->constData() && out->unicode() != '/')
1575 ++in;
1576 in += 3;
1577 continue;
1578 } else if (in == end - 3 && in[0].unicode() == '/' && in[1].unicode() == '.'
1579 && in[2].unicode() == '.') {
1580 while (out > path->constData() && (--out)->unicode() != '/')
1581 ;
1582 if (out->unicode() == '/')
1583 ++out;
1584 in += 3;
1585 break;
1586 }
1587
1588 // otherwise move the first path segment in
1589 // the input buffer to the end of the output
1590 // buffer, including the initial "/" character
1591 // (if any) and any subsequent characters up
1592 // to, but not including, the next "/"
1593 // character or the end of the input buffer.
1594 *out++ = *in++;
1595 while (in < end && in->unicode() != '/')
1596 *out++ = *in++;
1597 }
1598 path->truncate(out - path->constData());
1599}
1600
1602{
1603 Q_ASSERT(!source == !position);
1604 if (error) {
1605 if (source) {
1606 *source = error->source;
1607 *position = error->position;
1608 }
1609 return error->code;
1610 }
1611
1612 // There are three more cases of invalid URLs that QUrl recognizes and they
1613 // are only possible with constructed URLs (setXXX methods), not with
1614 // parsing. Therefore, they are tested here.
1615 //
1616 // Two cases are a non-empty path that doesn't start with a slash and:
1617 // - with an authority
1618 // - without an authority, without scheme but the path with a colon before
1619 // the first slash
1620 // The third case is an empty authority and a non-empty path that starts
1621 // with "//".
1622 // Those cases are considered invalid because toString() would produce a URL
1623 // that wouldn't be parsed back to the same QUrl.
1624
1625 if (path.isEmpty())
1626 return NoError;
1627 if (path.at(0) == u'/') {
1628 if (hasAuthority() || path.size() == 1 || path.at(1) != u'/')
1629 return NoError;
1630 if (source) {
1631 *source = path;
1632 *position = 0;
1633 }
1635 }
1636
1638 if (source) {
1639 *source = path;
1640 *position = 0;
1641 }
1643 }
1645 return NoError;
1646
1647 // check for a path of "text:text/"
1648 for (qsizetype i = 0; i < path.size(); ++i) {
1649 ushort c = path.at(i).unicode();
1650 if (c == '/') {
1651 // found the slash before the colon
1652 return NoError;
1653 }
1654 if (c == ':') {
1655 // found the colon before the slash, it's invalid
1656 if (source) {
1657 *source = path;
1658 *position = i;
1659 }
1661 }
1662 }
1663 return NoError;
1664}
1665
1668{
1669 // What we need to look out for, that the regular parser tolerates:
1670 // - percent signs not followed by two hex digits
1671 // - forbidden characters, which should always appear encoded
1672 // '"' / '<' / '>' / '\' / '^' / '`' / '{' / '|' / '}' / BKSP
1673 // control characters
1674 // - delimiters not allowed in certain positions
1675 // . scheme: parser is already strict
1676 // . user info: gen-delims except ":" disallowed ("/" / "?" / "#" / "[" / "]" / "@")
1677 // . host: parser is stricter than the standard
1678 // . port: parser is stricter than the standard
1679 // . path: all delimiters allowed
1680 // . fragment: all delimiters allowed
1681 // . query: all delimiters allowed
1682 static const char forbidden[] = "\"<>\\^`{|}\x7F";
1683 static const char forbiddenUserInfo[] = ":/?#[]@";
1684
1685 Q_ASSERT(section != Authority && section != Hierarchy && section != FullUrl);
1686
1687 const ushort *const data = reinterpret_cast<const ushort *>(input.constData());
1688 for (size_t i = size_t(begin); i < size_t(end); ++i) {
1689 uint uc = data[i];
1690 if (uc >= 0x80)
1691 continue;
1692
1693 bool error = false;
1694 if ((uc == '%' && (size_t(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1695 || uc <= 0x20 || strchr(forbidden, uc)) {
1696 // found an error
1697 error = true;
1698 } else if (section & UserInfo) {
1699 if (section == UserInfo && strchr(forbiddenUserInfo + 1, uc))
1700 error = true;
1701 else if (section != UserInfo && strchr(forbiddenUserInfo, uc))
1702 error = true;
1703 }
1704
1705 if (!error)
1706 continue;
1707
1708 ErrorCode errorCode = ErrorCode(int(section) << 8);
1709 if (section == UserInfo) {
1710 // is it the user name or the password?
1711 errorCode = InvalidUserNameError;
1712 for (size_t j = size_t(begin); j < i; ++j)
1713 if (data[j] == ':') {
1714 errorCode = InvalidPasswordError;
1715 break;
1716 }
1717 }
1718
1719 setError(errorCode, input, i);
1720 return false;
1721 }
1722
1723 // no errors
1724 return true;
1725}
1726
1727#if 0
1728inline void QUrlPrivate::validate() const
1729{
1730 QUrlPrivate *that = (QUrlPrivate *)this;
1731 that->encodedOriginal = that->toEncoded(); // may detach
1732 parse(ParseOnly);
1733
1734 QURL_SETFLAG(that->stateFlags, Validated);
1735
1736 if (!isValid)
1737 return;
1738
1739 QString auth = authority(); // causes the non-encoded forms to be valid
1740
1741 // authority() calls canonicalHost() which sets this
1742 if (!isHostValid)
1743 return;
1744
1745 if (scheme == "mailto"_L1) {
1746 if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1747 that->isValid = false;
1748 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "expected empty host, username,"
1749 "port and password"),
1750 0, 0);
1751 }
1752 } else if (scheme == ftpScheme() || scheme == httpScheme()) {
1753 if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1754 that->isValid = false;
1755 that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "the host is empty, but not the path"),
1756 0, 0);
1757 }
1758 }
1759}
1760#endif
1761
1836{
1837 setUrl(url, parsingMode);
1838}
1839
1844{
1845}
1846
1850QUrl::QUrl(const QUrl &other) noexcept : d(other.d)
1851{
1852 if (d)
1853 d->ref.ref();
1854}
1855
1860{
1861 if (d && !d->ref.deref())
1862 delete d;
1863}
1864
1874bool QUrl::isValid() const
1875{
1876 if (isEmpty()) {
1877 // also catches d == nullptr
1878 return false;
1879 }
1880 return d->validityError() == QUrlPrivate::NoError;
1881}
1882
1888bool QUrl::isEmpty() const
1889{
1890 if (!d) return true;
1891 return d->isEmpty();
1892}
1893
1902{
1903 if (d && !d->ref.deref())
1904 delete d;
1905 d = nullptr;
1906}
1907
1926void QUrl::setUrl(const QString &url, ParsingMode parsingMode)
1927{
1928 if (parsingMode == DecodedMode) {
1929 qWarning("QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1930 } else {
1931 detach();
1932 d->parse(url, parsingMode);
1933 }
1934}
1935
1959void QUrl::setScheme(const QString &scheme)
1960{
1961 detach();
1962 d->clearError();
1963 if (scheme.isEmpty()) {
1964 // schemes are not allowed to be empty
1965 d->sectionIsPresent &= ~QUrlPrivate::Scheme;
1966 d->flags &= ~QUrlPrivate::IsLocalFile;
1967 d->scheme.clear();
1968 } else {
1969 d->setScheme(scheme, scheme.size(), /* do set error */ true);
1970 }
1971}
1972
1984{
1985 if (!d) return QString();
1986
1987 return d->scheme;
1988}
1989
2020{
2021 detach();
2022 d->clearError();
2023
2024 if (mode == DecodedMode) {
2025 qWarning("QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2026 return;
2027 }
2028
2030 if (authority.isNull()) {
2031 // QUrlPrivate::setAuthority cleared almost everything
2032 // but it leaves the Host bit set
2033 d->sectionIsPresent &= ~QUrlPrivate::Authority;
2034 }
2035}
2036
2052QString QUrl::authority(ComponentFormattingOptions options) const
2053{
2055 if (!d)
2056 return result;
2057
2058 if (options == QUrl::FullyDecoded) {
2059 qWarning("QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2060 return result;
2061 }
2062
2064 return result;
2065}
2066
2091{
2092 detach();
2093 d->clearError();
2094 QString trimmed = userInfo.trimmed();
2095 if (mode == DecodedMode) {
2096 qWarning("QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2097 return;
2098 }
2099
2100 d->setUserInfo(trimmed, 0, trimmed.size());
2101 if (userInfo.isNull()) {
2102 // QUrlPrivate::setUserInfo cleared almost everything
2103 // but it leaves the UserName bit set
2104 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2106 d->sectionIsPresent &= ~QUrlPrivate::UserInfo;
2107 d->userName.clear();
2108 d->password.clear();
2109 }
2110}
2111
2126QString QUrl::userInfo(ComponentFormattingOptions options) const
2127{
2129 if (!d)
2130 return result;
2131
2132 if (options == QUrl::FullyDecoded) {
2133 qWarning("QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2134 return result;
2135 }
2136
2138 return result;
2139}
2140
2162{
2163 detach();
2164 d->clearError();
2165
2167 if (mode == DecodedMode) {
2170 }
2171
2172 d->setUserName(data, 0, data.size());
2173 if (userName.isNull())
2174 d->sectionIsPresent &= ~QUrlPrivate::UserName;
2176 d->userName.clear();
2177}
2178
2196QString QUrl::userName(ComponentFormattingOptions options) const
2197{
2199 if (d)
2200 d->appendUserName(result, options);
2201 return result;
2202}
2203
2225{
2226 detach();
2227 d->clearError();
2228
2230 if (mode == DecodedMode) {
2233 }
2234
2235 d->setPassword(data, 0, data.size());
2236 if (password.isNull())
2237 d->sectionIsPresent &= ~QUrlPrivate::Password;
2239 d->password.clear();
2240}
2241
2259QString QUrl::password(ComponentFormattingOptions options) const
2260{
2262 if (d)
2263 d->appendPassword(result, options);
2264 return result;
2265}
2266
2287{
2288 detach();
2289 d->clearError();
2290
2291 QString data = host;
2292 if (mode == DecodedMode) {
2295 }
2296
2297 if (d->setHost(data, 0, data.size(), mode)) {
2298 if (host.isNull())
2299 d->sectionIsPresent &= ~QUrlPrivate::Host;
2300 } else if (!data.startsWith(u'[')) {
2301 // setHost failed, it might be IPv6 or IPvFuture in need of bracketing
2302 Q_ASSERT(d->error);
2303
2304 data.prepend(u'[');
2305 data.append(u']');
2306 if (!d->setHost(data, 0, data.size(), mode)) {
2307 // failed again
2308 if (data.contains(u':')) {
2309 // source data contains ':', so it's an IPv6 error
2311 }
2312 } else {
2313 // succeeded
2314 d->clearError();
2315 }
2316 }
2317}
2318
2337QString QUrl::host(ComponentFormattingOptions options) const
2338{
2340 if (d) {
2341 d->appendHost(result, options);
2342 if (result.startsWith(u'['))
2343 result = result.mid(1, result.size() - 2);
2344 }
2345 return result;
2346}
2347
2356{
2357 detach();
2358 d->clearError();
2359
2360 if (port < -1 || port > 65535) {
2362 port = -1;
2363 }
2364
2365 d->port = port;
2366 if (port != -1)
2368}
2369
2380int QUrl::port(int defaultPort) const
2381{
2382 if (!d) return defaultPort;
2383 return d->port == -1 ? defaultPort : d->port;
2384}
2385
2412{
2413 detach();
2414 d->clearError();
2415
2416 QString data = path;
2417 if (mode == DecodedMode) {
2420 }
2421
2422 d->setPath(data, 0, data.size());
2423
2424 // optimized out, since there is no path delimiter
2425// if (path.isNull())
2426// d->sectionIsPresent &= ~QUrlPrivate::Path;
2427// else
2429 d->path.clear();
2430}
2431
2465QString QUrl::path(ComponentFormattingOptions options) const
2466{
2468 if (d)
2469 d->appendPath(result, options, QUrlPrivate::Path);
2470 return result;
2471}
2472
2494QString QUrl::fileName(ComponentFormattingOptions options) const
2495{
2496 const QString ourPath = path(options);
2497 const qsizetype slash = ourPath.lastIndexOf(u'/');
2498 if (slash == -1)
2499 return ourPath;
2500 return ourPath.mid(slash + 1);
2501}
2502
2510bool QUrl::hasQuery() const
2511{
2512 if (!d) return false;
2513 return d->hasQuery();
2514}
2515
2548{
2549 detach();
2550 d->clearError();
2551
2552 QString data = query;
2553 if (mode == DecodedMode) {
2556 }
2557
2558 d->setQuery(data, 0, data.size());
2559 if (query.isNull())
2560 d->sectionIsPresent &= ~QUrlPrivate::Query;
2562 d->query.clear();
2563}
2564
2577{
2578 detach();
2579 d->clearError();
2580
2581 // we know the data is in the right format
2582 d->query = query.toString();
2583 if (query.isEmpty())
2584 d->sectionIsPresent &= ~QUrlPrivate::Query;
2585 else
2587}
2588
2606QString QUrl::query(ComponentFormattingOptions options) const
2607{
2609 if (d) {
2611 if (d->hasQuery() && result.isNull())
2612 result.detach();
2613 }
2614 return result;
2615}
2616
2646{
2647 detach();
2648 d->clearError();
2649
2651 if (mode == DecodedMode) {
2654 }
2655
2656 d->setFragment(data, 0, data.size());
2657 if (fragment.isNull())
2658 d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2660 d->fragment.clear();
2661}
2662
2679QString QUrl::fragment(ComponentFormattingOptions options) const
2680{
2682 if (d) {
2684 if (d->hasFragment() && result.isNull())
2685 result.detach();
2686 }
2687 return result;
2688}
2689
2698{
2699 if (!d) return false;
2700 return d->hasFragment();
2701}
2702
2722QUrl QUrl::resolved(const QUrl &relative) const
2723{
2724 if (!d) return relative;
2725 if (!relative.d) return *this;
2726
2727 QUrl t;
2728 if (!relative.d->scheme.isEmpty()) {
2729 t = relative;
2730 t.detach();
2731 } else {
2732 if (relative.d->hasAuthority()) {
2733 t = relative;
2734 t.detach();
2735 } else {
2736 t.d = new QUrlPrivate;
2737
2738 // copy the authority
2739 t.d->userName = d->userName;
2740 t.d->password = d->password;
2741 t.d->host = d->host;
2742 t.d->port = d->port;
2743 t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2744
2745 if (relative.d->path.isEmpty()) {
2746 t.d->path = d->path;
2747 if (relative.d->hasQuery()) {
2748 t.d->query = relative.d->query;
2749 t.d->sectionIsPresent |= QUrlPrivate::Query;
2750 } else if (d->hasQuery()) {
2751 t.d->query = d->query;
2752 t.d->sectionIsPresent |= QUrlPrivate::Query;
2753 }
2754 } else {
2755 t.d->path = relative.d->path.startsWith(u'/')
2756 ? relative.d->path
2757 : d->mergePaths(relative.d->path);
2758 if (relative.d->hasQuery()) {
2759 t.d->query = relative.d->query;
2760 t.d->sectionIsPresent |= QUrlPrivate::Query;
2761 }
2762 }
2763 }
2764 t.d->scheme = d->scheme;
2765 if (d->hasScheme())
2766 t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2767 else
2768 t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2770 }
2771 t.d->fragment = relative.d->fragment;
2772 if (relative.d->hasFragment())
2773 t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2774 else
2775 t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2776
2777 removeDotsFromPath(&t.d->path);
2778
2779#if defined(QURL_DEBUG)
2780 qDebug("QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2782 qUtf16Printable(relative.url()),
2783 qUtf16Printable(t.url()));
2784#endif
2785 return t;
2786}
2787
2798{
2799 if (!d) return true;
2800 return !d->hasScheme();
2801}
2802
2815{
2816 return toString(options);
2817}
2818
2829{
2830 QString url;
2831 if (!isValid()) {
2832 // also catches isEmpty()
2833 return url;
2834 }
2835 if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2836 qWarning("QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2837 options &= ~QUrl::FullyDecoded;
2838 //options |= QUrl::PrettyDecoded; // no-op, value is 0
2839 }
2840
2841 // return just the path if:
2842 // - QUrl::PreferLocalFile is passed
2843 // - QUrl::RemovePath isn't passed (rather stupid if the user did...)
2844 // - there's no query or fragment to return
2845 // that is, either they aren't present, or we're removing them
2846 // - it's a local file
2848 && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2849 && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2850 && isLocalFile()) {
2851 url = d->toLocalFile(options | QUrl::FullyDecoded);
2852 return url;
2853 }
2854
2855 // for the full URL, we consider that the reserved characters are prettier if encoded
2856 if (options & DecodeReserved)
2857 options &= ~EncodeReserved;
2858 else
2859 options |= EncodeReserved;
2860
2861 if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2862 url += d->scheme + u':';
2863
2864 bool pathIsAbsolute = d->path.startsWith(u'/');
2865 if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2866 url += "//"_L1;
2868 } else if (isLocalFile() && pathIsAbsolute) {
2869 // Comply with the XDG file URI spec, which requires triple slashes.
2870 url += "//"_L1;
2871 }
2872
2873 if (!(options & QUrl::RemovePath))
2874 d->appendPath(url, options, QUrlPrivate::FullUrl);
2875
2876 if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2877 url += u'?';
2878 d->appendQuery(url, options, QUrlPrivate::FullUrl);
2879 }
2880 if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2881 url += u'#';
2883 }
2884
2885 return url;
2886}
2887
2904{
2905 return toString(options | RemovePassword);
2906}
2907
2922{
2923 if (!isValid()) {
2924 // also catches isEmpty()
2925 return QUrl();
2926 }
2927 QUrl that = *this;
2928 if (options & RemoveScheme)
2929 that.setScheme(QString());
2930 if ((options & RemoveAuthority) == RemoveAuthority) {
2931 that.setAuthority(QString());
2932 } else {
2933 if ((options & RemoveUserInfo) == RemoveUserInfo)
2934 that.setUserInfo(QString());
2935 else if (options & RemovePassword)
2936 that.setPassword(QString());
2937 if (options & RemovePort)
2938 that.setPort(-1);
2939 }
2940 if (options & RemoveQuery)
2941 that.setQuery(QString());
2942 if (options & RemoveFragment)
2943 that.setFragment(QString());
2944 if (options & RemovePath) {
2945 that.setPath(QString());
2946 } else if (options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2947 that.detach();
2948 QString path;
2950 that.d->setPath(path, 0, path.size());
2951 }
2952 return that;
2953}
2954
2965{
2966 options &= ~(FullyDecoded | FullyEncoded);
2967 return toString(options | FullyEncoded).toLatin1();
2968}
2969
2986{
2987 return QUrl(QString::fromUtf8(input), mode);
2988}
2989
2999{
3001 return QString::fromUtf8(ba, ba.size());
3002}
3003
3017{
3018 return input.toUtf8().toPercentEncoding(exclude, include);
3019}
3020
3038QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions options)
3039{
3041 ForbidLeadingDot /*FIXME: make configurable*/, options);
3042}
3043
3061QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
3062{
3063 return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/, options)
3064 .toLatin1();
3065}
3066
3073bool QUrl::operator <(const QUrl &url) const
3074{
3075 if (!d || !url.d) {
3076 bool thisIsEmpty = !d || d->isEmpty();
3077 bool thatIsEmpty = !url.d || url.d->isEmpty();
3078
3079 // sort an empty URL first
3080 return thisIsEmpty && !thatIsEmpty;
3081 }
3082
3083 int cmp;
3084 cmp = d->scheme.compare(url.d->scheme);
3085 if (cmp != 0)
3086 return cmp < 0;
3087
3088 cmp = d->userName.compare(url.d->userName);
3089 if (cmp != 0)
3090 return cmp < 0;
3091
3092 cmp = d->password.compare(url.d->password);
3093 if (cmp != 0)
3094 return cmp < 0;
3095
3096 cmp = d->host.compare(url.d->host);
3097 if (cmp != 0)
3098 return cmp < 0;
3099
3100 if (d->port != url.d->port)
3101 return d->port < url.d->port;
3102
3103 cmp = d->path.compare(url.d->path);
3104 if (cmp != 0)
3105 return cmp < 0;
3106
3107 if (d->hasQuery() != url.d->hasQuery())
3108 return url.d->hasQuery();
3109
3110 cmp = d->query.compare(url.d->query);
3111 if (cmp != 0)
3112 return cmp < 0;
3113
3114 if (d->hasFragment() != url.d->hasFragment())
3115 return url.d->hasFragment();
3116
3117 cmp = d->fragment.compare(url.d->fragment);
3118 return cmp < 0;
3119}
3120
3127bool QUrl::operator ==(const QUrl &url) const
3128{
3129 if (!d && !url.d)
3130 return true;
3131 if (!d)
3132 return url.d->isEmpty();
3133 if (!url.d)
3134 return d->isEmpty();
3135
3136 // First, compare which sections are present, since it speeds up the
3137 // processing considerably. We just have to ignore the host-is-present flag
3138 // for local files (the "file" protocol), due to the requirements of the
3139 // XDG file URI specification.
3141 if (isLocalFile())
3142 mask &= ~QUrlPrivate::Host;
3143 return (d->sectionIsPresent & mask) == (url.d->sectionIsPresent & mask) &&
3144 d->scheme == url.d->scheme &&
3145 d->userName == url.d->userName &&
3146 d->password == url.d->password &&
3147 d->host == url.d->host &&
3148 d->port == url.d->port &&
3149 d->path == url.d->path &&
3150 d->query == url.d->query &&
3151 d->fragment == url.d->fragment;
3152}
3153
3164bool QUrl::matches(const QUrl &url, FormattingOptions options) const
3165{
3166 if (!d && !url.d)
3167 return true;
3168 if (!d)
3169 return url.d->isEmpty();
3170 if (!url.d)
3171 return d->isEmpty();
3172
3173 // First, compare which sections are present, since it speeds up the
3174 // processing considerably. We just have to ignore the host-is-present flag
3175 // for local files (the "file" protocol), due to the requirements of the
3176 // XDG file URI specification.
3178 if (isLocalFile())
3179 mask &= ~QUrlPrivate::Host;
3180
3181 if (options.testFlag(QUrl::RemoveScheme))
3182 mask &= ~QUrlPrivate::Scheme;
3183 else if (d->scheme != url.d->scheme)
3184 return false;
3185
3186 if (options.testFlag(QUrl::RemovePassword))
3187 mask &= ~QUrlPrivate::Password;
3188 else if (d->password != url.d->password)
3189 return false;
3190
3191 if (options.testFlag(QUrl::RemoveUserInfo))
3192 mask &= ~QUrlPrivate::UserName;
3193 else if (d->userName != url.d->userName)
3194 return false;
3195
3196 if (options.testFlag(QUrl::RemovePort))
3197 mask &= ~QUrlPrivate::Port;
3198 else if (d->port != url.d->port)
3199 return false;
3200
3201 if (options.testFlag(QUrl::RemoveAuthority))
3202 mask &= ~QUrlPrivate::Host;
3203 else if (d->host != url.d->host)
3204 return false;
3205
3206 if (options.testFlag(QUrl::RemoveQuery))
3207 mask &= ~QUrlPrivate::Query;
3208 else if (d->query != url.d->query)
3209 return false;
3210
3211 if (options.testFlag(QUrl::RemoveFragment))
3212 mask &= ~QUrlPrivate::Fragment;
3213 else if (d->fragment != url.d->fragment)
3214 return false;
3215
3216 if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3217 return false;
3218
3219 if (options.testFlag(QUrl::RemovePath))
3220 return true;
3221
3222 // Compare paths, after applying path-related options
3223 QString path1;
3224 d->appendPath(path1, options, QUrlPrivate::Path);
3225 QString path2;
3226 url.d->appendPath(path2, options, QUrlPrivate::Path);
3227 return path1 == path2;
3228}
3229
3236bool QUrl::operator !=(const QUrl &url) const
3237{
3238 return !(*this == url);
3239}
3240
3245{
3246 if (!d) {
3247 if (url.d) {
3248 url.d->ref.ref();
3249 d = url.d;
3250 }
3251 } else {
3252 if (url.d)
3253 qAtomicAssign(d, url.d);
3254 else
3255 clear();
3256 }
3257 return *this;
3258}
3259
3264{
3265 if (url.isEmpty()) {
3266 clear();
3267 } else {
3268 detach();
3269 d->parse(url, TolerantMode);
3270 }
3271 return *this;
3272}
3273
3288{
3289 if (!d)
3290 d = new QUrlPrivate;
3291 else
3292 qAtomicDetach(d);
3293}
3294
3299{
3300 return !d || d->ref.loadRelaxed() == 1;
3301}
3302
3303static QString fromNativeSeparators(const QString &pathName)
3304{
3305#if defined(Q_OS_WIN)
3306 QString result(pathName);
3307 const QChar nativeSeparator = u'\\';
3308 auto i = result.indexOf(nativeSeparator);
3309 if (i != -1) {
3310 QChar * const data = result.data();
3311 const auto length = result.length();
3312 for (; i < length; ++i) {
3313 if (data[i] == nativeSeparator)
3314 data[i] = u'/';
3315 }
3316 }
3317 return result;
3318#else
3319 return pathName;
3320#endif
3321}
3322
3355{
3356 QUrl url;
3357 if (localFile.isEmpty())
3358 return url;
3360 QString deslashified = fromNativeSeparators(localFile);
3361
3362 // magic for drives on windows
3363 if (deslashified.size() > 1 && deslashified.at(1) == u':' && deslashified.at(0) != u'/') {
3364 deslashified.prepend(u'/');
3365 } else if (deslashified.startsWith("//"_L1)) {
3366 // magic for shared drive on windows
3367 qsizetype indexOfPath = deslashified.indexOf(u'/', 2);
3368 QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3369 // Check for Windows-specific WebDAV specification: "//host@SSL/path".
3370 if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3371 hostSpec.truncate(hostSpec.size() - 4);
3372 scheme = webDavScheme();
3373 }
3374
3375 // hosts can't be IPv6 addresses without [], so we can use QUrlPrivate::setHost
3376 url.detach();
3377 if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3379 return url;
3380
3381 // Path hostname is not a valid URL host, so set it entirely in the path
3382 // (by leaving deslashified unchanged)
3383 } else if (indexOfPath > 2) {
3384 deslashified = deslashified.right(deslashified.size() - indexOfPath);
3385 } else {
3386 deslashified.clear();
3387 }
3388 }
3389
3391 url.setPath(deslashified, DecodedMode);
3392 return url;
3393}
3394
3412{
3413 // the call to isLocalFile() also ensures that we're parsed
3414 if (!isLocalFile())
3415 return QString();
3416
3418}
3419
3432{
3433 return d && d->isLocalFile();
3434}
3435
3441bool QUrl::isParentOf(const QUrl &childUrl) const
3442{
3443 QString childPath = childUrl.path();
3444
3445 if (!d)
3446 return ((childUrl.scheme().isEmpty())
3447 && (childUrl.authority().isEmpty())
3448 && childPath.size() > 0 && childPath.at(0) == u'/');
3449
3450 QString ourPath = path();
3451
3452 return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3453 && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3454 && childPath.startsWith(ourPath)
3455 && ((ourPath.endsWith(u'/') && childPath.size() > ourPath.size())
3456 || (!ourPath.endsWith(u'/') && childPath.size() > ourPath.size()
3457 && childPath.at(ourPath.size()) == u'/')));
3458}
3459
3460
3461#ifndef QT_NO_DATASTREAM
3470{
3471 QByteArray u;
3472 if (url.isValid())
3473 u = url.toEncoded();
3474 out << u;
3475 return out;
3476}
3477
3486{
3487 QByteArray u;
3488 in >> u;
3490 return in;
3491}
3492#endif // QT_NO_DATASTREAM
3493
3494#ifndef QT_NO_DEBUG_STREAM
3496{
3497 QDebugStateSaver saver(d);
3498 d.nospace() << "QUrl(" << url.toDisplayString() << ')';
3499 return d;
3500}
3501#endif
3502
3503static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
3504{
3505 QChar c = size_t(errorPosition) < size_t(errorSource.size()) ?
3506 errorSource.at(errorPosition) : QChar(QChar::Null);
3507
3508 switch (errorCode) {
3510 Q_UNREACHABLE_RETURN(QString()); // QUrl::errorString should have treated this condition
3511
3513 auto msg = "Invalid scheme (character '%1' not permitted)"_L1;
3514 return msg.arg(c);
3515 }
3516
3518 return "Invalid user name (character '%1' not permitted)"_L1
3519 .arg(c);
3520
3522 return "Invalid password (character '%1' not permitted)"_L1
3523 .arg(c);
3524
3526 if (errorPosition >= 0)
3527 return "Invalid hostname (character '%1' not permitted)"_L1
3528 .arg(c);
3529 else
3530 return QStringLiteral("Invalid hostname (contains invalid characters)");
3532 return QString(); // doesn't happen yet
3534 return QStringLiteral("Invalid IPv6 address");
3536 return "Invalid IPv6 address (character '%1' not permitted)"_L1.arg(c);
3538 return "Invalid IPvFuture address (character '%1' not permitted)"_L1.arg(c);
3540 return QStringLiteral("Expected ']' to match '[' in hostname");
3541
3543 return QStringLiteral("Invalid port or port number out of range");
3545 return QStringLiteral("Port field was empty");
3546
3548 return "Invalid path (character '%1' not permitted)"_L1
3549 .arg(c);
3550
3552 return "Invalid query (character '%1' not permitted)"_L1
3553 .arg(c);
3554
3556 return "Invalid fragment (character '%1' not permitted)"_L1
3557 .arg(c);
3558
3560 return QStringLiteral("Path component is relative and authority is present");
3562 return QStringLiteral("Path component starts with '//' and authority is absent");
3564 return QStringLiteral("Relative URL's path component contains ':' before any '/'");
3565 }
3566
3567 Q_UNREACHABLE_RETURN(QString());
3568}
3569
3570static inline void appendComponentIfPresent(QString &msg, bool present, const char *componentName,
3571 const QString &component)
3572{
3573 if (present)
3574 msg += QLatin1StringView(componentName) % u'"' % component % "\","_L1;
3575}
3576
3591{
3592 QString msg;
3593 if (!d)
3594 return msg;
3595
3596 QString errorSource;
3597 qsizetype errorPosition = 0;
3598 QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3599 if (errorCode == QUrlPrivate::NoError)
3600 return msg;
3601
3602 msg += errorMessage(errorCode, errorSource, errorPosition);
3603 msg += "; source was \""_L1;
3604 msg += errorSource;
3605 msg += "\";"_L1;
3607 " scheme = ", d->scheme);
3609 " userinfo = ", userInfo());
3611 " host = ", d->host);
3612 appendComponentIfPresent(msg, d->port != -1,
3613 " port = ", QString::number(d->port));
3615 " path = ", d->path);
3617 " query = ", d->query);
3619 " fragment = ", d->fragment);
3620 if (msg.endsWith(u','))
3621 msg.chop(1);
3622 return msg;
3623}
3624
3631{
3632 QStringList lst;
3633 lst.reserve(urls.size());
3634 for (const QUrl &url : urls)
3635 lst.append(url.toString(options));
3636 return lst;
3637
3638}
3639
3647{
3648 QList<QUrl> lst;
3649 lst.reserve(urls.size());
3650 for (const QString &str : urls)
3651 lst.append(QUrl(str, mode));
3652 return lst;
3653}
3654
3672size_t qHash(const QUrl &url, size_t seed) noexcept
3673{
3674 if (!url.d)
3675 return qHash(-1, seed); // the hash of an unset port (-1)
3676
3677 return qHash(url.d->scheme) ^
3678 qHash(url.d->userName) ^
3679 qHash(url.d->password) ^
3680 qHash(url.d->host) ^
3681 qHash(url.d->port, seed) ^
3682 qHash(url.d->path) ^
3683 qHash(url.d->query) ^
3684 qHash(url.d->fragment);
3685}
3686
3688{
3689 if (url.scheme() == ftpScheme()) {
3691 if (path.startsWith("//"_L1))
3693 }
3694 return url;
3695}
3696
3697static bool isIp6(const QString &text)
3698{
3700 return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) == nullptr;
3701}
3702
3743QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirectory,
3744 UserInputResolutionOptions options)
3745{
3746 QString trimmedString = userInput.trimmed();
3747
3748 if (trimmedString.isEmpty())
3749 return QUrl();
3750
3751 // Check for IPv6 addresses, since a path starting with ":" is absolute (a resource)
3752 // and IPv6 addresses can start with "c:" too
3753 if (isIp6(trimmedString)) {
3754 QUrl url;
3755 url.setHost(trimmedString);
3756 url.setScheme(QStringLiteral("http"));
3757 return url;
3758 }
3759
3760 const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3761
3762 // Check for a relative path
3763 if (!workingDirectory.isEmpty()) {
3764 const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3765 if (fileInfo.exists())
3766 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3767
3768 // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes)
3769 if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3770 return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3771 }
3772
3773 // Check first for files, since on Windows drive letters can be interpreted as schemes
3774 if (QDir::isAbsolutePath(trimmedString))
3775 return QUrl::fromLocalFile(trimmedString);
3776
3777 QUrl urlPrepended = QUrl("http://"_L1 + trimmedString, QUrl::TolerantMode);
3778
3779 // Check the most common case of a valid url with a scheme
3780 // We check if the port would be valid by adding the scheme to handle the case host:port
3781 // where the host would be interpreted as the scheme
3782 if (url.isValid()
3783 && !url.scheme().isEmpty()
3784 && urlPrepended.port() == -1)
3785 return adjustFtpPath(url);
3786
3787 // Else, try the prepended one and adjust the scheme from the host name
3788 if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3789 qsizetype dotIndex = trimmedString.indexOf(u'.');
3790 const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3791 if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3792 urlPrepended.setScheme(ftpScheme());
3793 return adjustFtpPath(urlPrepended);
3794 }
3795
3796 return QUrl();
3797}
3798
\inmodule QtCore
Definition qatomic.h:112
bool ref() noexcept
bool deref() noexcept
T loadRelaxed() const noexcept
constexpr qsizetype size() const noexcept
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:474
static QByteArray fromPercentEncoding(const QByteArray &pctEncoded, char percent='%')
QByteArray toPercentEncoding(const QByteArray &exclude=QByteArray(), const QByteArray &include=QByteArray(), char percent='%') const
\inmodule QtCore
Definition qchar.h:48
@ Null
Definition qchar.h:51
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
Definition qchar.h:458
\inmodule QtCore\reentrant
Definition qdatastream.h:30
\inmodule QtCore
\inmodule QtCore
@ DefaultNormalization
Definition qdir_p.h:31
@ RemotePath
Definition qdir_p.h:33
\inmodule QtCore
Definition qdir.h:19
static bool isAbsolutePath(const QString &path)
Returns true if path is absolute; returns false if it is relative.
Definition qdir.h:183
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString absoluteFilePath() const
Returns an absolute path including the file name.
bool exists() const
Returns true if the file exists; otherwise returns false.
size_t qHash(const QUrl &url, size_t seed) noexcept
Returns the hash value for the url.
Definition qurl.cpp:3672
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
Represents an immutable JsonPath like path in the Qml code model (from a DomItem to another DomItem)
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
constexpr void truncate(qsizetype n) noexcept
Truncates this string view to length length.
constexpr void chop(qsizetype n) noexcept
Truncates this string view by length characters.
constexpr bool isEmpty() const noexcept
Returns whether this string view is empty - that is, whether {size() == 0}.
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
const_iterator constEnd() const noexcept
constexpr QStringView left(qsizetype n) const noexcept
bool endsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
QString toString() const
Returns a deep copy of this string view's data as a QString.
Definition qstring.h:1014
int compare(QStringView other, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
const_iterator constBegin() const noexcept
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
QString right(qsizetype n) const
Returns a substring that contains the n rightmost characters of the string.
Definition qstring.cpp:5180
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first character in the string.
Definition qstring.h:1197
QByteArray toLatin1() const &
Definition qstring.h:559
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
const_iterator constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just after the last character in...
Definition qstring.h:1211
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1173
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6180
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5710
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
bool isNull() const
Returns true if this string is null; otherwise returns false.
Definition qstring.h:898
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after the last character in the ...
Definition qstring.h:1205
void detach()
Definition qstring.h:1103
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.cpp:6498
QChar * data()
Returns a pointer to the data stored in the QString.
Definition qstring.h:1095
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:7822
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString trimmed() const &
Definition qstring.h:380
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
QString & prepend(QChar c)
Definition qstring.h:411
const_iterator constBegin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in the st...
Definition qstring.h:1203
qsizetype length() const
Returns the number of characters in this string.
Definition qstring.h:187
bool isEmpty() const
Definition qurl.cpp:505
void setQuery(const QString &value, qsizetype from, qsizetype end)
Definition qurl.cpp:1118
QAtomicInt ref
Definition qurl.cpp:553
void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const
Definition qurl.cpp:901
bool hasScheme() const
Definition qurl.cpp:537
void setUserInfo(const QString &userInfo, qsizetype from, qsizetype end)
Definition qurl.cpp:1081
void appendHost(QString &appendTo, QUrl::FormattingOptions options) const
Definition qurl.cpp:1154
void setPath(const QString &value, qsizetype from, qsizetype end)
Definition qurl.cpp:1106
bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end)
Definition qurl.cpp:1666
QString host
Definition qurl.cpp:559
uchar sectionIsPresent
Definition qurl.cpp:570
std::unique_ptr< Error > cloneError() const
Definition qurl.cpp:602
void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
Definition qurl.cpp:1012
bool hasPort() const
Definition qurl.cpp:543
QString toLocalFile(QUrl::FormattingOptions options) const
Definition qurl.cpp:1462
std::unique_ptr< Error > error
Definition qurl.cpp:564
ErrorCode validityError(QString *source=nullptr, qsizetype *position=nullptr) const
Definition qurl.cpp:1601
bool hasQuery() const
Definition qurl.cpp:545
void setFragment(const QString &value, qsizetype from, qsizetype end)
Definition qurl.cpp:1112
bool hasUserInfo() const
Definition qurl.cpp:539
QString mergePaths(const QString &relativePath) const
Definition qurl.cpp:1497
bool isLocalFile() const
Definition qurl.cpp:548
@ InvalidIPv6AddressError
Definition qurl.cpp:471
@ InvalidIPv4AddressError
Definition qurl.cpp:470
@ InvalidCharacterInIPv6Error
Definition qurl.cpp:472
@ InvalidPasswordError
Definition qurl.cpp:467
@ InvalidPathError
Definition qurl.cpp:479
@ InvalidSchemeError
Definition qurl.cpp:463
@ InvalidIPvFutureError
Definition qurl.cpp:473
@ InvalidUserNameError
Definition qurl.cpp:465
@ PortEmptyError
Definition qurl.cpp:477
@ InvalidFragmentError
Definition qurl.cpp:483
@ AuthorityPresentAndPathIsRelative
Definition qurl.cpp:487
@ AuthorityAbsentAndPathIsDoubleSlash
Definition qurl.cpp:488
@ InvalidPortError
Definition qurl.cpp:476
@ RelativeUrlPathContainsColonBeforeSlash
Definition qurl.cpp:489
@ InvalidRegNameError
Definition qurl.cpp:469
@ InvalidQueryError
Definition qurl.cpp:481
@ HostMissingEndBracket
Definition qurl.cpp:474
QString path
Definition qurl.cpp:560
bool hasPath() const
Definition qurl.cpp:544
QUrlPrivate()
Definition qurl.cpp:577
void clearError()
Definition qurl.cpp:607
bool setScheme(const QString &value, qsizetype len, bool doSetError)
Definition qurl.cpp:947
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:835
uchar flags
Definition qurl.cpp:571
@ IsLocalFile
Definition qurl.cpp:457
QString scheme
Definition qurl.cpp:556
void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const
Definition qurl.cpp:894
void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:849
bool hasFragment() const
Definition qurl.cpp:546
void setPassword(const QString &value, qsizetype from, qsizetype end)
Definition qurl.cpp:1100
void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:908
bool validateComponent(Section section, const QString &input)
Definition qurl.cpp:513
void setError(ErrorCode errorCode, const QString &source, qsizetype supplement=-1)
Definition qurl.cpp:612
bool hasUserName() const
Definition qurl.cpp:540
QString fragment
Definition qurl.cpp:562
QString query
Definition qurl.cpp:561
QString userName
Definition qurl.cpp:557
bool hasAuthority() const
Definition qurl.cpp:538
bool hasHost() const
Definition qurl.cpp:542
void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:939
QString password
Definition qurl.cpp:558
void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition qurl.cpp:932
bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode)
Definition qurl.cpp:1268
bool hasPassword() const
Definition qurl.cpp:541
void setUserName(const QString &value, qsizetype from, qsizetype end)
Definition qurl.cpp:1094
void parse(const QString &url, QUrl::ParsingMode parsingMode)
Definition qurl.cpp:1359
\inmodule QtCore
Definition qurlquery.h:20
constexpr bool testFlag(E1 f) const
Definition qurl.h:82
\inmodule QtCore
Definition qurl.h:94
static QUrl fromLocalFile(const QString &localfile)
Returns a QUrl representation of localFile, interpreted as a local file.
Definition qurl.cpp:3354
QString userInfo(ComponentFormattingOptions options=PrettyDecoded) const
Returns the user info of the URL, or an empty string if the user info is undefined.
Definition qurl.cpp:2126
bool hasQuery() const
Definition qurl.cpp:2510
static QList< QUrl > fromStringList(const QStringList &uris, ParsingMode mode=TolerantMode)
Definition qurl.cpp:3646
QString fragment(ComponentFormattingOptions options=PrettyDecoded) const
Returns the fragment of the URL.
Definition qurl.cpp:2679
QUrl()
Constructs an empty QUrl object.
Definition qurl.cpp:1843
bool operator!=(const QUrl &url) const
Returns true if this URL and the given url are not equal; otherwise returns false.
Definition qurl.cpp:3236
bool matches(const QUrl &url, FormattingOptions options) const
Definition qurl.cpp:3164
bool isLocalFile() const
Definition qurl.cpp:3431
QString url(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2814
QString query(ComponentFormattingOptions=PrettyDecoded) const
Returns the query string of the URL if there's a query string, or an empty result if not.
Definition qurl.cpp:2606
static QByteArray toAce(const QString &domain, AceProcessingOptions options={})
Definition qurl.cpp:3061
bool operator<(const QUrl &url) const
Definition qurl.cpp:3073
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
Definition qurl.cpp:2494
static QStringList toStringList(const QList< QUrl > &uris, FormattingOptions options=FormattingOptions(PrettyDecoded))
Definition qurl.cpp:3630
QUrl resolved(const QUrl &relative) const
Returns the result of the merge of this URL with relative.
Definition qurl.cpp:2722
void setPassword(const QString &password, ParsingMode mode=DecodedMode)
Sets the URL's password to password.
Definition qurl.cpp:2224
void setUserName(const QString &userName, ParsingMode mode=DecodedMode)
Sets the URL's user name to userName.
Definition qurl.cpp:2161
void setFragment(const QString &fragment, ParsingMode mode=TolerantMode)
Sets the fragment of the URL to fragment.
Definition qurl.cpp:2645
bool hasFragment() const
Definition qurl.cpp:2697
static QString fromPercentEncoding(const QByteArray &)
Returns a decoded copy of input.
Definition qurl.cpp:2998
bool isRelative() const
Returns true if the URL is relative; otherwise returns false.
Definition qurl.cpp:2797
bool isDetached() const
Definition qurl.cpp:3298
bool isValid() const
Returns true if the URL is non-empty and valid; otherwise returns false.
Definition qurl.cpp:1874
~QUrl()
Destructor; called immediately before the object is deleted.
Definition qurl.cpp:1859
QString userName(ComponentFormattingOptions options=FullyDecoded) const
Returns the user name of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2196
QString host(ComponentFormattingOptions=FullyDecoded) const
Returns the host of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2337
void setQuery(const QString &query, ParsingMode mode=TolerantMode)
Sets the query string of the URL to query.
Definition qurl.cpp:2547
static QUrl fromUserInput(const QString &userInput, const QString &workingDirectory=QString(), UserInputResolutionOptions options=DefaultResolution)
Returns a valid URL from a user supplied userInput string if one can be deduced.
Definition qurl.cpp:3743
bool operator==(const QUrl &url) const
Returns true if this URL and the given url are equal; otherwise returns false.
Definition qurl.cpp:3127
@ AssumeLocalFile
Definition qurl.h:175
void detach()
Definition qurl.cpp:3287
QByteArray toEncoded(FormattingOptions options=FullyEncoded) const
Returns the encoded representation of the URL if it's valid; otherwise an empty QByteArray is returne...
Definition qurl.cpp:2964
QString password(ComponentFormattingOptions=FullyDecoded) const
Returns the password of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2259
ParsingMode
The parsing mode controls the way QUrl parses strings.
Definition qurl.h:96
@ DecodedMode
Definition qurl.h:99
@ TolerantMode
Definition qurl.h:97
@ StrictMode
Definition qurl.h:98
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition qurl.cpp:1888
static QByteArray toPercentEncoding(const QString &, const QByteArray &exclude=QByteArray(), const QByteArray &include=QByteArray())
Returns an encoded copy of input.
Definition qurl.cpp:3016
void setUrl(const QString &url, ParsingMode mode=TolerantMode)
Parses url and sets this object to that value.
Definition qurl.cpp:1926
QString authority(ComponentFormattingOptions options=PrettyDecoded) const
Returns the authority of the URL if it is defined; otherwise an empty string is returned.
Definition qurl.cpp:2052
bool isParentOf(const QUrl &url) const
Returns true if this URL is a parent of childUrl.
Definition qurl.cpp:3441
QUrl adjusted(FormattingOptions options) const
Definition qurl.cpp:2921
QString scheme() const
Returns the scheme of the URL.
Definition qurl.cpp:1983
void setScheme(const QString &scheme)
Sets the scheme of the URL to scheme.
Definition qurl.cpp:1959
void clear()
Resets the content of the QUrl.
Definition qurl.cpp:1901
QString errorString() const
Definition qurl.cpp:3590
@ RemovePassword
Definition qurl.h:106
@ RemoveScheme
Definition qurl.h:105
@ StripTrailingSlash
Definition qurl.h:115
@ RemoveFragment
Definition qurl.h:112
@ RemoveQuery
Definition qurl.h:111
@ RemoveFilename
Definition qurl.h:116
@ PreferLocalFile
Definition qurl.h:114
@ NormalizePathSegments
Definition qurl.h:117
@ RemovePath
Definition qurl.h:110
@ RemoveUserInfo
Definition qurl.h:107
@ RemoveAuthority
Definition qurl.h:109
@ RemovePort
Definition qurl.h:108
static QString fromAce(const QByteArray &domain, AceProcessingOptions options={})
Definition qurl.cpp:3038
void setHost(const QString &host, ParsingMode mode=DecodedMode)
Sets the host of the URL to host.
Definition qurl.cpp:2286
int port(int defaultPort=-1) const
Definition qurl.cpp:2380
void setAuthority(const QString &authority, ParsingMode mode=TolerantMode)
Sets the authority of the URL to authority.
Definition qurl.cpp:2019
@ PrettyDecoded
Definition qurl.h:121
@ EncodeReserved
Definition qurl.h:125
@ FullyDecoded
Definition qurl.h:130
@ EncodeDelimiters
Definition qurl.h:124
@ EncodeUnicode
Definition qurl.h:123
@ DecodeReserved
Definition qurl.h:126
@ FullyEncoded
Definition qurl.h:129
QDataStream & operator>>(QDataStream &in, QUrl &url)
Reads a url into url from the stream in and returns a reference to the stream.
Definition qurl.cpp:3485
void setUserInfo(const QString &userInfo, ParsingMode mode=TolerantMode)
Sets the user info of the URL to userInfo.
Definition qurl.cpp:2090
void setPath(const QString &path, ParsingMode mode=DecodedMode)
Sets the path of the URL to path.
Definition qurl.cpp:2411
QString toDisplayString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Definition qurl.cpp:2903
QUrl & operator=(const QUrl &copy) noexcept
Assigns the specified url to this object.
Definition qurl.cpp:3244
static QUrl fromEncoded(QByteArrayView input, ParsingMode mode=TolerantMode)
Parses input and returns the corresponding QUrl.
Definition qurl.cpp:2985
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Returns a string representation of the URL.
Definition qurl.cpp:2828
void setPort(int port)
Sets the port of the URL to port.
Definition qurl.cpp:2355
QDataStream & operator<<(QDataStream &out, const QUrl &url)
Writes url url to the stream out and returns a reference to the stream.
Definition qurl.cpp:3469
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
Definition qurl.cpp:3411
QString path(ComponentFormattingOptions options=FullyDecoded) const
Returns the path of the URL.
Definition qurl.cpp:2465
QHash< int, QWidget * > hash
[35multi]
QString str
[2]
b clear()
QString text
void setHost()
quint8 IPv6Address[16]
void toString(QString &appendTo, IPv4Address address)
bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end)
quint32 IPv4Address
const QChar * parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
Combined button and popup list for selecting options.
constexpr bool isAsciiDigit(char32_t c) noexcept
Definition qtools_p.h:67
constexpr bool isAsciiLower(char32_t c) noexcept
Definition qtools_p.h:77
constexpr bool isAsciiLetterOrNumber(char32_t c) noexcept
Definition qtools_p.h:82
constexpr bool isAsciiUpper(char32_t c) noexcept
Definition qtools_p.h:72
constexpr bool isHexDigit(char32_t c) noexcept
Definition qtools_p.h:37
@ CaseInsensitive
static jboolean copy(JNIEnv *, jobject)
QT_WARNING_POP void qAtomicAssign(T *&d, T *x)
This is a helper for the assignment operators of implicitly shared classes.
Definition qatomic.h:180
void qAtomicDetach(T *&d)
This is a helper for the detach method of implicitly shared classes.
Definition qatomic.h:199
#define Q_LIKELY(x)
DBusConnection const char DBusError * error
QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormalizations flags, bool *ok)
Definition qdir.cpp:2204
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
EGLOutputPortEXT port
size_t qHash(const QFileSystemWatcherPathKey &key, size_t seed=0)
#define qDebug
[1]
Definition qlogging.h:160
#define qWarning
Definition qlogging.h:162
return ret
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint ref
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLsizei GLsizei GLchar * source
GLenum query
const GLubyte * c
GLenum GLsizei len
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint in
GLuint GLuint64EXT address
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
GLenum GLenum GLenum input
static qreal component(const QPointF &point, unsigned int i)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define qUtf16Printable(string)
Definition qstring.h:1403
#define QStringLiteral(str)
ErrorCode
Definition main.cpp:3196
#define QT_TRANSLATE_NOOP(scope, x)
unsigned char uchar
Definition qtypes.h:27
unsigned long ulong
Definition qtypes.h:30
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
unsigned short ushort
Definition qtypes.h:28
static const ushort *const passwordInIsolation
Definition qurl.cpp:737
static const ushort *const pathInUrl
Definition qurl.cpp:797
static QString recodeFromUser(const QString &input, const ushort *actions, qsizetype from, qsizetype to)
Definition qurl.cpp:807
static const ushort userNameInUrl[]
Definition qurl.cpp:784
QDebug operator<<(QDebug d, const QUrl &url)
Definition qurl.cpp:3495
static QString fileScheme()
Definition qurl.cpp:423
static const ushort *const pathInIsolation
Definition qurl.cpp:738
static const QChar * parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
Definition qurl.cpp:1176
static void appendComponentIfPresent(QString &msg, bool present, const char *componentName, const QString &component)
Definition qurl.cpp:3570
static void removeDotsFromPath(QString *path)
Definition qurl.cpp:1525
static QString webDavSslTag()
Definition qurl.cpp:433
static const ushort *const passwordInUrl
Definition qurl.cpp:796
static const ushort userNameInUserInfo[]
Definition qurl.cpp:742
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3503
static void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options, const ushort *actions)
Definition qurl.cpp:820
static const ushort *const queryInIsolation
Definition qurl.cpp:739
static bool isHex(char c)
Definition qurl.cpp:412
static const ushort userNameInIsolation[]
Definition qurl.cpp:718
static const QChar * parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
Definition qurl.cpp:1221
static const ushort userNameInAuthority[]
Definition qurl.cpp:763
static const ushort *const fragmentInIsolation
Definition qurl.cpp:740
static const ushort *const fragmentInUrl
Definition qurl.cpp:799
static QUrl adjustFtpPath(QUrl url)
Definition qurl.cpp:3687
static const ushort *const passwordInAuthority
Definition qurl.cpp:782
static QString ftpScheme()
Definition qurl.cpp:418
static bool isIp6(const QString &text)
Definition qurl.cpp:3697
static const ushort *const queryInUrl
Definition qurl.cpp:798
static QString webDavScheme()
Definition qurl.cpp:428
static QString fromNativeSeparators(const QString &pathName)
Definition qurl.cpp:3303
static const ushort *const passwordInUserInfo
Definition qurl.cpp:761
static void parseDecodedComponent(QString &data)
Definition qurl.cpp:801
QT_BEGIN_NAMESPACE Q_AUTOTEST_EXPORT qsizetype qt_urlRecode(QString &appendTo, QStringView url, QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications=nullptr)
@ AllowLeadingDot
Definition qurl_p.h:30
@ ForbidLeadingDot
Definition qurl_p.h:30
QString Q_CORE_EXPORT qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot, QUrl::AceProcessingOptions options={})
Definition qurlidna.cpp:889
@ ToAceOnly
Definition qurl_p.h:31
@ NormalizeAce
Definition qurl_p.h:31
#define decode(x)
#define encode(x)
#define leave(x)
QT_BEGIN_NAMESPACE typedef uchar * output
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QUrl url("example.com")
[constructor-url-reference]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
qsizetype position
Definition qurl.cpp:496
ErrorCode code
Definition qurl.cpp:497