QtBase  v6.3.1
qurl.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtCore module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
428 #include "qurl.h"
429 #include "qurl_p.h"
430 #include "qplatformdefs.h"
431 #include "qstring.h"
432 #include "qstringlist.h"
433 #include "qdebug.h"
434 #include "qhash.h"
435 #include "qdatastream.h"
436 #include "private/qipaddress_p.h"
437 #include "qurlquery.h"
438 #include "private/qdir_p.h"
439 
441 
442 // in qstring.cpp:
443 void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept;
444 
445 inline static bool isHex(char c)
446 {
447  c |= 0x20;
448  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
449 }
450 
451 static inline QString ftpScheme()
452 {
453  return QStringLiteral("ftp");
454 }
455 
456 static inline QString fileScheme()
457 {
458  return QStringLiteral("file");
459 }
460 
461 static inline QString webDavScheme()
462 {
463  return QStringLiteral("webdavs");
464 }
465 
466 static inline QString webDavSslTag()
467 {
468  return QStringLiteral("@SSL");
469 }
470 
472 {
473 public:
474  enum Section : uchar {
475  Scheme = 0x01,
476  UserName = 0x02,
477  Password = 0x04,
479  Host = 0x08,
480  Port = 0x10,
482  Path = 0x20,
484  Query = 0x40,
485  Fragment = 0x80,
486  FullUrl = 0xff
487  };
488 
489  enum Flags : uchar {
490  IsLocalFile = 0x01
491  };
492 
493  enum ErrorCode {
494  // the high byte of the error code matches the Section
495  // the first item in each value must be the generic "Invalid xxx Error"
497 
499 
501 
508 
511 
513 
515 
517 
518  // the following three cases are only possible in combination with
519  // presence/absence of the path, authority and scheme. See validityError().
523 
524  NoError = 0
525  };
526 
527  struct Error {
530  int position;
531  };
532 
533  QUrlPrivate();
534  QUrlPrivate(const QUrlPrivate &copy);
536 
537  void parse(const QString &url, QUrl::ParsingMode parsingMode);
538  bool isEmpty() const
539  { return sectionIsPresent == 0 && port == -1 && path.isEmpty(); }
540 
541  std::unique_ptr<Error> cloneError() const;
542  void clearError();
543  void setError(ErrorCode errorCode, const QString &source, int supplement = -1);
544  ErrorCode validityError(QString *source = nullptr, int *position = nullptr) const;
545  bool validateComponent(Section section, const QString &input, int begin, int end);
546  bool validateComponent(Section section, const QString &input)
547  { return validateComponent(section, input, 0, uint(input.length())); }
548 
549  // no QString scheme() const;
550  void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
551  void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
552  void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const;
553  void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const;
554  void appendHost(QString &appendTo, QUrl::FormattingOptions options) const;
555  void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
556  void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
557  void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const;
558 
559  // the "end" parameters are like STL iterators: they point to one past the last valid element
560  bool setScheme(const QString &value, int len, bool doSetError);
561  void setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode);
562  void setUserInfo(const QString &userInfo, int from, int end);
563  void setUserName(const QString &value, int from, int end);
564  void setPassword(const QString &value, int from, int end);
565  bool setHost(const QString &value, int from, int end, QUrl::ParsingMode mode);
566  void setPath(const QString &value, int from, int end);
567  void setQuery(const QString &value, int from, int end);
568  void setFragment(const QString &value, int from, int end);
569 
570  inline bool hasScheme() const { return sectionIsPresent & Scheme; }
571  inline bool hasAuthority() const { return sectionIsPresent & Authority; }
572  inline bool hasUserInfo() const { return sectionIsPresent & UserInfo; }
573  inline bool hasUserName() const { return sectionIsPresent & UserName; }
574  inline bool hasPassword() const { return sectionIsPresent & Password; }
575  inline bool hasHost() const { return sectionIsPresent & Host; }
576  inline bool hasPort() const { return port != -1; }
577  inline bool hasPath() const { return !path.isEmpty(); }
578  inline bool hasQuery() const { return sectionIsPresent & Query; }
579  inline bool hasFragment() const { return sectionIsPresent & Fragment; }
580 
581  inline bool isLocalFile() const { return flags & IsLocalFile; }
583 
584  QString mergePaths(const QString &relativePath) const;
585 
587  int port;
588 
596 
597  std::unique_ptr<Error> error;
598 
599  // not used for:
600  // - Port (port == -1 means absence)
601  // - Path (there's no path delimiter, so we optimize its use out of existence)
602  // Schemes are never supposed to be empty, but we keep the flag anyway
605 
606  // 32-bit: 2 bytes tail padding available
607  // 64-bit: 6 bytes tail padding available
608 };
609 
611  : ref(1), port(-1),
612  sectionIsPresent(0),
613  flags(0)
614 {
615 }
616 
618  : ref(1), port(copy.port),
619  scheme(copy.scheme),
620  userName(copy.userName),
621  password(copy.password),
622  host(copy.host),
623  path(copy.path),
624  query(copy.query),
625  fragment(copy.fragment),
626  error(copy.cloneError()),
627  sectionIsPresent(copy.sectionIsPresent),
628  flags(copy.flags)
629 {
630 }
631 
633  = default;
634 
635 std::unique_ptr<QUrlPrivate::Error> QUrlPrivate::cloneError() const
636 {
637  return error ? std::make_unique<Error>(*error) : nullptr;
638 }
639 
641 {
642  error.reset();
643 }
644 
645 inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, int supplement)
646 {
647  if (error) {
648  // don't overwrite an error set in a previous section during parsing
649  return;
650  }
651  error = std::make_unique<Error>();
652  error->code = errorCode;
653  error->source = source;
654  error->position = supplement;
655 }
656 
657 // From RFC 3986, Appendix A Collected ABNF for URI
658 // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
659 //[...]
660 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
661 //
662 // authority = [ userinfo "@" ] host [ ":" port ]
663 // userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
664 // host = IP-literal / IPv4address / reg-name
665 // port = *DIGIT
666 //[...]
667 // reg-name = *( unreserved / pct-encoded / sub-delims )
668 //[..]
669 // pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
670 //
671 // query = *( pchar / "/" / "?" )
672 //
673 // fragment = *( pchar / "/" / "?" )
674 //
675 // pct-encoded = "%" HEXDIG HEXDIG
676 //
677 // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
678 // reserved = gen-delims / sub-delims
679 // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
680 // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
681 // / "*" / "+" / "," / ";" / "="
682 // the path component has a complex ABNF that basically boils down to
683 // slash-separated segments of "pchar"
684 
685 // The above is the strict definition of the URL components and we mostly
686 // adhere to it, with few exceptions. QUrl obeys the following behavior:
687 // - percent-encoding sequences always use uppercase HEXDIG;
688 // - unreserved characters are *always* decoded, no exceptions;
689 // - the space character and bytes with the high bit set are controlled by
690 // the EncodeSpaces and EncodeUnicode bits;
691 // - control characters, the percent sign itself, and bytes with the high
692 // bit set that don't form valid UTF-8 sequences are always encoded,
693 // except in FullyDecoded mode;
694 // - sub-delims are always left alone, except in FullyDecoded mode;
695 // - gen-delim change behavior depending on which section of the URL (or
696 // the entire URL) we're looking at; see below;
697 // - characters not mentioned above, like "<", and ">", are usually
698 // decoded in individual sections of the URL, but encoded when the full
699 // URL is put together (we can change on subjective definition of
700 // "pretty").
701 //
702 // The behavior for the delimiters bears some explanation. The spec says in
703 // section 2.2:
704 // URIs that differ in the replacement of a reserved character with its
705 // corresponding percent-encoded octet are not equivalent.
706 // (note: QUrl API mistakenly uses the "reserved" term, so we will refer to
707 // them here as "delimiters").
708 //
709 // For that reason, we cannot encode delimiters found in decoded form and we
710 // cannot decode the ones found in encoded form if that would change the
711 // interpretation. Conversely, we *can* perform the transformation if it would
712 // not change the interpretation. From the last component of a URL to the first,
713 // here are the gen-delims we can unambiguously transform when the field is
714 // taken in isolation:
715 // - fragment: none, since it's the last
716 // - query: "#" is unambiguous
717 // - path: "#" and "?" are unambiguous
718 // - host: completely special but never ambiguous, see setHost() below.
719 // - password: the "#", "?", "/", "[", "]" and "@" characters are unambiguous
720 // - username: the "#", "?", "/", "[", "]", "@", and ":" characters are unambiguous
721 // - scheme: doesn't accept any delimiter, see setScheme() below.
722 //
723 // Internally, QUrl stores each component in the format that corresponds to the
724 // default mode (PrettyDecoded). It deviates from the "strict" FullyEncoded
725 // mode in the following way:
726 // - spaces are decoded
727 // - valid UTF-8 sequences are decoded
728 // - gen-delims that can be unambiguously transformed are decoded
729 // - characters controlled by DecodeReserved are often decoded, though this behavior
730 // can change depending on the subjective definition of "pretty"
731 //
732 // Note that the list of gen-delims that we can transform is different for the
733 // user info (user name + password) and the authority (user info + host +
734 // port).
735 
736 
737 // list the recoding table modifications to be used with the recodeFromUser and
738 // appendToUser functions, according to the rules above. Spaces and UTF-8
739 // sequences are handled outside the tables.
740 
741 // the encodedXXX tables are run with the delimiters set to "leave" by default;
742 // the decodedXXX tables are run with the delimiters set to "decode" by default
743 // (except for the query, which doesn't use these functions)
744 
745 namespace {
746 template <typename T> constexpr ushort decode(T x) noexcept { return ushort(x); }
747 template <typename T> constexpr ushort leave(T x) noexcept { return ushort(0x100 | x); }
748 template <typename T> constexpr ushort encode(T x) noexcept { return ushort(0x200 | x); }
749 }
750 
751 static const ushort userNameInIsolation[] = {
752  decode(':'), // 0
753  decode('@'), // 1
754  decode(']'), // 2
755  decode('['), // 3
756  decode('/'), // 4
757  decode('?'), // 5
758  decode('#'), // 6
759 
760  decode('"'), // 7
761  decode('<'),
762  decode('>'),
763  decode('^'),
764  decode('\\'),
765  decode('|'),
766  decode('{'),
767  decode('}'),
768  0
769 };
770 static const ushort * const passwordInIsolation = userNameInIsolation + 1;
771 static const ushort * const pathInIsolation = userNameInIsolation + 5;
772 static const ushort * const queryInIsolation = userNameInIsolation + 6;
773 static const ushort * const fragmentInIsolation = userNameInIsolation + 7;
774 
775 static const ushort userNameInUserInfo[] = {
776  encode(':'), // 0
777  decode('@'), // 1
778  decode(']'), // 2
779  decode('['), // 3
780  decode('/'), // 4
781  decode('?'), // 5
782  decode('#'), // 6
783 
784  decode('"'), // 7
785  decode('<'),
786  decode('>'),
787  decode('^'),
788  decode('\\'),
789  decode('|'),
790  decode('{'),
791  decode('}'),
792  0
793 };
794 static const ushort * const passwordInUserInfo = userNameInUserInfo + 1;
795 
796 static const ushort userNameInAuthority[] = {
797  encode(':'), // 0
798  encode('@'), // 1
799  encode(']'), // 2
800  encode('['), // 3
801  decode('/'), // 4
802  decode('?'), // 5
803  decode('#'), // 6
804 
805  decode('"'), // 7
806  decode('<'),
807  decode('>'),
808  decode('^'),
809  decode('\\'),
810  decode('|'),
811  decode('{'),
812  decode('}'),
813  0
814 };
815 static const ushort * const passwordInAuthority = userNameInAuthority + 1;
816 
817 static const ushort userNameInUrl[] = {
818  encode(':'), // 0
819  encode('@'), // 1
820  encode(']'), // 2
821  encode('['), // 3
822  encode('/'), // 4
823  encode('?'), // 5
824  encode('#'), // 6
825 
826  // no need to list encode(x) for the other characters
827  0
828 };
829 static const ushort * const passwordInUrl = userNameInUrl + 1;
830 static const ushort * const pathInUrl = userNameInUrl + 5;
831 static const ushort * const queryInUrl = userNameInUrl + 6;
832 static const ushort * const fragmentInUrl = userNameInUrl + 6;
833 
834 static inline void parseDecodedComponent(QString &data)
835 {
836  data.replace(QLatin1Char('%'), QLatin1String("%25"));
837 }
838 
839 static inline QString
840 recodeFromUser(const QString &input, const ushort *actions, int from, int to)
841 {
842  QString output;
843  const QChar *begin = input.constData() + from;
844  const QChar *end = input.constData() + to;
845  if (qt_urlRecode(output, QStringView{begin, end}, {}, actions))
846  return output;
847 
848  return input.mid(from, to - from);
849 }
850 
851 // appendXXXX functions: copy from the internal form to the external, user form.
852 // the internal value is stored in its PrettyDecoded form, so that case is easy.
853 static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
854  const ushort *actions)
855 {
856  // Test ComponentFormattingOptions, ignore FormattingOptions.
857  if ((options & 0xFFFF0000) == QUrl::PrettyDecoded) {
858  appendTo += value;
859  return;
860  }
861 
862  if (!qt_urlRecode(appendTo, value, options, actions))
863  appendTo += value;
864 }
865 
866 inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
867 {
868  if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
869  appendUserInfo(appendTo, options, appendingTo);
870 
871  // add '@' only if we added anything
872  if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0))
873  appendTo += QLatin1Char('@');
874  }
875  appendHost(appendTo, options);
876  if (!(options & QUrl::RemovePort) && port != -1)
877  appendTo += QLatin1Char(':') + QString::number(port);
878 }
879 
880 inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
881 {
882  if (Q_LIKELY(!hasUserInfo()))
883  return;
884 
885  const ushort *userNameActions;
886  const ushort *passwordActions;
887  if (options & QUrl::EncodeDelimiters) {
888  userNameActions = userNameInUrl;
889  passwordActions = passwordInUrl;
890  } else {
891  switch (appendingTo) {
892  case UserInfo:
893  userNameActions = userNameInUserInfo;
894  passwordActions = passwordInUserInfo;
895  break;
896 
897  case Authority:
898  userNameActions = userNameInAuthority;
899  passwordActions = passwordInAuthority;
900  break;
901 
902  case FullUrl:
903  userNameActions = userNameInUrl;
904  passwordActions = passwordInUrl;
905  break;
906 
907  default:
908  // can't happen
909  Q_UNREACHABLE();
910  break;
911  }
912  }
913 
914  if (!qt_urlRecode(appendTo, userName, options, userNameActions))
915  appendTo += userName;
916  if (options & QUrl::RemovePassword || !hasPassword()) {
917  return;
918  } else {
919  appendTo += QLatin1Char(':');
920  if (!qt_urlRecode(appendTo, password, options, passwordActions))
921  appendTo += password;
922  }
923 }
924 
925 inline void QUrlPrivate::appendUserName(QString &appendTo, QUrl::FormattingOptions options) const
926 {
927  // only called from QUrl::userName()
928  appendToUser(appendTo, userName, options,
929  options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation);
930 }
931 
932 inline void QUrlPrivate::appendPassword(QString &appendTo, QUrl::FormattingOptions options) const
933 {
934  // only called from QUrl::password()
935  appendToUser(appendTo, password, options,
936  options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation);
937 }
938 
939 inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
940 {
941  QString thePath = path;
942  if (options & QUrl::NormalizePathSegments) {
944  }
945 
946  QStringView thePathView(thePath);
947  if (options & QUrl::RemoveFilename) {
948  const int slash = path.lastIndexOf(QLatin1Char('/'));
949  if (slash == -1)
950  return;
951  thePathView = QStringView{path}.left(slash + 1);
952  }
953  // check if we need to remove trailing slashes
954  if (options & QUrl::StripTrailingSlash) {
955  while (thePathView.length() > 1 && thePathView.endsWith(QLatin1Char('/')))
956  thePathView.chop(1);
957  }
958 
959  appendToUser(appendTo, thePathView, options,
960  appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation);
961 }
962 
963 inline void QUrlPrivate::appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
964 {
965  appendToUser(appendTo, fragment, options,
966  options & QUrl::EncodeDelimiters ? fragmentInUrl :
967  appendingTo == FullUrl ? nullptr : fragmentInIsolation);
968 }
969 
970 inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
971 {
972  appendToUser(appendTo, query, options,
973  appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation);
974 }
975 
976 // setXXX functions
977 
978 inline bool QUrlPrivate::setScheme(const QString &value, int len, bool doSetError)
979 {
980  // schemes are strictly RFC-compliant:
981  // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
982  // we also lowercase the scheme
983 
984  // schemes in URLs are not allowed to be empty, but they can be in
985  // "Relative URIs" which QUrl also supports. QUrl::setScheme does
986  // not call us with len == 0, so this can only be from parse()
987  scheme.clear();
988  if (len == 0)
989  return false;
990 
992 
993  // validate it:
994  int needsLowercasing = -1;
995  const ushort *p = value.utf16();
996  for (int i = 0; i < len; ++i) {
997  if (p[i] >= 'a' && p[i] <= 'z')
998  continue;
999  if (p[i] >= 'A' && p[i] <= 'Z') {
1000  needsLowercasing = i;
1001  continue;
1002  }
1003  if (i) {
1004  if (p[i] >= '0' && p[i] <= '9')
1005  continue;
1006  if (p[i] == '+' || p[i] == '-' || p[i] == '.')
1007  continue;
1008  }
1009 
1010  // found something else
1011  // don't call setError needlessly:
1012  // if we've been called from parse(), it will try to recover
1013  if (doSetError)
1015  return false;
1016  }
1017 
1018  scheme = value.left(len);
1019 
1020  if (needsLowercasing != -1) {
1021  // schemes are ASCII only, so we don't need the full Unicode toLower
1022  QChar *schemeData = scheme.data(); // force detaching here
1023  for (int i = needsLowercasing; i >= 0; --i) {
1024  ushort c = schemeData[i].unicode();
1025  if (c >= 'A' && c <= 'Z')
1026  schemeData[i] = QChar(c + 0x20);
1027  }
1028  }
1029 
1030  // did we set to the file protocol?
1031  if (scheme == fileScheme()
1032 #ifdef Q_OS_WIN
1033  || scheme == webDavScheme()
1034 #endif
1035  ) {
1036  flags |= IsLocalFile;
1037  } else {
1038  flags &= ~IsLocalFile;
1039  }
1040  return true;
1041 }
1042 
1043 inline void QUrlPrivate::setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode)
1044 {
1047  port = -1;
1048 
1049  // we never actually _loop_
1050  while (from != end) {
1051  int userInfoIndex = auth.indexOf(QLatin1Char('@'), from);
1052  if (uint(userInfoIndex) < uint(end)) {
1053  setUserInfo(auth, from, userInfoIndex);
1054  if (mode == QUrl::StrictMode && !validateComponent(UserInfo, auth, from, userInfoIndex))
1055  break;
1056  from = userInfoIndex + 1;
1057  }
1058 
1059  int colonIndex = auth.lastIndexOf(QLatin1Char(':'), end - 1);
1060  if (colonIndex < from)
1061  colonIndex = -1;
1062 
1063  if (uint(colonIndex) < uint(end)) {
1064  if (auth.at(from).unicode() == '[') {
1065  // check if colonIndex isn't inside the "[...]" part
1066  int closingBracket = auth.indexOf(QLatin1Char(']'), from);
1067  if (uint(closingBracket) > uint(colonIndex))
1068  colonIndex = -1;
1069  }
1070  }
1071 
1072  if (uint(colonIndex) < uint(end) - 1) {
1073  // found a colon with digits after it
1074  unsigned long x = 0;
1075  for (int i = colonIndex + 1; i < end; ++i) {
1076  ushort c = auth.at(i).unicode();
1077  if (c >= '0' && c <= '9') {
1078  x *= 10;
1079  x += c - '0';
1080  } else {
1081  x = ulong(-1); // x != ushort(x)
1082  break;
1083  }
1084  }
1085  if (x == ushort(x)) {
1086  port = ushort(x);
1087  } else {
1088  setError(InvalidPortError, auth, colonIndex + 1);
1089  if (mode == QUrl::StrictMode)
1090  break;
1091  }
1092  }
1093 
1094  setHost(auth, from, qMin<uint>(end, colonIndex), mode);
1095  if (mode == QUrl::StrictMode && !validateComponent(Host, auth, from, qMin<uint>(end, colonIndex))) {
1096  // clear host too
1098  break;
1099  }
1100 
1101  // success
1102  return;
1103  }
1104  // clear all sections but host
1106  userName.clear();
1107  password.clear();
1108  host.clear();
1109  port = -1;
1110 }
1111 
1112 inline void QUrlPrivate::setUserInfo(const QString &userInfo, int from, int end)
1113 {
1114  int delimIndex = userInfo.indexOf(QLatin1Char(':'), from);
1115  setUserName(userInfo, from, qMin<uint>(delimIndex, end));
1116 
1117  if (uint(delimIndex) >= uint(end)) {
1118  password.clear();
1120  } else {
1121  setPassword(userInfo, delimIndex + 1, end);
1122  }
1123 }
1124 
1125 inline void QUrlPrivate::setUserName(const QString &value, int from, int end)
1126 {
1128  userName = recodeFromUser(value, userNameInIsolation, from, end);
1129 }
1130 
1131 inline void QUrlPrivate::setPassword(const QString &value, int from, int end)
1132 {
1134  password = recodeFromUser(value, passwordInIsolation, from, end);
1135 }
1136 
1137 inline void QUrlPrivate::setPath(const QString &value, int from, int end)
1138 {
1139  // sectionIsPresent |= Path; // not used, save some cycles
1140  path = recodeFromUser(value, pathInIsolation, from, end);
1141 }
1142 
1143 inline void QUrlPrivate::setFragment(const QString &value, int from, int end)
1144 {
1146  fragment = recodeFromUser(value, fragmentInIsolation, from, end);
1147 }
1148 
1149 inline void QUrlPrivate::setQuery(const QString &value, int from, int iend)
1150 {
1152  query = recodeFromUser(value, queryInIsolation, from, iend);
1153 }
1154 
1155 // Host handling
1156 // The RFC says the host is:
1157 // host = IP-literal / IPv4address / reg-name
1158 // IP-literal = "[" ( IPv6address / IPvFuture ) "]"
1159 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1160 // [a strict definition of IPv6Address and IPv4Address]
1161 // reg-name = *( unreserved / pct-encoded / sub-delims )
1162 //
1163 // We deviate from the standard in all but IPvFuture. For IPvFuture we accept
1164 // and store only exactly what the RFC says we should. No percent-encoding is
1165 // permitted in this field, so Unicode characters and space aren't either.
1166 //
1167 // For IPv4 addresses, we accept broken addresses like inet_aton does (that is,
1168 // less than three dots). However, we correct the address to the proper form
1169 // and store the corrected address. After correction, we comply to the RFC and
1170 // it's exclusively composed of unreserved characters.
1171 //
1172 // For IPv6 addresses, we accept addresses including trailing (embedded) IPv4
1173 // addresses, the so-called v4-compat and v4-mapped addresses. We also store
1174 // those addresses like that in the hostname field, which violates the spec.
1175 // IPv6 hosts are stored with the square brackets in the QString. It also
1176 // requires no transformation in any way.
1177 //
1178 // As for registered names, it's the other way around: we accept only valid
1179 // hostnames as specified by STD 3 and IDNA. That means everything we accept is
1180 // valid in the RFC definition above, but there are many valid reg-names
1181 // according to the RFC that we do not accept in the name of security. Since we
1182 // do accept IDNA, reg-names are subject to ACE encoding and decoding, which is
1183 // specified by the DecodeUnicode flag. The hostname is stored in its Unicode form.
1184 
1185 inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions options) const
1186 {
1187  if (host.isEmpty())
1188  return;
1189  if (host.at(0).unicode() == '[') {
1190  // IPv6 addresses might contain a zone-id which needs to be recoded
1191  if (options != 0)
1192  if (qt_urlRecode(appendTo, host, options, nullptr))
1193  return;
1194  appendTo += host;
1195  } else {
1196  // this is either an IPv4Address or a reg-name
1197  // if it is a reg-name, it is already stored in Unicode form
1198  if (options & QUrl::EncodeUnicode && !(options & 0x4000000))
1199  appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot, {});
1200  else
1201  appendTo += host;
1202  }
1203 }
1204 
1205 // the whole IPvFuture is passed and parsed here, including brackets;
1206 // returns null if the parsing was successful, or the QChar of the first failure
1207 static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
1208 {
1209  // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1210  static const char acceptable[] =
1211  "!$&'()*+,;=" // sub-delims
1212  ":" // ":"
1213  "-._~"; // unreserved
1214 
1215  // the brackets and the "v" have been checked
1216  const QChar *const origBegin = begin;
1217  if (begin[3].unicode() != '.')
1218  return &begin[3];
1219  if ((begin[2].unicode() >= 'A' && begin[2].unicode() <= 'F') ||
1220  (begin[2].unicode() >= 'a' && begin[2].unicode() <= 'f') ||
1221  (begin[2].unicode() >= '0' && begin[2].unicode() <= '9')) {
1222  // this is so unlikely that we'll just go down the slow path
1223  // decode the whole string, skipping the "[vH." and "]" which we already know to be there
1224  host += QStringView(begin, 4);
1225 
1226  // uppercase the version, if necessary
1227  if (begin[2].unicode() >= 'a')
1228  host[host.length() - 2] = QChar{begin[2].unicode() - 0x20};
1229 
1230  begin += 4;
1231  --end;
1232 
1233  QString decoded;
1234  if (mode == QUrl::TolerantMode && qt_urlRecode(decoded, QStringView{begin, end}, QUrl::FullyDecoded, nullptr)) {
1235  begin = decoded.constBegin();
1236  end = decoded.constEnd();
1237  }
1238 
1239  for ( ; begin != end; ++begin) {
1240  if (begin->unicode() >= 'A' && begin->unicode() <= 'Z')
1241  host += *begin;
1242  else if (begin->unicode() >= 'a' && begin->unicode() <= 'z')
1243  host += *begin;
1244  else if (begin->unicode() >= '0' && begin->unicode() <= '9')
1245  host += *begin;
1246  else if (begin->unicode() < 0x80 && strchr(acceptable, begin->unicode()) != nullptr)
1247  host += *begin;
1248  else
1249  return decoded.isEmpty() ? begin : &origBegin[2];
1250  }
1251  host += QLatin1Char(']');
1252  return nullptr;
1253  }
1254  return &origBegin[2];
1255 }
1256 
1257 // ONLY the IPv6 address is parsed here, WITHOUT the brackets
1258 static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode)
1259 {
1260  QStringView decoded(begin, end);
1261  QString decodedBuffer;
1262  if (mode == QUrl::TolerantMode) {
1263  // this struct is kept in automatic storage because it's only 4 bytes
1264  const ushort decodeColon[] = { decode(':'), 0 };
1265  if (qt_urlRecode(decodedBuffer, decoded, QUrl::ComponentFormattingOption::PrettyDecoded, decodeColon))
1266  decoded = decodedBuffer;
1267  }
1268 
1269  const QStringView zoneIdIdentifier(u"%25");
1271  QStringView zoneId;
1272 
1273  int zoneIdPosition = decoded.indexOf(zoneIdIdentifier);
1274  if ((zoneIdPosition != -1) && (decoded.lastIndexOf(zoneIdIdentifier) == zoneIdPosition)) {
1275  zoneId = decoded.mid(zoneIdPosition + zoneIdIdentifier.size());
1276  decoded.truncate(zoneIdPosition);
1277 
1278  // was there anything after the zone ID separator?
1279  if (zoneId.isEmpty())
1280  return end;
1281  }
1282 
1283  // did the address become empty after removing the zone ID?
1284  // (it might have always been empty)
1285  if (decoded.isEmpty())
1286  return end;
1287 
1288  const QChar *ret = QIPAddressUtils::parseIp6(address, decoded.constBegin(), decoded.constEnd());
1289  if (ret)
1290  return begin + (ret - decoded.constBegin());
1291 
1292  host.reserve(host.size() + (end - begin) + 2); // +2 for the brackets
1293  host += QLatin1Char('[');
1295 
1296  if (!zoneId.isEmpty()) {
1297  host += zoneIdIdentifier;
1298  host += zoneId;
1299  }
1300  host += QLatin1Char(']');
1301  return nullptr;
1302 }
1303 
1304 inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl::ParsingMode mode)
1305 {
1306  const QChar *begin = value.constData() + from;
1307  const QChar *end = value.constData() + iend;
1308 
1309  const int len = end - begin;
1310  host.clear();
1312  if (len == 0)
1313  return true;
1314 
1315  if (begin[0].unicode() == '[') {
1316  // IPv6Address or IPvFuture
1317  // smallest IPv6 address is "[::]" (len = 4)
1318  // smallest IPvFuture address is "[v7.X]" (len = 6)
1319  if (end[-1].unicode() != ']') {
1321  return false;
1322  }
1323 
1324  if (len > 5 && begin[1].unicode() == 'v') {
1325  const QChar *c = parseIpFuture(host, begin, end, mode);
1326  if (c)
1327  setError(InvalidIPvFutureError, value, c - value.constData());
1328  return !c;
1329  } else if (begin[1].unicode() == 'v') {
1331  }
1332 
1333  const QChar *c = parseIp6(host, begin + 1, end - 1, mode);
1334  if (!c)
1335  return true;
1336 
1337  if (c == end - 1)
1339  else
1341  return false;
1342  }
1343 
1344  // check if it's an IPv4 address
1346  if (QIPAddressUtils::parseIp4(ip4, begin, end)) {
1347  // yes, it was
1349  return true;
1350  }
1351 
1352  // This is probably a reg-name.
1353  // But it can also be an encoded string that, when decoded becomes one
1354  // of the types above.
1355  //
1356  // Two types of encoding are possible:
1357  // percent encoding (e.g., "%31%30%2E%30%2E%30%2E%31" -> "10.0.0.1")
1358  // Unicode encoding (some non-ASCII characters case-fold to digits
1359  // when nameprepping is done)
1360  //
1361  // The qt_ACE_do function below does IDNA normalization and the STD3 check.
1362  // That means a Unicode string may become an IPv4 address, but it cannot
1363  // produce a '[' or a '%'.
1364 
1365  // check for percent-encoding first
1366  QString s;
1367  if (mode == QUrl::TolerantMode && qt_urlRecode(s, QStringView{begin, end}, { }, nullptr)) {
1368  // something was decoded
1369  // anything encoded left?
1370  int pos = s.indexOf(QChar(0x25)); // '%'
1371  if (pos != -1) {
1373  return false;
1374  }
1375 
1376  // recurse
1377  return setHost(s, 0, s.length(), QUrl::StrictMode);
1378  }
1379 
1380  s = qt_ACE_do(value.mid(from, iend - from), NormalizeAce, ForbidLeadingDot, {});
1381  if (s.isEmpty()) {
1383  return false;
1384  }
1385 
1386  // check IPv4 again
1387  if (QIPAddressUtils::parseIp4(ip4, s.constBegin(), s.constEnd())) {
1389  } else {
1390  host = s;
1391  }
1392  return true;
1393 }
1394 
1395 inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode)
1396 {
1397  // URI-reference = URI / relative-ref
1398  // URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
1399  // relative-ref = relative-part [ "?" query ] [ "#" fragment ]
1400  // hier-part = "//" authority path-abempty
1401  // / other path types
1402  // relative-part = "//" authority path-abempty
1403  // / other path types here
1404 
1405  sectionIsPresent = 0;
1406  flags = 0;
1407  clearError();
1408 
1409  // find the important delimiters
1410  int colon = -1;
1411  int question = -1;
1412  int hash = -1;
1413  const int len = url.length();
1414  const QChar *const begin = url.constData();
1415  const ushort *const data = reinterpret_cast<const ushort *>(begin);
1416 
1417  for (int i = 0; i < len; ++i) {
1418  uint uc = data[i];
1419  if (uc == '#' && hash == -1) {
1420  hash = i;
1421 
1422  // nothing more to be found
1423  break;
1424  }
1425 
1426  if (question == -1) {
1427  if (uc == ':' && colon == -1)
1428  colon = i;
1429  else if (uc == '?')
1430  question = i;
1431  }
1432  }
1433 
1434  // check if we have a scheme
1435  int hierStart;
1436  if (colon != -1 && setScheme(url, colon, /* don't set error */ false)) {
1437  hierStart = colon + 1;
1438  } else {
1439  // recover from a failed scheme: it might not have been a scheme at all
1440  scheme.clear();
1441  sectionIsPresent = 0;
1442  hierStart = 0;
1443  }
1444 
1445  int pathStart;
1446  int hierEnd = qMin<uint>(qMin<uint>(question, hash), len);
1447  if (hierEnd - hierStart >= 2 && data[hierStart] == '/' && data[hierStart + 1] == '/') {
1448  // we have an authority, it ends at the first slash after these
1449  int authorityEnd = hierEnd;
1450  for (int i = hierStart + 2; i < authorityEnd ; ++i) {
1451  if (data[i] == '/') {
1452  authorityEnd = i;
1453  break;
1454  }
1455  }
1456 
1457  setAuthority(url, hierStart + 2, authorityEnd, parsingMode);
1458 
1459  // even if we failed to set the authority properly, let's try to recover
1460  pathStart = authorityEnd;
1461  setPath(url, pathStart, hierEnd);
1462  } else {
1463  userName.clear();
1464  password.clear();
1465  host.clear();
1466  port = -1;
1467  pathStart = hierStart;
1468 
1469  if (hierStart < hierEnd)
1470  setPath(url, hierStart, hierEnd);
1471  else
1472  path.clear();
1473  }
1474 
1475  if (uint(question) < uint(hash))
1476  setQuery(url, question + 1, qMin<uint>(hash, len));
1477 
1478  if (hash != -1)
1479  setFragment(url, hash + 1, len);
1480 
1481  if (error || parsingMode == QUrl::TolerantMode)
1482  return;
1483 
1484  // The parsing so far was partially tolerant of errors, except for the
1485  // scheme parser (which is always strict) and the authority (which was
1486  // executed in strict mode).
1487  // If we haven't found any errors so far, continue the strict-mode parsing
1488  // from the path component onwards.
1489 
1490  if (!validateComponent(Path, url, pathStart, hierEnd))
1491  return;
1492  if (uint(question) < uint(hash) && !validateComponent(Query, url, question + 1, qMin<uint>(hash, len)))
1493  return;
1494  if (hash != -1)
1496 }
1497 
1499 {
1500  QString tmp;
1501  QString ourPath;
1502  appendPath(ourPath, options, QUrlPrivate::Path);
1503 
1504  // magic for shared drive on windows
1505  if (!host.isEmpty()) {
1506  tmp = QLatin1String("//") + host;
1507 #ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only.
1508  if (scheme == webDavScheme())
1509  tmp += webDavSslTag();
1510 #endif
1511  if (!ourPath.isEmpty() && !ourPath.startsWith(QLatin1Char('/')))
1512  tmp += QLatin1Char('/');
1513  tmp += ourPath;
1514  } else {
1515  tmp = ourPath;
1516 #ifdef Q_OS_WIN
1517  // magic for drives on windows
1518  if (ourPath.length() > 2 && ourPath.at(0) == QLatin1Char('/') && ourPath.at(2) == QLatin1Char(':'))
1519  tmp.remove(0, 1);
1520 #endif
1521  }
1522  return tmp;
1523 }
1524 
1525 /*
1526  From http://www.ietf.org/rfc/rfc3986.txt, 5.2.3: Merge paths
1527 
1528  Returns a merge of the current path with the relative path passed
1529  as argument.
1530 
1531  Note: \a relativePath is relative (does not start with '/').
1532 */
1533 inline QString QUrlPrivate::mergePaths(const QString &relativePath) const
1534 {
1535  // If the base URI has a defined authority component and an empty
1536  // path, then return a string consisting of "/" concatenated with
1537  // the reference's path; otherwise,
1538  if (!host.isEmpty() && path.isEmpty())
1539  return QLatin1Char('/') + relativePath;
1540 
1541  // Return a string consisting of the reference's path component
1542  // appended to all but the last segment of the base URI's path
1543  // (i.e., excluding any characters after the right-most "/" in the
1544  // base URI path, or excluding the entire base URI path if it does
1545  // not contain any "/" characters).
1546  QString newPath;
1547  if (!path.contains(QLatin1Char('/')))
1548  newPath = relativePath;
1549  else
1550  newPath = QStringView{path}.left(path.lastIndexOf(QLatin1Char('/')) + 1) + relativePath;
1551 
1552  return newPath;
1553 }
1554 
1555 /*
1556  From http://www.ietf.org/rfc/rfc3986.txt, 5.2.4: Remove dot segments
1557 
1558  Removes unnecessary ../ and ./ from the path. Used for normalizing
1559  the URL.
1560 */
1561 static void removeDotsFromPath(QString *path)
1562 {
1563  // The input buffer is initialized with the now-appended path
1564  // components and the output buffer is initialized to the empty
1565  // string.
1566  QChar *out = path->data();
1567  const QChar *in = out;
1568  const QChar *end = out + path->size();
1569 
1570  // If the input buffer consists only of
1571  // "." or "..", then remove that from the input
1572  // buffer;
1573  if (path->size() == 1 && in[0].unicode() == '.')
1574  ++in;
1575  else if (path->size() == 2 && in[0].unicode() == '.' && in[1].unicode() == '.')
1576  in += 2;
1577  // While the input buffer is not empty, loop:
1578  while (in < end) {
1579 
1580  // otherwise, if the input buffer begins with a prefix of "../" or "./",
1581  // then remove that prefix from the input buffer;
1582  if (path->size() >= 2 && in[0].unicode() == '.' && in[1].unicode() == '/')
1583  in += 2;
1584  else if (path->size() >= 3 && in[0].unicode() == '.'
1585  && in[1].unicode() == '.' && in[2].unicode() == '/')
1586  in += 3;
1587 
1588  // otherwise, if the input buffer begins with a prefix of
1589  // "/./" or "/.", where "." is a complete path segment,
1590  // then replace that prefix with "/" in the input buffer;
1591  if (in <= end - 3 && in[0].unicode() == '/' && in[1].unicode() == '.'
1592  && in[2].unicode() == '/') {
1593  in += 2;
1594  continue;
1595  } else if (in == end - 2 && in[0].unicode() == '/' && in[1].unicode() == '.') {
1596  *out++ = QLatin1Char('/');
1597  in += 2;
1598  break;
1599  }
1600 
1601  // otherwise, if the input buffer begins with a prefix
1602  // of "/../" or "/..", where ".." is a complete path
1603  // segment, then replace that prefix with "/" in the
1604  // input buffer and remove the last //segment and its
1605  // preceding "/" (if any) from the output buffer;
1606  if (in <= end - 4 && in[0].unicode() == '/' && in[1].unicode() == '.'
1607  && in[2].unicode() == '.' && in[3].unicode() == '/') {
1608  while (out > path->constData() && (--out)->unicode() != '/')
1609  ;
1610  if (out == path->constData() && out->unicode() != '/')
1611  ++in;
1612  in += 3;
1613  continue;
1614  } else if (in == end - 3 && in[0].unicode() == '/' && in[1].unicode() == '.'
1615  && in[2].unicode() == '.') {
1616  while (out > path->constData() && (--out)->unicode() != '/')
1617  ;
1618  if (out->unicode() == '/')
1619  ++out;
1620  in += 3;
1621  break;
1622  }
1623 
1624  // otherwise move the first path segment in
1625  // the input buffer to the end of the output
1626  // buffer, including the initial "/" character
1627  // (if any) and any subsequent characters up
1628  // to, but not including, the next "/"
1629  // character or the end of the input buffer.
1630  *out++ = *in++;
1631  while (in < end && in->unicode() != '/')
1632  *out++ = *in++;
1633  }
1634  path->truncate(out - path->constData());
1635 }
1636 
1638 {
1639  Q_ASSERT(!source == !position);
1640  if (error) {
1641  if (source) {
1642  *source = error->source;
1643  *position = error->position;
1644  }
1645  return error->code;
1646  }
1647 
1648  // There are three more cases of invalid URLs that QUrl recognizes and they
1649  // are only possible with constructed URLs (setXXX methods), not with
1650  // parsing. Therefore, they are tested here.
1651  //
1652  // Two cases are a non-empty path that doesn't start with a slash and:
1653  // - with an authority
1654  // - without an authority, without scheme but the path with a colon before
1655  // the first slash
1656  // The third case is an empty authority and a non-empty path that starts
1657  // with "//".
1658  // Those cases are considered invalid because toString() would produce a URL
1659  // that wouldn't be parsed back to the same QUrl.
1660 
1661  if (path.isEmpty())
1662  return NoError;
1663  if (path.at(0) == QLatin1Char('/')) {
1664  if (hasAuthority() || path.length() == 1 || path.at(1) != QLatin1Char('/'))
1665  return NoError;
1666  if (source) {
1667  *source = path;
1668  *position = 0;
1669  }
1671  }
1672 
1674  if (source) {
1675  *source = path;
1676  *position = 0;
1677  }
1679  }
1681  return NoError;
1682 
1683  // check for a path of "text:text/"
1684  for (int i = 0; i < path.length(); ++i) {
1685  ushort c = path.at(i).unicode();
1686  if (c == '/') {
1687  // found the slash before the colon
1688  return NoError;
1689  }
1690  if (c == ':') {
1691  // found the colon before the slash, it's invalid
1692  if (source) {
1693  *source = path;
1694  *position = i;
1695  }
1697  }
1698  }
1699  return NoError;
1700 }
1701 
1703  int begin, int end)
1704 {
1705  // What we need to look out for, that the regular parser tolerates:
1706  // - percent signs not followed by two hex digits
1707  // - forbidden characters, which should always appear encoded
1708  // '"' / '<' / '>' / '\' / '^' / '`' / '{' / '|' / '}' / BKSP
1709  // control characters
1710  // - delimiters not allowed in certain positions
1711  // . scheme: parser is already strict
1712  // . user info: gen-delims except ":" disallowed ("/" / "?" / "#" / "[" / "]" / "@")
1713  // . host: parser is stricter than the standard
1714  // . port: parser is stricter than the standard
1715  // . path: all delimiters allowed
1716  // . fragment: all delimiters allowed
1717  // . query: all delimiters allowed
1718  static const char forbidden[] = "\"<>\\^`{|}\x7F";
1719  static const char forbiddenUserInfo[] = ":/?#[]@";
1720 
1721  Q_ASSERT(section != Authority && section != Hierarchy && section != FullUrl);
1722 
1723  const ushort *const data = reinterpret_cast<const ushort *>(input.constData());
1724  for (uint i = uint(begin); i < uint(end); ++i) {
1725  uint uc = data[i];
1726  if (uc >= 0x80)
1727  continue;
1728 
1729  bool error = false;
1730  if ((uc == '%' && (uint(end) < i + 2 || !isHex(data[i + 1]) || !isHex(data[i + 2])))
1731  || uc <= 0x20 || strchr(forbidden, uc)) {
1732  // found an error
1733  error = true;
1734  } else if (section & UserInfo) {
1735  if (section == UserInfo && strchr(forbiddenUserInfo + 1, uc))
1736  error = true;
1737  else if (section != UserInfo && strchr(forbiddenUserInfo, uc))
1738  error = true;
1739  }
1740 
1741  if (!error)
1742  continue;
1743 
1744  ErrorCode errorCode = ErrorCode(int(section) << 8);
1745  if (section == UserInfo) {
1746  // is it the user name or the password?
1747  errorCode = InvalidUserNameError;
1748  for (uint j = uint(begin); j < i; ++j)
1749  if (data[j] == ':') {
1750  errorCode = InvalidPasswordError;
1751  break;
1752  }
1753  }
1754 
1755  setError(errorCode, input, i);
1756  return false;
1757  }
1758 
1759  // no errors
1760  return true;
1761 }
1762 
1763 #if 0
1764 inline void QUrlPrivate::validate() const
1765 {
1766  QUrlPrivate *that = (QUrlPrivate *)this;
1767  that->encodedOriginal = that->toEncoded(); // may detach
1768  parse(ParseOnly);
1769 
1770  QURL_SETFLAG(that->stateFlags, Validated);
1771 
1772  if (!isValid)
1773  return;
1774 
1775  QString auth = authority(); // causes the non-encoded forms to be valid
1776 
1777  // authority() calls canonicalHost() which sets this
1778  if (!isHostValid)
1779  return;
1780 
1781  if (scheme == QLatin1String("mailto")) {
1782  if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) {
1783  that->isValid = false;
1784  that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "expected empty host, username,"
1785  "port and password"),
1786  0, 0);
1787  }
1788  } else if (scheme == ftpScheme() || scheme == httpScheme()) {
1789  if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) {
1790  that->isValid = false;
1791  that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "the host is empty, but not the path"),
1792  0, 0);
1793  }
1794  }
1795 }
1796 #endif
1797 
1858 QUrl::QUrl(const QString &url, ParsingMode parsingMode) : d(nullptr)
1859 {
1860  setUrl(url, parsingMode);
1861 }
1862 
1867 {
1868 }
1869 
1874 {
1875  if (d)
1876  d->ref.ref();
1877 }
1878 
1883 {
1884  if (d && !d->ref.deref())
1885  delete d;
1886 }
1887 
1897 bool QUrl::isValid() const
1898 {
1899  if (isEmpty()) {
1900  // also catches d == nullptr
1901  return false;
1902  }
1903  return d->validityError() == QUrlPrivate::NoError;
1904 }
1905 
1911 bool QUrl::isEmpty() const
1912 {
1913  if (!d) return true;
1914  return d->isEmpty();
1915 }
1916 
1925 {
1926  if (d && !d->ref.deref())
1927  delete d;
1928  d = nullptr;
1929 }
1930 
1949 void QUrl::setUrl(const QString &url, ParsingMode parsingMode)
1950 {
1951  if (parsingMode == DecodedMode) {
1952  qWarning("QUrl: QUrl::DecodedMode is not permitted when parsing a full URL");
1953  } else {
1954  detach();
1955  d->parse(url, parsingMode);
1956  }
1957 }
1958 
1982 void QUrl::setScheme(const QString &scheme)
1983 {
1984  detach();
1985  d->clearError();
1986  if (scheme.isEmpty()) {
1987  // schemes are not allowed to be empty
1989  d->flags &= ~QUrlPrivate::IsLocalFile;
1990  d->scheme.clear();
1991  } else {
1992  d->setScheme(scheme, scheme.length(), /* do set error */ true);
1993  }
1994 }
1995 
2007 {
2008  if (!d) return QString();
2009 
2010  return d->scheme;
2011 }
2012 
2043 {
2044  detach();
2045  d->clearError();
2046 
2047  if (mode == DecodedMode) {
2048  qWarning("QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function");
2049  return;
2050  }
2051 
2053  if (authority.isNull()) {
2054  // QUrlPrivate::setAuthority cleared almost everything
2055  // but it leaves the Host bit set
2057  }
2058 }
2059 
2075 QString QUrl::authority(ComponentFormattingOptions options) const
2076 {
2077  QString result;
2078  if (!d)
2079  return result;
2080 
2081  if (options == QUrl::FullyDecoded) {
2082  qWarning("QUrl::authority(): QUrl::FullyDecoded is not permitted in this function");
2083  return result;
2084  }
2085 
2087  return result;
2088 }
2089 
2114 {
2115  detach();
2116  d->clearError();
2118  if (mode == DecodedMode) {
2119  qWarning("QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function");
2120  return;
2121  }
2122 
2123  d->setUserInfo(trimmed, 0, trimmed.length());
2124  if (userInfo.isNull()) {
2125  // QUrlPrivate::setUserInfo cleared almost everything
2126  // but it leaves the UserName bit set
2130  d->userName.clear();
2131  d->password.clear();
2132  }
2133 }
2134 
2149 QString QUrl::userInfo(ComponentFormattingOptions options) const
2150 {
2151  QString result;
2152  if (!d)
2153  return result;
2154 
2155  if (options == QUrl::FullyDecoded) {
2156  qWarning("QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function");
2157  return result;
2158  }
2159 
2161  return result;
2162 }
2163 
2185 {
2186  detach();
2187  d->clearError();
2188 
2189  QString data = userName;
2190  if (mode == DecodedMode) {
2191  parseDecodedComponent(data);
2192  mode = TolerantMode;
2193  }
2194 
2195  d->setUserName(data, 0, data.length());
2196  if (userName.isNull())
2199  d->userName.clear();
2200 }
2201 
2219 QString QUrl::userName(ComponentFormattingOptions options) const
2220 {
2221  QString result;
2222  if (d)
2223  d->appendUserName(result, options);
2224  return result;
2225 }
2226 
2248 {
2249  detach();
2250  d->clearError();
2251 
2252  QString data = password;
2253  if (mode == DecodedMode) {
2254  parseDecodedComponent(data);
2255  mode = TolerantMode;
2256  }
2257 
2258  d->setPassword(data, 0, data.length());
2259  if (password.isNull())
2262  d->password.clear();
2263 }
2264 
2282 QString QUrl::password(ComponentFormattingOptions options) const
2283 {
2284  QString result;
2285  if (d)
2286  d->appendPassword(result, options);
2287  return result;
2288 }
2289 
2310 {
2311  detach();
2312  d->clearError();
2313 
2314  QString data = host;
2315  if (mode == DecodedMode) {
2316  parseDecodedComponent(data);
2317  mode = TolerantMode;
2318  }
2319 
2320  if (d->setHost(data, 0, data.length(), mode)) {
2321  if (host.isNull())
2323  } else if (!data.startsWith(QLatin1Char('['))) {
2324  // setHost failed, it might be IPv6 or IPvFuture in need of bracketing
2325  Q_ASSERT(d->error);
2326 
2327  data.prepend(QLatin1Char('['));
2328  data.append(QLatin1Char(']'));
2329  if (!d->setHost(data, 0, data.length(), mode)) {
2330  // failed again
2331  if (data.contains(QLatin1Char(':'))) {
2332  // source data contains ':', so it's an IPv6 error
2334  }
2335  } else {
2336  // succeeded
2337  d->clearError();
2338  }
2339  }
2340 }
2341 
2360 QString QUrl::host(ComponentFormattingOptions options) const
2361 {
2362  QString result;
2363  if (d) {
2364  d->appendHost(result, options);
2365  if (result.startsWith(QLatin1Char('[')))
2366  result = result.mid(1, result.length() - 2);
2367  }
2368  return result;
2369 }
2370 
2379 {
2380  detach();
2381  d->clearError();
2382 
2383  if (port < -1 || port > 65535) {
2385  port = -1;
2386  }
2387 
2388  d->port = port;
2389  if (port != -1)
2391 }
2392 
2403 int QUrl::port(int defaultPort) const
2404 {
2405  if (!d) return defaultPort;
2406  return d->port == -1 ? defaultPort : d->port;
2407 }
2408 
2435 {
2436  detach();
2437  d->clearError();
2438 
2439  QString data = path;
2440  if (mode == DecodedMode) {
2441  parseDecodedComponent(data);
2442  mode = TolerantMode;
2443  }
2444 
2445  d->setPath(data, 0, data.length());
2446 
2447  // optimized out, since there is no path delimiter
2448 // if (path.isNull())
2449 // d->sectionIsPresent &= ~QUrlPrivate::Path;
2450 // else
2452  d->path.clear();
2453 }
2454 
2488 QString QUrl::path(ComponentFormattingOptions options) const
2489 {
2490  QString result;
2491  if (d)
2492  d->appendPath(result, options, QUrlPrivate::Path);
2493  return result;
2494 }
2495 
2517 QString QUrl::fileName(ComponentFormattingOptions options) const
2518 {
2519  const QString ourPath = path(options);
2520  const int slash = ourPath.lastIndexOf(QLatin1Char('/'));
2521  if (slash == -1)
2522  return ourPath;
2523  return ourPath.mid(slash + 1);
2524 }
2525 
2533 bool QUrl::hasQuery() const
2534 {
2535  if (!d) return false;
2536  return d->hasQuery();
2537 }
2538 
2571 {
2572  detach();
2573  d->clearError();
2574 
2575  QString data = query;
2576  if (mode == DecodedMode) {
2577  parseDecodedComponent(data);
2578  mode = TolerantMode;
2579  }
2580 
2581  d->setQuery(data, 0, data.length());
2582  if (query.isNull())
2585  d->query.clear();
2586 }
2587 
2600 {
2601  detach();
2602  d->clearError();
2603 
2604  // we know the data is in the right format
2605  d->query = query.toString();
2606  if (query.isEmpty())
2608  else
2610 }
2611 
2629 QString QUrl::query(ComponentFormattingOptions options) const
2630 {
2631  QString result;
2632  if (d) {
2633  d->appendQuery(result, options, QUrlPrivate::Query);
2634  if (d->hasQuery() && result.isNull())
2635  result.detach();
2636  }
2637  return result;
2638 }
2639 
2669 {
2670  detach();
2671  d->clearError();
2672 
2673  QString data = fragment;
2674  if (mode == DecodedMode) {
2675  parseDecodedComponent(data);
2676  mode = TolerantMode;
2677  }
2678 
2679  d->setFragment(data, 0, data.length());
2680  if (fragment.isNull())
2683  d->fragment.clear();
2684 }
2685 
2702 QString QUrl::fragment(ComponentFormattingOptions options) const
2703 {
2704  QString result;
2705  if (d) {
2707  if (d->hasFragment() && result.isNull())
2708  result.detach();
2709  }
2710  return result;
2711 }
2712 
2720 bool QUrl::hasFragment() const
2721 {
2722  if (!d) return false;
2723  return d->hasFragment();
2724 }
2725 
2745 QUrl QUrl::resolved(const QUrl &relative) const
2746 {
2747  if (!d) return relative;
2748  if (!relative.d) return *this;
2749 
2750  QUrl t;
2751  if (!relative.d->scheme.isEmpty()) {
2752  t = relative;
2753  t.detach();
2754  } else {
2755  if (relative.d->hasAuthority()) {
2756  t = relative;
2757  t.detach();
2758  } else {
2759  t.d = new QUrlPrivate;
2760 
2761  // copy the authority
2762  t.d->userName = d->userName;
2763  t.d->password = d->password;
2764  t.d->host = d->host;
2765  t.d->port = d->port;
2766  t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority;
2767 
2768  if (relative.d->path.isEmpty()) {
2769  t.d->path = d->path;
2770  if (relative.d->hasQuery()) {
2771  t.d->query = relative.d->query;
2772  t.d->sectionIsPresent |= QUrlPrivate::Query;
2773  } else if (d->hasQuery()) {
2774  t.d->query = d->query;
2775  t.d->sectionIsPresent |= QUrlPrivate::Query;
2776  }
2777  } else {
2778  t.d->path = relative.d->path.startsWith(QLatin1Char('/'))
2779  ? relative.d->path
2780  : d->mergePaths(relative.d->path);
2781  if (relative.d->hasQuery()) {
2782  t.d->query = relative.d->query;
2783  t.d->sectionIsPresent |= QUrlPrivate::Query;
2784  }
2785  }
2786  }
2787  t.d->scheme = d->scheme;
2788  if (d->hasScheme())
2789  t.d->sectionIsPresent |= QUrlPrivate::Scheme;
2790  else
2791  t.d->sectionIsPresent &= ~QUrlPrivate::Scheme;
2792  t.d->flags |= d->flags & QUrlPrivate::IsLocalFile;
2793  }
2794  t.d->fragment = relative.d->fragment;
2795  if (relative.d->hasFragment())
2796  t.d->sectionIsPresent |= QUrlPrivate::Fragment;
2797  else
2798  t.d->sectionIsPresent &= ~QUrlPrivate::Fragment;
2799 
2800  removeDotsFromPath(&t.d->path);
2801 
2802 #if defined(QURL_DEBUG)
2803  qDebug("QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"",
2804  qUtf16Printable(url()),
2805  qUtf16Printable(relative.url()),
2806  qUtf16Printable(t.url()));
2807 #endif
2808  return t;
2809 }
2810 
2820 bool QUrl::isRelative() const
2821 {
2822  if (!d) return true;
2823  return !d->hasScheme();
2824 }
2825 
2838 {
2839  return toString(options);
2840 }
2841 
2852 {
2853  QString url;
2854  if (!isValid()) {
2855  // also catches isEmpty()
2856  return url;
2857  }
2858  if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) {
2859  qWarning("QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL");
2860  options &= ~QUrl::FullyDecoded;
2861  //options |= QUrl::PrettyDecoded; // no-op, value is 0
2862  }
2863 
2864  // return just the path if:
2865  // - QUrl::PreferLocalFile is passed
2866  // - QUrl::RemovePath isn't passed (rather stupid if the user did...)
2867  // - there's no query or fragment to return
2868  // that is, either they aren't present, or we're removing them
2869  // - it's a local file
2870  if (options.testFlag(QUrl::PreferLocalFile) && !options.testFlag(QUrl::RemovePath)
2871  && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery))
2872  && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment))
2873  && isLocalFile()) {
2874  url = d->toLocalFile(options | QUrl::FullyDecoded);
2875  return url;
2876  }
2877 
2878  // for the full URL, we consider that the reserved characters are prettier if encoded
2879  if (options & DecodeReserved)
2880  options &= ~EncodeReserved;
2881  else
2882  options |= EncodeReserved;
2883 
2884  if (!(options & QUrl::RemoveScheme) && d->hasScheme())
2885  url += d->scheme + QLatin1Char(':');
2886 
2887  bool pathIsAbsolute = d->path.startsWith(QLatin1Char('/'));
2888  if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) {
2889  url += QLatin1String("//");
2891  } else if (isLocalFile() && pathIsAbsolute) {
2892  // Comply with the XDG file URI spec, which requires triple slashes.
2893  url += QLatin1String("//");
2894  }
2895 
2896  if (!(options & QUrl::RemovePath))
2897  d->appendPath(url, options, QUrlPrivate::FullUrl);
2898 
2899  if (!(options & QUrl::RemoveQuery) && d->hasQuery()) {
2900  url += QLatin1Char('?');
2901  d->appendQuery(url, options, QUrlPrivate::FullUrl);
2902  }
2903  if (!(options & QUrl::RemoveFragment) && d->hasFragment()) {
2904  url += QLatin1Char('#');
2905  d->appendFragment(url, options, QUrlPrivate::FullUrl);
2906  }
2907 
2908  return url;
2909 }
2910 
2927 {
2928  return toString(options | RemovePassword);
2929 }
2930 
2945 {
2946  if (!isValid()) {
2947  // also catches isEmpty()
2948  return QUrl();
2949  }
2950  QUrl that = *this;
2951  if (options & RemoveScheme)
2952  that.setScheme(QString());
2953  if ((options & RemoveAuthority) == RemoveAuthority) {
2954  that.setAuthority(QString());
2955  } else {
2956  if ((options & RemoveUserInfo) == RemoveUserInfo)
2957  that.setUserInfo(QString());
2958  else if (options & RemovePassword)
2959  that.setPassword(QString());
2960  if (options & RemovePort)
2961  that.setPort(-1);
2962  }
2963  if (options & RemoveQuery)
2964  that.setQuery(QString());
2965  if (options & RemoveFragment)
2966  that.setFragment(QString());
2967  if (options & RemovePath) {
2968  that.setPath(QString());
2969  } else if (options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) {
2970  that.detach();
2971  QString path;
2973  that.d->setPath(path, 0, path.length());
2974  }
2975  return that;
2976 }
2977 
2988 {
2989  options &= ~(FullyDecoded | FullyEncoded);
2990  return toString(options | FullyEncoded).toLatin1();
2991 }
2992 
3005 {
3006  return QUrl(QString::fromUtf8(input.constData(), input.size()), mode);
3007 }
3008 
3018 {
3020  return QString::fromUtf8(ba, ba.size());
3021 }
3022 
3035 QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclude, const QByteArray &include)
3036 {
3037  return input.toUtf8().toPercentEncoding(exclude, include);
3038 }
3039 
3057 QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions options)
3058 {
3059  return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce,
3060  ForbidLeadingDot /*FIXME: make configurable*/, options);
3061 }
3062 
3080 QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options)
3081 {
3082  return qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/, options)
3083  .toLatin1();
3084 }
3085 
3092 bool QUrl::operator <(const QUrl &url) const
3093 {
3094  if (!d || !url.d) {
3095  bool thisIsEmpty = !d || d->isEmpty();
3096  bool thatIsEmpty = !url.d || url.d->isEmpty();
3097 
3098  // sort an empty URL first
3099  return thisIsEmpty && !thatIsEmpty;
3100  }
3101 
3102  int cmp;
3103  cmp = d->scheme.compare(url.d->scheme);
3104  if (cmp != 0)
3105  return cmp < 0;
3106 
3107  cmp = d->userName.compare(url.d->userName);
3108  if (cmp != 0)
3109  return cmp < 0;
3110 
3111  cmp = d->password.compare(url.d->password);
3112  if (cmp != 0)
3113  return cmp < 0;
3114 
3115  cmp = d->host.compare(url.d->host);
3116  if (cmp != 0)
3117  return cmp < 0;
3118 
3119  if (d->port != url.d->port)
3120  return d->port < url.d->port;
3121 
3122  cmp = d->path.compare(url.d->path);
3123  if (cmp != 0)
3124  return cmp < 0;
3125 
3126  if (d->hasQuery() != url.d->hasQuery())
3127  return url.d->hasQuery();
3128 
3129  cmp = d->query.compare(url.d->query);
3130  if (cmp != 0)
3131  return cmp < 0;
3132 
3133  if (d->hasFragment() != url.d->hasFragment())
3134  return url.d->hasFragment();
3135 
3136  cmp = d->fragment.compare(url.d->fragment);
3137  return cmp < 0;
3138 }
3139 
3146 bool QUrl::operator ==(const QUrl &url) const
3147 {
3148  if (!d && !url.d)
3149  return true;
3150  if (!d)
3151  return url.d->isEmpty();
3152  if (!url.d)
3153  return d->isEmpty();
3154 
3155  // First, compare which sections are present, since it speeds up the
3156  // processing considerably. We just have to ignore the host-is-present flag
3157  // for local files (the "file" protocol), due to the requirements of the
3158  // XDG file URI specification.
3159  int mask = QUrlPrivate::FullUrl;
3160  if (isLocalFile())
3161  mask &= ~QUrlPrivate::Host;
3162  return (d->sectionIsPresent & mask) == (url.d->sectionIsPresent & mask) &&
3163  d->scheme == url.d->scheme &&
3164  d->userName == url.d->userName &&
3165  d->password == url.d->password &&
3166  d->host == url.d->host &&
3167  d->port == url.d->port &&
3168  d->path == url.d->path &&
3169  d->query == url.d->query &&
3170  d->fragment == url.d->fragment;
3171 }
3172 
3183 bool QUrl::matches(const QUrl &url, FormattingOptions options) const
3184 {
3185  if (!d && !url.d)
3186  return true;
3187  if (!d)
3188  return url.d->isEmpty();
3189  if (!url.d)
3190  return d->isEmpty();
3191 
3192  // First, compare which sections are present, since it speeds up the
3193  // processing considerably. We just have to ignore the host-is-present flag
3194  // for local files (the "file" protocol), due to the requirements of the
3195  // XDG file URI specification.
3196  int mask = QUrlPrivate::FullUrl;
3197  if (isLocalFile())
3198  mask &= ~QUrlPrivate::Host;
3199 
3200  if (options.testFlag(QUrl::RemoveScheme))
3202  else if (d->scheme != url.d->scheme)
3203  return false;
3204 
3205  if (options.testFlag(QUrl::RemovePassword))
3207  else if (d->password != url.d->password)
3208  return false;
3209 
3210  if (options.testFlag(QUrl::RemoveUserInfo))
3212  else if (d->userName != url.d->userName)
3213  return false;
3214 
3215  if (options.testFlag(QUrl::RemovePort))
3216  mask &= ~QUrlPrivate::Port;
3217  else if (d->port != url.d->port)
3218  return false;
3219 
3220  if (options.testFlag(QUrl::RemoveAuthority))
3221  mask &= ~QUrlPrivate::Host;
3222  else if (d->host != url.d->host)
3223  return false;
3224 
3225  if (options.testFlag(QUrl::RemoveQuery))
3227  else if (d->query != url.d->query)
3228  return false;
3229 
3230  if (options.testFlag(QUrl::RemoveFragment))
3232  else if (d->fragment != url.d->fragment)
3233  return false;
3234 
3235  if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask))
3236  return false;
3237 
3238  if (options.testFlag(QUrl::RemovePath))
3239  return true;
3240 
3241  // Compare paths, after applying path-related options
3242  QString path1;
3243  d->appendPath(path1, options, QUrlPrivate::Path);
3244  QString path2;
3245  url.d->appendPath(path2, options, QUrlPrivate::Path);
3246  return path1 == path2;
3247 }
3248 
3255 bool QUrl::operator !=(const QUrl &url) const
3256 {
3257  return !(*this == url);
3258 }
3259 
3264 {
3265  if (!d) {
3266  if (url.d) {
3267  url.d->ref.ref();
3268  d = url.d;
3269  }
3270  } else {
3271  if (url.d)
3272  qAtomicAssign(d, url.d);
3273  else
3274  clear();
3275  }
3276  return *this;
3277 }
3278 
3283 {
3284  if (url.isEmpty()) {
3285  clear();
3286  } else {
3287  detach();
3288  d->parse(url, TolerantMode);
3289  }
3290  return *this;
3291 }
3292 
3307 {
3308  if (!d)
3309  d = new QUrlPrivate;
3310  else
3311  qAtomicDetach(d);
3312 }
3313 
3317 bool QUrl::isDetached() const
3318 {
3319  return !d || d->ref.loadRelaxed() == 1;
3320 }
3321 
3322 static QString fromNativeSeparators(const QString &pathName)
3323 {
3324 #if defined(Q_OS_WIN)
3325  QString result(pathName);
3326  const QChar nativeSeparator = u'\\';
3327  auto i = result.indexOf(nativeSeparator);
3328  if (i != -1) {
3329  QChar * const data = result.data();
3330  const auto length = result.length();
3331  for (; i < length; ++i) {
3332  if (data[i] == nativeSeparator)
3333  data[i] = u'/';
3334  }
3335  }
3336  return result;
3337 #else
3338  return pathName;
3339 #endif
3340 }
3341 
3374 {
3375  QUrl url;
3376  if (localFile.isEmpty())
3377  return url;
3378  QString scheme = fileScheme();
3379  QString deslashified = fromNativeSeparators(localFile);
3380 
3381  // magic for drives on windows
3382  if (deslashified.length() > 1 && deslashified.at(1) == QLatin1Char(':') && deslashified.at(0) != QLatin1Char('/')) {
3383  deslashified.prepend(QLatin1Char('/'));
3384  } else if (deslashified.startsWith(QLatin1String("//"))) {
3385  // magic for shared drive on windows
3386  int indexOfPath = deslashified.indexOf(QLatin1Char('/'), 2);
3387  QStringView hostSpec = QStringView{deslashified}.mid(2, indexOfPath - 2);
3388  // Check for Windows-specific WebDAV specification: "//host@SSL/path".
3389  if (hostSpec.endsWith(webDavSslTag(), Qt::CaseInsensitive)) {
3390  hostSpec.truncate(hostSpec.size() - 4);
3391  scheme = webDavScheme();
3392  }
3393 
3394  // hosts can't be IPv6 addresses without [], so we can use QUrlPrivate::setHost
3395  url.detach();
3396  if (!url.d->setHost(hostSpec.toString(), 0, hostSpec.size(), StrictMode)) {
3397  if (url.d->error->code != QUrlPrivate::InvalidRegNameError)
3398  return url;
3399 
3400  // Path hostname is not a valid URL host, so set it entirely in the path
3401  // (by leaving deslashified unchanged)
3402  } else if (indexOfPath > 2) {
3403  deslashified = deslashified.right(deslashified.length() - indexOfPath);
3404  } else {
3405  deslashified.clear();
3406  }
3407  }
3408 
3409  url.setScheme(scheme);
3410  url.setPath(deslashified, DecodedMode);
3411  return url;
3412 }
3413 
3431 {
3432  // the call to isLocalFile() also ensures that we're parsed
3433  if (!isLocalFile())
3434  return QString();
3435 
3436  return d->toLocalFile(QUrl::FullyDecoded);
3437 }
3438 
3450 bool QUrl::isLocalFile() const
3451 {
3452  return d && d->isLocalFile();
3453 }
3454 
3460 bool QUrl::isParentOf(const QUrl &childUrl) const
3461 {
3462  QString childPath = childUrl.path();
3463 
3464  if (!d)
3465  return ((childUrl.scheme().isEmpty())
3466  && (childUrl.authority().isEmpty())
3467  && childPath.length() > 0 && childPath.at(0) == QLatin1Char('/'));
3468 
3469  QString ourPath = path();
3470 
3471  return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
3472  && (childUrl.authority().isEmpty() || authority() == childUrl.authority())
3473  && childPath.startsWith(ourPath)
3474  && ((ourPath.endsWith(QLatin1Char('/')) && childPath.length() > ourPath.length())
3475  || (!ourPath.endsWith(QLatin1Char('/'))
3476  && childPath.length() > ourPath.length() && childPath.at(ourPath.length()) == QLatin1Char('/'))));
3477 }
3478 
3479 
3480 #ifndef QT_NO_DATASTREAM
3489 {
3490  QByteArray u;
3491  if (url.isValid())
3492  u = url.toEncoded();
3493  out << u;
3494  return out;
3495 }
3496 
3505 {
3506  QByteArray u;
3507  in >> u;
3509  return in;
3510 }
3511 #endif // QT_NO_DATASTREAM
3512 
3513 #ifndef QT_NO_DEBUG_STREAM
3515 {
3516  QDebugStateSaver saver(d);
3517  d.nospace() << "QUrl(" << url.toDisplayString() << ')';
3518  return d;
3519 }
3520 #endif
3521 
3522 static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, int errorPosition)
3523 {
3524  QChar c = uint(errorPosition) < uint(errorSource.length()) ?
3525  errorSource.at(errorPosition) : QChar(QChar::Null);
3526 
3527  switch (errorCode) {
3528  case QUrlPrivate::NoError:
3529  Q_ASSERT_X(false, "QUrl::errorString",
3530  "Impossible: QUrl::errorString should have treated this condition");
3531  Q_UNREACHABLE();
3532  return QString();
3533 
3535  auto msg = QLatin1String("Invalid scheme (character '%1' not permitted)");
3536  return msg.arg(c);
3537  }
3538 
3540  return QLatin1String("Invalid user name (character '%1' not permitted)")
3541  .arg(c);
3542 
3544  return QLatin1String("Invalid password (character '%1' not permitted)")
3545  .arg(c);
3546 
3548  if (errorPosition != -1)
3549  return QLatin1String("Invalid hostname (character '%1' not permitted)")
3550  .arg(c);
3551  else
3552  return QStringLiteral("Invalid hostname (contains invalid characters)");
3554  return QString(); // doesn't happen yet
3556  return QStringLiteral("Invalid IPv6 address");
3558  return QLatin1String("Invalid IPv6 address (character '%1' not permitted)").arg(c);
3560  return QLatin1String("Invalid IPvFuture address (character '%1' not permitted)").arg(c);
3562  return QStringLiteral("Expected ']' to match '[' in hostname");
3563 
3565  return QStringLiteral("Invalid port or port number out of range");
3567  return QStringLiteral("Port field was empty");
3568 
3570  return QLatin1String("Invalid path (character '%1' not permitted)")
3571  .arg(c);
3572 
3574  return QLatin1String("Invalid query (character '%1' not permitted)")
3575  .arg(c);
3576 
3578  return QLatin1String("Invalid fragment (character '%1' not permitted)")
3579  .arg(c);
3580 
3582  return QStringLiteral("Path component is relative and authority is present");
3584  return QStringLiteral("Path component starts with '//' and authority is absent");
3586  return QStringLiteral("Relative URL's path component contains ':' before any '/'");
3587  }
3588 
3589  Q_ASSERT_X(false, "QUrl::errorString", "Cannot happen, unknown error");
3590  Q_UNREACHABLE();
3591  return QString();
3592 }
3593 
3594 static inline void appendComponentIfPresent(QString &msg, bool present, const char *componentName,
3595  const QString &component)
3596 {
3597  if (present) {
3598  msg += QLatin1String(componentName);
3599  msg += QLatin1Char('"');
3600  msg += component;
3601  msg += QLatin1String("\",");
3602  }
3603 }
3604 
3619 {
3620  QString msg;
3621  if (!d)
3622  return msg;
3623 
3624  QString errorSource;
3625  int errorPosition = 0;
3626  QUrlPrivate::ErrorCode errorCode = d->validityError(&errorSource, &errorPosition);
3627  if (errorCode == QUrlPrivate::NoError)
3628  return msg;
3629 
3630  msg += errorMessage(errorCode, errorSource, errorPosition);
3631  msg += QLatin1String("; source was \"");
3632  msg += errorSource;
3633  msg += QLatin1String("\";");
3634  appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Scheme,
3635  " scheme = ", d->scheme);
3636  appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::UserInfo,
3637  " userinfo = ", userInfo());
3638  appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Host,
3639  " host = ", d->host);
3640  appendComponentIfPresent(msg, d->port != -1,
3641  " port = ", QString::number(d->port));
3642  appendComponentIfPresent(msg, !d->path.isEmpty(),
3643  " path = ", d->path);
3644  appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Query,
3645  " query = ", d->query);
3646  appendComponentIfPresent(msg, d->sectionIsPresent & QUrlPrivate::Fragment,
3647  " fragment = ", d->fragment);
3648  if (msg.endsWith(QLatin1Char(',')))
3649  msg.chop(1);
3650  return msg;
3651 }
3652 
3659 {
3660  QStringList lst;
3661  lst.reserve(urls.size());
3662  for (const QUrl &url : urls)
3663  lst.append(url.toString(options));
3664  return lst;
3665 
3666 }
3667 
3675 {
3676  QList<QUrl> lst;
3677  lst.reserve(urls.size());
3678  for (const QString &str : urls)
3679  lst.append(QUrl(str, mode));
3680  return lst;
3681 }
3682 
3700 size_t qHash(const QUrl &url, size_t seed) noexcept
3701 {
3702  if (!url.d)
3703  return qHash(-1, seed); // the hash of an unset port (-1)
3704 
3705  return qHash(url.d->scheme) ^
3706  qHash(url.d->userName) ^
3707  qHash(url.d->password) ^
3708  qHash(url.d->host) ^
3709  qHash(url.d->port, seed) ^
3710  qHash(url.d->path) ^
3711  qHash(url.d->query) ^
3712  qHash(url.d->fragment);
3713 }
3714 
3715 static QUrl adjustFtpPath(QUrl url)
3716 {
3717  if (url.scheme() == ftpScheme()) {
3719  if (path.startsWith(QLatin1String("//")))
3721  }
3722  return url;
3723 }
3724 
3725 static bool isIp6(const QString &text)
3726 {
3728  return !text.isEmpty() && QIPAddressUtils::parseIp6(address, text.begin(), text.end()) == nullptr;
3729 }
3730 
3771 QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirectory,
3772  UserInputResolutionOptions options)
3773 {
3774  QString trimmedString = userInput.trimmed();
3775 
3776  if (trimmedString.isEmpty())
3777  return QUrl();
3778 
3779  // Check for IPv6 addresses, since a path starting with ":" is absolute (a resource)
3780  // and IPv6 addresses can start with "c:" too
3781  if (isIp6(trimmedString)) {
3782  QUrl url;
3783  url.setHost(trimmedString);
3784  url.setScheme(QStringLiteral("http"));
3785  return url;
3786  }
3787 
3788  const QUrl url = QUrl(trimmedString, QUrl::TolerantMode);
3789 
3790  // Check for a relative path
3791  if (!workingDirectory.isEmpty()) {
3792  const QFileInfo fileInfo(QDir(workingDirectory), userInput);
3793  if (fileInfo.exists())
3794  return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3795 
3796  // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes)
3797  if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput))
3798  return QUrl::fromLocalFile(fileInfo.absoluteFilePath());
3799  }
3800 
3801  // Check first for files, since on Windows drive letters can be interpreted as schemes
3802  if (QDir::isAbsolutePath(trimmedString))
3803  return QUrl::fromLocalFile(trimmedString);
3804 
3805  QUrl urlPrepended = QUrl(QLatin1String("http://") + trimmedString, QUrl::TolerantMode);
3806 
3807  // Check the most common case of a valid url with a scheme
3808  // We check if the port would be valid by adding the scheme to handle the case host:port
3809  // where the host would be interpreted as the scheme
3810  if (url.isValid()
3811  && !url.scheme().isEmpty()
3812  && urlPrepended.port() == -1)
3813  return adjustFtpPath(url);
3814 
3815  // Else, try the prepended one and adjust the scheme from the host name
3816  if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) {
3817  int dotIndex = trimmedString.indexOf(QLatin1Char('.'));
3818  const QStringView hostscheme = QStringView{trimmedString}.left(dotIndex);
3819  if (hostscheme.compare(ftpScheme(), Qt::CaseInsensitive) == 0)
3820  urlPrepended.setScheme(ftpScheme());
3821  return adjustFtpPath(urlPrepended);
3822  }
3823 
3824  return QUrl();
3825 }
3826 
small capitals from c petite p scientific f u
Definition: afcover.h:88
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
const char msg[]
Definition: arch.cpp:46
#define value
[5]
const char const char FT_Int * supplement
Definition: cffdrivr.c:699
FT_Error error
Definition: cffdrivr.c:657
The QAtomicInt class provides platform-independent atomic operations on int.
Definition: qatomic.h:158
bool ref() noexcept
Definition: qbasicatomic.h:101
bool deref() noexcept
Definition: qbasicatomic.h:102
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
qsizetype size() const noexcept
Definition: qbytearray.h:470
static QByteArray fromPercentEncoding(const QByteArray &pctEncoded, char percent='%')
QByteArray toPercentEncoding(const QByteArray &exclude=QByteArray(), const QByteArray &include=QByteArray(), char percent='%') const
constexpr qsizetype length() const noexcept
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
@ Null
Definition: qchar.h:87
constexpr char16_t unicode() const noexcept
Definition: qchar.h:489
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:66
operator<<(QDataStream &ds, qfloat16 f)
Definition: qfloat16.cpp:327
The QDebug class provides an output stream for debugging information.
Definition: qdebug.h:65
Convenience class for custom QDebug operators.
Definition: qdebug.h:176
The QDir class provides access to directory structures and their contents.
Definition: qdir.h:55
static bool isAbsolutePath(const QString &path)
Definition: qdir.h:211
@ DefaultNormalization
Definition: qdir_p.h:65
@ RemotePath
Definition: qdir_p.h:67
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:57
QString absoluteFilePath() const
Definition: qfileinfo.cpp:556
bool exists() const
Definition: qfileinfo.cpp:697
template< typename Enum > size_t qHash(QFlags< Enum > flags, size_t seed=0) noexcept
size_t qHash(const QUrl &url, size_t seed) noexcept
Definition: qurl.cpp:3700
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
QString arg(Args &&...args) const
qsizetype size() const noexcept
Definition: qlist.h:414
void reserve(qsizetype size)
Definition: qlist.h:757
void append(parameter_type t)
Definition: qlist.h:469
The QString class provides a Unicode character string.
Definition: qstring.h:388
QString right(qsizetype n) const
Definition: qstring.cpp:4970
iterator begin()
Definition: qstring.h:1331
QByteArray toLatin1() const &
Definition: qstring.h:745
QString & prepend(QChar c)
Definition: qstring.h:656
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.h:514
const_iterator constEnd() const
Definition: qstring.h:1345
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5092
void reserve(qsizetype size)
Definition: qstring.h:1307
static QString fromLatin1(QByteArrayView ba)
Definition: qstring.cpp:5488
void truncate(qsizetype pos)
Definition: qstring.cpp:5934
void clear()
Definition: qstring.h:1240
bool isNull() const
Definition: qstring.h:1078
qsizetype size() const
Definition: qstring.h:413
static QString fromUtf8(QByteArrayView utf8)
Definition: qstring.cpp:5632
QString mid(qsizetype position, qsizetype n=-1) const
Definition: qstring.cpp:4994
iterator end()
Definition: qstring.h:1339
void detach()
Definition: qstring.h:1236
const QChar at(qsizetype i) const
Definition: qstring.h:1212
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:5143
bool isEmpty() const
Definition: qstring.h:1216
int compare(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstring.cpp:6263
QChar * data()
Definition: qstring.h:1228
static QString number(int, int base=10)
Definition: qstring.cpp:7538
QString left(qsizetype n) const
Definition: qstring.cpp:4951
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:4197
QString trimmed() const &
Definition: qstring.h:623
QString & remove(qsizetype i, qsizetype len)
Definition: qstring.cpp:3252
const_iterator constBegin() const
Definition: qstring.h:1337
qsizetype length() const
Definition: qstring.h:415
The QStringList class provides a list of strings.
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
constexpr void truncate(qsizetype n) noexcept
Definition: qstringview.h:291
constexpr qsizetype length() const noexcept
Definition: qstringview.h:464
constexpr void chop(qsizetype n) noexcept
Definition: qstringview.h:293
constexpr bool isEmpty() const noexcept
Definition: qstringview.h:463
constexpr qsizetype size() const noexcept
Definition: qstringview.h:239
constexpr QStringView left(qsizetype n) const noexcept
Definition: qstringview.h:267
bool endsWith(QStringView s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstringview.h:320
QString toString() const
Definition: qstring.h:1165
int compare(QStringView other, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition: qstringview.h:304
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Definition: qstringview.h:261
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:130
static QUrl fromLocalFile(const QString &localfile)
Definition: qurl.cpp:3373
QString userInfo(ComponentFormattingOptions options=PrettyDecoded) const
Definition: qurl.cpp:2149
bool hasQuery() const
Definition: qurl.cpp:2533
static QList< QUrl > fromStringList(const QStringList &uris, ParsingMode mode=TolerantMode)
Definition: qurl.cpp:3674
QString fragment(ComponentFormattingOptions options=PrettyDecoded) const
Definition: qurl.cpp:2702
QUrl()
Definition: qurl.cpp:1866
bool operator!=(const QUrl &url) const
Definition: qurl.cpp:3255
bool matches(const QUrl &url, FormattingOptions options) const
Definition: qurl.cpp:3183
bool isLocalFile() const
Definition: qurl.cpp:3450
QString url(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Definition: qurl.cpp:2837
QString query(ComponentFormattingOptions=PrettyDecoded) const
Definition: qurl.cpp:2629
static QByteArray toAce(const QString &domain, AceProcessingOptions options={})
Definition: qurl.cpp:3080
bool operator<(const QUrl &url) const
Definition: qurl.cpp:3092
QUrl & operator=(const QUrl &copy)
Definition: qurl.cpp:3263
QString fileName(ComponentFormattingOptions options=FullyDecoded) const
Definition: qurl.cpp:2517
static QStringList toStringList(const QList< QUrl > &uris, FormattingOptions options=FormattingOptions(PrettyDecoded))
Definition: qurl.cpp:3658
QUrl resolved(const QUrl &relative) const
Definition: qurl.cpp:2745
void setPassword(const QString &password, ParsingMode mode=DecodedMode)
Definition: qurl.cpp:2247
void setUserName(const QString &userName, ParsingMode mode=DecodedMode)
Definition: qurl.cpp:2184
void setFragment(const QString &fragment, ParsingMode mode=TolerantMode)
Definition: qurl.cpp:2668
bool hasFragment() const
Definition: qurl.cpp:2720
static QString fromPercentEncoding(const QByteArray &)
Definition: qurl.cpp:3017
bool isRelative() const
Definition: qurl.cpp:2820
bool isDetached() const
Definition: qurl.cpp:3317
bool isValid() const
Definition: qurl.cpp:1897
~QUrl()
Definition: qurl.cpp:1882
QString userName(ComponentFormattingOptions options=FullyDecoded) const
Definition: qurl.cpp:2219
QString host(ComponentFormattingOptions=FullyDecoded) const
Definition: qurl.cpp:2360
void setQuery(const QString &query, ParsingMode mode=TolerantMode)
Definition: qurl.cpp:2570
static QUrl fromUserInput(const QString &userInput, const QString &workingDirectory=QString(), UserInputResolutionOptions options=DefaultResolution)
Definition: qurl.cpp:3771
bool operator==(const QUrl &url) const
Definition: qurl.cpp:3146
@ AssumeLocalFile
Definition: qurl.h:208
void detach()
Definition: qurl.cpp:3306
QByteArray toEncoded(FormattingOptions options=FullyEncoded) const
Definition: qurl.cpp:2987
QString password(ComponentFormattingOptions=FullyDecoded) const
Definition: qurl.cpp:2282
ParsingMode
Definition: qurl.h:132
@ DecodedMode
Definition: qurl.h:135
@ TolerantMode
Definition: qurl.h:133
@ StrictMode
Definition: qurl.h:134
bool isEmpty() const
Definition: qurl.cpp:1911
static QByteArray toPercentEncoding(const QString &, const QByteArray &exclude=QByteArray(), const QByteArray &include=QByteArray())
Definition: qurl.cpp:3035
void setUrl(const QString &url, ParsingMode mode=TolerantMode)
Definition: qurl.cpp:1949
QString authority(ComponentFormattingOptions options=PrettyDecoded) const
Definition: qurl.cpp:2075
bool isParentOf(const QUrl &url) const
Definition: qurl.cpp:3460
QUrl adjusted(FormattingOptions options) const
Definition: qurl.cpp:2944
QString scheme() const
Definition: qurl.cpp:2006
static QUrl fromEncoded(const QByteArray &url, ParsingMode mode=TolerantMode)
Definition: qurl.cpp:3004
void setScheme(const QString &scheme)
Definition: qurl.cpp:1982
void clear()
Definition: qurl.cpp:1924
QString errorString() const
Definition: qurl.cpp:3618
@ RemovePassword
Definition: qurl.h:142
@ RemoveScheme
Definition: qurl.h:141
@ StripTrailingSlash
Definition: qurl.h:151
@ RemoveFragment
Definition: qurl.h:148
@ RemoveQuery
Definition: qurl.h:147
@ RemoveFilename
Definition: qurl.h:152
@ PreferLocalFile
Definition: qurl.h:150
@ NormalizePathSegments
Definition: qurl.h:153
@ RemovePath
Definition: qurl.h:146
@ RemoveUserInfo
Definition: qurl.h:143
@ RemoveAuthority
Definition: qurl.h:145
@ RemovePort
Definition: qurl.h:144
static QString fromAce(const QByteArray &domain, AceProcessingOptions options={})
Definition: qurl.cpp:3057
void setHost(const QString &host, ParsingMode mode=DecodedMode)
Definition: qurl.cpp:2309
int port(int defaultPort=-1) const
Definition: qurl.cpp:2403
void setAuthority(const QString &authority, ParsingMode mode=TolerantMode)
Definition: qurl.cpp:2042
@ PrettyDecoded
Definition: qurl.h:157
@ EncodeReserved
Definition: qurl.h:161
@ FullyDecoded
Definition: qurl.h:166
@ EncodeDelimiters
Definition: qurl.h:160
@ EncodeUnicode
Definition: qurl.h:159
@ DecodeReserved
Definition: qurl.h:162
@ FullyEncoded
Definition: qurl.h:165
QDataStream & operator>>(QDataStream &in, QUrl &url)
Definition: qurl.cpp:3504
void setUserInfo(const QString &userInfo, ParsingMode mode=TolerantMode)
Definition: qurl.cpp:2113
void setPath(const QString &path, ParsingMode mode=DecodedMode)
Definition: qurl.cpp:2434
QString toDisplayString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Definition: qurl.cpp:2926
QString toString(FormattingOptions options=FormattingOptions(PrettyDecoded)) const
Definition: qurl.cpp:2851
void setPort(int port)
Definition: qurl.cpp:2378
QDataStream & operator<<(QDataStream &out, const QUrl &url)
Definition: qurl.cpp:3488
QString toLocalFile() const
Definition: qurl.cpp:3430
QString path(ComponentFormattingOptions options=FullyDecoded) const
Definition: qurl.cpp:2488
bool isEmpty() const
Definition: qurl.cpp:538
bool setScheme(const QString &value, int len, bool doSetError)
Definition: qurl.cpp:978
QAtomicInt ref
Definition: qurl.cpp:586
void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const
Definition: qurl.cpp:932
bool hasScheme() const
Definition: qurl.cpp:570
void setPath(const QString &value, int from, int end)
Definition: qurl.cpp:1137
void appendHost(QString &appendTo, QUrl::FormattingOptions options) const
Definition: qurl.cpp:1185
void setFragment(const QString &value, int from, int end)
Definition: qurl.cpp:1143
ErrorCode validityError(QString *source=nullptr, int *position=nullptr) const
Definition: qurl.cpp:1637
QString host
Definition: qurl.cpp:592
uchar sectionIsPresent
Definition: qurl.cpp:603
std::unique_ptr< Error > cloneError() const
Definition: qurl.cpp:635
bool hasPort() const
Definition: qurl.cpp:576
void setPassword(const QString &value, int from, int end)
Definition: qurl.cpp:1131
QString toLocalFile(QUrl::FormattingOptions options) const
Definition: qurl.cpp:1498
std::unique_ptr< Error > error
Definition: qurl.cpp:597
void setError(ErrorCode errorCode, const QString &source, int supplement=-1)
Definition: qurl.cpp:645
bool hasQuery() const
Definition: qurl.cpp:578
bool hasUserInfo() const
Definition: qurl.cpp:572
QString mergePaths(const QString &relativePath) const
Definition: qurl.cpp:1533
bool isLocalFile() const
Definition: qurl.cpp:581
@ InvalidIPv6AddressError
Definition: qurl.cpp:504
@ InvalidIPv4AddressError
Definition: qurl.cpp:503
@ InvalidCharacterInIPv6Error
Definition: qurl.cpp:505
@ InvalidPasswordError
Definition: qurl.cpp:500
@ InvalidPathError
Definition: qurl.cpp:512
@ InvalidSchemeError
Definition: qurl.cpp:496
@ InvalidIPvFutureError
Definition: qurl.cpp:506
@ InvalidUserNameError
Definition: qurl.cpp:498
@ PortEmptyError
Definition: qurl.cpp:510
@ InvalidFragmentError
Definition: qurl.cpp:516
@ AuthorityPresentAndPathIsRelative
Definition: qurl.cpp:520
@ AuthorityAbsentAndPathIsDoubleSlash
Definition: qurl.cpp:521
@ InvalidPortError
Definition: qurl.cpp:509
@ RelativeUrlPathContainsColonBeforeSlash
Definition: qurl.cpp:522
@ InvalidRegNameError
Definition: qurl.cpp:502
@ InvalidQueryError
Definition: qurl.cpp:514
@ HostMissingEndBracket
Definition: qurl.cpp:507
QString path
Definition: qurl.cpp:593
bool hasPath() const
Definition: qurl.cpp:577
QUrlPrivate()
Definition: qurl.cpp:610
void clearError()
Definition: qurl.cpp:640
void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition: qurl.cpp:866
uchar flags
Definition: qurl.cpp:604
@ IsLocalFile
Definition: qurl.cpp:490
QString scheme
Definition: qurl.cpp:589
void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const
Definition: qurl.cpp:925
void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition: qurl.cpp:880
int port
Definition: qurl.cpp:587
bool hasFragment() const
Definition: qurl.cpp:579
void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition: qurl.cpp:939
bool validateComponent(Section section, const QString &input)
Definition: qurl.cpp:546
void setUserInfo(const QString &userInfo, int from, int end)
Definition: qurl.cpp:1112
void setUserName(const QString &value, int from, int end)
Definition: qurl.cpp:1125
bool hasUserName() const
Definition: qurl.cpp:573
void setQuery(const QString &value, int from, int end)
Definition: qurl.cpp:1149
QString fragment
Definition: qurl.cpp:595
QString query
Definition: qurl.cpp:594
QString userName
Definition: qurl.cpp:590
bool hasAuthority() const
Definition: qurl.cpp:571
bool hasHost() const
Definition: qurl.cpp:575
void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition: qurl.cpp:970
QString password
Definition: qurl.cpp:591
void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const
Definition: qurl.cpp:963
bool validateComponent(Section section, const QString &input, int begin, int end)
Definition: qurl.cpp:1702
bool hasPassword() const
Definition: qurl.cpp:574
bool setHost(const QString &value, int from, int end, QUrl::ParsingMode mode)
Definition: qurl.cpp:1304
void parse(const QString &url, QUrl::ParsingMode parsingMode)
Definition: qurl.cpp:1395
@ Hierarchy
Definition: qurl.cpp:483
@ UserName
Definition: qurl.cpp:476
@ UserInfo
Definition: qurl.cpp:478
@ Password
Definition: qurl.cpp:477
@ Fragment
Definition: qurl.cpp:485
@ Authority
Definition: qurl.cpp:481
void setAuthority(const QString &auth, int from, int end, QUrl::ParsingMode mode)
Definition: qurl.cpp:1043
The QUrlQuery class provides a way to manipulate a key-value pairs in a URL's query.
Definition: qurlquery.h:56
constexpr bool testFlag(E1 f) const
Definition: qurl.h:118
QHash< int, QWidget * > hash
[35multi]
QString str
[2]
QString text
[meta data]
QHighDpiScaling::Point position(T, QHighDpiScaling::Point::Kind)
quint8 IPv6Address[16]
Definition: qipaddress_p.h:62
void toString(QString &appendTo, IPv4Address address)
Definition: qipaddress.cpp:131
bool parseIp4(IPv4Address &address, const QChar *begin, const QChar *end)
Definition: qipaddress.cpp:75
quint32 IPv4Address
Definition: qipaddress_p.h:61
const QChar * parseIp6(IPv6Address &address, const QChar *begin, const QChar *end)
Definition: qipaddress.cpp:154
@ CaseInsensitive
Definition: qnamespace.h:1283
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION QByteArrayView trimmed(QByteArrayView s) noexcept
#define QString()
Definition: parse-defines.h:51
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld endif[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1 beq endif SRC MASK if dst_r_bpp DST_R else add endif PF add sub src_basereg pixdeinterleave mask_basereg pixdeinterleave dst_r_basereg process_pixblock_head pixblock_size cache_preload_simple process_pixblock_tail pixinterleave dst_w_basereg irp beq endif process_pixblock_tail_head tst beq irp if pixblock_size chunk_size tst beq pixld SRC pixld MASK if DST_R else pixld DST_R endif if
QT_WARNING_POP void qAtomicAssign(T *&d, T *x)
Definition: qatomic.h:241
void qAtomicDetach(T *&d)
Definition: qatomic.h:260
#define Q_LIKELY(x)
#define Q_UNREACHABLE()
QString qt_normalizePathSegments(const QString &name, QDirPrivate::PathNormalizations flags, bool *ok)
Definition: qdir.cpp:2159
EGLOutputPortEXT port
EGLOutputLayerEXT EGLint EGLAttrib value
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
unsigned long ulong
Definition: qglobal.h:335
unsigned int uint
Definition: qglobal.h:334
unsigned short ushort
Definition: qglobal.h:333
#define qDebug
[1]
Definition: qlogging.h:177
#define qWarning
Definition: qlogging.h:179
GLenum GLuint GLenum GLsizei length
Definition: qopengl.h:270
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum GLenum dst
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
Definition: qopenglext.h:2738
const GLubyte * c
Definition: qopenglext.h:12701
GLenum GLsizei len
Definition: qopenglext.h:3292
GLdouble GLdouble t
[9]
Definition: qopenglext.h:243
GLuint in
Definition: qopenglext.h:8870
GLuint GLuint64EXT address
Definition: qopenglext.h:11428
GLsizei const GLchar *const * path
Definition: qopenglext.h:4283
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLdouble s
[6]
Definition: qopenglext.h:235
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
GLenum GLenum GLenum input
Definition: qopenglext.h:10816
#define Q_ASSERT(cond)
Definition: qrandom.cpp:84
#define Q_ASSERT_X(cond, x, msg)
Definition: qrandom.cpp:85
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QStringLiteral(str)
QT_BEGIN_NAMESPACE void qt_from_latin1(char16_t *dst, const char *str, size_t size) noexcept
Definition: qstring.cpp:783
QT_BEGIN_NAMESPACE Q_AUTOTEST_EXPORT qsizetype qt_urlRecode(QString &appendTo, QStringView url, QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications=nullptr)
Definition: qurlrecode.cpp:674
QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot, QUrl::AceProcessingOptions options)
Definition: qurlidna.cpp:923
@ AllowLeadingDot
Definition: qurl_p.h:66
@ ForbidLeadingDot
Definition: qurl_p.h:66
@ ToAceOnly
Definition: qurl_p.h:67
@ NormalizeAce
Definition: qurl_p.h:67
#define decode(x)
Definition: qurlquery.cpp:242
#define encode(x)
Definition: qurlquery.cpp:244
#define leave(x)
Definition: qurlquery.cpp:243
ErrorCode
Definition: main.cpp:3133
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QUrl url("http://www.example.com/List of holidays.xml")
[0]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
void ref() noexcept
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:53
QString source
Definition: qurl.cpp:528
ErrorCode code
Definition: qurl.cpp:529
Definition: main.cpp:38
T1_FIELD_DICT_PRIVATE password
Definition: t1tokens.h:64
@ Fragment
Definition: tst_qurl.cpp:3709
@ Authority
Definition: tst_qurl.cpp:3705
@ Query
Definition: tst_qurl.cpp:3708
@ Password
Definition: tst_qurl.cpp:3701
@ UserInfo
Definition: tst_qurl.cpp:3702
@ Host
Definition: tst_qurl.cpp:3703
@ Port
Definition: tst_qurl.cpp:3704
@ Scheme
Definition: tst_qurl.cpp:3699
@ UserName
Definition: tst_qurl.cpp:3700