| 1 | // Copyright (C) 2016 The Qt Company Ltd. | 
| 2 | // Copyright (C) 2016 Intel Corporation. | 
| 3 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only | 
| 4 |  | 
| 5 | /*! | 
| 6 |     \class QUrl | 
| 7 |     \inmodule QtCore | 
| 8 |  | 
| 9 |     \brief The QUrl class provides a convenient interface for working | 
| 10 |     with URLs. | 
| 11 |  | 
| 12 |     \reentrant | 
| 13 |     \ingroup io | 
| 14 |     \ingroup network | 
| 15 |     \ingroup shared | 
| 16 |  | 
| 17 |     \compares weak | 
| 18 |  | 
| 19 |     It can parse and construct URLs in both encoded and unencoded | 
| 20 |     form. QUrl also has support for internationalized domain names | 
| 21 |     (IDNs). | 
| 22 |  | 
| 23 |     The most common way to use QUrl is to initialize it via the constructor by | 
| 24 |     passing a QString containing a full URL. QUrl objects can also be created | 
| 25 |     from a QByteArray containing a full URL using QUrl::fromEncoded(), or | 
| 26 |     heuristically from incomplete URLs using QUrl::fromUserInput(). The URL | 
| 27 |     representation can be obtained from a QUrl using either QUrl::toString() or | 
| 28 |     QUrl::toEncoded(). | 
| 29 |  | 
| 30 |     URLs can be represented in two forms: encoded or unencoded. The | 
| 31 |     unencoded representation is suitable for showing to users, but | 
| 32 |     the encoded representation is typically what you would send to | 
| 33 |     a web server. For example, the unencoded URL | 
| 34 |     "http://bühler.example.com/List of applicants.xml" | 
| 35 |     would be sent to the server as | 
| 36 |     "http://xn--bhler-kva.example.com/List%20of%20applicants.xml". | 
| 37 |  | 
| 38 |     A URL can also be constructed piece by piece by calling | 
| 39 |     setScheme(), setUserName(), setPassword(), setHost(), setPort(), | 
| 40 |     setPath(), setQuery() and setFragment(). Some convenience | 
| 41 |     functions are also available: setAuthority() sets the user name, | 
| 42 |     password, host and port. setUserInfo() sets the user name and | 
| 43 |     password at once. | 
| 44 |  | 
| 45 |     Call isValid() to check if the URL is valid. This can be done at any point | 
| 46 |     during the constructing of a URL. If isValid() returns \c false, you should | 
| 47 |     clear() the URL before proceeding, or start over by parsing a new URL with | 
| 48 |     setUrl(). | 
| 49 |  | 
| 50 |     Constructing a query is particularly convenient through the use of the \l | 
| 51 |     QUrlQuery class and its methods QUrlQuery::setQueryItems(), | 
| 52 |     QUrlQuery::addQueryItem() and QUrlQuery::removeQueryItem(). Use | 
| 53 |     QUrlQuery::setQueryDelimiters() to customize the delimiters used for | 
| 54 |     generating the query string. | 
| 55 |  | 
| 56 |     For the convenience of generating encoded URL strings or query | 
| 57 |     strings, there are two static functions called | 
| 58 |     fromPercentEncoding() and toPercentEncoding() which deal with | 
| 59 |     percent encoding and decoding of QString objects. | 
| 60 |  | 
| 61 |     fromLocalFile() constructs a QUrl by parsing a local | 
| 62 |     file path. toLocalFile() converts a URL to a local file path. | 
| 63 |  | 
| 64 |     The human readable representation of the URL is fetched with | 
| 65 |     toString(). This representation is appropriate for displaying a | 
| 66 |     URL to a user in unencoded form. The encoded form however, as | 
| 67 |     returned by toEncoded(), is for internal use, passing to web | 
| 68 |     servers, mail clients and so on. Both forms are technically correct | 
| 69 |     and represent the same URL unambiguously -- in fact, passing either | 
| 70 |     form to QUrl's constructor or to setUrl() will yield the same QUrl | 
| 71 |     object. | 
| 72 |  | 
| 73 |     QUrl conforms to the URI specification from | 
| 74 |     \l{RFC 3986} (Uniform Resource Identifier: Generic Syntax), and includes | 
| 75 |     scheme extensions from \l{RFC 1738} (Uniform Resource Locators). Case | 
| 76 |     folding rules in QUrl conform to \l{RFC 3491} (Nameprep: A Stringprep | 
| 77 |     Profile for Internationalized Domain Names (IDN)). It is also compatible with the | 
| 78 |     \l{http://freedesktop.org/wiki/Specifications/file-uri-spec/}{file URI specification} | 
| 79 |     from freedesktop.org, provided that the locale encodes file names using | 
| 80 |     UTF-8 (required by IDN). | 
| 81 |  | 
| 82 |     \section2 Relative URLs vs Relative Paths | 
| 83 |  | 
| 84 |     Calling isRelative() will return whether or not the URL is relative. | 
| 85 |     A relative URL has no \l {scheme}. For example: | 
| 86 |  | 
| 87 |     \snippet code/src_corelib_io_qurl.cpp 8 | 
| 88 |  | 
| 89 |     Notice that a URL can be absolute while containing a relative path, and | 
| 90 |     vice versa: | 
| 91 |  | 
| 92 |     \snippet code/src_corelib_io_qurl.cpp 9 | 
| 93 |  | 
| 94 |     A relative URL can be resolved by passing it as an argument to resolved(), | 
| 95 |     which returns an absolute URL. isParentOf() is used for determining whether | 
| 96 |     one URL is a parent of another. | 
| 97 |  | 
| 98 |     \section2 Error checking | 
| 99 |  | 
| 100 |     QUrl is capable of detecting many errors in URLs while parsing it or when | 
| 101 |     components of the URL are set with individual setter methods (like | 
| 102 |     setScheme(), setHost() or setPath()). If the parsing or setter function is | 
| 103 |     successful, any previously recorded error conditions will be discarded. | 
| 104 |  | 
| 105 |     By default, QUrl setter methods operate in QUrl::TolerantMode, which means | 
| 106 |     they accept some common mistakes and mis-representation of data. An | 
| 107 |     alternate method of parsing is QUrl::StrictMode, which applies further | 
| 108 |     checks. See QUrl::ParsingMode for a description of the difference of the | 
| 109 |     parsing modes. | 
| 110 |  | 
| 111 |     QUrl only checks for conformance with the URL specification. It does not | 
| 112 |     try to verify that high-level protocol URLs are in the format they are | 
| 113 |     expected to be by handlers elsewhere. For example, the following URIs are | 
| 114 |     all considered valid by QUrl, even if they do not make sense when used: | 
| 115 |  | 
| 116 |     \list | 
| 117 |       \li "http:/filename.html" | 
| 118 |       \li "mailto://example.com" | 
| 119 |     \endlist | 
| 120 |  | 
| 121 |     When the parser encounters an error, it signals the event by making | 
| 122 |     isValid() return false and toString() / toEncoded() return an empty string. | 
| 123 |     If it is necessary to show the user the reason why the URL failed to parse, | 
| 124 |     the error condition can be obtained from QUrl by calling errorString(). | 
| 125 |     Note that this message is highly technical and may not make sense to | 
| 126 |     end-users. | 
| 127 |  | 
| 128 |     QUrl is capable of recording only one error condition. If more than one | 
| 129 |     error is found, it is undefined which error is reported. | 
| 130 |  | 
| 131 |     \section2 Character Conversions | 
| 132 |  | 
| 133 |     Follow these rules to avoid erroneous character conversion when | 
| 134 |     dealing with URLs and strings: | 
| 135 |  | 
| 136 |     \list | 
| 137 |     \li When creating a QString to contain a URL from a QByteArray or a | 
| 138 |        char*, always use QString::fromUtf8(). | 
| 139 |     \endlist | 
| 140 | */ | 
| 141 |  | 
| 142 | /*! | 
| 143 |     \enum QUrl::ParsingMode | 
| 144 |  | 
| 145 |     The parsing mode controls the way QUrl parses strings. | 
| 146 |  | 
| 147 |     \value TolerantMode QUrl will try to correct some common errors in URLs. | 
| 148 |                         This mode is useful for parsing URLs coming from sources | 
| 149 |                         not known to be strictly standards-conforming. | 
| 150 |  | 
| 151 |     \value StrictMode Only valid URLs are accepted. This mode is useful for | 
| 152 |                       general URL validation. | 
| 153 |  | 
| 154 |     \value DecodedMode QUrl will interpret the URL component in the fully-decoded form, | 
| 155 |                        where percent characters stand for themselves, not as the beginning | 
| 156 |                        of a percent-encoded sequence. This mode is only valid for the | 
| 157 |                        setters setting components of a URL; it is not permitted in | 
| 158 |                        the QUrl constructor, in fromEncoded() or in setUrl(). | 
| 159 |                        For more information on this mode, see the documentation for | 
| 160 |                        \l {QUrl::ComponentFormattingOption}{QUrl::FullyDecoded}. | 
| 161 |  | 
| 162 |     In TolerantMode, the parser has the following behaviour: | 
| 163 |  | 
| 164 |     \list | 
| 165 |  | 
| 166 |     \li Spaces and "%20": unencoded space characters will be accepted and will | 
| 167 |     be treated as equivalent to "%20". | 
| 168 |  | 
| 169 |     \li Single "%" characters: Any occurrences of a percent character "%" not | 
| 170 |     followed by exactly two hexadecimal characters (e.g., "13% coverage.html") | 
| 171 |     will be replaced by "%25". Note that one lone "%" character will trigger | 
| 172 |     the correction mode for all percent characters. | 
| 173 |  | 
| 174 |     \li Reserved and unreserved characters: An encoded URL should only | 
| 175 |     contain a few characters as literals; all other characters should | 
| 176 |     be percent-encoded. In TolerantMode, these characters will be | 
| 177 |     accepted if they are found in the URL: | 
| 178 |             space / double-quote / "<" / ">" / "\" / | 
| 179 |             "^" / "`" / "{" / "|" / "}" | 
| 180 |     Those same characters can be decoded again by passing QUrl::DecodeReserved | 
| 181 |     to toString() or toEncoded(). In the getters of individual components, | 
| 182 |     those characters are often returned in decoded form. | 
| 183 |  | 
| 184 |     \endlist | 
| 185 |  | 
| 186 |     When in StrictMode, if a parsing error is found, isValid() will return \c | 
| 187 |     false and errorString() will return a message describing the error. | 
| 188 |     If more than one error is detected, it is undefined which error gets | 
| 189 |     reported. | 
| 190 |  | 
| 191 |     Note that TolerantMode is not usually enough for parsing user input, which | 
| 192 |     often contains more errors and expectations than the parser can deal with. | 
| 193 |     When dealing with data coming directly from the user -- as opposed to data | 
| 194 |     coming from data-transfer sources, such as other programs -- it is | 
| 195 |     recommended to use fromUserInput(). | 
| 196 |  | 
| 197 |     \sa fromUserInput(), setUrl(), toString(), toEncoded(), QUrl::FormattingOptions | 
| 198 | */ | 
| 199 |  | 
| 200 | /*! | 
| 201 |     \enum QUrl::UrlFormattingOption | 
| 202 |  | 
| 203 |     The formatting options define how the URL is formatted when written out | 
| 204 |     as text. | 
| 205 |  | 
| 206 |     \value None The format of the URL is unchanged. | 
| 207 |     \value RemoveScheme  The scheme is removed from the URL. | 
| 208 |     \value RemovePassword  Any password in the URL is removed. | 
| 209 |     \value RemoveUserInfo  Any user information in the URL is removed. | 
| 210 |     \value RemovePort      Any specified port is removed from the URL. | 
| 211 |     \value RemoveAuthority | 
| 212 |     \value RemovePath   The URL's path is removed, leaving only the scheme, | 
| 213 |                         host address, and port (if present). | 
| 214 |     \value RemoveQuery  The query part of the URL (following a '?' character) | 
| 215 |                         is removed. | 
| 216 |     \value RemoveFragment | 
| 217 |     \value RemoveFilename The filename (i.e. everything after the last '/' in the path) is removed. | 
| 218 |             The trailing '/' is kept, unless StripTrailingSlash is set. | 
| 219 |             Only valid if RemovePath is not set. | 
| 220 |     \value PreferLocalFile If the URL is a local file according to isLocalFile() | 
| 221 |      and contains no query or fragment, a local file path is returned. | 
| 222 |     \value StripTrailingSlash  The trailing slash is removed from the path, if one is present. | 
| 223 |     \value NormalizePathSegments  Modifies the path to remove redundant directory separators, | 
| 224 |              and to resolve "."s and ".."s (as far as possible). For non-local paths, adjacent | 
| 225 |              slashes are preserved. | 
| 226 |  | 
| 227 |     Note that the case folding rules in \l{RFC 3491}{Nameprep}, which QUrl | 
| 228 |     conforms to, require host names to always be converted to lower case, | 
| 229 |     regardless of the Qt::FormattingOptions used. | 
| 230 |  | 
| 231 |     The options from QUrl::ComponentFormattingOptions are also possible. | 
| 232 |  | 
| 233 |     \sa QUrl::ComponentFormattingOptions | 
| 234 | */ | 
| 235 |  | 
| 236 | /*! | 
| 237 |     \enum QUrl::ComponentFormattingOption | 
| 238 |     \since 5.0 | 
| 239 |  | 
| 240 |     The component formatting options define how the components of an URL will | 
| 241 |     be formatted when written out as text. They can be combined with the | 
| 242 |     options from QUrl::FormattingOptions when used in toString() and | 
| 243 |     toEncoded(). | 
| 244 |  | 
| 245 |     \value PrettyDecoded   The component is returned in a "pretty form", with | 
| 246 |                            most percent-encoded characters decoded. The exact | 
| 247 |                            behavior of PrettyDecoded varies from component to | 
| 248 |                            component and may also change from Qt release to Qt | 
| 249 |                            release. This is the default. | 
| 250 |  | 
| 251 |     \value EncodeSpaces    Leave space characters in their encoded form ("%20"). | 
| 252 |  | 
| 253 |     \value EncodeUnicode   Leave non-US-ASCII characters encoded in their UTF-8 | 
| 254 |                            percent-encoded form (e.g., "%C3%A9" for the U+00E9 | 
| 255 |                            codepoint, LATIN SMALL LETTER E WITH ACUTE). | 
| 256 |  | 
| 257 |     \value EncodeDelimiters Leave certain delimiters in their encoded form, as | 
| 258 |                             would appear in the URL when the full URL is | 
| 259 |                             represented as text. The delimiters are affected | 
| 260 |                             by this option change from component to component. | 
| 261 |                             This flag has no effect in toString() or toEncoded(). | 
| 262 |  | 
| 263 |     \value EncodeReserved  Leave US-ASCII characters not permitted in the URL by | 
| 264 |                            the specification in their encoded form. This is the | 
| 265 |                            default on toString() and toEncoded(). | 
| 266 |  | 
| 267 |     \value DecodeReserved  Decode the US-ASCII characters that the URL specification | 
| 268 |                            does not allow to appear in the URL. This is the | 
| 269 |                            default on the getters of individual components. | 
| 270 |  | 
| 271 |     \value FullyEncoded    Leave all characters in their properly-encoded form, | 
| 272 |                            as this component would appear as part of a URL. When | 
| 273 |                            used with toString(), this produces a fully-compliant | 
| 274 |                            URL in QString form, exactly equal to the result of | 
| 275 |                            toEncoded() | 
| 276 |  | 
| 277 |     \value FullyDecoded    Attempt to decode as much as possible. For individual | 
| 278 |                            components of the URL, this decodes every percent | 
| 279 |                            encoding sequence, including control characters (U+0000 | 
| 280 |                            to U+001F) and UTF-8 sequences found in percent-encoded form. | 
| 281 |                            Use of this mode may cause data loss, see below for more information. | 
| 282 |  | 
| 283 |     The values of EncodeReserved and DecodeReserved should not be used together | 
| 284 |     in one call. The behavior is undefined if that happens. They are provided | 
| 285 |     as separate values because the behavior of the "pretty mode" with regards | 
| 286 |     to reserved characters is different on certain components and specially on | 
| 287 |     the full URL. | 
| 288 |  | 
| 289 |     \section2 Full decoding | 
| 290 |  | 
| 291 |     The FullyDecoded mode is similar to the behavior of the functions returning | 
| 292 |     QString in Qt 4.x, in that every character represents itself and never has | 
| 293 |     any special meaning. This is true even for the percent character ('%'), | 
| 294 |     which should be interpreted to mean a literal percent, not the beginning of | 
| 295 |     a percent-encoded sequence. The same actual character, in all other | 
| 296 |     decoding modes, is represented by the sequence "%25". | 
| 297 |  | 
| 298 |     Whenever re-applying data obtained with QUrl::FullyDecoded into a QUrl, | 
| 299 |     care must be taken to use the QUrl::DecodedMode parameter to the setters | 
| 300 |     (like setPath() and setUserName()). Failure to do so may cause | 
| 301 |     re-interpretation of the percent character ('%') as the beginning of a | 
| 302 |     percent-encoded sequence. | 
| 303 |  | 
| 304 |     This mode is quite useful when portions of a URL are used in a non-URL | 
| 305 |     context. For example, to extract the username, password or file paths in an | 
| 306 |     FTP client application, the FullyDecoded mode should be used. | 
| 307 |  | 
| 308 |     This mode should be used with care, since there are two conditions that | 
| 309 |     cannot be reliably represented in the returned QString. They are: | 
| 310 |  | 
| 311 |     \list | 
| 312 |       \li \b{Non-UTF-8 sequences:} URLs may contain sequences of | 
| 313 |       percent-encoded characters that do not form valid UTF-8 sequences. Since | 
| 314 |       URLs need to be decoded using UTF-8, any decoder failure will result in | 
| 315 |       the QString containing one or more replacement characters where the | 
| 316 |       sequence existed. | 
| 317 |  | 
| 318 |       \li \b{Encoded delimiters:} URLs are also allowed to make a distinction | 
| 319 |       between a delimiter found in its literal form and its equivalent in | 
| 320 |       percent-encoded form. This is most commonly found in the query, but is | 
| 321 |       permitted in most parts of the URL. | 
| 322 |     \endlist | 
| 323 |  | 
| 324 |     The following example illustrates the problem: | 
| 325 |  | 
| 326 |     \snippet code/src_corelib_io_qurl.cpp 10 | 
| 327 |  | 
| 328 |     If the two URLs were used via HTTP GET, the interpretation by the web | 
| 329 |     server would probably be different. In the first case, it would interpret | 
| 330 |     as one parameter, with a key of "q" and value "a+=b&c". In the second | 
| 331 |     case, it would probably interpret as two parameters, one with a key of "q" | 
| 332 |     and value "a =b", and the second with a key "c" and no value. | 
| 333 |  | 
| 334 |     \sa QUrl::FormattingOptions | 
| 335 | */ | 
| 336 |  | 
| 337 | /*! | 
| 338 |     \enum QUrl::UserInputResolutionOption | 
| 339 |     \since 5.4 | 
| 340 |  | 
| 341 |     The user input resolution options define how fromUserInput() should | 
| 342 |     interpret strings that could either be a relative path or the short | 
| 343 |     form of a HTTP URL. For instance \c{file.pl} can be either a local file | 
| 344 |     or the URL \c{http://file.pl}. | 
| 345 |  | 
| 346 |     \value DefaultResolution  The default resolution mechanism is to check | 
| 347 |                               whether a local file exists, in the working | 
| 348 |                               directory given to fromUserInput, and only | 
| 349 |                               return a local path in that case. Otherwise a URL | 
| 350 |                               is assumed. | 
| 351 |     \value AssumeLocalFile    This option makes fromUserInput() always return | 
| 352 |                               a local path unless the input contains a scheme, such as | 
| 353 |                               \c{http://file.pl}. This is useful for applications | 
| 354 |                               such as text editors, which are able to create | 
| 355 |                               the file if it doesn't exist. | 
| 356 |  | 
| 357 |     \sa fromUserInput() | 
| 358 | */ | 
| 359 |  | 
| 360 | /*! | 
| 361 |     \enum  QUrl::AceProcessingOption | 
| 362 |     \since 6.3 | 
| 363 |  | 
| 364 |     The ACE processing options control the way URLs are transformed to and from | 
| 365 |     ASCII-Compatible Encoding. | 
| 366 |  | 
| 367 |     \value IgnoreIDNWhitelist         Ignore the IDN whitelist when converting URLs | 
| 368 |                                       to Unicode. | 
| 369 |     \value AceTransitionalProcessing  Use transitional processing described in UTS #46. | 
| 370 |                                       This allows better compatibility with IDNA 2003 | 
| 371 |                                       specification. | 
| 372 |  | 
| 373 |     The default is to use nontransitional processing and to allow non-ASCII | 
| 374 |     characters only inside URLs whose top-level domains are listed in the IDN whitelist. | 
| 375 |  | 
| 376 |     \sa toAce(), fromAce(), idnWhitelist() | 
| 377 | */ | 
| 378 |  | 
| 379 | /*! | 
| 380 |     \fn QUrl::QUrl(QUrl &&other) | 
| 381 |  | 
| 382 |     Move-constructs a QUrl instance, making it point at the same | 
| 383 |     object that \a other was pointing to. | 
| 384 |  | 
| 385 |     \since 5.2 | 
| 386 | */ | 
| 387 |  | 
| 388 | /*! | 
| 389 |     \fn QUrl &QUrl::operator=(QUrl &&other) | 
| 390 |  | 
| 391 |     Move-assigns \a other to this QUrl instance. | 
| 392 |  | 
| 393 |     \since 5.2 | 
| 394 | */ | 
| 395 |  | 
| 396 | #include "qurl.h" | 
| 397 | #include "qurl_p.h" | 
| 398 | #include "qplatformdefs.h" | 
| 399 | #include "qstring.h" | 
| 400 | #include "qstringlist.h" | 
| 401 | #include "qdebug.h" | 
| 402 | #include "qhash.h" | 
| 403 | #include "qdatastream.h" | 
| 404 | #include "private/qipaddress_p.h" | 
| 405 | #include "qurlquery.h" | 
| 406 | #include "private/qdir_p.h" | 
| 407 | #include <private/qtools_p.h> | 
| 408 |  | 
| 409 | QT_BEGIN_NAMESPACE | 
| 410 |  | 
| 411 | using namespace Qt::StringLiterals; | 
| 412 | using namespace QtMiscUtils; | 
| 413 |  | 
| 414 | inline static bool isHex(char c) | 
| 415 | { | 
| 416 |     c |= 0x20; | 
| 417 |     return isAsciiDigit(c) || (c >= 'a' && c <= 'f'); | 
| 418 | } | 
| 419 |  | 
| 420 | static inline QString ftpScheme() | 
| 421 | { | 
| 422 |     return QStringLiteral("ftp" ); | 
| 423 | } | 
| 424 |  | 
| 425 | static inline QString fileScheme() | 
| 426 | { | 
| 427 |     return QStringLiteral("file" ); | 
| 428 | } | 
| 429 |  | 
| 430 | static inline QString webDavScheme() | 
| 431 | { | 
| 432 |     return QStringLiteral("webdavs" ); | 
| 433 | } | 
| 434 |  | 
| 435 | static inline QString webDavSslTag() | 
| 436 | { | 
| 437 |     return QStringLiteral("@SSL" ); | 
| 438 | } | 
| 439 |  | 
| 440 | class QUrlPrivate | 
| 441 | { | 
| 442 | public: | 
| 443 |     enum Section : uchar { | 
| 444 |         Scheme = 0x01, | 
| 445 |         UserName = 0x02, | 
| 446 |         Password = 0x04, | 
| 447 |         UserInfo = UserName | Password, | 
| 448 |         Host = 0x08, | 
| 449 |         Port = 0x10, | 
| 450 |         Authority = UserInfo | Host | Port, | 
| 451 |         Path = 0x20, | 
| 452 |         Hierarchy = Authority | Path, | 
| 453 |         Query = 0x40, | 
| 454 |         Fragment = 0x80, | 
| 455 |         FullUrl = 0xff | 
| 456 |     }; | 
| 457 |  | 
| 458 |     enum Flags : uchar { | 
| 459 |         IsLocalFile = 0x01 | 
| 460 |     }; | 
| 461 |  | 
| 462 |     enum ErrorCode { | 
| 463 |         // the high byte of the error code matches the Section | 
| 464 |         // the first item in each value must be the generic "Invalid xxx Error" | 
| 465 |         InvalidSchemeError = Scheme << 8, | 
| 466 |  | 
| 467 |         InvalidUserNameError = UserName << 8, | 
| 468 |  | 
| 469 |         InvalidPasswordError = Password << 8, | 
| 470 |  | 
| 471 |         InvalidRegNameError = Host << 8, | 
| 472 |         InvalidIPv4AddressError, | 
| 473 |         InvalidIPv6AddressError, | 
| 474 |         InvalidCharacterInIPv6Error, | 
| 475 |         InvalidIPvFutureError, | 
| 476 |         HostMissingEndBracket, | 
| 477 |  | 
| 478 |         InvalidPortError = Port << 8, | 
| 479 |         PortEmptyError, | 
| 480 |  | 
| 481 |         InvalidPathError = Path << 8, | 
| 482 |  | 
| 483 |         InvalidQueryError = Query << 8, | 
| 484 |  | 
| 485 |         InvalidFragmentError = Fragment << 8, | 
| 486 |  | 
| 487 |         // the following three cases are only possible in combination with | 
| 488 |         // presence/absence of the path, authority and scheme. See validityError(). | 
| 489 |         AuthorityPresentAndPathIsRelative = Authority << 8 | Path << 8 | 0x10000, | 
| 490 |         AuthorityAbsentAndPathIsDoubleSlash, | 
| 491 |         RelativeUrlPathContainsColonBeforeSlash = Scheme << 8 | Authority << 8 | Path << 8 | 0x10000, | 
| 492 |  | 
| 493 |         NoError = 0 | 
| 494 |     }; | 
| 495 |  | 
| 496 |     struct Error { | 
| 497 |         QString source; | 
| 498 |         qsizetype position; | 
| 499 |         ErrorCode code; | 
| 500 |     }; | 
| 501 |  | 
| 502 |     QUrlPrivate(); | 
| 503 |     QUrlPrivate(const QUrlPrivate ©); | 
| 504 |     ~QUrlPrivate(); | 
| 505 |  | 
| 506 |     void parse(const QString &url, QUrl::ParsingMode parsingMode); | 
| 507 |     bool isEmpty() const | 
| 508 |     { return sectionIsPresent == 0 && port == -1 && path.isEmpty(); } | 
| 509 |  | 
| 510 |     std::unique_ptr<Error> cloneError() const; | 
| 511 |     void clearError(); | 
| 512 |     void setError(ErrorCode errorCode, const QString &source, qsizetype supplement = -1); | 
| 513 |     ErrorCode validityError(QString *source = nullptr, qsizetype *position = nullptr) const; | 
| 514 |     bool validateComponent(Section section, const QString &input, qsizetype begin, qsizetype end); | 
| 515 |     bool validateComponent(Section section, const QString &input) | 
| 516 |     { return validateComponent(section, input, begin: 0, end: input.size()); } | 
| 517 |  | 
| 518 |     // no QString scheme() const; | 
| 519 |     void appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; | 
| 520 |     void appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; | 
| 521 |     void appendUserName(QString &appendTo, QUrl::FormattingOptions options) const; | 
| 522 |     void appendPassword(QString &appendTo, QUrl::FormattingOptions options) const; | 
| 523 |     void appendHost(QString &appendTo, QUrl::FormattingOptions options) const; | 
| 524 |     void appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; | 
| 525 |     void appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; | 
| 526 |     void appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const; | 
| 527 |  | 
| 528 |     // the "end" parameters are like STL iterators: they point to one past the last valid element | 
| 529 |     bool setScheme(const QString &value, qsizetype len, bool doSetError); | 
| 530 |     void setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode); | 
| 531 |     void setUserInfo(const QString &userInfo, qsizetype from, qsizetype end); | 
| 532 |     void setUserName(const QString &value, qsizetype from, qsizetype end); | 
| 533 |     void setPassword(const QString &value, qsizetype from, qsizetype end); | 
| 534 |     bool setHost(const QString &value, qsizetype from, qsizetype end, QUrl::ParsingMode mode); | 
| 535 |     void setPath(const QString &value, qsizetype from, qsizetype end); | 
| 536 |     void setQuery(const QString &value, qsizetype from, qsizetype end); | 
| 537 |     void setFragment(const QString &value, qsizetype from, qsizetype end); | 
| 538 |  | 
| 539 |     inline bool hasScheme() const { return sectionIsPresent & Scheme; } | 
| 540 |     inline bool hasAuthority() const { return sectionIsPresent & Authority; } | 
| 541 |     inline bool hasUserInfo() const { return sectionIsPresent & UserInfo; } | 
| 542 |     inline bool hasUserName() const { return sectionIsPresent & UserName; } | 
| 543 |     inline bool hasPassword() const { return sectionIsPresent & Password; } | 
| 544 |     inline bool hasHost() const { return sectionIsPresent & Host; } | 
| 545 |     inline bool hasPort() const { return port != -1; } | 
| 546 |     inline bool hasPath() const { return !path.isEmpty(); } | 
| 547 |     inline bool hasQuery() const { return sectionIsPresent & Query; } | 
| 548 |     inline bool hasFragment() const { return sectionIsPresent & Fragment; } | 
| 549 |  | 
| 550 |     inline bool isLocalFile() const { return flags & IsLocalFile; } | 
| 551 |     QString toLocalFile(QUrl::FormattingOptions options) const; | 
| 552 |  | 
| 553 |     bool normalizePathSegments(QString *path) const | 
| 554 |     { | 
| 555 |         QDirPrivate::PathNormalizations mode = QDirPrivate::UrlNormalizationMode; | 
| 556 |         if (!isLocalFile()) | 
| 557 |             mode |= QDirPrivate::RemotePath; | 
| 558 |         return qt_normalizePathSegments(path, flags: mode); | 
| 559 |     } | 
| 560 |     QString mergePaths(const QString &relativePath) const; | 
| 561 |  | 
| 562 |     QAtomicInt ref; | 
| 563 |     int port; | 
| 564 |  | 
| 565 |     QString scheme; | 
| 566 |     QString userName; | 
| 567 |     QString password; | 
| 568 |     QString host; | 
| 569 |     QString path; | 
| 570 |     QString query; | 
| 571 |     QString fragment; | 
| 572 |  | 
| 573 |     std::unique_ptr<Error> error; | 
| 574 |  | 
| 575 |     // not used for: | 
| 576 |     //  - Port (port == -1 means absence) | 
| 577 |     //  - Path (there's no path delimiter, so we optimize its use out of existence) | 
| 578 |     // Schemes are never supposed to be empty, but we keep the flag anyway | 
| 579 |     uchar sectionIsPresent; | 
| 580 |     uchar flags; | 
| 581 |  | 
| 582 |     // 32-bit: 2 bytes tail padding available | 
| 583 |     // 64-bit: 6 bytes tail padding available | 
| 584 | }; | 
| 585 |  | 
| 586 | inline QUrlPrivate::QUrlPrivate() | 
| 587 |     : ref(1), port(-1), | 
| 588 |       sectionIsPresent(0), | 
| 589 |       flags(0) | 
| 590 | { | 
| 591 | } | 
| 592 |  | 
| 593 | inline QUrlPrivate::QUrlPrivate(const QUrlPrivate ©) | 
| 594 |     : ref(1), port(copy.port), | 
| 595 |       scheme(copy.scheme), | 
| 596 |       userName(copy.userName), | 
| 597 |       password(copy.password), | 
| 598 |       host(copy.host), | 
| 599 |       path(copy.path), | 
| 600 |       query(copy.query), | 
| 601 |       fragment(copy.fragment), | 
| 602 |       error(copy.cloneError()), | 
| 603 |       sectionIsPresent(copy.sectionIsPresent), | 
| 604 |       flags(copy.flags) | 
| 605 | { | 
| 606 | } | 
| 607 |  | 
| 608 | inline QUrlPrivate::~QUrlPrivate() | 
| 609 |     = default; | 
| 610 |  | 
| 611 | std::unique_ptr<QUrlPrivate::Error> QUrlPrivate::cloneError() const | 
| 612 | { | 
| 613 |     return error ? std::make_unique<Error>(args&: *error) : nullptr; | 
| 614 | } | 
| 615 |  | 
| 616 | inline void QUrlPrivate::clearError() | 
| 617 | { | 
| 618 |     error.reset(); | 
| 619 | } | 
| 620 |  | 
| 621 | inline void QUrlPrivate::setError(ErrorCode errorCode, const QString &source, qsizetype supplement) | 
| 622 | { | 
| 623 |     if (error) { | 
| 624 |         // don't overwrite an error set in a previous section during parsing | 
| 625 |         return; | 
| 626 |     } | 
| 627 |     error = std::make_unique<Error>(); | 
| 628 |     error->code = errorCode; | 
| 629 |     error->source = source; | 
| 630 |     error->position = supplement; | 
| 631 | } | 
| 632 |  | 
| 633 | // From RFC 3986, Appendix A Collected ABNF for URI | 
| 634 | //    URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ] | 
| 635 | //[...] | 
| 636 | //    scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) | 
| 637 | // | 
| 638 | //    authority     = [ userinfo "@" ] host [ ":" port ] | 
| 639 | //    userinfo      = *( unreserved / pct-encoded / sub-delims / ":" ) | 
| 640 | //    host          = IP-literal / IPv4address / reg-name | 
| 641 | //    port          = *DIGIT | 
| 642 | //[...] | 
| 643 | //    reg-name      = *( unreserved / pct-encoded / sub-delims ) | 
| 644 | //[..] | 
| 645 | //    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@" | 
| 646 | // | 
| 647 | //    query         = *( pchar / "/" / "?" ) | 
| 648 | // | 
| 649 | //    fragment      = *( pchar / "/" / "?" ) | 
| 650 | // | 
| 651 | //    pct-encoded   = "%" HEXDIG HEXDIG | 
| 652 | // | 
| 653 | //    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~" | 
| 654 | //    reserved      = gen-delims / sub-delims | 
| 655 | //    gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@" | 
| 656 | //    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")" | 
| 657 | //                  / "*" / "+" / "," / ";" / "=" | 
| 658 | // the path component has a complex ABNF that basically boils down to | 
| 659 | // slash-separated segments of "pchar" | 
| 660 |  | 
| 661 | // The above is the strict definition of the URL components and we mostly | 
| 662 | // adhere to it, with few exceptions. QUrl obeys the following behavior: | 
| 663 | //  - percent-encoding sequences always use uppercase HEXDIG; | 
| 664 | //  - unreserved characters are *always* decoded, no exceptions; | 
| 665 | //  - the space character and bytes with the high bit set are controlled by | 
| 666 | //    the EncodeSpaces and EncodeUnicode bits; | 
| 667 | //  - control characters, the percent sign itself, and bytes with the high | 
| 668 | //    bit set that don't form valid UTF-8 sequences are always encoded, | 
| 669 | //    except in FullyDecoded mode; | 
| 670 | //  - sub-delims are always left alone, except in FullyDecoded mode; | 
| 671 | //  - gen-delim change behavior depending on which section of the URL (or | 
| 672 | //    the entire URL) we're looking at; see below; | 
| 673 | //  - characters not mentioned above, like "<", and ">", are usually | 
| 674 | //    decoded in individual sections of the URL, but encoded when the full | 
| 675 | //    URL is put together (we can change on subjective definition of | 
| 676 | //    "pretty"). | 
| 677 | // | 
| 678 | // The behavior for the delimiters bears some explanation. The spec says in | 
| 679 | // section 2.2: | 
| 680 | //     URIs that differ in the replacement of a reserved character with its | 
| 681 | //     corresponding percent-encoded octet are not equivalent. | 
| 682 | // (note: QUrl API mistakenly uses the "reserved" term, so we will refer to | 
| 683 | // them here as "delimiters"). | 
| 684 | // | 
| 685 | // For that reason, we cannot encode delimiters found in decoded form and we | 
| 686 | // cannot decode the ones found in encoded form if that would change the | 
| 687 | // interpretation. Conversely, we *can* perform the transformation if it would | 
| 688 | // not change the interpretation. From the last component of a URL to the first, | 
| 689 | // here are the gen-delims we can unambiguously transform when the field is | 
| 690 | // taken in isolation: | 
| 691 | //  - fragment: none, since it's the last | 
| 692 | //  - query: "#" is unambiguous | 
| 693 | //  - path: "#" and "?" are unambiguous | 
| 694 | //  - host: completely special but never ambiguous, see setHost() below. | 
| 695 | //  - password: the "#", "?", "/", "[", "]" and "@" characters are unambiguous | 
| 696 | //  - username: the "#", "?", "/", "[", "]", "@", and ":" characters are unambiguous | 
| 697 | //  - scheme: doesn't accept any delimiter, see setScheme() below. | 
| 698 | // | 
| 699 | // Internally, QUrl stores each component in the format that corresponds to the | 
| 700 | // default mode (PrettyDecoded). It deviates from the "strict" FullyEncoded | 
| 701 | // mode in the following way: | 
| 702 | //  - spaces are decoded | 
| 703 | //  - valid UTF-8 sequences are decoded | 
| 704 | //  - gen-delims that can be unambiguously transformed are decoded | 
| 705 | //  - characters controlled by DecodeReserved are often decoded, though this behavior | 
| 706 | //    can change depending on the subjective definition of "pretty" | 
| 707 | // | 
| 708 | // Note that the list of gen-delims that we can transform is different for the | 
| 709 | // user info (user name + password) and the authority (user info + host + | 
| 710 | // port). | 
| 711 |  | 
| 712 |  | 
| 713 | // list the recoding table modifications to be used with the recodeFromUser and | 
| 714 | // appendToUser functions, according to the rules above. Spaces and UTF-8 | 
| 715 | // sequences are handled outside the tables. | 
| 716 |  | 
| 717 | // the encodedXXX tables are run with the delimiters set to "leave" by default; | 
| 718 | // the decodedXXX tables are run with the delimiters set to "decode" by default | 
| 719 | // (except for the query, which doesn't use these functions) | 
| 720 |  | 
| 721 | namespace { | 
| 722 | template <typename T> constexpr ushort decode(T x) noexcept { return ushort(x); } | 
| 723 | template <typename T> constexpr ushort leave(T x) noexcept { return ushort(0x100 | x); } | 
| 724 | template <typename T> constexpr ushort encode(T x) noexcept { return ushort(0x200 | x); } | 
| 725 | } | 
| 726 |  | 
| 727 | static const ushort userNameInIsolation[] = { | 
| 728 |     decode(x: ':'), // 0 | 
| 729 |     decode(x: '@'), // 1 | 
| 730 |     decode(x: ']'), // 2 | 
| 731 |     decode(x: '['), // 3 | 
| 732 |     decode(x: '/'), // 4 | 
| 733 |     decode(x: '?'), // 5 | 
| 734 |     decode(x: '#'), // 6 | 
| 735 |  | 
| 736 |     decode(x: '"'), // 7 | 
| 737 |     decode(x: '<'), | 
| 738 |     decode(x: '>'), | 
| 739 |     decode(x: '^'), | 
| 740 |     decode(x: '\\'), | 
| 741 |     decode(x: '|'), | 
| 742 |     decode(x: '{'), | 
| 743 |     decode(x: '}'), | 
| 744 |     0 | 
| 745 | }; | 
| 746 | static const ushort * const passwordInIsolation = userNameInIsolation + 1; | 
| 747 | static const ushort * const pathInIsolation = userNameInIsolation + 5; | 
| 748 | static const ushort * const queryInIsolation = userNameInIsolation + 6; | 
| 749 | static const ushort * const fragmentInIsolation = userNameInIsolation + 7; | 
| 750 |  | 
| 751 | static const ushort localPathFromUser[] = { | 
| 752 |     // we force-decode some of the gen-delims, because | 
| 753 |     //    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@" | 
| 754 |     // the gen-delim lines are leave() in qt_urlRecode, so we don't need to | 
| 755 |     // repeat them if we want to keep them decoded | 
| 756 |     // decode(':'), // allowed | 
| 757 |     // decode('@'), // allowed | 
| 758 |     encode(x: ']'), | 
| 759 |     encode(x: '['), | 
| 760 |     // decode('/'), // special and allowed | 
| 761 |     // decode('?'), // handled by path() and others | 
| 762 |     // decode('#'), // ditto | 
| 763 |  | 
| 764 |     // the rest is like pathInIsolation above | 
| 765 |     decode(x: '"'), | 
| 766 |     decode(x: '<'), | 
| 767 |     decode(x: '>'), | 
| 768 |     decode(x: '^'), | 
| 769 |     decode(x: '\\'), | 
| 770 |     decode(x: '|'), | 
| 771 |     decode(x: '{'), | 
| 772 |     decode(x: '}'), | 
| 773 |  | 
| 774 |     0 | 
| 775 | }; | 
| 776 |  | 
| 777 | static const ushort userNameInUserInfo[] =  { | 
| 778 |     encode(x: ':'), // 0 | 
| 779 |     decode(x: '@'), // 1 | 
| 780 |     decode(x: ']'), // 2 | 
| 781 |     decode(x: '['), // 3 | 
| 782 |     decode(x: '/'), // 4 | 
| 783 |     decode(x: '?'), // 5 | 
| 784 |     decode(x: '#'), // 6 | 
| 785 |  | 
| 786 |     decode(x: '"'), // 7 | 
| 787 |     decode(x: '<'), | 
| 788 |     decode(x: '>'), | 
| 789 |     decode(x: '^'), | 
| 790 |     decode(x: '\\'), | 
| 791 |     decode(x: '|'), | 
| 792 |     decode(x: '{'), | 
| 793 |     decode(x: '}'), | 
| 794 |     0 | 
| 795 | }; | 
| 796 | static const ushort * const passwordInUserInfo = userNameInUserInfo + 1; | 
| 797 |  | 
| 798 | static const ushort userNameInAuthority[] = { | 
| 799 |     encode(x: ':'), // 0 | 
| 800 |     encode(x: '@'), // 1 | 
| 801 |     encode(x: ']'), // 2 | 
| 802 |     encode(x: '['), // 3 | 
| 803 |     decode(x: '/'), // 4 | 
| 804 |     decode(x: '?'), // 5 | 
| 805 |     decode(x: '#'), // 6 | 
| 806 |  | 
| 807 |     decode(x: '"'), // 7 | 
| 808 |     decode(x: '<'), | 
| 809 |     decode(x: '>'), | 
| 810 |     decode(x: '^'), | 
| 811 |     decode(x: '\\'), | 
| 812 |     decode(x: '|'), | 
| 813 |     decode(x: '{'), | 
| 814 |     decode(x: '}'), | 
| 815 |     0 | 
| 816 | }; | 
| 817 | static const ushort * const passwordInAuthority = userNameInAuthority + 1; | 
| 818 |  | 
| 819 | static const ushort userNameInUrl[] = { | 
| 820 |     encode(x: ':'), // 0 | 
| 821 |     encode(x: '@'), // 1 | 
| 822 |     encode(x: ']'), // 2 | 
| 823 |     encode(x: '['), // 3 | 
| 824 |     encode(x: '/'), // 4 | 
| 825 |     encode(x: '?'), // 5 | 
| 826 |     encode(x: '#'), // 6 | 
| 827 |  | 
| 828 |     // no need to list encode(x) for the other characters | 
| 829 |     0 | 
| 830 | }; | 
| 831 | static const ushort * const passwordInUrl = userNameInUrl + 1; | 
| 832 | static const ushort * const pathInUrl = userNameInUrl + 5; | 
| 833 | static const ushort * const queryInUrl = userNameInUrl + 6; | 
| 834 | static const ushort * const fragmentInUrl = userNameInUrl + 6; | 
| 835 |  | 
| 836 | static inline void parseDecodedComponent(QString &data) | 
| 837 | { | 
| 838 |     data.replace(c: u'%', after: "%25"_L1 ); | 
| 839 | } | 
| 840 |  | 
| 841 | static inline QString | 
| 842 | recodeFromUser(const QString &input, const ushort *actions, qsizetype from, qsizetype to) | 
| 843 | { | 
| 844 |     QString output; | 
| 845 |     const QChar *begin = input.constData() + from; | 
| 846 |     const QChar *end = input.constData() + to; | 
| 847 |     if (qt_urlRecode(appendTo&: output, url: QStringView{begin, end}, encoding: {}, tableModifications: actions)) | 
| 848 |         return output; | 
| 849 |  | 
| 850 |     return input.mid(position: from, n: to - from); | 
| 851 | } | 
| 852 |  | 
| 853 | // appendXXXX functions: copy from the internal form to the external, user form. | 
| 854 | // the internal value is stored in its PrettyDecoded form, so that case is easy. | 
| 855 | static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options, | 
| 856 |                                 const ushort *actions) | 
| 857 | { | 
| 858 |     // The stored value is already QUrl::PrettyDecoded, so there's nothing to | 
| 859 |     // do if that's what the user asked for (test only | 
| 860 |     // ComponentFormattingOptions, ignore FormattingOptions). | 
| 861 |     if ((options & 0xFFFF0000) == QUrl::PrettyDecoded || | 
| 862 |             !qt_urlRecode(appendTo, url: value, encoding: options, tableModifications: actions)) | 
| 863 |         appendTo += value; | 
| 864 |  | 
| 865 |     // copy nullness, if necessary, because QString::operator+=(QStringView) doesn't | 
| 866 |     if (appendTo.isNull() && !value.isNull()) | 
| 867 |         appendTo.detach(); | 
| 868 | } | 
| 869 |  | 
| 870 | inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const | 
| 871 | { | 
| 872 |     if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) { | 
| 873 |         appendUserInfo(appendTo, options, appendingTo); | 
| 874 |  | 
| 875 |         // add '@' only if we added anything | 
| 876 |         if (hasUserName() || (hasPassword() && (options & QUrl::RemovePassword) == 0)) | 
| 877 |             appendTo += u'@'; | 
| 878 |     } | 
| 879 |     appendHost(appendTo, options); | 
| 880 |     if (!(options & QUrl::RemovePort) && port != -1) | 
| 881 |         appendTo += u':' + QString::number(port); | 
| 882 | } | 
| 883 |  | 
| 884 | inline void QUrlPrivate::appendUserInfo(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const | 
| 885 | { | 
| 886 |     if (Q_LIKELY(!hasUserInfo())) | 
| 887 |         return; | 
| 888 |  | 
| 889 |     const ushort *userNameActions; | 
| 890 |     const ushort *passwordActions; | 
| 891 |     if (options & QUrl::EncodeDelimiters) { | 
| 892 |         userNameActions = userNameInUrl; | 
| 893 |         passwordActions = passwordInUrl; | 
| 894 |     } else { | 
| 895 |         switch (appendingTo) { | 
| 896 |         case UserInfo: | 
| 897 |             userNameActions = userNameInUserInfo; | 
| 898 |             passwordActions = passwordInUserInfo; | 
| 899 |             break; | 
| 900 |  | 
| 901 |         case Authority: | 
| 902 |             userNameActions = userNameInAuthority; | 
| 903 |             passwordActions = passwordInAuthority; | 
| 904 |             break; | 
| 905 |  | 
| 906 |         case FullUrl: | 
| 907 |             userNameActions = userNameInUrl; | 
| 908 |             passwordActions = passwordInUrl; | 
| 909 |             break; | 
| 910 |  | 
| 911 |         default: | 
| 912 |             // can't happen | 
| 913 |             Q_UNREACHABLE(); | 
| 914 |             break; | 
| 915 |         } | 
| 916 |     } | 
| 917 |  | 
| 918 |     if (!qt_urlRecode(appendTo, url: userName, encoding: options, tableModifications: userNameActions)) | 
| 919 |         appendTo += userName; | 
| 920 |     if (options & QUrl::RemovePassword || !hasPassword()) { | 
| 921 |         return; | 
| 922 |     } else { | 
| 923 |         appendTo += u':'; | 
| 924 |         if (!qt_urlRecode(appendTo, url: password, encoding: options, tableModifications: passwordActions)) | 
| 925 |             appendTo += password; | 
| 926 |     } | 
| 927 | } | 
| 928 |  | 
| 929 | inline void QUrlPrivate::appendUserName(QString &appendTo, QUrl::FormattingOptions options) const | 
| 930 | { | 
| 931 |     // only called from QUrl::userName() | 
| 932 |     appendToUser(appendTo, value: userName, options, | 
| 933 |                  actions: options & QUrl::EncodeDelimiters ? userNameInUrl : userNameInIsolation); | 
| 934 | } | 
| 935 |  | 
| 936 | inline void QUrlPrivate::appendPassword(QString &appendTo, QUrl::FormattingOptions options) const | 
| 937 | { | 
| 938 |     // only called from QUrl::password() | 
| 939 |     appendToUser(appendTo, value: password, options, | 
| 940 |                  actions: options & QUrl::EncodeDelimiters ? passwordInUrl : passwordInIsolation); | 
| 941 | } | 
| 942 |  | 
| 943 | inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const | 
| 944 | { | 
| 945 |     QString thePath = path; | 
| 946 |     if (options & QUrl::NormalizePathSegments) | 
| 947 |         normalizePathSegments(path: &thePath); | 
| 948 |  | 
| 949 |     QStringView thePathView(thePath); | 
| 950 |     if (options & QUrl::RemoveFilename) { | 
| 951 |         const qsizetype slash = thePathView.lastIndexOf(c: u'/'); | 
| 952 |         if (slash == -1) | 
| 953 |             return; | 
| 954 |         thePathView = thePathView.left(n: slash + 1); | 
| 955 |     } | 
| 956 |     // check if we need to remove trailing slashes | 
| 957 |     if (options & QUrl::StripTrailingSlash) { | 
| 958 |         while (thePathView.size() > 1 && thePathView.endsWith(c: u'/')) | 
| 959 |             thePathView.chop(n: 1); | 
| 960 |     } | 
| 961 |  | 
| 962 |     appendToUser(appendTo, value: thePathView, options, | 
| 963 |                  actions: appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? pathInUrl : pathInIsolation); | 
| 964 | } | 
| 965 |  | 
| 966 | inline void QUrlPrivate::appendFragment(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const | 
| 967 | { | 
| 968 |     appendToUser(appendTo, value: fragment, options, | 
| 969 |                  actions: options & QUrl::EncodeDelimiters ? fragmentInUrl : | 
| 970 |                  appendingTo == FullUrl ? nullptr : fragmentInIsolation); | 
| 971 | } | 
| 972 |  | 
| 973 | inline void QUrlPrivate::appendQuery(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const | 
| 974 | { | 
| 975 |     appendToUser(appendTo, value: query, options, | 
| 976 |                  actions: appendingTo == FullUrl || options & QUrl::EncodeDelimiters ? queryInUrl : queryInIsolation); | 
| 977 | } | 
| 978 |  | 
| 979 | // setXXX functions | 
| 980 |  | 
| 981 | inline bool QUrlPrivate::setScheme(const QString &value, qsizetype len, bool doSetError) | 
| 982 | { | 
| 983 |     // schemes are strictly RFC-compliant: | 
| 984 |     //    scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) | 
| 985 |     // we also lowercase the scheme | 
| 986 |  | 
| 987 |     // schemes in URLs are not allowed to be empty, but they can be in | 
| 988 |     // "Relative URIs" which QUrl also supports. QUrl::setScheme does | 
| 989 |     // not call us with len == 0, so this can only be from parse() | 
| 990 |     scheme.clear(); | 
| 991 |     if (len == 0) | 
| 992 |         return false; | 
| 993 |  | 
| 994 |     sectionIsPresent |= Scheme; | 
| 995 |  | 
| 996 |     // validate it: | 
| 997 |     qsizetype needsLowercasing = -1; | 
| 998 |     const ushort *p = reinterpret_cast<const ushort *>(value.data()); | 
| 999 |     for (qsizetype i = 0; i < len; ++i) { | 
| 1000 |         if (isAsciiLower(c: p[i])) | 
| 1001 |             continue; | 
| 1002 |         if (isAsciiUpper(c: p[i])) { | 
| 1003 |             needsLowercasing = i; | 
| 1004 |             continue; | 
| 1005 |         } | 
| 1006 |         if (i) { | 
| 1007 |             if (isAsciiDigit(c: p[i])) | 
| 1008 |                 continue; | 
| 1009 |             if (p[i] == '+' || p[i] == '-' || p[i] == '.') | 
| 1010 |                 continue; | 
| 1011 |         } | 
| 1012 |  | 
| 1013 |         // found something else | 
| 1014 |         // don't call setError needlessly: | 
| 1015 |         // if we've been called from parse(), it will try to recover | 
| 1016 |         if (doSetError) | 
| 1017 |             setError(errorCode: InvalidSchemeError, source: value, supplement: i); | 
| 1018 |         return false; | 
| 1019 |     } | 
| 1020 |  | 
| 1021 |     scheme = value.left(n: len); | 
| 1022 |  | 
| 1023 |     if (needsLowercasing != -1) { | 
| 1024 |         // schemes are ASCII only, so we don't need the full Unicode toLower | 
| 1025 |         QChar *schemeData = scheme.data(); // force detaching here | 
| 1026 |         for (qsizetype i = needsLowercasing; i >= 0; --i) { | 
| 1027 |             ushort c = schemeData[i].unicode(); | 
| 1028 |             if (isAsciiUpper(c)) | 
| 1029 |                 schemeData[i] = QChar(c + 0x20); | 
| 1030 |         } | 
| 1031 |     } | 
| 1032 |  | 
| 1033 |     // did we set to the file protocol? | 
| 1034 |     if (scheme == fileScheme() | 
| 1035 | #ifdef Q_OS_WIN | 
| 1036 |         || scheme == webDavScheme() | 
| 1037 | #endif | 
| 1038 |        ) { | 
| 1039 |         flags |= IsLocalFile; | 
| 1040 |     } else { | 
| 1041 |         flags &= ~IsLocalFile; | 
| 1042 |     } | 
| 1043 |     return true; | 
| 1044 | } | 
| 1045 |  | 
| 1046 | inline void QUrlPrivate::setAuthority(const QString &auth, qsizetype from, qsizetype end, QUrl::ParsingMode mode) | 
| 1047 | { | 
| 1048 |     sectionIsPresent &= ~Authority; | 
| 1049 |     port = -1; | 
| 1050 |     if (from == end && !auth.isNull()) | 
| 1051 |         sectionIsPresent |= Host;   // empty but not null authority implies host | 
| 1052 |  | 
| 1053 |     // we never actually _loop_ | 
| 1054 |     while (from != end) { | 
| 1055 |         qsizetype userInfoIndex = auth.indexOf(c: u'@', from); | 
| 1056 |         if (size_t(userInfoIndex) < size_t(end)) { | 
| 1057 |             setUserInfo(userInfo: auth, from, end: userInfoIndex); | 
| 1058 |             if (mode == QUrl::StrictMode && !validateComponent(section: UserInfo, input: auth, begin: from, end: userInfoIndex)) | 
| 1059 |                 break; | 
| 1060 |             from = userInfoIndex + 1; | 
| 1061 |         } | 
| 1062 |  | 
| 1063 |         qsizetype colonIndex = auth.lastIndexOf(c: u':', from: end - 1); | 
| 1064 |         if (colonIndex < from) | 
| 1065 |             colonIndex = -1; | 
| 1066 |  | 
| 1067 |         if (size_t(colonIndex) < size_t(end)) { | 
| 1068 |             if (auth.at(i: from).unicode() == '[') { | 
| 1069 |                 // check if colonIndex isn't inside the "[...]" part | 
| 1070 |                 qsizetype closingBracket = auth.indexOf(c: u']', from); | 
| 1071 |                 if (size_t(closingBracket) > size_t(colonIndex)) | 
| 1072 |                     colonIndex = -1; | 
| 1073 |             } | 
| 1074 |         } | 
| 1075 |  | 
| 1076 |         if (size_t(colonIndex) < size_t(end) - 1) { | 
| 1077 |             // found a colon with digits after it | 
| 1078 |             unsigned long x = 0; | 
| 1079 |             for (qsizetype i = colonIndex + 1; i < end; ++i) { | 
| 1080 |                 ushort c = auth.at(i).unicode(); | 
| 1081 |                 if (isAsciiDigit(c)) { | 
| 1082 |                     x *= 10; | 
| 1083 |                     x += c - '0'; | 
| 1084 |                 } else { | 
| 1085 |                     x = ulong(-1); // x != ushort(x) | 
| 1086 |                     break; | 
| 1087 |                 } | 
| 1088 |             } | 
| 1089 |             if (x == ushort(x)) { | 
| 1090 |                 port = ushort(x); | 
| 1091 |             } else { | 
| 1092 |                 setError(errorCode: InvalidPortError, source: auth, supplement: colonIndex + 1); | 
| 1093 |                 if (mode == QUrl::StrictMode) | 
| 1094 |                     break; | 
| 1095 |             } | 
| 1096 |         } | 
| 1097 |  | 
| 1098 |         setHost(value: auth, from, end: qMin<size_t>(a: end, b: colonIndex), mode); | 
| 1099 |         if (mode == QUrl::StrictMode && !validateComponent(section: Host, input: auth, begin: from, end: qMin<size_t>(a: end, b: colonIndex))) { | 
| 1100 |             // clear host too | 
| 1101 |             sectionIsPresent &= ~Authority; | 
| 1102 |             break; | 
| 1103 |         } | 
| 1104 |  | 
| 1105 |         // success | 
| 1106 |         return; | 
| 1107 |     } | 
| 1108 |     // clear all sections but host | 
| 1109 |     sectionIsPresent &= ~Authority | Host; | 
| 1110 |     userName.clear(); | 
| 1111 |     password.clear(); | 
| 1112 |     host.clear(); | 
| 1113 |     port = -1; | 
| 1114 | } | 
| 1115 |  | 
| 1116 | inline void QUrlPrivate::setUserInfo(const QString &userInfo, qsizetype from, qsizetype end) | 
| 1117 | { | 
| 1118 |     qsizetype delimIndex = userInfo.indexOf(c: u':', from); | 
| 1119 |     setUserName(value: userInfo, from, end: qMin<size_t>(a: delimIndex, b: end)); | 
| 1120 |  | 
| 1121 |     if (size_t(delimIndex) >= size_t(end)) { | 
| 1122 |         password.clear(); | 
| 1123 |         sectionIsPresent &= ~Password; | 
| 1124 |     } else { | 
| 1125 |         setPassword(value: userInfo, from: delimIndex + 1, end); | 
| 1126 |     } | 
| 1127 | } | 
| 1128 |  | 
| 1129 | inline void QUrlPrivate::setUserName(const QString &value, qsizetype from, qsizetype end) | 
| 1130 | { | 
| 1131 |     sectionIsPresent |= UserName; | 
| 1132 |     userName = recodeFromUser(input: value, actions: userNameInIsolation, from, to: end); | 
| 1133 | } | 
| 1134 |  | 
| 1135 | inline void QUrlPrivate::setPassword(const QString &value, qsizetype from, qsizetype end) | 
| 1136 | { | 
| 1137 |     sectionIsPresent |= Password; | 
| 1138 |     password = recodeFromUser(input: value, actions: passwordInIsolation, from, to: end); | 
| 1139 | } | 
| 1140 |  | 
| 1141 | inline void QUrlPrivate::setPath(const QString &value, qsizetype from, qsizetype end) | 
| 1142 | { | 
| 1143 |     // sectionIsPresent |= Path; // not used, save some cycles | 
| 1144 |     path = recodeFromUser(input: value, actions: pathInIsolation, from, to: end); | 
| 1145 | } | 
| 1146 |  | 
| 1147 | inline void QUrlPrivate::setFragment(const QString &value, qsizetype from, qsizetype end) | 
| 1148 | { | 
| 1149 |     sectionIsPresent |= Fragment; | 
| 1150 |     fragment = recodeFromUser(input: value, actions: fragmentInIsolation, from, to: end); | 
| 1151 | } | 
| 1152 |  | 
| 1153 | inline void QUrlPrivate::setQuery(const QString &value, qsizetype from, qsizetype iend) | 
| 1154 | { | 
| 1155 |     sectionIsPresent |= Query; | 
| 1156 |     query = recodeFromUser(input: value, actions: queryInIsolation, from, to: iend); | 
| 1157 | } | 
| 1158 |  | 
| 1159 | // Host handling | 
| 1160 | // The RFC says the host is: | 
| 1161 | //    host          = IP-literal / IPv4address / reg-name | 
| 1162 | //    IP-literal    = "[" ( IPv6address / IPvFuture  ) "]" | 
| 1163 | //    IPvFuture     = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) | 
| 1164 | //  [a strict definition of IPv6Address and IPv4Address] | 
| 1165 | //     reg-name      = *( unreserved / pct-encoded / sub-delims ) | 
| 1166 | // | 
| 1167 | // We deviate from the standard in all but IPvFuture. For IPvFuture we accept | 
| 1168 | // and store only exactly what the RFC says we should. No percent-encoding is | 
| 1169 | // permitted in this field, so Unicode characters and space aren't either. | 
| 1170 | // | 
| 1171 | // For IPv4 addresses, we accept broken addresses like inet_aton does (that is, | 
| 1172 | // less than three dots). However, we correct the address to the proper form | 
| 1173 | // and store the corrected address. After correction, we comply to the RFC and | 
| 1174 | // it's exclusively composed of unreserved characters. | 
| 1175 | // | 
| 1176 | // For IPv6 addresses, we accept addresses including trailing (embedded) IPv4 | 
| 1177 | // addresses, the so-called v4-compat and v4-mapped addresses. We also store | 
| 1178 | // those addresses like that in the hostname field, which violates the spec. | 
| 1179 | // IPv6 hosts are stored with the square brackets in the QString. It also | 
| 1180 | // requires no transformation in any way. | 
| 1181 | // | 
| 1182 | // As for registered names, it's the other way around: we accept only valid | 
| 1183 | // hostnames as specified by STD 3 and IDNA. That means everything we accept is | 
| 1184 | // valid in the RFC definition above, but there are many valid reg-names | 
| 1185 | // according to the RFC that we do not accept in the name of security. Since we | 
| 1186 | // do accept IDNA, reg-names are subject to ACE encoding and decoding, which is | 
| 1187 | // specified by the DecodeUnicode flag. The hostname is stored in its Unicode form. | 
| 1188 |  | 
| 1189 | inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions options) const | 
| 1190 | { | 
| 1191 |     if (host.isEmpty()) { | 
| 1192 |         if ((sectionIsPresent & Host) && appendTo.isNull()) | 
| 1193 |             appendTo.detach(); | 
| 1194 |         return; | 
| 1195 |     } | 
| 1196 |     if (host.at(i: 0).unicode() == '[') { | 
| 1197 |         // IPv6 addresses might contain a zone-id which needs to be recoded | 
| 1198 |         if (options != 0) | 
| 1199 |             if (qt_urlRecode(appendTo, url: host, encoding: options, tableModifications: nullptr)) | 
| 1200 |                 return; | 
| 1201 |         appendTo += host; | 
| 1202 |     } else { | 
| 1203 |         // this is either an IPv4Address or a reg-name | 
| 1204 |         // if it is a reg-name, it is already stored in Unicode form | 
| 1205 |         if (options & QUrl::EncodeUnicode && !(options & 0x4000000)) | 
| 1206 |             appendTo += qt_ACE_do(domain: host, op: ToAceOnly, dot: AllowLeadingDot, options: {}); | 
| 1207 |         else | 
| 1208 |             appendTo += host; | 
| 1209 |     } | 
| 1210 | } | 
| 1211 |  | 
| 1212 | // the whole IPvFuture is passed and parsed here, including brackets; | 
| 1213 | // returns null if the parsing was successful, or the QChar of the first failure | 
| 1214 | static const QChar *parseIpFuture(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode) | 
| 1215 | { | 
| 1216 |     //    IPvFuture     = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) | 
| 1217 |     static const char acceptable[] = | 
| 1218 |             "!$&'()*+,;="  // sub-delims | 
| 1219 |             ":"            // ":" | 
| 1220 |             "-._~" ;       // unreserved | 
| 1221 |  | 
| 1222 |     // the brackets and the "v" have been checked | 
| 1223 |     const QChar *const origBegin = begin; | 
| 1224 |     if (begin[3].unicode() != '.') | 
| 1225 |         return &begin[3]; | 
| 1226 |     if (isHexDigit(c: begin[2].unicode())) { | 
| 1227 |         // this is so unlikely that we'll just go down the slow path | 
| 1228 |         // decode the whole string, skipping the "[vH." and "]" which we already know to be there | 
| 1229 |         host += QStringView(begin, 4); | 
| 1230 |  | 
| 1231 |         // uppercase the version, if necessary | 
| 1232 |         if (begin[2].unicode() >= 'a') | 
| 1233 |             host[host.size() - 2] = QChar{begin[2].unicode() - 0x20}; | 
| 1234 |  | 
| 1235 |         begin += 4; | 
| 1236 |         --end; | 
| 1237 |  | 
| 1238 |         QString decoded; | 
| 1239 |         if (mode == QUrl::TolerantMode && qt_urlRecode(appendTo&: decoded, url: QStringView{begin, end}, encoding: QUrl::FullyDecoded, tableModifications: nullptr)) { | 
| 1240 |             begin = decoded.constBegin(); | 
| 1241 |             end = decoded.constEnd(); | 
| 1242 |         } | 
| 1243 |  | 
| 1244 |         for ( ; begin != end; ++begin) { | 
| 1245 |             if (isAsciiLetterOrNumber(c: begin->unicode())) | 
| 1246 |                 host += *begin; | 
| 1247 |             else if (begin->unicode() < 0x80 && strchr(s: acceptable, c: begin->unicode()) != nullptr) | 
| 1248 |                 host += *begin; | 
| 1249 |             else | 
| 1250 |                 return decoded.isEmpty() ? begin : &origBegin[2]; | 
| 1251 |         } | 
| 1252 |         host += u']'; | 
| 1253 |         return nullptr; | 
| 1254 |     } | 
| 1255 |     return &origBegin[2]; | 
| 1256 | } | 
| 1257 |  | 
| 1258 | // ONLY the IPv6 address is parsed here, WITHOUT the brackets | 
| 1259 | static const QChar *parseIp6(QString &host, const QChar *begin, const QChar *end, QUrl::ParsingMode mode) | 
| 1260 | { | 
| 1261 |     QStringView decoded(begin, end); | 
| 1262 |     QString decodedBuffer; | 
| 1263 |     if (mode == QUrl::TolerantMode) { | 
| 1264 |         // this struct is kept in automatic storage because it's only 4 bytes | 
| 1265 |         const ushort decodeColon[] = { decode(x: ':'), 0 }; | 
| 1266 |         if (qt_urlRecode(appendTo&: decodedBuffer, url: decoded, encoding: QUrl::ComponentFormattingOption::PrettyDecoded, tableModifications: decodeColon)) | 
| 1267 |             decoded = decodedBuffer; | 
| 1268 |     } | 
| 1269 |  | 
| 1270 |     const QStringView zoneIdIdentifier(u"%25" ); | 
| 1271 |     QIPAddressUtils::IPv6Address address; | 
| 1272 |     QStringView zoneId; | 
| 1273 |  | 
| 1274 |     qsizetype zoneIdPosition = decoded.indexOf(s: zoneIdIdentifier); | 
| 1275 |     if ((zoneIdPosition != -1) && (decoded.lastIndexOf(s: zoneIdIdentifier) == zoneIdPosition)) { | 
| 1276 |         zoneId = decoded.mid(pos: zoneIdPosition + zoneIdIdentifier.size()); | 
| 1277 |         decoded.truncate(n: zoneIdPosition); | 
| 1278 |  | 
| 1279 |         // was there anything after the zone ID separator? | 
| 1280 |         if (zoneId.isEmpty()) | 
| 1281 |             return end; | 
| 1282 |     } | 
| 1283 |  | 
| 1284 |     // did the address become empty after removing the zone ID? | 
| 1285 |     // (it might have always been empty) | 
| 1286 |     if (decoded.isEmpty()) | 
| 1287 |         return end; | 
| 1288 |  | 
| 1289 |     const QChar *ret = QIPAddressUtils::parseIp6(address, begin: decoded.constBegin(), end: decoded.constEnd()); | 
| 1290 |     if (ret) | 
| 1291 |         return begin + (ret - decoded.constBegin()); | 
| 1292 |  | 
| 1293 |     host.reserve(asize: host.size() + (end - begin) + 2);  // +2 for the brackets | 
| 1294 |     host += u'['; | 
| 1295 |     QIPAddressUtils::toString(appendTo&: host, address); | 
| 1296 |  | 
| 1297 |     if (!zoneId.isEmpty()) { | 
| 1298 |         host += zoneIdIdentifier; | 
| 1299 |         host += zoneId; | 
| 1300 |     } | 
| 1301 |     host += u']'; | 
| 1302 |     return nullptr; | 
| 1303 | } | 
| 1304 |  | 
| 1305 | inline bool | 
| 1306 | QUrlPrivate::setHost(const QString &value, qsizetype from, qsizetype iend, QUrl::ParsingMode mode) | 
| 1307 | { | 
| 1308 |     const QChar *begin = value.constData() + from; | 
| 1309 |     const QChar *end = value.constData() + iend; | 
| 1310 |  | 
| 1311 |     const qsizetype len = end - begin; | 
| 1312 |     host.clear(); | 
| 1313 |     sectionIsPresent &= ~Host; | 
| 1314 |     if (!value.isNull() || (sectionIsPresent & Authority)) | 
| 1315 |         sectionIsPresent |= Host; | 
| 1316 |     if (len == 0) | 
| 1317 |         return true; | 
| 1318 |  | 
| 1319 |     if (begin[0].unicode() == '[') { | 
| 1320 |         // IPv6Address or IPvFuture | 
| 1321 |         // smallest IPv6 address is      "[::]"   (len = 4) | 
| 1322 |         // smallest IPvFuture address is "[v7.X]" (len = 6) | 
| 1323 |         if (end[-1].unicode() != ']') { | 
| 1324 |             setError(errorCode: HostMissingEndBracket, source: value); | 
| 1325 |             return false; | 
| 1326 |         } | 
| 1327 |  | 
| 1328 |         if (len > 5 && begin[1].unicode() == 'v') { | 
| 1329 |             const QChar *c = parseIpFuture(host, begin, end, mode); | 
| 1330 |             if (c) | 
| 1331 |                 setError(errorCode: InvalidIPvFutureError, source: value, supplement: c - value.constData()); | 
| 1332 |             return !c; | 
| 1333 |         } else if (begin[1].unicode() == 'v') { | 
| 1334 |             setError(errorCode: InvalidIPvFutureError, source: value, supplement: from); | 
| 1335 |         } | 
| 1336 |  | 
| 1337 |         const QChar *c = parseIp6(host, begin: begin + 1, end: end - 1, mode); | 
| 1338 |         if (!c) | 
| 1339 |             return true; | 
| 1340 |  | 
| 1341 |         if (c == end - 1) | 
| 1342 |             setError(errorCode: InvalidIPv6AddressError, source: value, supplement: from); | 
| 1343 |         else | 
| 1344 |             setError(errorCode: InvalidCharacterInIPv6Error, source: value, supplement: c - value.constData()); | 
| 1345 |         return false; | 
| 1346 |     } | 
| 1347 |  | 
| 1348 |     // check if it's an IPv4 address | 
| 1349 |     QIPAddressUtils::IPv4Address ip4; | 
| 1350 |     if (QIPAddressUtils::parseIp4(address&: ip4, begin, end)) { | 
| 1351 |         // yes, it was | 
| 1352 |         QIPAddressUtils::toString(appendTo&: host, address: ip4); | 
| 1353 |         return true; | 
| 1354 |     } | 
| 1355 |  | 
| 1356 |     // This is probably a reg-name. | 
| 1357 |     // But it can also be an encoded string that, when decoded becomes one | 
| 1358 |     // of the types above. | 
| 1359 |     // | 
| 1360 |     // Two types of encoding are possible: | 
| 1361 |     //  percent encoding (e.g., "%31%30%2E%30%2E%30%2E%31" -> "10.0.0.1") | 
| 1362 |     //  Unicode encoding (some non-ASCII characters case-fold to digits | 
| 1363 |     //                    when nameprepping is done) | 
| 1364 |     // | 
| 1365 |     // The qt_ACE_do function below does IDNA normalization and the STD3 check. | 
| 1366 |     // That means a Unicode string may become an IPv4 address, but it cannot | 
| 1367 |     // produce a '[' or a '%'. | 
| 1368 |  | 
| 1369 |     // check for percent-encoding first | 
| 1370 |     QString s; | 
| 1371 |     if (mode == QUrl::TolerantMode && qt_urlRecode(appendTo&: s, url: QStringView{begin, end}, encoding: { }, tableModifications: nullptr)) { | 
| 1372 |         // something was decoded | 
| 1373 |         // anything encoded left? | 
| 1374 |         qsizetype pos = s.indexOf(c: QChar(0x25)); // '%' | 
| 1375 |         if (pos != -1) { | 
| 1376 |             setError(errorCode: InvalidRegNameError, source: s, supplement: pos); | 
| 1377 |             return false; | 
| 1378 |         } | 
| 1379 |  | 
| 1380 |         // recurse | 
| 1381 |         return setHost(value: s, from: 0, iend: s.size(), mode: QUrl::StrictMode); | 
| 1382 |     } | 
| 1383 |  | 
| 1384 |     s = qt_ACE_do(domain: value.mid(position: from, n: iend - from), op: NormalizeAce, dot: ForbidLeadingDot, options: {}); | 
| 1385 |     if (s.isEmpty()) { | 
| 1386 |         setError(errorCode: InvalidRegNameError, source: value); | 
| 1387 |         return false; | 
| 1388 |     } | 
| 1389 |  | 
| 1390 |     // check IPv4 again | 
| 1391 |     if (QIPAddressUtils::parseIp4(address&: ip4, begin: s.constBegin(), end: s.constEnd())) { | 
| 1392 |         QIPAddressUtils::toString(appendTo&: host, address: ip4); | 
| 1393 |     } else { | 
| 1394 |         host = s; | 
| 1395 |     } | 
| 1396 |     return true; | 
| 1397 | } | 
| 1398 |  | 
| 1399 | inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode) | 
| 1400 | { | 
| 1401 |     //   URI-reference = URI / relative-ref | 
| 1402 |     //   URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ] | 
| 1403 |     //   relative-ref  = relative-part [ "?" query ] [ "#" fragment ] | 
| 1404 |     //   hier-part     = "//" authority path-abempty | 
| 1405 |     //                 / other path types | 
| 1406 |     //   relative-part = "//" authority path-abempty | 
| 1407 |     //                 /  other path types here | 
| 1408 |  | 
| 1409 |     sectionIsPresent = 0; | 
| 1410 |     flags = 0; | 
| 1411 |     clearError(); | 
| 1412 |  | 
| 1413 |     // find the important delimiters | 
| 1414 |     qsizetype colon = -1; | 
| 1415 |     qsizetype question = -1; | 
| 1416 |     qsizetype hash = -1; | 
| 1417 |     const qsizetype len = url.size(); | 
| 1418 |     const QChar *const begin = url.constData(); | 
| 1419 |     const ushort *const data = reinterpret_cast<const ushort *>(begin); | 
| 1420 |  | 
| 1421 |     for (qsizetype i = 0; i < len; ++i) { | 
| 1422 |         size_t uc = data[i]; | 
| 1423 |         if (uc == '#' && hash == -1) { | 
| 1424 |             hash = i; | 
| 1425 |  | 
| 1426 |             // nothing more to be found | 
| 1427 |             break; | 
| 1428 |         } | 
| 1429 |  | 
| 1430 |         if (question == -1) { | 
| 1431 |             if (uc == ':' && colon == -1) | 
| 1432 |                 colon = i; | 
| 1433 |             else if (uc == '?') | 
| 1434 |                 question = i; | 
| 1435 |         } | 
| 1436 |     } | 
| 1437 |  | 
| 1438 |     // check if we have a scheme | 
| 1439 |     qsizetype hierStart; | 
| 1440 |     if (colon != -1 && setScheme(value: url, len: colon, /* don't set error */ doSetError: false)) { | 
| 1441 |         hierStart = colon + 1; | 
| 1442 |     } else { | 
| 1443 |         // recover from a failed scheme: it might not have been a scheme at all | 
| 1444 |         scheme.clear(); | 
| 1445 |         sectionIsPresent = 0; | 
| 1446 |         hierStart = 0; | 
| 1447 |     } | 
| 1448 |  | 
| 1449 |     qsizetype pathStart; | 
| 1450 |     qsizetype hierEnd = qMin<size_t>(a: qMin<size_t>(a: question, b: hash), b: len); | 
| 1451 |     if (hierEnd - hierStart >= 2 && data[hierStart] == '/' && data[hierStart + 1] == '/') { | 
| 1452 |         // we have an authority, it ends at the first slash after these | 
| 1453 |         qsizetype authorityEnd = hierEnd; | 
| 1454 |         for (qsizetype i = hierStart + 2; i < authorityEnd ; ++i) { | 
| 1455 |             if (data[i] == '/') { | 
| 1456 |                 authorityEnd = i; | 
| 1457 |                 break; | 
| 1458 |             } | 
| 1459 |         } | 
| 1460 |  | 
| 1461 |         setAuthority(auth: url, from: hierStart + 2, end: authorityEnd, mode: parsingMode); | 
| 1462 |  | 
| 1463 |         // even if we failed to set the authority properly, let's try to recover | 
| 1464 |         pathStart = authorityEnd; | 
| 1465 |         setPath(value: url, from: pathStart, end: hierEnd); | 
| 1466 |     } else { | 
| 1467 |         userName.clear(); | 
| 1468 |         password.clear(); | 
| 1469 |         host.clear(); | 
| 1470 |         port = -1; | 
| 1471 |         pathStart = hierStart; | 
| 1472 |  | 
| 1473 |         if (hierStart < hierEnd) | 
| 1474 |             setPath(value: url, from: hierStart, end: hierEnd); | 
| 1475 |         else | 
| 1476 |             path.clear(); | 
| 1477 |     } | 
| 1478 |  | 
| 1479 |     if (size_t(question) < size_t(hash)) | 
| 1480 |         setQuery(value: url, from: question + 1, iend: qMin<size_t>(a: hash, b: len)); | 
| 1481 |  | 
| 1482 |     if (hash != -1) | 
| 1483 |         setFragment(value: url, from: hash + 1, end: len); | 
| 1484 |  | 
| 1485 |     if (error || parsingMode == QUrl::TolerantMode) | 
| 1486 |         return; | 
| 1487 |  | 
| 1488 |     // The parsing so far was partially tolerant of errors, except for the | 
| 1489 |     // scheme parser (which is always strict) and the authority (which was | 
| 1490 |     // executed in strict mode). | 
| 1491 |     // If we haven't found any errors so far, continue the strict-mode parsing | 
| 1492 |     // from the path component onwards. | 
| 1493 |  | 
| 1494 |     if (!validateComponent(section: Path, input: url, begin: pathStart, end: hierEnd)) | 
| 1495 |         return; | 
| 1496 |     if (size_t(question) < size_t(hash) && !validateComponent(section: Query, input: url, begin: question + 1, end: qMin<size_t>(a: hash, b: len))) | 
| 1497 |         return; | 
| 1498 |     if (hash != -1) | 
| 1499 |         validateComponent(section: Fragment, input: url, begin: hash + 1, end: len); | 
| 1500 | } | 
| 1501 |  | 
| 1502 | QString QUrlPrivate::toLocalFile(QUrl::FormattingOptions options) const | 
| 1503 | { | 
| 1504 |     QString tmp; | 
| 1505 |     QString ourPath; | 
| 1506 |     appendPath(appendTo&: ourPath, options, appendingTo: QUrlPrivate::Path); | 
| 1507 |  | 
| 1508 |     // magic for shared drive on windows | 
| 1509 |     if (!host.isEmpty()) { | 
| 1510 |         tmp = "//"_L1  + host; | 
| 1511 | #ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only. | 
| 1512 |         if (scheme == webDavScheme()) | 
| 1513 |             tmp += webDavSslTag(); | 
| 1514 | #endif | 
| 1515 |         if (!ourPath.isEmpty() && !ourPath.startsWith(c: u'/')) | 
| 1516 |             tmp += u'/'; | 
| 1517 |         tmp += ourPath; | 
| 1518 |     } else { | 
| 1519 |         tmp = ourPath; | 
| 1520 | #ifdef Q_OS_WIN | 
| 1521 |         // magic for drives on windows | 
| 1522 |         if (ourPath.length() > 2 && ourPath.at(0) == u'/' && ourPath.at(2) == u':') | 
| 1523 |             tmp.remove(0, 1); | 
| 1524 | #endif | 
| 1525 |     } | 
| 1526 |     return tmp; | 
| 1527 | } | 
| 1528 |  | 
| 1529 | /* | 
| 1530 |     From http://www.ietf.org/rfc/rfc3986.txt, 5.2.3: Merge paths | 
| 1531 |  | 
| 1532 |     Returns a merge of the current path with the relative path passed | 
| 1533 |     as argument. | 
| 1534 |  | 
| 1535 |     Note: \a relativePath is relative (does not start with '/'). | 
| 1536 | */ | 
| 1537 | inline QString QUrlPrivate::mergePaths(const QString &relativePath) const | 
| 1538 | { | 
| 1539 |     // If the base URI has a defined authority component and an empty | 
| 1540 |     // path, then return a string consisting of "/" concatenated with | 
| 1541 |     // the reference's path; otherwise, | 
| 1542 |     if (!host.isEmpty() && path.isEmpty()) | 
| 1543 |         return u'/' + relativePath; | 
| 1544 |  | 
| 1545 |     // Return a string consisting of the reference's path component | 
| 1546 |     // appended to all but the last segment of the base URI's path | 
| 1547 |     // (i.e., excluding any characters after the right-most "/" in the | 
| 1548 |     // base URI path, or excluding the entire base URI path if it does | 
| 1549 |     // not contain any "/" characters). | 
| 1550 |     QString newPath; | 
| 1551 |     if (!path.contains(c: u'/')) | 
| 1552 |         newPath = relativePath; | 
| 1553 |     else | 
| 1554 |         newPath = QStringView{path}.left(n: path.lastIndexOf(c: u'/') + 1) + relativePath; | 
| 1555 |  | 
| 1556 |     return newPath; | 
| 1557 | } | 
| 1558 |  | 
| 1559 | // Authority-less URLs cannot have paths starting with double slashes (see | 
| 1560 | // QUrlPrivate::validityError). We refuse to turn a valid URL into invalid by | 
| 1561 | // way of QUrl::resolved(). | 
| 1562 | static void fixupNonAuthorityPath(QString *path) | 
| 1563 | { | 
| 1564 |     if (path->isEmpty() || path->at(i: 0) != u'/') | 
| 1565 |         return; | 
| 1566 |  | 
| 1567 |     // Find the first non-slash character, because its position is equal to the | 
| 1568 |     // number of slashes. We'll remove all but one of them. | 
| 1569 |     qsizetype i = 0; | 
| 1570 |     while (i + 1 < path->size() && path->at(i: i + 1) == u'/') | 
| 1571 |         ++i; | 
| 1572 |     if (i) | 
| 1573 |         path->remove(i: 0, len: i); | 
| 1574 | } | 
| 1575 |  | 
| 1576 | inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, qsizetype *position) const | 
| 1577 | { | 
| 1578 |     Q_ASSERT(!source == !position); | 
| 1579 |     if (error) { | 
| 1580 |         if (source) { | 
| 1581 |             *source = error->source; | 
| 1582 |             *position = error->position; | 
| 1583 |         } | 
| 1584 |         return error->code; | 
| 1585 |     } | 
| 1586 |  | 
| 1587 |     // There are three more cases of invalid URLs that QUrl recognizes and they | 
| 1588 |     // are only possible with constructed URLs (setXXX methods), not with | 
| 1589 |     // parsing. Therefore, they are tested here. | 
| 1590 |     // | 
| 1591 |     // Two cases are a non-empty path that doesn't start with a slash and: | 
| 1592 |     //  - with an authority | 
| 1593 |     //  - without an authority, without scheme but the path with a colon before | 
| 1594 |     //    the first slash | 
| 1595 |     // The third case is an empty authority and a non-empty path that starts | 
| 1596 |     // with "//". | 
| 1597 |     // Those cases are considered invalid because toString() would produce a URL | 
| 1598 |     // that wouldn't be parsed back to the same QUrl. | 
| 1599 |  | 
| 1600 |     if (path.isEmpty()) | 
| 1601 |         return NoError; | 
| 1602 |     if (path.at(i: 0) == u'/') { | 
| 1603 |         if (hasAuthority() || path.size() == 1 || path.at(i: 1) != u'/') | 
| 1604 |             return NoError; | 
| 1605 |         if (source) { | 
| 1606 |             *source = path; | 
| 1607 |             *position = 0; | 
| 1608 |         } | 
| 1609 |         return AuthorityAbsentAndPathIsDoubleSlash; | 
| 1610 |     } | 
| 1611 |  | 
| 1612 |     if (sectionIsPresent & QUrlPrivate::Host) { | 
| 1613 |         if (source) { | 
| 1614 |             *source = path; | 
| 1615 |             *position = 0; | 
| 1616 |         } | 
| 1617 |         return AuthorityPresentAndPathIsRelative; | 
| 1618 |     } | 
| 1619 |     if (sectionIsPresent & QUrlPrivate::Scheme) | 
| 1620 |         return NoError; | 
| 1621 |  | 
| 1622 |     // check for a path of "text:text/" | 
| 1623 |     for (qsizetype i = 0; i < path.size(); ++i) { | 
| 1624 |         ushort c = path.at(i).unicode(); | 
| 1625 |         if (c == '/') { | 
| 1626 |             // found the slash before the colon | 
| 1627 |             return NoError; | 
| 1628 |         } | 
| 1629 |         if (c == ':') { | 
| 1630 |             // found the colon before the slash, it's invalid | 
| 1631 |             if (source) { | 
| 1632 |                 *source = path; | 
| 1633 |                 *position = i; | 
| 1634 |             } | 
| 1635 |             return RelativeUrlPathContainsColonBeforeSlash; | 
| 1636 |         } | 
| 1637 |     } | 
| 1638 |     return NoError; | 
| 1639 | } | 
| 1640 |  | 
| 1641 | bool QUrlPrivate::validateComponent(QUrlPrivate::Section section, const QString &input, | 
| 1642 |                                     qsizetype begin, qsizetype end) | 
| 1643 | { | 
| 1644 |     // What we need to look out for, that the regular parser tolerates: | 
| 1645 |     //  - percent signs not followed by two hex digits | 
| 1646 |     //  - forbidden characters, which should always appear encoded | 
| 1647 |     //    '"' / '<' / '>' / '\' / '^' / '`' / '{' / '|' / '}' / BKSP | 
| 1648 |     //    control characters | 
| 1649 |     //  - delimiters not allowed in certain positions | 
| 1650 |     //    . scheme: parser is already strict | 
| 1651 |     //    . user info: gen-delims except ":" disallowed ("/" / "?" / "#" / "[" / "]" / "@") | 
| 1652 |     //    . host: parser is stricter than the standard | 
| 1653 |     //    . port: parser is stricter than the standard | 
| 1654 |     //    . path: all delimiters allowed | 
| 1655 |     //    . fragment: all delimiters allowed | 
| 1656 |     //    . query: all delimiters allowed | 
| 1657 |     static const char forbidden[] = "\"<>\\^`{|}\x7F" ; | 
| 1658 |     static const char forbiddenUserInfo[] = ":/?#[]@" ; | 
| 1659 |  | 
| 1660 |     Q_ASSERT(section != Authority && section != Hierarchy && section != FullUrl); | 
| 1661 |  | 
| 1662 |     const ushort *const data = reinterpret_cast<const ushort *>(input.constData()); | 
| 1663 |     for (size_t i = size_t(begin); i < size_t(end); ++i) { | 
| 1664 |         uint uc = data[i]; | 
| 1665 |         if (uc >= 0x80) | 
| 1666 |             continue; | 
| 1667 |  | 
| 1668 |         bool error = false; | 
| 1669 |         if ((uc == '%' && (size_t(end) < i + 2 || !isHex(c: data[i + 1]) || !isHex(c: data[i + 2]))) | 
| 1670 |                 || uc <= 0x20 || strchr(s: forbidden, c: uc)) { | 
| 1671 |             // found an error | 
| 1672 |             error = true; | 
| 1673 |         } else if (section & UserInfo) { | 
| 1674 |             if (section == UserInfo && strchr(s: forbiddenUserInfo + 1, c: uc)) | 
| 1675 |                 error = true; | 
| 1676 |             else if (section != UserInfo && strchr(s: forbiddenUserInfo, c: uc)) | 
| 1677 |                 error = true; | 
| 1678 |         } | 
| 1679 |  | 
| 1680 |         if (!error) | 
| 1681 |             continue; | 
| 1682 |  | 
| 1683 |         ErrorCode errorCode = ErrorCode(int(section) << 8); | 
| 1684 |         if (section == UserInfo) { | 
| 1685 |             // is it the user name or the password? | 
| 1686 |             errorCode = InvalidUserNameError; | 
| 1687 |             for (size_t j = size_t(begin); j < i; ++j) | 
| 1688 |                 if (data[j] == ':') { | 
| 1689 |                     errorCode = InvalidPasswordError; | 
| 1690 |                     break; | 
| 1691 |                 } | 
| 1692 |         } | 
| 1693 |  | 
| 1694 |         setError(errorCode, source: input, supplement: i); | 
| 1695 |         return false; | 
| 1696 |     } | 
| 1697 |  | 
| 1698 |     // no errors | 
| 1699 |     return true; | 
| 1700 | } | 
| 1701 |  | 
| 1702 | #if 0 | 
| 1703 | inline void QUrlPrivate::validate() const | 
| 1704 | { | 
| 1705 |     QUrlPrivate *that = (QUrlPrivate *)this; | 
| 1706 |     that->encodedOriginal = that->toEncoded(); // may detach | 
| 1707 |     parse(ParseOnly); | 
| 1708 |  | 
| 1709 |     QURL_SETFLAG(that->stateFlags, Validated); | 
| 1710 |  | 
| 1711 |     if (!isValid) | 
| 1712 |         return; | 
| 1713 |  | 
| 1714 |     QString auth = authority(); // causes the non-encoded forms to be valid | 
| 1715 |  | 
| 1716 |     // authority() calls canonicalHost() which sets this | 
| 1717 |     if (!isHostValid) | 
| 1718 |         return; | 
| 1719 |  | 
| 1720 |     if (scheme == "mailto"_L1 ) { | 
| 1721 |         if (!host.isEmpty() || port != -1 || !userName.isEmpty() || !password.isEmpty()) { | 
| 1722 |             that->isValid = false; | 
| 1723 |             that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "expected empty host, username,"  | 
| 1724 |                                                            "port and password" ), | 
| 1725 |                                       0, 0); | 
| 1726 |         } | 
| 1727 |     } else if (scheme == ftpScheme() || scheme == httpScheme()) { | 
| 1728 |         if (host.isEmpty() && !(path.isEmpty() && encodedPath.isEmpty())) { | 
| 1729 |             that->isValid = false; | 
| 1730 |             that->errorInfo.setParams(0, QT_TRANSLATE_NOOP(QUrl, "the host is empty, but not the path" ), | 
| 1731 |                                       0, 0); | 
| 1732 |         } | 
| 1733 |     } | 
| 1734 | } | 
| 1735 | #endif | 
| 1736 |  | 
| 1737 | /*! | 
| 1738 |     \macro QT_NO_URL_CAST_FROM_STRING | 
| 1739 |     \relates QUrl | 
| 1740 |  | 
| 1741 |     Disables automatic conversions from QString (or char *) to QUrl. | 
| 1742 |  | 
| 1743 |     Compiling your code with this define is useful when you have a lot of | 
| 1744 |     code that uses QString for file names and you wish to convert it to | 
| 1745 |     use QUrl for network transparency. In any code that uses QUrl, it can | 
| 1746 |     help avoid missing QUrl::resolved() calls, and other misuses of | 
| 1747 |     QString to QUrl conversions. | 
| 1748 |  | 
| 1749 |     For example, if you have code like | 
| 1750 |  | 
| 1751 |     \code | 
| 1752 |         url = filename; // probably not what you want | 
| 1753 |     \endcode | 
| 1754 |  | 
| 1755 |     you can rewrite it as | 
| 1756 |  | 
| 1757 |     \code | 
| 1758 |         url = QUrl::fromLocalFile(filename); | 
| 1759 |         url = baseurl.resolved(QUrl(filename)); | 
| 1760 |     \endcode | 
| 1761 |  | 
| 1762 |     \sa QT_NO_CAST_FROM_ASCII | 
| 1763 | */ | 
| 1764 |  | 
| 1765 |  | 
| 1766 | /*! | 
| 1767 |     Constructs a URL by parsing \a url. Note this constructor expects a proper | 
| 1768 |     URL or URL-Reference and will not attempt to guess intent. For example, the | 
| 1769 |     following declaration: | 
| 1770 |  | 
| 1771 |     \snippet code/src_corelib_io_qurl.cpp constructor-url-reference | 
| 1772 |  | 
| 1773 |     Will construct a valid URL but it may not be what one expects, as the | 
| 1774 |     scheme() part of the input is missing. For a string like the above, | 
| 1775 |     applications may want to use fromUserInput(). For this constructor or | 
| 1776 |     setUrl(), the following is probably what was intended: | 
| 1777 |  | 
| 1778 |     \snippet code/src_corelib_io_qurl.cpp constructor-url | 
| 1779 |  | 
| 1780 |     QUrl will automatically percent encode | 
| 1781 |     all characters that are not allowed in a URL and decode the percent-encoded | 
| 1782 |     sequences that represent an unreserved character (letters, digits, hyphens, | 
| 1783 |     underscores, dots and tildes). All other characters are left in their | 
| 1784 |     original forms. | 
| 1785 |  | 
| 1786 |     Parses the \a url using the parser mode \a parsingMode. In TolerantMode | 
| 1787 |     (the default), QUrl will correct certain mistakes, notably the presence of | 
| 1788 |     a percent character ('%') not followed by two hexadecimal digits, and it | 
| 1789 |     will accept any character in any position. In StrictMode, encoding mistakes | 
| 1790 |     will not be tolerated and QUrl will also check that certain forbidden | 
| 1791 |     characters are not present in unencoded form. If an error is detected in | 
| 1792 |     StrictMode, isValid() will return false. The parsing mode DecodedMode is not | 
| 1793 |     permitted in this context. | 
| 1794 |  | 
| 1795 |     Example: | 
| 1796 |  | 
| 1797 |     \snippet code/src_corelib_io_qurl.cpp 0 | 
| 1798 |  | 
| 1799 |     To construct a URL from an encoded string, you can also use fromEncoded(): | 
| 1800 |  | 
| 1801 |     \snippet code/src_corelib_io_qurl.cpp 1 | 
| 1802 |  | 
| 1803 |     Both functions are equivalent and, in Qt 5, both functions accept encoded | 
| 1804 |     data. Usually, the choice of the QUrl constructor or setUrl() versus | 
| 1805 |     fromEncoded() will depend on the source data: the constructor and setUrl() | 
| 1806 |     take a QString, whereas fromEncoded takes a QByteArray. | 
| 1807 |  | 
| 1808 |     \sa setUrl(), fromEncoded(), TolerantMode | 
| 1809 | */ | 
| 1810 | QUrl::QUrl(const QString &url, ParsingMode parsingMode) : d(nullptr) | 
| 1811 | { | 
| 1812 |     setUrl(url, mode: parsingMode); | 
| 1813 | } | 
| 1814 |  | 
| 1815 | /*! | 
| 1816 |     Constructs an empty QUrl object. | 
| 1817 | */ | 
| 1818 | QUrl::QUrl() : d(nullptr) | 
| 1819 | { | 
| 1820 | } | 
| 1821 |  | 
| 1822 | /*! | 
| 1823 |     Constructs a copy of \a other. | 
| 1824 | */ | 
| 1825 | QUrl::QUrl(const QUrl &other) noexcept : d(other.d) | 
| 1826 | { | 
| 1827 |     if (d) | 
| 1828 |         d->ref.ref(); | 
| 1829 | } | 
| 1830 |  | 
| 1831 | /*! | 
| 1832 |     Destructor; called immediately before the object is deleted. | 
| 1833 | */ | 
| 1834 | QUrl::~QUrl() | 
| 1835 | { | 
| 1836 |     if (d && !d->ref.deref()) | 
| 1837 |         delete d; | 
| 1838 | } | 
| 1839 |  | 
| 1840 | /*! | 
| 1841 |     Returns \c true if the URL is non-empty and valid; otherwise returns \c false. | 
| 1842 |  | 
| 1843 |     The URL is run through a conformance test. Every part of the URL | 
| 1844 |     must conform to the standard encoding rules of the URI standard | 
| 1845 |     for the URL to be reported as valid. | 
| 1846 |  | 
| 1847 |     \snippet code/src_corelib_io_qurl.cpp 2 | 
| 1848 | */ | 
| 1849 | bool QUrl::isValid() const | 
| 1850 | { | 
| 1851 |     if (isEmpty()) { | 
| 1852 |         // also catches d == nullptr | 
| 1853 |         return false; | 
| 1854 |     } | 
| 1855 |     return d->validityError() == QUrlPrivate::NoError; | 
| 1856 | } | 
| 1857 |  | 
| 1858 | /*! | 
| 1859 |     Returns \c true if the URL has no data; otherwise returns \c false. | 
| 1860 |  | 
| 1861 |     \sa clear() | 
| 1862 | */ | 
| 1863 | bool QUrl::isEmpty() const | 
| 1864 | { | 
| 1865 |     if (!d) return true; | 
| 1866 |     return d->isEmpty(); | 
| 1867 | } | 
| 1868 |  | 
| 1869 | /*! | 
| 1870 |     Resets the content of the QUrl. After calling this function, the | 
| 1871 |     QUrl is equal to one that has been constructed with the default | 
| 1872 |     empty constructor. | 
| 1873 |  | 
| 1874 |     \sa isEmpty() | 
| 1875 | */ | 
| 1876 | void QUrl::clear() | 
| 1877 | { | 
| 1878 |     if (d && !d->ref.deref()) | 
| 1879 |         delete d; | 
| 1880 |     d = nullptr; | 
| 1881 | } | 
| 1882 |  | 
| 1883 | /*! | 
| 1884 |     Parses \a url and sets this object to that value. QUrl will automatically | 
| 1885 |     percent encode all characters that are not allowed in a URL and decode the | 
| 1886 |     percent-encoded sequences that represent an unreserved character (letters, | 
| 1887 |     digits, hyphens, underscores, dots and tildes). All other characters are | 
| 1888 |     left in their original forms. | 
| 1889 |  | 
| 1890 |     Parses the \a url using the parser mode \a parsingMode. In TolerantMode | 
| 1891 |     (the default), QUrl will correct certain mistakes, notably the presence of | 
| 1892 |     a percent character ('%') not followed by two hexadecimal digits, and it | 
| 1893 |     will accept any character in any position. In StrictMode, encoding mistakes | 
| 1894 |     will not be tolerated and QUrl will also check that certain forbidden | 
| 1895 |     characters are not present in unencoded form. If an error is detected in | 
| 1896 |     StrictMode, isValid() will return false. The parsing mode DecodedMode is | 
| 1897 |     not permitted in this context and will produce a run-time warning. | 
| 1898 |  | 
| 1899 |     \sa url(), toString() | 
| 1900 | */ | 
| 1901 | void QUrl::setUrl(const QString &url, ParsingMode parsingMode) | 
| 1902 | { | 
| 1903 |     if (parsingMode == DecodedMode) { | 
| 1904 |         qWarning(msg: "QUrl: QUrl::DecodedMode is not permitted when parsing a full URL" ); | 
| 1905 |     } else { | 
| 1906 |         detach(); | 
| 1907 |         d->parse(url, parsingMode); | 
| 1908 |     } | 
| 1909 | } | 
| 1910 |  | 
| 1911 | /*! | 
| 1912 |     Sets the scheme of the URL to \a scheme. As a scheme can only | 
| 1913 |     contain ASCII characters, no conversion or decoding is done on the | 
| 1914 |     input. It must also start with an ASCII letter. | 
| 1915 |  | 
| 1916 |     The scheme describes the type (or protocol) of the URL. It's | 
| 1917 |     represented by one or more ASCII characters at the start the URL. | 
| 1918 |  | 
| 1919 |     A scheme is strictly \l {RFC 3986}-compliant: | 
| 1920 |         \tt {scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )} | 
| 1921 |  | 
| 1922 |     The following example shows a URL where the scheme is "ftp": | 
| 1923 |  | 
| 1924 |     \image qurl-authority2.png | 
| 1925 |  | 
| 1926 |     To set the scheme, the following call is used: | 
| 1927 |     \snippet code/src_corelib_io_qurl.cpp 11 | 
| 1928 |  | 
| 1929 |     The scheme can also be empty, in which case the URL is interpreted | 
| 1930 |     as relative. | 
| 1931 |  | 
| 1932 |     \sa scheme(), isRelative() | 
| 1933 | */ | 
| 1934 | void QUrl::setScheme(const QString &scheme) | 
| 1935 | { | 
| 1936 |     detach(); | 
| 1937 |     d->clearError(); | 
| 1938 |     if (scheme.isEmpty()) { | 
| 1939 |         // schemes are not allowed to be empty | 
| 1940 |         d->sectionIsPresent &= ~QUrlPrivate::Scheme; | 
| 1941 |         d->flags &= ~QUrlPrivate::IsLocalFile; | 
| 1942 |         d->scheme.clear(); | 
| 1943 |     } else { | 
| 1944 |         d->setScheme(value: scheme, len: scheme.size(), /* do set error */ doSetError: true); | 
| 1945 |     } | 
| 1946 | } | 
| 1947 |  | 
| 1948 | /*! | 
| 1949 |     Returns the scheme of the URL. If an empty string is returned, | 
| 1950 |     this means the scheme is undefined and the URL is then relative. | 
| 1951 |  | 
| 1952 |     The scheme can only contain US-ASCII letters or digits, which means it | 
| 1953 |     cannot contain any character that would otherwise require encoding. | 
| 1954 |     Additionally, schemes are always returned in lowercase form. | 
| 1955 |  | 
| 1956 |     \sa setScheme(), isRelative() | 
| 1957 | */ | 
| 1958 | QString QUrl::scheme() const | 
| 1959 | { | 
| 1960 |     if (!d) return QString(); | 
| 1961 |  | 
| 1962 |     return d->scheme; | 
| 1963 | } | 
| 1964 |  | 
| 1965 | /*! | 
| 1966 |     Sets the authority of the URL to \a authority. | 
| 1967 |  | 
| 1968 |     The authority of a URL is the combination of user info, a host | 
| 1969 |     name and a port. All of these elements are optional; an empty | 
| 1970 |     authority is therefore valid. | 
| 1971 |  | 
| 1972 |     The user info and host are separated by a '@', and the host and | 
| 1973 |     port are separated by a ':'. If the user info is empty, the '@' | 
| 1974 |     must be omitted; although a stray ':' is permitted if the port is | 
| 1975 |     empty. | 
| 1976 |  | 
| 1977 |     The following example shows a valid authority string: | 
| 1978 |  | 
| 1979 |     \image qurl-authority.png | 
| 1980 |  | 
| 1981 |     The \a authority data is interpreted according to \a mode: in StrictMode, | 
| 1982 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 1983 |     and some characters (including space) are not allowed in undecoded form. In | 
| 1984 |     TolerantMode (the default), all characters are accepted in undecoded form | 
| 1985 |     and the tolerant parser will correct stray '%' not followed by two hex | 
| 1986 |     characters. | 
| 1987 |  | 
| 1988 |     This function does not allow \a mode to be QUrl::DecodedMode. To set fully | 
| 1989 |     decoded data, call setUserName(), setPassword(), setHost() and setPort() | 
| 1990 |     individually. | 
| 1991 |  | 
| 1992 |     \sa setUserInfo(), setHost(), setPort() | 
| 1993 | */ | 
| 1994 | void QUrl::setAuthority(const QString &authority, ParsingMode mode) | 
| 1995 | { | 
| 1996 |     detach(); | 
| 1997 |     d->clearError(); | 
| 1998 |  | 
| 1999 |     if (mode == DecodedMode) { | 
| 2000 |         qWarning(msg: "QUrl::setAuthority(): QUrl::DecodedMode is not permitted in this function" ); | 
| 2001 |         return; | 
| 2002 |     } | 
| 2003 |  | 
| 2004 |     d->setAuthority(auth: authority, from: 0, end: authority.size(), mode); | 
| 2005 | } | 
| 2006 |  | 
| 2007 | /*! | 
| 2008 |     Returns the authority of the URL if it is defined; otherwise | 
| 2009 |     an empty string is returned. | 
| 2010 |  | 
| 2011 |     This function returns an unambiguous value, which may contain that | 
| 2012 |     characters still percent-encoded, plus some control sequences not | 
| 2013 |     representable in decoded form in QString. | 
| 2014 |  | 
| 2015 |     The \a options argument controls how to format the user info component. The | 
| 2016 |     value of QUrl::FullyDecoded is not permitted in this function. If you need | 
| 2017 |     to obtain fully decoded data, call userName(), password(), host() and | 
| 2018 |     port() individually. | 
| 2019 |  | 
| 2020 |     \sa setAuthority(), userInfo(), userName(), password(), host(), port() | 
| 2021 | */ | 
| 2022 | QString QUrl::authority(ComponentFormattingOptions options) const | 
| 2023 | { | 
| 2024 |     QString result; | 
| 2025 |     if (!d) | 
| 2026 |         return result; | 
| 2027 |  | 
| 2028 |     if (options == QUrl::FullyDecoded) { | 
| 2029 |         qWarning(msg: "QUrl::authority(): QUrl::FullyDecoded is not permitted in this function" ); | 
| 2030 |         return result; | 
| 2031 |     } | 
| 2032 |  | 
| 2033 |     d->appendAuthority(appendTo&: result, options, appendingTo: QUrlPrivate::Authority); | 
| 2034 |     return result; | 
| 2035 | } | 
| 2036 |  | 
| 2037 | /*! | 
| 2038 |     Sets the user info of the URL to \a userInfo. The user info is an | 
| 2039 |     optional part of the authority of the URL, as described in | 
| 2040 |     setAuthority(). | 
| 2041 |  | 
| 2042 |     The user info consists of a user name and optionally a password, | 
| 2043 |     separated by a ':'. If the password is empty, the colon must be | 
| 2044 |     omitted. The following example shows a valid user info string: | 
| 2045 |  | 
| 2046 |     \image qurl-authority3.png | 
| 2047 |  | 
| 2048 |     The \a userInfo data is interpreted according to \a mode: in StrictMode, | 
| 2049 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 2050 |     and some characters (including space) are not allowed in undecoded form. In | 
| 2051 |     TolerantMode (the default), all characters are accepted in undecoded form | 
| 2052 |     and the tolerant parser will correct stray '%' not followed by two hex | 
| 2053 |     characters. | 
| 2054 |  | 
| 2055 |     This function does not allow \a mode to be QUrl::DecodedMode. To set fully | 
| 2056 |     decoded data, call setUserName() and setPassword() individually. | 
| 2057 |  | 
| 2058 |     \sa userInfo(), setUserName(), setPassword(), setAuthority() | 
| 2059 | */ | 
| 2060 | void QUrl::setUserInfo(const QString &userInfo, ParsingMode mode) | 
| 2061 | { | 
| 2062 |     detach(); | 
| 2063 |     d->clearError(); | 
| 2064 |     QString trimmed = userInfo.trimmed(); | 
| 2065 |     if (mode == DecodedMode) { | 
| 2066 |         qWarning(msg: "QUrl::setUserInfo(): QUrl::DecodedMode is not permitted in this function" ); | 
| 2067 |         return; | 
| 2068 |     } | 
| 2069 |  | 
| 2070 |     d->setUserInfo(userInfo: trimmed, from: 0, end: trimmed.size()); | 
| 2071 |     if (userInfo.isNull()) { | 
| 2072 |         // QUrlPrivate::setUserInfo cleared almost everything | 
| 2073 |         // but it leaves the UserName bit set | 
| 2074 |         d->sectionIsPresent &= ~QUrlPrivate::UserInfo; | 
| 2075 |     } else if (mode == StrictMode && !d->validateComponent(section: QUrlPrivate::UserInfo, input: userInfo)) { | 
| 2076 |         d->sectionIsPresent &= ~QUrlPrivate::UserInfo; | 
| 2077 |         d->userName.clear(); | 
| 2078 |         d->password.clear(); | 
| 2079 |     } | 
| 2080 | } | 
| 2081 |  | 
| 2082 | /*! | 
| 2083 |     Returns the user info of the URL, or an empty string if the user | 
| 2084 |     info is undefined. | 
| 2085 |  | 
| 2086 |     This function returns an unambiguous value, which may contain that | 
| 2087 |     characters still percent-encoded, plus some control sequences not | 
| 2088 |     representable in decoded form in QString. | 
| 2089 |  | 
| 2090 |     The \a options argument controls how to format the user info component. The | 
| 2091 |     value of QUrl::FullyDecoded is not permitted in this function. If you need | 
| 2092 |     to obtain fully decoded data, call userName() and password() individually. | 
| 2093 |  | 
| 2094 |     \sa setUserInfo(), userName(), password(), authority() | 
| 2095 | */ | 
| 2096 | QString QUrl::userInfo(ComponentFormattingOptions options) const | 
| 2097 | { | 
| 2098 |     QString result; | 
| 2099 |     if (!d) | 
| 2100 |         return result; | 
| 2101 |  | 
| 2102 |     if (options == QUrl::FullyDecoded) { | 
| 2103 |         qWarning(msg: "QUrl::userInfo(): QUrl::FullyDecoded is not permitted in this function" ); | 
| 2104 |         return result; | 
| 2105 |     } | 
| 2106 |  | 
| 2107 |     d->appendUserInfo(appendTo&: result, options, appendingTo: QUrlPrivate::UserInfo); | 
| 2108 |     return result; | 
| 2109 | } | 
| 2110 |  | 
| 2111 | /*! | 
| 2112 |     Sets the URL's user name to \a userName. The \a userName is part | 
| 2113 |     of the user info element in the authority of the URL, as described | 
| 2114 |     in setUserInfo(). | 
| 2115 |  | 
| 2116 |     The \a userName data is interpreted according to \a mode: in StrictMode, | 
| 2117 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 2118 |     and some characters (including space) are not allowed in undecoded form. In | 
| 2119 |     TolerantMode (the default), all characters are accepted in undecoded form | 
| 2120 |     and the tolerant parser will correct stray '%' not followed by two hex | 
| 2121 |     characters. In DecodedMode, '%' stand for themselves and encoded characters | 
| 2122 |     are not possible. | 
| 2123 |  | 
| 2124 |     QUrl::DecodedMode should be used when setting the user name from a data | 
| 2125 |     source which is not a URL, such as a password dialog shown to the user or | 
| 2126 |     with a user name obtained by calling userName() with the QUrl::FullyDecoded | 
| 2127 |     formatting option. | 
| 2128 |  | 
| 2129 |     \sa userName(), setUserInfo() | 
| 2130 | */ | 
| 2131 | void QUrl::setUserName(const QString &userName, ParsingMode mode) | 
| 2132 | { | 
| 2133 |     detach(); | 
| 2134 |     d->clearError(); | 
| 2135 |  | 
| 2136 |     QString data = userName; | 
| 2137 |     if (mode == DecodedMode) { | 
| 2138 |         parseDecodedComponent(data); | 
| 2139 |         mode = TolerantMode; | 
| 2140 |     } | 
| 2141 |  | 
| 2142 |     d->setUserName(value: data, from: 0, end: data.size()); | 
| 2143 |     if (userName.isNull()) | 
| 2144 |         d->sectionIsPresent &= ~QUrlPrivate::UserName; | 
| 2145 |     else if (mode == StrictMode && !d->validateComponent(section: QUrlPrivate::UserName, input: userName)) | 
| 2146 |         d->userName.clear(); | 
| 2147 | } | 
| 2148 |  | 
| 2149 | /*! | 
| 2150 |     Returns the user name of the URL if it is defined; otherwise | 
| 2151 |     an empty string is returned. | 
| 2152 |  | 
| 2153 |     The \a options argument controls how to format the user name component. All | 
| 2154 |     values produce an unambiguous result. With QUrl::FullyDecoded, all | 
| 2155 |     percent-encoded sequences are decoded; otherwise, the returned value may | 
| 2156 |     contain some percent-encoded sequences for some control sequences not | 
| 2157 |     representable in decoded form in QString. | 
| 2158 |  | 
| 2159 |     Note that QUrl::FullyDecoded may cause data loss if those non-representable | 
| 2160 |     sequences are present. It is recommended to use that value when the result | 
| 2161 |     will be used in a non-URL context, such as setting in QAuthenticator or | 
| 2162 |     negotiating a login. | 
| 2163 |  | 
| 2164 |     \sa setUserName(), userInfo() | 
| 2165 | */ | 
| 2166 | QString QUrl::userName(ComponentFormattingOptions options) const | 
| 2167 | { | 
| 2168 |     QString result; | 
| 2169 |     if (d) | 
| 2170 |         d->appendUserName(appendTo&: result, options); | 
| 2171 |     return result; | 
| 2172 | } | 
| 2173 |  | 
| 2174 | /*! | 
| 2175 |     Sets the URL's password to \a password. The \a password is part of | 
| 2176 |     the user info element in the authority of the URL, as described in | 
| 2177 |     setUserInfo(). | 
| 2178 |  | 
| 2179 |     The \a password data is interpreted according to \a mode: in StrictMode, | 
| 2180 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 2181 |     and some characters (including space) are not allowed in undecoded form. In | 
| 2182 |     TolerantMode, all characters are accepted in undecoded form and the | 
| 2183 |     tolerant parser will correct stray '%' not followed by two hex characters. | 
| 2184 |     In DecodedMode, '%' stand for themselves and encoded characters are not | 
| 2185 |     possible. | 
| 2186 |  | 
| 2187 |     QUrl::DecodedMode should be used when setting the password from a data | 
| 2188 |     source which is not a URL, such as a password dialog shown to the user or | 
| 2189 |     with a password obtained by calling password() with the QUrl::FullyDecoded | 
| 2190 |     formatting option. | 
| 2191 |  | 
| 2192 |     \sa password(), setUserInfo() | 
| 2193 | */ | 
| 2194 | void QUrl::setPassword(const QString &password, ParsingMode mode) | 
| 2195 | { | 
| 2196 |     detach(); | 
| 2197 |     d->clearError(); | 
| 2198 |  | 
| 2199 |     QString data = password; | 
| 2200 |     if (mode == DecodedMode) { | 
| 2201 |         parseDecodedComponent(data); | 
| 2202 |         mode = TolerantMode; | 
| 2203 |     } | 
| 2204 |  | 
| 2205 |     d->setPassword(value: data, from: 0, end: data.size()); | 
| 2206 |     if (password.isNull()) | 
| 2207 |         d->sectionIsPresent &= ~QUrlPrivate::Password; | 
| 2208 |     else if (mode == StrictMode && !d->validateComponent(section: QUrlPrivate::Password, input: password)) | 
| 2209 |         d->password.clear(); | 
| 2210 | } | 
| 2211 |  | 
| 2212 | /*! | 
| 2213 |     Returns the password of the URL if it is defined; otherwise | 
| 2214 |     an empty string is returned. | 
| 2215 |  | 
| 2216 |     The \a options argument controls how to format the user name component. All | 
| 2217 |     values produce an unambiguous result. With QUrl::FullyDecoded, all | 
| 2218 |     percent-encoded sequences are decoded; otherwise, the returned value may | 
| 2219 |     contain some percent-encoded sequences for some control sequences not | 
| 2220 |     representable in decoded form in QString. | 
| 2221 |  | 
| 2222 |     Note that QUrl::FullyDecoded may cause data loss if those non-representable | 
| 2223 |     sequences are present. It is recommended to use that value when the result | 
| 2224 |     will be used in a non-URL context, such as setting in QAuthenticator or | 
| 2225 |     negotiating a login. | 
| 2226 |  | 
| 2227 |     \sa setPassword() | 
| 2228 | */ | 
| 2229 | QString QUrl::password(ComponentFormattingOptions options) const | 
| 2230 | { | 
| 2231 |     QString result; | 
| 2232 |     if (d) | 
| 2233 |         d->appendPassword(appendTo&: result, options); | 
| 2234 |     return result; | 
| 2235 | } | 
| 2236 |  | 
| 2237 | /*! | 
| 2238 |     Sets the host of the URL to \a host. The host is part of the | 
| 2239 |     authority. | 
| 2240 |  | 
| 2241 |     The \a host data is interpreted according to \a mode: in StrictMode, | 
| 2242 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 2243 |     and some characters (including space) are not allowed in undecoded form. In | 
| 2244 |     TolerantMode, all characters are accepted in undecoded form and the | 
| 2245 |     tolerant parser will correct stray '%' not followed by two hex characters. | 
| 2246 |     In DecodedMode, '%' stand for themselves and encoded characters are not | 
| 2247 |     possible. | 
| 2248 |  | 
| 2249 |     Note that, in all cases, the result of the parsing must be a valid hostname | 
| 2250 |     according to STD 3 rules, as modified by the Internationalized Resource | 
| 2251 |     Identifiers specification (RFC 3987). Invalid hostnames are not permitted | 
| 2252 |     and will cause isValid() to become false. | 
| 2253 |  | 
| 2254 |     \sa host(), setAuthority() | 
| 2255 | */ | 
| 2256 | void QUrl::setHost(const QString &host, ParsingMode mode) | 
| 2257 | { | 
| 2258 |     detach(); | 
| 2259 |     d->clearError(); | 
| 2260 |  | 
| 2261 |     QString data = host; | 
| 2262 |     if (mode == DecodedMode) { | 
| 2263 |         parseDecodedComponent(data); | 
| 2264 |         mode = TolerantMode; | 
| 2265 |     } | 
| 2266 |  | 
| 2267 |     if (d->setHost(value: data, from: 0, iend: data.size(), mode)) { | 
| 2268 |         return; | 
| 2269 |     } else if (!data.startsWith(c: u'[')) { | 
| 2270 |         // setHost failed, it might be IPv6 or IPvFuture in need of bracketing | 
| 2271 |         Q_ASSERT(d->error); | 
| 2272 |  | 
| 2273 |         data.prepend(c: u'['); | 
| 2274 |         data.append(c: u']'); | 
| 2275 |         if (!d->setHost(value: data, from: 0, iend: data.size(), mode)) { | 
| 2276 |             // failed again | 
| 2277 |             if (data.contains(c: u':')) { | 
| 2278 |                 // source data contains ':', so it's an IPv6 error | 
| 2279 |                 d->error->code = QUrlPrivate::InvalidIPv6AddressError; | 
| 2280 |             } | 
| 2281 |             d->sectionIsPresent &= ~QUrlPrivate::Host; | 
| 2282 |         } else { | 
| 2283 |             // succeeded | 
| 2284 |             d->clearError(); | 
| 2285 |         } | 
| 2286 |     } | 
| 2287 | } | 
| 2288 |  | 
| 2289 | /*! | 
| 2290 |     Returns the host of the URL if it is defined; otherwise | 
| 2291 |     an empty string is returned. | 
| 2292 |  | 
| 2293 |     The \a options argument controls how the hostname will be formatted. The | 
| 2294 |     QUrl::EncodeUnicode option will cause this function to return the hostname | 
| 2295 |     in the ASCII-Compatible Encoding (ACE) form, which is suitable for use in | 
| 2296 |     channels that are not 8-bit clean or that require the legacy hostname (such | 
| 2297 |     as DNS requests or in HTTP request headers). If that flag is not present, | 
| 2298 |     this function returns the International Domain Name (IDN) in Unicode form, | 
| 2299 |     according to the list of permissible top-level domains (see | 
| 2300 |     idnWhitelist()). | 
| 2301 |  | 
| 2302 |     All other flags are ignored. Host names cannot contain control or percent | 
| 2303 |     characters, so the returned value can be considered fully decoded. | 
| 2304 |  | 
| 2305 |     \sa setHost(), idnWhitelist(), setIdnWhitelist(), authority() | 
| 2306 | */ | 
| 2307 | QString QUrl::host(ComponentFormattingOptions options) const | 
| 2308 | { | 
| 2309 |     QString result; | 
| 2310 |     if (d) { | 
| 2311 |         d->appendHost(appendTo&: result, options); | 
| 2312 |         if (result.startsWith(c: u'[')) | 
| 2313 |             result = result.mid(position: 1, n: result.size() - 2); | 
| 2314 |     } | 
| 2315 |     return result; | 
| 2316 | } | 
| 2317 |  | 
| 2318 | /*! | 
| 2319 |     Sets the port of the URL to \a port. The port is part of the | 
| 2320 |     authority of the URL, as described in setAuthority(). | 
| 2321 |  | 
| 2322 |     \a port must be between 0 and 65535 inclusive. Setting the | 
| 2323 |     port to -1 indicates that the port is unspecified. | 
| 2324 | */ | 
| 2325 | void QUrl::setPort(int port) | 
| 2326 | { | 
| 2327 |     detach(); | 
| 2328 |     d->clearError(); | 
| 2329 |  | 
| 2330 |     if (port < -1 || port > 65535) { | 
| 2331 |         d->setError(errorCode: QUrlPrivate::InvalidPortError, source: QString::number(port), supplement: 0); | 
| 2332 |         port = -1; | 
| 2333 |     } | 
| 2334 |  | 
| 2335 |     d->port = port; | 
| 2336 |     if (port != -1) | 
| 2337 |         d->sectionIsPresent |= QUrlPrivate::Host; | 
| 2338 | } | 
| 2339 |  | 
| 2340 | /*! | 
| 2341 |     \since 4.1 | 
| 2342 |  | 
| 2343 |     Returns the port of the URL, or \a defaultPort if the port is | 
| 2344 |     unspecified. | 
| 2345 |  | 
| 2346 |     Example: | 
| 2347 |  | 
| 2348 |     \snippet code/src_corelib_io_qurl.cpp 3 | 
| 2349 | */ | 
| 2350 | int QUrl::port(int defaultPort) const | 
| 2351 | { | 
| 2352 |     if (!d) return defaultPort; | 
| 2353 |     return d->port == -1 ? defaultPort : d->port; | 
| 2354 | } | 
| 2355 |  | 
| 2356 | /*! | 
| 2357 |     Sets the path of the URL to \a path. The path is the part of the | 
| 2358 |     URL that comes after the authority but before the query string. | 
| 2359 |  | 
| 2360 |     \image qurl-ftppath.png | 
| 2361 |  | 
| 2362 |     For non-hierarchical schemes, the path will be everything | 
| 2363 |     following the scheme declaration, as in the following example: | 
| 2364 |  | 
| 2365 |     \image qurl-mailtopath.png | 
| 2366 |  | 
| 2367 |     The \a path data is interpreted according to \a mode: in StrictMode, | 
| 2368 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 2369 |     and some characters (including space) are not allowed in undecoded form. In | 
| 2370 |     TolerantMode, all characters are accepted in undecoded form and the | 
| 2371 |     tolerant parser will correct stray '%' not followed by two hex characters. | 
| 2372 |     In DecodedMode, '%' stand for themselves and encoded characters are not | 
| 2373 |     possible. | 
| 2374 |  | 
| 2375 |     QUrl::DecodedMode should be used when setting the path from a data source | 
| 2376 |     which is not a URL, such as a dialog shown to the user or with a path | 
| 2377 |     obtained by calling path() with the QUrl::FullyDecoded formatting option. | 
| 2378 |  | 
| 2379 |     \sa path() | 
| 2380 | */ | 
| 2381 | void QUrl::setPath(const QString &path, ParsingMode mode) | 
| 2382 | { | 
| 2383 |     detach(); | 
| 2384 |     d->clearError(); | 
| 2385 |  | 
| 2386 |     QString data = path; | 
| 2387 |     if (mode == DecodedMode) { | 
| 2388 |         parseDecodedComponent(data); | 
| 2389 |         mode = TolerantMode; | 
| 2390 |     } | 
| 2391 |  | 
| 2392 |     d->setPath(value: data, from: 0, end: data.size()); | 
| 2393 |  | 
| 2394 |     // optimized out, since there is no path delimiter | 
| 2395 | //    if (path.isNull()) | 
| 2396 | //        d->sectionIsPresent &= ~QUrlPrivate::Path; | 
| 2397 | //    else | 
| 2398 |     if (mode == StrictMode && !d->validateComponent(section: QUrlPrivate::Path, input: path)) | 
| 2399 |         d->path.clear(); | 
| 2400 | } | 
| 2401 |  | 
| 2402 | /*! | 
| 2403 |     Returns the path of the URL. | 
| 2404 |  | 
| 2405 |     \snippet code/src_corelib_io_qurl.cpp 12 | 
| 2406 |  | 
| 2407 |     The \a options argument controls how to format the path component. All | 
| 2408 |     values produce an unambiguous result. With QUrl::FullyDecoded, all | 
| 2409 |     percent-encoded sequences are decoded; otherwise, the returned value may | 
| 2410 |     contain some percent-encoded sequences for some control sequences not | 
| 2411 |     representable in decoded form in QString. | 
| 2412 |  | 
| 2413 |     Note that QUrl::FullyDecoded may cause data loss if those non-representable | 
| 2414 |     sequences are present. It is recommended to use that value when the result | 
| 2415 |     will be used in a non-URL context, such as sending to an FTP server. | 
| 2416 |  | 
| 2417 |     An example of data loss is when you have non-Unicode percent-encoded sequences | 
| 2418 |     and use FullyDecoded (the default): | 
| 2419 |  | 
| 2420 |     \snippet code/src_corelib_io_qurl.cpp 13 | 
| 2421 |  | 
| 2422 |     In this example, there will be some level of data loss because the \c %FF cannot | 
| 2423 |     be converted. | 
| 2424 |  | 
| 2425 |     Data loss can also occur when the path contains sub-delimiters (such as \c +): | 
| 2426 |  | 
| 2427 |     \snippet code/src_corelib_io_qurl.cpp 14 | 
| 2428 |  | 
| 2429 |     Other decoding examples: | 
| 2430 |  | 
| 2431 |     \snippet code/src_corelib_io_qurl.cpp 15 | 
| 2432 |  | 
| 2433 |     \sa setPath() | 
| 2434 | */ | 
| 2435 | QString QUrl::path(ComponentFormattingOptions options) const | 
| 2436 | { | 
| 2437 |     QString result; | 
| 2438 |     if (d) | 
| 2439 |         d->appendPath(appendTo&: result, options, appendingTo: QUrlPrivate::Path); | 
| 2440 |     return result; | 
| 2441 | } | 
| 2442 |  | 
| 2443 | /*! | 
| 2444 |     \since 5.2 | 
| 2445 |  | 
| 2446 |     Returns the name of the file, excluding the directory path. | 
| 2447 |  | 
| 2448 |     Note that, if this QUrl object is given a path ending in a slash, the name of the file is considered empty. | 
| 2449 |  | 
| 2450 |     If the path doesn't contain any slash, it is fully returned as the fileName. | 
| 2451 |  | 
| 2452 |     Example: | 
| 2453 |  | 
| 2454 |     \snippet code/src_corelib_io_qurl.cpp 7 | 
| 2455 |  | 
| 2456 |     The \a options argument controls how to format the file name component. All | 
| 2457 |     values produce an unambiguous result. With QUrl::FullyDecoded, all | 
| 2458 |     percent-encoded sequences are decoded; otherwise, the returned value may | 
| 2459 |     contain some percent-encoded sequences for some control sequences not | 
| 2460 |     representable in decoded form in QString. | 
| 2461 |  | 
| 2462 |     \sa path() | 
| 2463 | */ | 
| 2464 | QString QUrl::fileName(ComponentFormattingOptions options) const | 
| 2465 | { | 
| 2466 |     const QString ourPath = path(options); | 
| 2467 |     const qsizetype slash = ourPath.lastIndexOf(c: u'/'); | 
| 2468 |     if (slash == -1) | 
| 2469 |         return ourPath; | 
| 2470 |     return ourPath.mid(position: slash + 1); | 
| 2471 | } | 
| 2472 |  | 
| 2473 | /*! | 
| 2474 |     \since 4.2 | 
| 2475 |  | 
| 2476 |     Returns \c true if this URL contains a Query (i.e., if ? was seen on it). | 
| 2477 |  | 
| 2478 |     \sa setQuery(), query(), hasFragment() | 
| 2479 | */ | 
| 2480 | bool QUrl::hasQuery() const | 
| 2481 | { | 
| 2482 |     if (!d) return false; | 
| 2483 |     return d->hasQuery(); | 
| 2484 | } | 
| 2485 |  | 
| 2486 | /*! | 
| 2487 |     Sets the query string of the URL to \a query. | 
| 2488 |  | 
| 2489 |     This function is useful if you need to pass a query string that | 
| 2490 |     does not fit into the key-value pattern, or that uses a different | 
| 2491 |     scheme for encoding special characters than what is suggested by | 
| 2492 |     QUrl. | 
| 2493 |  | 
| 2494 |     Passing a value of QString() to \a query (a null QString) unsets | 
| 2495 |     the query completely. However, passing a value of QString("") | 
| 2496 |     will set the query to an empty value, as if the original URL | 
| 2497 |     had a lone "?". | 
| 2498 |  | 
| 2499 |     The \a query data is interpreted according to \a mode: in StrictMode, | 
| 2500 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 2501 |     and some characters (including space) are not allowed in undecoded form. In | 
| 2502 |     TolerantMode, all characters are accepted in undecoded form and the | 
| 2503 |     tolerant parser will correct stray '%' not followed by two hex characters. | 
| 2504 |     In DecodedMode, '%' stand for themselves and encoded characters are not | 
| 2505 |     possible. | 
| 2506 |  | 
| 2507 |     Query strings often contain percent-encoded sequences, so use of | 
| 2508 |     DecodedMode is discouraged. One special sequence to be aware of is that of | 
| 2509 |     the plus character ('+'). QUrl does not convert spaces to plus characters, | 
| 2510 |     even though HTML forms posted by web browsers do. In order to represent an | 
| 2511 |     actual plus character in a query, the sequence "%2B" is usually used. This | 
| 2512 |     function will leave "%2B" sequences untouched in TolerantMode or | 
| 2513 |     StrictMode. | 
| 2514 |  | 
| 2515 |     \sa query(), hasQuery() | 
| 2516 | */ | 
| 2517 | void QUrl::setQuery(const QString &query, ParsingMode mode) | 
| 2518 | { | 
| 2519 |     detach(); | 
| 2520 |     d->clearError(); | 
| 2521 |  | 
| 2522 |     QString data = query; | 
| 2523 |     if (mode == DecodedMode) { | 
| 2524 |         parseDecodedComponent(data); | 
| 2525 |         mode = TolerantMode; | 
| 2526 |     } | 
| 2527 |  | 
| 2528 |     d->setQuery(value: data, from: 0, iend: data.size()); | 
| 2529 |     if (query.isNull()) | 
| 2530 |         d->sectionIsPresent &= ~QUrlPrivate::Query; | 
| 2531 |     else if (mode == StrictMode && !d->validateComponent(section: QUrlPrivate::Query, input: query)) | 
| 2532 |         d->query.clear(); | 
| 2533 | } | 
| 2534 |  | 
| 2535 | /*! | 
| 2536 |     \overload | 
| 2537 |     \since 5.0 | 
| 2538 |     Sets the query string of the URL to \a query. | 
| 2539 |  | 
| 2540 |     This function reconstructs the query string from the QUrlQuery object and | 
| 2541 |     sets on this QUrl object. This function does not have parsing parameters | 
| 2542 |     because the QUrlQuery contains data that is already parsed. | 
| 2543 |  | 
| 2544 |     \sa query(), hasQuery() | 
| 2545 | */ | 
| 2546 | void QUrl::setQuery(const QUrlQuery &query) | 
| 2547 | { | 
| 2548 |     detach(); | 
| 2549 |     d->clearError(); | 
| 2550 |  | 
| 2551 |     // we know the data is in the right format | 
| 2552 |     d->query = query.toString(); | 
| 2553 |     if (query.isEmpty()) | 
| 2554 |         d->sectionIsPresent &= ~QUrlPrivate::Query; | 
| 2555 |     else | 
| 2556 |         d->sectionIsPresent |= QUrlPrivate::Query; | 
| 2557 | } | 
| 2558 |  | 
| 2559 | /*! | 
| 2560 |     Returns the query string of the URL if there's a query string, or an empty | 
| 2561 |     result if not. To determine if the parsed URL contained a query string, use | 
| 2562 |     hasQuery(). | 
| 2563 |  | 
| 2564 |     The \a options argument controls how to format the query component. All | 
| 2565 |     values produce an unambiguous result. With QUrl::FullyDecoded, all | 
| 2566 |     percent-encoded sequences are decoded; otherwise, the returned value may | 
| 2567 |     contain some percent-encoded sequences for some control sequences not | 
| 2568 |     representable in decoded form in QString. | 
| 2569 |  | 
| 2570 |     Note that use of QUrl::FullyDecoded in queries is discouraged, as queries | 
| 2571 |     often contain data that is supposed to remain percent-encoded, including | 
| 2572 |     the use of the "%2B" sequence to represent a plus character ('+'). | 
| 2573 |  | 
| 2574 |     \sa setQuery(), hasQuery() | 
| 2575 | */ | 
| 2576 | QString QUrl::query(ComponentFormattingOptions options) const | 
| 2577 | { | 
| 2578 |     QString result; | 
| 2579 |     if (d) { | 
| 2580 |         d->appendQuery(appendTo&: result, options, appendingTo: QUrlPrivate::Query); | 
| 2581 |         if (d->hasQuery() && result.isNull()) | 
| 2582 |             result.detach(); | 
| 2583 |     } | 
| 2584 |     return result; | 
| 2585 | } | 
| 2586 |  | 
| 2587 | /*! | 
| 2588 |     Sets the fragment of the URL to \a fragment. The fragment is the | 
| 2589 |     last part of the URL, represented by a '#' followed by a string of | 
| 2590 |     characters. It is typically used in HTTP for referring to a | 
| 2591 |     certain link or point on a page: | 
| 2592 |  | 
| 2593 |     \image qurl-fragment.png | 
| 2594 |  | 
| 2595 |     The fragment is sometimes also referred to as the URL "reference". | 
| 2596 |  | 
| 2597 |     Passing an argument of QString() (a null QString) will unset the fragment. | 
| 2598 |     Passing an argument of QString("") (an empty but not null QString) will set the | 
| 2599 |     fragment to an empty string (as if the original URL had a lone "#"). | 
| 2600 |  | 
| 2601 |     The \a fragment data is interpreted according to \a mode: in StrictMode, | 
| 2602 |     any '%' characters must be followed by exactly two hexadecimal characters | 
| 2603 |     and some characters (including space) are not allowed in undecoded form. In | 
| 2604 |     TolerantMode, all characters are accepted in undecoded form and the | 
| 2605 |     tolerant parser will correct stray '%' not followed by two hex characters. | 
| 2606 |     In DecodedMode, '%' stand for themselves and encoded characters are not | 
| 2607 |     possible. | 
| 2608 |  | 
| 2609 |     QUrl::DecodedMode should be used when setting the fragment from a data | 
| 2610 |     source which is not a URL or with a fragment obtained by calling | 
| 2611 |     fragment() with the QUrl::FullyDecoded formatting option. | 
| 2612 |  | 
| 2613 |     \sa fragment(), hasFragment() | 
| 2614 | */ | 
| 2615 | void QUrl::setFragment(const QString &fragment, ParsingMode mode) | 
| 2616 | { | 
| 2617 |     detach(); | 
| 2618 |     d->clearError(); | 
| 2619 |  | 
| 2620 |     QString data = fragment; | 
| 2621 |     if (mode == DecodedMode) { | 
| 2622 |         parseDecodedComponent(data); | 
| 2623 |         mode = TolerantMode; | 
| 2624 |     } | 
| 2625 |  | 
| 2626 |     d->setFragment(value: data, from: 0, end: data.size()); | 
| 2627 |     if (fragment.isNull()) | 
| 2628 |         d->sectionIsPresent &= ~QUrlPrivate::Fragment; | 
| 2629 |     else if (mode == StrictMode && !d->validateComponent(section: QUrlPrivate::Fragment, input: fragment)) | 
| 2630 |         d->fragment.clear(); | 
| 2631 | } | 
| 2632 |  | 
| 2633 | /*! | 
| 2634 |     Returns the fragment of the URL. To determine if the parsed URL contained a | 
| 2635 |     fragment, use hasFragment(). | 
| 2636 |  | 
| 2637 |     The \a options argument controls how to format the fragment component. All | 
| 2638 |     values produce an unambiguous result. With QUrl::FullyDecoded, all | 
| 2639 |     percent-encoded sequences are decoded; otherwise, the returned value may | 
| 2640 |     contain some percent-encoded sequences for some control sequences not | 
| 2641 |     representable in decoded form in QString. | 
| 2642 |  | 
| 2643 |     Note that QUrl::FullyDecoded may cause data loss if those non-representable | 
| 2644 |     sequences are present. It is recommended to use that value when the result | 
| 2645 |     will be used in a non-URL context. | 
| 2646 |  | 
| 2647 |     \sa setFragment(), hasFragment() | 
| 2648 | */ | 
| 2649 | QString QUrl::fragment(ComponentFormattingOptions options) const | 
| 2650 | { | 
| 2651 |     QString result; | 
| 2652 |     if (d) { | 
| 2653 |         d->appendFragment(appendTo&: result, options, appendingTo: QUrlPrivate::Fragment); | 
| 2654 |         if (d->hasFragment() && result.isNull()) | 
| 2655 |             result.detach(); | 
| 2656 |     } | 
| 2657 |     return result; | 
| 2658 | } | 
| 2659 |  | 
| 2660 | /*! | 
| 2661 |     \since 4.2 | 
| 2662 |  | 
| 2663 |     Returns \c true if this URL contains a fragment (i.e., if # was seen on it). | 
| 2664 |  | 
| 2665 |     \sa fragment(), setFragment() | 
| 2666 | */ | 
| 2667 | bool QUrl::hasFragment() const | 
| 2668 | { | 
| 2669 |     if (!d) return false; | 
| 2670 |     return d->hasFragment(); | 
| 2671 | } | 
| 2672 |  | 
| 2673 | /*! | 
| 2674 |     Returns the result of the merge of this URL with \a relative. This | 
| 2675 |     URL is used as a base to convert \a relative to an absolute URL. | 
| 2676 |  | 
| 2677 |     If \a relative is not a relative URL, this function will return \a | 
| 2678 |     relative directly. Otherwise, the paths of the two URLs are | 
| 2679 |     merged, and the new URL returned has the scheme and authority of | 
| 2680 |     the base URL, but with the merged path, as in the following | 
| 2681 |     example: | 
| 2682 |  | 
| 2683 |     \snippet code/src_corelib_io_qurl.cpp 5 | 
| 2684 |  | 
| 2685 |     Calling resolved() with ".." returns a QUrl whose directory is | 
| 2686 |     one level higher than the original. Similarly, calling resolved() | 
| 2687 |     with "../.." removes two levels from the path. If \a relative is | 
| 2688 |     "/", the path becomes "/". | 
| 2689 |  | 
| 2690 |     \sa isRelative() | 
| 2691 | */ | 
| 2692 | QUrl QUrl::resolved(const QUrl &relative) const | 
| 2693 | { | 
| 2694 |     if (!d) return relative; | 
| 2695 |     if (!relative.d) return *this; | 
| 2696 |  | 
| 2697 |     QUrl t; | 
| 2698 |     if (!relative.d->scheme.isEmpty()) { | 
| 2699 |         t = relative; | 
| 2700 |         t.detach(); | 
| 2701 |     } else { | 
| 2702 |         if (relative.d->hasAuthority()) { | 
| 2703 |             t = relative; | 
| 2704 |             t.detach(); | 
| 2705 |         } else { | 
| 2706 |             t.d = new QUrlPrivate; | 
| 2707 |  | 
| 2708 |             // copy the authority | 
| 2709 |             t.d->userName = d->userName; | 
| 2710 |             t.d->password = d->password; | 
| 2711 |             t.d->host = d->host; | 
| 2712 |             t.d->port = d->port; | 
| 2713 |             t.d->sectionIsPresent = d->sectionIsPresent & QUrlPrivate::Authority; | 
| 2714 |  | 
| 2715 |             if (relative.d->path.isEmpty()) { | 
| 2716 |                 t.d->path = d->path; | 
| 2717 |                 if (relative.d->hasQuery()) { | 
| 2718 |                     t.d->query = relative.d->query; | 
| 2719 |                     t.d->sectionIsPresent |= QUrlPrivate::Query; | 
| 2720 |                 } else if (d->hasQuery()) { | 
| 2721 |                     t.d->query = d->query; | 
| 2722 |                     t.d->sectionIsPresent |= QUrlPrivate::Query; | 
| 2723 |                 } | 
| 2724 |             } else { | 
| 2725 |                 t.d->path = relative.d->path.startsWith(c: u'/') | 
| 2726 |                             ? relative.d->path | 
| 2727 |                             : d->mergePaths(relativePath: relative.d->path); | 
| 2728 |                 if (relative.d->hasQuery()) { | 
| 2729 |                     t.d->query = relative.d->query; | 
| 2730 |                     t.d->sectionIsPresent |= QUrlPrivate::Query; | 
| 2731 |                 } | 
| 2732 |             } | 
| 2733 |         } | 
| 2734 |         t.d->scheme = d->scheme; | 
| 2735 |         if (d->hasScheme()) | 
| 2736 |             t.d->sectionIsPresent |= QUrlPrivate::Scheme; | 
| 2737 |         else | 
| 2738 |             t.d->sectionIsPresent &= ~QUrlPrivate::Scheme; | 
| 2739 |         t.d->flags |= d->flags & QUrlPrivate::IsLocalFile; | 
| 2740 |     } | 
| 2741 |     t.d->fragment = relative.d->fragment; | 
| 2742 |     if (relative.d->hasFragment()) | 
| 2743 |         t.d->sectionIsPresent |= QUrlPrivate::Fragment; | 
| 2744 |     else | 
| 2745 |         t.d->sectionIsPresent &= ~QUrlPrivate::Fragment; | 
| 2746 |  | 
| 2747 |     t.d->normalizePathSegments(path: &t.d->path); | 
| 2748 |     if (!t.d->hasAuthority()) { | 
| 2749 |         if (t.d->isLocalFile() && t.d->path.startsWith(c: u'/')) | 
| 2750 |             t.d->sectionIsPresent |= QUrlPrivate::Host; | 
| 2751 |         else | 
| 2752 |             fixupNonAuthorityPath(path: &t.d->path); | 
| 2753 |     } | 
| 2754 |  | 
| 2755 | #if defined(QURL_DEBUG) | 
| 2756 |     qDebug("QUrl(\"%ls\").resolved(\"%ls\") = \"%ls\"" , | 
| 2757 |            qUtf16Printable(url()), | 
| 2758 |            qUtf16Printable(relative.url()), | 
| 2759 |            qUtf16Printable(t.url())); | 
| 2760 | #endif | 
| 2761 |     return t; | 
| 2762 | } | 
| 2763 |  | 
| 2764 | /*! | 
| 2765 |     Returns \c true if the URL is relative; otherwise returns \c false. A URL is | 
| 2766 |     relative reference if its scheme is undefined; this function is therefore | 
| 2767 |     equivalent to calling scheme().isEmpty(). | 
| 2768 |  | 
| 2769 |     Relative references are defined in RFC 3986 section 4.2. | 
| 2770 |  | 
| 2771 |     \sa {Relative URLs vs Relative Paths} | 
| 2772 | */ | 
| 2773 | bool QUrl::isRelative() const | 
| 2774 | { | 
| 2775 |     if (!d) return true; | 
| 2776 |     return !d->hasScheme(); | 
| 2777 | } | 
| 2778 |  | 
| 2779 | /*! | 
| 2780 |     Returns a string representation of the URL. The output can be customized by | 
| 2781 |     passing flags with \a options. The option QUrl::FullyDecoded is not | 
| 2782 |     permitted in this function since it would generate ambiguous data. | 
| 2783 |  | 
| 2784 |     The resulting QString can be passed back to a QUrl later on. | 
| 2785 |  | 
| 2786 |     Synonym for toString(options). | 
| 2787 |  | 
| 2788 |     \sa FormattingOptions, toEncoded(), toString() | 
| 2789 | */ | 
| 2790 | QString QUrl::url(FormattingOptions options) const | 
| 2791 | { | 
| 2792 |     return toString(options); | 
| 2793 | } | 
| 2794 |  | 
| 2795 | /*! | 
| 2796 |     Returns a string representation of the URL. The output can be customized by | 
| 2797 |     passing flags with \a options. The option QUrl::FullyDecoded is not | 
| 2798 |     permitted in this function since it would generate ambiguous data. | 
| 2799 |  | 
| 2800 |     The default formatting option is \l{QUrl::FormattingOptions}{PrettyDecoded}. | 
| 2801 |  | 
| 2802 |     \sa FormattingOptions, url(), setUrl() | 
| 2803 | */ | 
| 2804 | QString QUrl::toString(FormattingOptions options) const | 
| 2805 | { | 
| 2806 |     QString url; | 
| 2807 |     if (!isValid()) { | 
| 2808 |         // also catches isEmpty() | 
| 2809 |         return url; | 
| 2810 |     } | 
| 2811 |     if ((options & QUrl::FullyDecoded) == QUrl::FullyDecoded) { | 
| 2812 |         qWarning(msg: "QUrl: QUrl::FullyDecoded is not permitted when reconstructing the full URL" ); | 
| 2813 |         options &= ~QUrl::FullyDecoded; | 
| 2814 |         //options |= QUrl::PrettyDecoded; // no-op, value is 0 | 
| 2815 |     } | 
| 2816 |  | 
| 2817 |     // return just the path if: | 
| 2818 |     //  - QUrl::PreferLocalFile is passed | 
| 2819 |     //  - QUrl::RemovePath isn't passed (rather stupid if the user did...) | 
| 2820 |     //  - there's no query or fragment to return | 
| 2821 |     //    that is, either they aren't present, or we're removing them | 
| 2822 |     //  - it's a local file | 
| 2823 |     if (options.testFlag(f: QUrl::PreferLocalFile) && !options.testFlag(f: QUrl::RemovePath) | 
| 2824 |             && (!d->hasQuery() || options.testFlag(f: QUrl::RemoveQuery)) | 
| 2825 |             && (!d->hasFragment() || options.testFlag(f: QUrl::RemoveFragment)) | 
| 2826 |             && isLocalFile()) { | 
| 2827 |         url = d->toLocalFile(options: options | QUrl::FullyDecoded); | 
| 2828 |         return url; | 
| 2829 |     } | 
| 2830 |  | 
| 2831 |     // for the full URL, we consider that the reserved characters are prettier if encoded | 
| 2832 |     if (options & DecodeReserved) | 
| 2833 |         options &= ~EncodeReserved; | 
| 2834 |     else | 
| 2835 |         options |= EncodeReserved; | 
| 2836 |  | 
| 2837 |     if (!(options & QUrl::RemoveScheme) && d->hasScheme()) | 
| 2838 |         url += d->scheme + u':'; | 
| 2839 |  | 
| 2840 |     bool pathIsAbsolute = d->path.startsWith(c: u'/'); | 
| 2841 |     if (!((options & QUrl::RemoveAuthority) == QUrl::RemoveAuthority) && d->hasAuthority()) { | 
| 2842 |         url += "//"_L1 ; | 
| 2843 |         d->appendAuthority(appendTo&: url, options, appendingTo: QUrlPrivate::FullUrl); | 
| 2844 |     } else if (isLocalFile() && pathIsAbsolute) { | 
| 2845 |         // Comply with the XDG file URI spec, which requires triple slashes. | 
| 2846 |         url += "//"_L1 ; | 
| 2847 |     } | 
| 2848 |  | 
| 2849 |     if (!(options & QUrl::RemovePath)) | 
| 2850 |         d->appendPath(appendTo&: url, options, appendingTo: QUrlPrivate::FullUrl); | 
| 2851 |  | 
| 2852 |     if (!(options & QUrl::RemoveQuery) && d->hasQuery()) { | 
| 2853 |         url += u'?'; | 
| 2854 |         d->appendQuery(appendTo&: url, options, appendingTo: QUrlPrivate::FullUrl); | 
| 2855 |     } | 
| 2856 |     if (!(options & QUrl::RemoveFragment) && d->hasFragment()) { | 
| 2857 |         url += u'#'; | 
| 2858 |         d->appendFragment(appendTo&: url, options, appendingTo: QUrlPrivate::FullUrl); | 
| 2859 |     } | 
| 2860 |  | 
| 2861 |     return url; | 
| 2862 | } | 
| 2863 |  | 
| 2864 | /*! | 
| 2865 |     \since 5.0 | 
| 2866 |  | 
| 2867 |     Returns a human-displayable string representation of the URL. | 
| 2868 |     The output can be customized by passing flags with \a options. | 
| 2869 |     The option RemovePassword is always enabled, since passwords | 
| 2870 |     should never be shown back to users. | 
| 2871 |  | 
| 2872 |     With the default options, the resulting QString can be passed back | 
| 2873 |     to a QUrl later on, but any password that was present initially will | 
| 2874 |     be lost. | 
| 2875 |  | 
| 2876 |     \sa FormattingOptions, toEncoded(), toString() | 
| 2877 | */ | 
| 2878 |  | 
| 2879 | QString QUrl::toDisplayString(FormattingOptions options) const | 
| 2880 | { | 
| 2881 |     return toString(options: options | RemovePassword); | 
| 2882 | } | 
| 2883 |  | 
| 2884 | /*! | 
| 2885 |     \since 5.2 | 
| 2886 |  | 
| 2887 |     Returns an adjusted version of the URL. | 
| 2888 |     The output can be customized by passing flags with \a options. | 
| 2889 |  | 
| 2890 |     The encoding options from QUrl::ComponentFormattingOption don't make | 
| 2891 |     much sense for this method, nor does QUrl::PreferLocalFile. | 
| 2892 |  | 
| 2893 |     This is always equivalent to QUrl(url.toString(options)). | 
| 2894 |  | 
| 2895 |     \sa FormattingOptions, toEncoded(), toString() | 
| 2896 | */ | 
| 2897 | QUrl QUrl::adjusted(QUrl::FormattingOptions options) const | 
| 2898 | { | 
| 2899 |     if (!isValid()) { | 
| 2900 |         // also catches isEmpty() | 
| 2901 |         return QUrl(); | 
| 2902 |     } | 
| 2903 |     QUrl that = *this; | 
| 2904 |     if (options & RemoveScheme) | 
| 2905 |         that.setScheme(QString()); | 
| 2906 |     if ((options & RemoveAuthority) == RemoveAuthority) { | 
| 2907 |         that.setAuthority(authority: QString()); | 
| 2908 |     } else { | 
| 2909 |         if ((options & RemoveUserInfo) == RemoveUserInfo) | 
| 2910 |             that.setUserInfo(userInfo: QString()); | 
| 2911 |         else if (options & RemovePassword) | 
| 2912 |             that.setPassword(password: QString()); | 
| 2913 |         if (options & RemovePort) | 
| 2914 |             that.setPort(-1); | 
| 2915 |     } | 
| 2916 |     if (options & RemoveQuery) | 
| 2917 |         that.setQuery(query: QString()); | 
| 2918 |     if (options & RemoveFragment) | 
| 2919 |         that.setFragment(fragment: QString()); | 
| 2920 |     if (options & RemovePath) { | 
| 2921 |         that.setPath(path: QString()); | 
| 2922 |     } else if (options & (StripTrailingSlash | RemoveFilename | NormalizePathSegments)) { | 
| 2923 |         that.detach(); | 
| 2924 |         QString path; | 
| 2925 |         d->appendPath(appendTo&: path, options: options | FullyEncoded, appendingTo: QUrlPrivate::Path); | 
| 2926 |         that.d->setPath(value: path, from: 0, end: path.size()); | 
| 2927 |     } | 
| 2928 |     if (that.d->isLocalFile() && that.d->path.startsWith(c: u'/')) { | 
| 2929 |         // ensure absolute file URLs have an empty authority to comply with the | 
| 2930 |         // XDG file spec (note this may undo a RemoveAuthority) | 
| 2931 |         that.d->sectionIsPresent |= QUrlPrivate::Host; | 
| 2932 |     } | 
| 2933 |     return that; | 
| 2934 | } | 
| 2935 |  | 
| 2936 | /*! | 
| 2937 |     Returns the encoded representation of the URL if it's valid; | 
| 2938 |     otherwise an empty QByteArray is returned. The output can be | 
| 2939 |     customized by passing flags with \a options. | 
| 2940 |  | 
| 2941 |     The user info, path and fragment are all converted to UTF-8, and | 
| 2942 |     all non-ASCII characters are then percent encoded. The host name | 
| 2943 |     is encoded using Punycode. | 
| 2944 | */ | 
| 2945 | QByteArray QUrl::toEncoded(FormattingOptions options) const | 
| 2946 | { | 
| 2947 |     options &= ~(FullyDecoded | FullyEncoded); | 
| 2948 |     return toString(options: options | FullyEncoded).toLatin1(); | 
| 2949 | } | 
| 2950 |  | 
| 2951 | /*! | 
| 2952 |     Parses \a input and returns the corresponding QUrl. \a input is | 
| 2953 |     assumed to be in encoded form, containing only ASCII characters. | 
| 2954 |  | 
| 2955 |     Parses the URL using \a mode. See setUrl() for more information on | 
| 2956 |     this parameter. QUrl::DecodedMode is not permitted in this context. | 
| 2957 |  | 
| 2958 |     \note In Qt versions prior to 6.7, this function took a QByteArray, not | 
| 2959 |     QByteArrayView. If you experience compile errors, it's because your code | 
| 2960 |     is passing objects that are implicitly convertible to QByteArray, but not | 
| 2961 |     QByteArrayView. Wrap the corresponding argument in \c{QByteArray{~~~}} to | 
| 2962 |     make the cast explicit. This is backwards-compatible with old Qt versions. | 
| 2963 |  | 
| 2964 |     \sa toEncoded(), setUrl() | 
| 2965 | */ | 
| 2966 | QUrl QUrl::fromEncoded(QByteArrayView input, ParsingMode mode) | 
| 2967 | { | 
| 2968 |     return QUrl(QString::fromUtf8(utf8: input), mode); | 
| 2969 | } | 
| 2970 |  | 
| 2971 | /*! | 
| 2972 |     Returns a decoded copy of \a input. \a input is first decoded from | 
| 2973 |     percent encoding, then converted from UTF-8 to unicode. | 
| 2974 |  | 
| 2975 |     \note Given invalid input (such as a string containing the sequence "%G5", | 
| 2976 |     which is not a valid hexadecimal number) the output will be invalid as | 
| 2977 |     well. As an example: the sequence "%G5" could be decoded to 'W'. | 
| 2978 | */ | 
| 2979 | QString QUrl::fromPercentEncoding(const QByteArray &input) | 
| 2980 | { | 
| 2981 |     QByteArray ba = QByteArray::fromPercentEncoding(pctEncoded: input); | 
| 2982 |     return QString::fromUtf8(utf8: ba, size: ba.size()); | 
| 2983 | } | 
| 2984 |  | 
| 2985 | /*! | 
| 2986 |     Returns an encoded copy of \a input. \a input is first converted | 
| 2987 |     to UTF-8, and all ASCII-characters that are not in the unreserved group | 
| 2988 |     are percent encoded. To prevent characters from being percent encoded | 
| 2989 |     pass them to \a exclude. To force characters to be percent encoded pass | 
| 2990 |     them to \a include. | 
| 2991 |  | 
| 2992 |     Unreserved is defined as: | 
| 2993 |        \tt {ALPHA / DIGIT / "-" / "." / "_" / "~"} | 
| 2994 |  | 
| 2995 |     \snippet code/src_corelib_io_qurl.cpp 6 | 
| 2996 | */ | 
| 2997 | QByteArray QUrl::toPercentEncoding(const QString &input, const QByteArray &exclude, const QByteArray &include) | 
| 2998 | { | 
| 2999 |     return input.toUtf8().toPercentEncoding(exclude, include); | 
| 3000 | } | 
| 3001 |  | 
| 3002 | /*! | 
| 3003 |     \since 6.3 | 
| 3004 |  | 
| 3005 |     Returns the Unicode form of the given domain name | 
| 3006 |     \a domain, which is encoded in the ASCII Compatible Encoding (ACE). | 
| 3007 |     The output can be customized by passing flags with \a options. | 
| 3008 |     The result of this function is considered equivalent to \a domain. | 
| 3009 |  | 
| 3010 |     If the value in \a domain cannot be encoded, it will be converted | 
| 3011 |     to QString and returned. | 
| 3012 |  | 
| 3013 |     The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491 | 
| 3014 |     and RFC 3492 and updated by the Unicode Technical Standard #46. It is part | 
| 3015 |     of the Internationalizing Domain Names in Applications (IDNA) specification, | 
| 3016 |     which allows for domain names (like \c "example.com") to be written using | 
| 3017 |     non-US-ASCII characters. | 
| 3018 | */ | 
| 3019 | QString QUrl::fromAce(const QByteArray &domain, QUrl::AceProcessingOptions options) | 
| 3020 | { | 
| 3021 |     return qt_ACE_do(domain: QString::fromLatin1(ba: domain), op: NormalizeAce, | 
| 3022 |                      dot: ForbidLeadingDot /*FIXME: make configurable*/, options); | 
| 3023 | } | 
| 3024 |  | 
| 3025 | /*! | 
| 3026 |     \since 6.3 | 
| 3027 |  | 
| 3028 |     Returns the ASCII Compatible Encoding of the given domain name \a domain. | 
| 3029 |     The output can be customized by passing flags with \a options. | 
| 3030 |     The result of this function is considered equivalent to \a domain. | 
| 3031 |  | 
| 3032 |     The ASCII-Compatible Encoding (ACE) is defined by RFC 3490, RFC 3491 | 
| 3033 |     and RFC 3492 and updated by the Unicode Technical Standard #46. It is part | 
| 3034 |     of the Internationalizing Domain Names in Applications (IDNA) specification, | 
| 3035 |     which allows for domain names (like \c "example.com") to be written using | 
| 3036 |     non-US-ASCII characters. | 
| 3037 |  | 
| 3038 |     This function returns an empty QByteArray if \a domain is not a valid | 
| 3039 |     hostname. Note, in particular, that IPv6 literals are not valid domain | 
| 3040 |     names. | 
| 3041 | */ | 
| 3042 | QByteArray QUrl::toAce(const QString &domain, AceProcessingOptions options) | 
| 3043 | { | 
| 3044 |     return qt_ACE_do(domain, op: ToAceOnly, dot: ForbidLeadingDot /*FIXME: make configurable*/, options) | 
| 3045 |             .toLatin1(); | 
| 3046 | } | 
| 3047 |  | 
| 3048 | /*! | 
| 3049 |     \internal | 
| 3050 |  | 
| 3051 |     \fn bool QUrl::operator<(const QUrl &lhs, const QUrl &rhs) | 
| 3052 |  | 
| 3053 |     Returns \c true if URL \a lhs is "less than" URL \a rhs. This | 
| 3054 |     provides a means of ordering URLs. | 
| 3055 | */ | 
| 3056 |  | 
| 3057 | Qt::weak_ordering compareThreeWay(const QUrl &lhs, const QUrl &rhs) | 
| 3058 | { | 
| 3059 |     if (!lhs.d || !rhs.d) { | 
| 3060 |         bool thisIsEmpty = !lhs.d || lhs.d->isEmpty(); | 
| 3061 |         bool thatIsEmpty = !rhs.d || rhs.d->isEmpty(); | 
| 3062 |  | 
| 3063 |         // sort an empty URL first | 
| 3064 |         if (thisIsEmpty) { | 
| 3065 |             if (!thatIsEmpty) | 
| 3066 |                 return Qt::weak_ordering::less; | 
| 3067 |             else | 
| 3068 |                 return Qt::weak_ordering::equivalent; | 
| 3069 |         } else { | 
| 3070 |             return Qt::weak_ordering::greater; | 
| 3071 |         } | 
| 3072 |     } | 
| 3073 |  | 
| 3074 |     int cmp; | 
| 3075 |     cmp = lhs.d->scheme.compare(s: rhs.d->scheme); | 
| 3076 |     if (cmp != 0) | 
| 3077 |         return Qt::compareThreeWay(lhs: cmp, rhs: 0); | 
| 3078 |  | 
| 3079 |     cmp = lhs.d->userName.compare(s: rhs.d->userName); | 
| 3080 |     if (cmp != 0) | 
| 3081 |         return Qt::compareThreeWay(lhs: cmp, rhs: 0); | 
| 3082 |  | 
| 3083 |     cmp = lhs.d->password.compare(s: rhs.d->password); | 
| 3084 |     if (cmp != 0) | 
| 3085 |         return Qt::compareThreeWay(lhs: cmp, rhs: 0); | 
| 3086 |  | 
| 3087 |     cmp = lhs.d->host.compare(s: rhs.d->host); | 
| 3088 |     if (cmp != 0) | 
| 3089 |         return Qt::compareThreeWay(lhs: cmp, rhs: 0); | 
| 3090 |  | 
| 3091 |     if (lhs.d->port != rhs.d->port) | 
| 3092 |         return Qt::compareThreeWay(lhs: lhs.d->port, rhs: rhs.d->port); | 
| 3093 |  | 
| 3094 |     cmp = lhs.d->path.compare(s: rhs.d->path); | 
| 3095 |     if (cmp != 0) | 
| 3096 |         return Qt::compareThreeWay(lhs: cmp, rhs: 0); | 
| 3097 |  | 
| 3098 |     if (lhs.d->hasQuery() != rhs.d->hasQuery()) | 
| 3099 |         return rhs.d->hasQuery() ? Qt::weak_ordering::less : Qt::weak_ordering::greater; | 
| 3100 |  | 
| 3101 |     cmp = lhs.d->query.compare(s: rhs.d->query); | 
| 3102 |     if (cmp != 0) | 
| 3103 |         return Qt::compareThreeWay(lhs: cmp, rhs: 0); | 
| 3104 |  | 
| 3105 |     if (lhs.d->hasFragment() != rhs.d->hasFragment()) | 
| 3106 |         return rhs.d->hasFragment() ? Qt::weak_ordering::less : Qt::weak_ordering::greater; | 
| 3107 |  | 
| 3108 |     cmp = lhs.d->fragment.compare(s: rhs.d->fragment); | 
| 3109 |     return Qt::compareThreeWay(lhs: cmp, rhs: 0); | 
| 3110 | } | 
| 3111 |  | 
| 3112 | /*! | 
| 3113 |     \fn bool QUrl::operator==(const QUrl &lhs, const QUrl &rhs) | 
| 3114 |  | 
| 3115 |     Returns \c true if \a lhs and \a rhs URLs are equivalent; | 
| 3116 |     otherwise returns \c false. | 
| 3117 |  | 
| 3118 |     \sa matches() | 
| 3119 | */ | 
| 3120 |  | 
| 3121 | bool comparesEqual(const QUrl &lhs, const QUrl &rhs) | 
| 3122 | { | 
| 3123 |     if (!lhs.d && !rhs.d) | 
| 3124 |         return true; | 
| 3125 |     if (!lhs.d) | 
| 3126 |         return rhs.d->isEmpty(); | 
| 3127 |     if (!rhs.d) | 
| 3128 |         return lhs.d->isEmpty(); | 
| 3129 |  | 
| 3130 |     // First, compare which sections are present, since it speeds up the | 
| 3131 |     // processing considerably. We just have to ignore the host-is-present flag | 
| 3132 |     // for local files (the "file" protocol), due to the requirements of the | 
| 3133 |     // XDG file URI specification. | 
| 3134 |     int mask = QUrlPrivate::FullUrl; | 
| 3135 |     if (lhs.isLocalFile()) | 
| 3136 |         mask &= ~QUrlPrivate::Host; | 
| 3137 |     return (lhs.d->sectionIsPresent & mask) == (rhs.d->sectionIsPresent & mask) && | 
| 3138 |             lhs.d->scheme == rhs.d->scheme && | 
| 3139 |             lhs.d->userName == rhs.d->userName && | 
| 3140 |             lhs.d->password == rhs.d->password && | 
| 3141 |             lhs.d->host == rhs.d->host && | 
| 3142 |             lhs.d->port == rhs.d->port && | 
| 3143 |             lhs.d->path == rhs.d->path && | 
| 3144 |             lhs.d->query == rhs.d->query && | 
| 3145 |             lhs.d->fragment == rhs.d->fragment; | 
| 3146 | } | 
| 3147 |  | 
| 3148 | /*! | 
| 3149 |     \since 5.2 | 
| 3150 |  | 
| 3151 |     Returns \c true if this URL and the given \a url are equal after | 
| 3152 |     applying \a options to both; otherwise returns \c false. | 
| 3153 |  | 
| 3154 |     This is equivalent to calling adjusted(options) on both URLs | 
| 3155 |     and comparing the resulting urls, but faster. | 
| 3156 |  | 
| 3157 | */ | 
| 3158 | bool QUrl::matches(const QUrl &url, FormattingOptions options) const | 
| 3159 | { | 
| 3160 |     if (!d && !url.d) | 
| 3161 |         return true; | 
| 3162 |     if (!d) | 
| 3163 |         return url.d->isEmpty(); | 
| 3164 |     if (!url.d) | 
| 3165 |         return d->isEmpty(); | 
| 3166 |  | 
| 3167 |     // First, compare which sections are present, since it speeds up the | 
| 3168 |     // processing considerably. We just have to ignore the host-is-present flag | 
| 3169 |     // for local files (the "file" protocol), due to the requirements of the | 
| 3170 |     // XDG file URI specification. | 
| 3171 |     int mask = QUrlPrivate::FullUrl; | 
| 3172 |     if (isLocalFile()) | 
| 3173 |         mask &= ~QUrlPrivate::Host; | 
| 3174 |  | 
| 3175 |     if (options.testFlag(f: QUrl::RemoveScheme)) | 
| 3176 |         mask &= ~QUrlPrivate::Scheme; | 
| 3177 |     else if (d->scheme != url.d->scheme) | 
| 3178 |         return false; | 
| 3179 |  | 
| 3180 |     if (options.testFlag(f: QUrl::RemovePassword)) | 
| 3181 |         mask &= ~QUrlPrivate::Password; | 
| 3182 |     else if (d->password != url.d->password) | 
| 3183 |         return false; | 
| 3184 |  | 
| 3185 |     if (options.testFlag(f: QUrl::RemoveUserInfo)) | 
| 3186 |         mask &= ~QUrlPrivate::UserName; | 
| 3187 |     else if (d->userName != url.d->userName) | 
| 3188 |         return false; | 
| 3189 |  | 
| 3190 |     if (options.testFlag(f: QUrl::RemovePort)) | 
| 3191 |         mask &= ~QUrlPrivate::Port; | 
| 3192 |     else if (d->port != url.d->port) | 
| 3193 |         return false; | 
| 3194 |  | 
| 3195 |     if (options.testFlag(f: QUrl::RemoveAuthority)) | 
| 3196 |         mask &= ~QUrlPrivate::Host; | 
| 3197 |     else if (d->host != url.d->host) | 
| 3198 |         return false; | 
| 3199 |  | 
| 3200 |     if (options.testFlag(f: QUrl::RemoveQuery)) | 
| 3201 |         mask &= ~QUrlPrivate::Query; | 
| 3202 |     else if (d->query != url.d->query) | 
| 3203 |         return false; | 
| 3204 |  | 
| 3205 |     if (options.testFlag(f: QUrl::RemoveFragment)) | 
| 3206 |         mask &= ~QUrlPrivate::Fragment; | 
| 3207 |     else if (d->fragment != url.d->fragment) | 
| 3208 |         return false; | 
| 3209 |  | 
| 3210 |     if ((d->sectionIsPresent & mask) != (url.d->sectionIsPresent & mask)) | 
| 3211 |         return false; | 
| 3212 |  | 
| 3213 |     if (options.testFlag(f: QUrl::RemovePath)) | 
| 3214 |         return true; | 
| 3215 |  | 
| 3216 |     // Compare paths, after applying path-related options | 
| 3217 |     QString path1; | 
| 3218 |     d->appendPath(appendTo&: path1, options, appendingTo: QUrlPrivate::Path); | 
| 3219 |     QString path2; | 
| 3220 |     url.d->appendPath(appendTo&: path2, options, appendingTo: QUrlPrivate::Path); | 
| 3221 |     return path1 == path2; | 
| 3222 | } | 
| 3223 |  | 
| 3224 | /*! | 
| 3225 |     \fn bool QUrl::operator !=(const QUrl &lhs, const QUrl &rhs) | 
| 3226 |  | 
| 3227 |     Returns \c true if \a lhs and \a rhs URLs are not equal; | 
| 3228 |     otherwise returns \c false. | 
| 3229 |  | 
| 3230 |     \sa matches() | 
| 3231 | */ | 
| 3232 |  | 
| 3233 | /*! | 
| 3234 |     Assigns the specified \a url to this object. | 
| 3235 | */ | 
| 3236 | QUrl &QUrl::operator =(const QUrl &url) noexcept | 
| 3237 | { | 
| 3238 |     if (!d) { | 
| 3239 |         if (url.d) { | 
| 3240 |             url.d->ref.ref(); | 
| 3241 |             d = url.d; | 
| 3242 |         } | 
| 3243 |     } else { | 
| 3244 |         if (url.d) | 
| 3245 |             qAtomicAssign(d, x: url.d); | 
| 3246 |         else | 
| 3247 |             clear(); | 
| 3248 |     } | 
| 3249 |     return *this; | 
| 3250 | } | 
| 3251 |  | 
| 3252 | /*! | 
| 3253 |     Assigns the specified \a url to this object. | 
| 3254 | */ | 
| 3255 | QUrl &QUrl::operator =(const QString &url) | 
| 3256 | { | 
| 3257 |     if (url.isEmpty()) { | 
| 3258 |         clear(); | 
| 3259 |     } else { | 
| 3260 |         detach(); | 
| 3261 |         d->parse(url, parsingMode: TolerantMode); | 
| 3262 |     } | 
| 3263 |     return *this; | 
| 3264 | } | 
| 3265 |  | 
| 3266 | /*! | 
| 3267 |     \fn void QUrl::swap(QUrl &other) | 
| 3268 |     \since 4.8 | 
| 3269 |     \memberswap{URL} | 
| 3270 | */ | 
| 3271 |  | 
| 3272 | /*! | 
| 3273 |     \internal | 
| 3274 |  | 
| 3275 |     Forces a detach. | 
| 3276 | */ | 
| 3277 | void QUrl::detach() | 
| 3278 | { | 
| 3279 |     if (!d) | 
| 3280 |         d = new QUrlPrivate; | 
| 3281 |     else | 
| 3282 |         qAtomicDetach(d); | 
| 3283 | } | 
| 3284 |  | 
| 3285 | /*! | 
| 3286 |     \internal | 
| 3287 | */ | 
| 3288 | bool QUrl::isDetached() const | 
| 3289 | { | 
| 3290 |     return !d || d->ref.loadRelaxed() == 1; | 
| 3291 | } | 
| 3292 |  | 
| 3293 | static QString fromNativeSeparators(const QString &pathName) | 
| 3294 | { | 
| 3295 | #if defined(Q_OS_WIN) | 
| 3296 |     QString result(pathName); | 
| 3297 |     const QChar nativeSeparator = u'\\'; | 
| 3298 |     auto i = result.indexOf(nativeSeparator); | 
| 3299 |     if (i != -1) { | 
| 3300 |         QChar * const data = result.data(); | 
| 3301 |         const auto length = result.length(); | 
| 3302 |         for (; i < length; ++i) { | 
| 3303 |             if (data[i] == nativeSeparator) | 
| 3304 |                 data[i] = u'/'; | 
| 3305 |         } | 
| 3306 |     } | 
| 3307 |     return result; | 
| 3308 | #else | 
| 3309 |     return pathName; | 
| 3310 | #endif | 
| 3311 | } | 
| 3312 |  | 
| 3313 | /*! | 
| 3314 |     Returns a QUrl representation of \a localFile, interpreted as a local | 
| 3315 |     file. This function accepts paths separated by slashes as well as the | 
| 3316 |     native separator for this platform. | 
| 3317 |  | 
| 3318 |     This function also accepts paths with a doubled leading slash (or | 
| 3319 |     backslash) to indicate a remote file, as in | 
| 3320 |     "//servername/path/to/file.txt". Note that only certain platforms can | 
| 3321 |     actually open this file using QFile::open(). | 
| 3322 |  | 
| 3323 |     An empty \a localFile leads to an empty URL (since Qt 5.4). | 
| 3324 |  | 
| 3325 |     \snippet code/src_corelib_io_qurl.cpp 16 | 
| 3326 |  | 
| 3327 |     In the first line in snippet above, a file URL is constructed from a | 
| 3328 |     local, relative path. A file URL with a relative path only makes sense | 
| 3329 |     if there is a base URL to resolve it against. For example: | 
| 3330 |  | 
| 3331 |     \snippet code/src_corelib_io_qurl.cpp 17 | 
| 3332 |  | 
| 3333 |     To resolve such a URL, it's necessary to remove the scheme beforehand: | 
| 3334 |  | 
| 3335 |     \snippet code/src_corelib_io_qurl.cpp 18 | 
| 3336 |  | 
| 3337 |     For this reason, it is better to use a relative URL (that is, no scheme) | 
| 3338 |     for relative file paths: | 
| 3339 |  | 
| 3340 |     \snippet code/src_corelib_io_qurl.cpp 19 | 
| 3341 |  | 
| 3342 |     \sa toLocalFile(), isLocalFile(), QDir::toNativeSeparators() | 
| 3343 | */ | 
| 3344 | QUrl QUrl::fromLocalFile(const QString &localFile) | 
| 3345 | { | 
| 3346 |     QUrl url; | 
| 3347 |     QString deslashified = fromNativeSeparators(pathName: localFile); | 
| 3348 |     if (deslashified.isEmpty()) | 
| 3349 |         return url; | 
| 3350 |     QString scheme = fileScheme(); | 
| 3351 |     char16_t firstChar = deslashified.at(i: 0).unicode(); | 
| 3352 |     char16_t secondChar = deslashified.size() > 1 ? deslashified.at(i: 1).unicode() : u'\0'; | 
| 3353 |  | 
| 3354 |     // magic for drives on windows | 
| 3355 |     if (firstChar != u'/' && secondChar == u':') { | 
| 3356 |         deslashified.prepend(c: u'/'); | 
| 3357 |         firstChar = u'/'; | 
| 3358 |     } else if (firstChar == u'/' && secondChar == u'/') { | 
| 3359 |         // magic for shared drive on windows | 
| 3360 |         qsizetype indexOfPath = deslashified.indexOf(c: u'/', from: 2); | 
| 3361 |         QStringView hostSpec = QStringView{deslashified}.mid(pos: 2, n: indexOfPath - 2); | 
| 3362 |         // Check for Windows-specific WebDAV specification: "//host@SSL/path". | 
| 3363 |         if (hostSpec.endsWith(s: webDavSslTag(), cs: Qt::CaseInsensitive)) { | 
| 3364 |             hostSpec.truncate(n: hostSpec.size() - 4); | 
| 3365 |             scheme = webDavScheme(); | 
| 3366 |         } | 
| 3367 |  | 
| 3368 |         // hosts can't be IPv6 addresses without [], so we can use QUrlPrivate::setHost | 
| 3369 |         url.detach(); | 
| 3370 |         if (!url.d->setHost(value: hostSpec.toString(), from: 0, iend: hostSpec.size(), mode: StrictMode)) { | 
| 3371 |             if (url.d->error->code != QUrlPrivate::InvalidRegNameError) | 
| 3372 |                 return url; | 
| 3373 |  | 
| 3374 |             // Path hostname is not a valid URL host, so set it entirely in the path | 
| 3375 |             // (by leaving deslashified unchanged) | 
| 3376 |         } else if (indexOfPath > 2) { | 
| 3377 |             deslashified = deslashified.right(n: deslashified.size() - indexOfPath); | 
| 3378 |         } else { | 
| 3379 |             deslashified.clear(); | 
| 3380 |         } | 
| 3381 |     } | 
| 3382 |     if (firstChar == u'/') { | 
| 3383 |         // ensure absolute file URLs have an empty authority to comply with the XDG file spec | 
| 3384 |         url.detach(); | 
| 3385 |         url.d->sectionIsPresent |= QUrlPrivate::Host; | 
| 3386 |     } | 
| 3387 |  | 
| 3388 |     url.setScheme(scheme); | 
| 3389 |  | 
| 3390 |     // not directly using setPath here, as we do a few more transforms | 
| 3391 |     parseDecodedComponent(data&: deslashified); | 
| 3392 |     if (!qt_urlRecode(appendTo&: url.d->path, url: deslashified, encoding: {}, tableModifications: localPathFromUser)) | 
| 3393 |         url.d->path = deslashified; | 
| 3394 |  | 
| 3395 |     return url; | 
| 3396 | } | 
| 3397 |  | 
| 3398 | /*! | 
| 3399 |     Returns the path of this URL formatted as a local file path. The path | 
| 3400 |     returned will use forward slashes, even if it was originally created | 
| 3401 |     from one with backslashes. | 
| 3402 |  | 
| 3403 |     If this URL contains a non-empty hostname, it will be encoded in the | 
| 3404 |     returned value in the form found on SMB networks (for example, | 
| 3405 |     "//servername/path/to/file.txt"). | 
| 3406 |  | 
| 3407 |     \snippet code/src_corelib_io_qurl.cpp 20 | 
| 3408 |  | 
| 3409 |     Note: if the path component of this URL contains a non-UTF-8 binary | 
| 3410 |     sequence (such as %80), the behaviour of this function is undefined. | 
| 3411 |  | 
| 3412 |     \sa fromLocalFile(), isLocalFile() | 
| 3413 | */ | 
| 3414 | QString QUrl::toLocalFile() const | 
| 3415 | { | 
| 3416 |     // the call to isLocalFile() also ensures that we're parsed | 
| 3417 |     if (!isLocalFile()) | 
| 3418 |         return QString(); | 
| 3419 |  | 
| 3420 |     return d->toLocalFile(options: QUrl::FullyDecoded); | 
| 3421 | } | 
| 3422 |  | 
| 3423 | /*! | 
| 3424 |     \since 4.8 | 
| 3425 |     Returns \c true if this URL is pointing to a local file path. A URL is a | 
| 3426 |     local file path if the scheme is "file". | 
| 3427 |  | 
| 3428 |     Note that this function considers URLs with hostnames to be local file | 
| 3429 |     paths, even if the eventual file path cannot be opened with | 
| 3430 |     QFile::open(). | 
| 3431 |  | 
| 3432 |     \sa fromLocalFile(), toLocalFile() | 
| 3433 | */ | 
| 3434 | bool QUrl::isLocalFile() const | 
| 3435 | { | 
| 3436 |     return d && d->isLocalFile(); | 
| 3437 | } | 
| 3438 |  | 
| 3439 | /*! | 
| 3440 |     Returns \c true if this URL is a parent of \a childUrl. \a childUrl is a child | 
| 3441 |     of this URL if the two URLs share the same scheme and authority, | 
| 3442 |     and this URL's path is a parent of the path of \a childUrl. | 
| 3443 | */ | 
| 3444 | bool QUrl::isParentOf(const QUrl &childUrl) const | 
| 3445 | { | 
| 3446 |     QString childPath = childUrl.path(); | 
| 3447 |  | 
| 3448 |     if (!d) | 
| 3449 |         return ((childUrl.scheme().isEmpty()) | 
| 3450 |             && (childUrl.authority().isEmpty()) | 
| 3451 |             && childPath.size() > 0 && childPath.at(i: 0) == u'/'); | 
| 3452 |  | 
| 3453 |     QString ourPath = path(); | 
| 3454 |  | 
| 3455 |     return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme()) | 
| 3456 |             && (childUrl.authority().isEmpty() || authority() == childUrl.authority()) | 
| 3457 |             &&  childPath.startsWith(s: ourPath) | 
| 3458 |             && ((ourPath.endsWith(c: u'/') && childPath.size() > ourPath.size()) | 
| 3459 |                 || (!ourPath.endsWith(c: u'/') && childPath.size() > ourPath.size() | 
| 3460 |                     && childPath.at(i: ourPath.size()) == u'/'))); | 
| 3461 | } | 
| 3462 |  | 
| 3463 |  | 
| 3464 | #ifndef QT_NO_DATASTREAM | 
| 3465 | /*! \relates QUrl | 
| 3466 |  | 
| 3467 |     Writes url \a url to the stream \a out and returns a reference | 
| 3468 |     to the stream. | 
| 3469 |  | 
| 3470 |     \sa{Serializing Qt Data Types}{Format of the QDataStream operators} | 
| 3471 | */ | 
| 3472 | QDataStream &operator<<(QDataStream &out, const QUrl &url) | 
| 3473 | { | 
| 3474 |     QByteArray u; | 
| 3475 |     if (url.isValid()) | 
| 3476 |         u = url.toEncoded(); | 
| 3477 |     out << u; | 
| 3478 |     return out; | 
| 3479 | } | 
| 3480 |  | 
| 3481 | /*! \relates QUrl | 
| 3482 |  | 
| 3483 |     Reads a url into \a url from the stream \a in and returns a | 
| 3484 |     reference to the stream. | 
| 3485 |  | 
| 3486 |     \sa{Serializing Qt Data Types}{Format of the QDataStream operators} | 
| 3487 | */ | 
| 3488 | QDataStream &operator>>(QDataStream &in, QUrl &url) | 
| 3489 | { | 
| 3490 |     QByteArray u; | 
| 3491 |     in >> u; | 
| 3492 |     url.setUrl(url: QString::fromLatin1(ba: u)); | 
| 3493 |     return in; | 
| 3494 | } | 
| 3495 | #endif // QT_NO_DATASTREAM | 
| 3496 |  | 
| 3497 | #ifndef QT_NO_DEBUG_STREAM | 
| 3498 | QDebug operator<<(QDebug d, const QUrl &url) | 
| 3499 | { | 
| 3500 |     QDebugStateSaver saver(d); | 
| 3501 |     d.nospace() << "QUrl("  << url.toDisplayString() << ')'; | 
| 3502 |     return d; | 
| 3503 | } | 
| 3504 | #endif | 
| 3505 |  | 
| 3506 | static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition) | 
| 3507 | { | 
| 3508 |     QChar c = size_t(errorPosition) < size_t(errorSource.size()) ? | 
| 3509 |                 errorSource.at(i: errorPosition) : QChar(QChar::Null); | 
| 3510 |  | 
| 3511 |     switch (errorCode) { | 
| 3512 |     case QUrlPrivate::NoError: | 
| 3513 |         Q_UNREACHABLE_RETURN(QString()); // QUrl::errorString should have treated this condition | 
| 3514 |  | 
| 3515 |     case QUrlPrivate::InvalidSchemeError: { | 
| 3516 |         auto msg = "Invalid scheme (character '%1' not permitted)"_L1 ; | 
| 3517 |         return msg.arg(args&: c); | 
| 3518 |     } | 
| 3519 |  | 
| 3520 |     case QUrlPrivate::InvalidUserNameError: | 
| 3521 |         return "Invalid user name (character '%1' not permitted)"_L1  | 
| 3522 |                 .arg(args&: c); | 
| 3523 |  | 
| 3524 |     case QUrlPrivate::InvalidPasswordError: | 
| 3525 |         return "Invalid password (character '%1' not permitted)"_L1  | 
| 3526 |                 .arg(args&: c); | 
| 3527 |  | 
| 3528 |     case QUrlPrivate::InvalidRegNameError: | 
| 3529 |         if (errorPosition >= 0) | 
| 3530 |             return "Invalid hostname (character '%1' not permitted)"_L1  | 
| 3531 |                     .arg(args&: c); | 
| 3532 |         else | 
| 3533 |             return QStringLiteral("Invalid hostname (contains invalid characters)" ); | 
| 3534 |     case QUrlPrivate::InvalidIPv4AddressError: | 
| 3535 |         return QString(); // doesn't happen yet | 
| 3536 |     case QUrlPrivate::InvalidIPv6AddressError: | 
| 3537 |         return QStringLiteral("Invalid IPv6 address" ); | 
| 3538 |     case QUrlPrivate::InvalidCharacterInIPv6Error: | 
| 3539 |         return "Invalid IPv6 address (character '%1' not permitted)"_L1 .arg(args&: c); | 
| 3540 |     case QUrlPrivate::InvalidIPvFutureError: | 
| 3541 |         return "Invalid IPvFuture address (character '%1' not permitted)"_L1 .arg(args&: c); | 
| 3542 |     case QUrlPrivate::HostMissingEndBracket: | 
| 3543 |         return QStringLiteral("Expected ']' to match '[' in hostname" ); | 
| 3544 |  | 
| 3545 |     case QUrlPrivate::InvalidPortError: | 
| 3546 |         return QStringLiteral("Invalid port or port number out of range" ); | 
| 3547 |     case QUrlPrivate::PortEmptyError: | 
| 3548 |         return QStringLiteral("Port field was empty" ); | 
| 3549 |  | 
| 3550 |     case QUrlPrivate::InvalidPathError: | 
| 3551 |         return "Invalid path (character '%1' not permitted)"_L1  | 
| 3552 |                 .arg(args&: c); | 
| 3553 |  | 
| 3554 |     case QUrlPrivate::InvalidQueryError: | 
| 3555 |         return "Invalid query (character '%1' not permitted)"_L1  | 
| 3556 |                 .arg(args&: c); | 
| 3557 |  | 
| 3558 |     case QUrlPrivate::InvalidFragmentError: | 
| 3559 |         return "Invalid fragment (character '%1' not permitted)"_L1  | 
| 3560 |                 .arg(args&: c); | 
| 3561 |  | 
| 3562 |     case QUrlPrivate::AuthorityPresentAndPathIsRelative: | 
| 3563 |         return QStringLiteral("Path component is relative and authority is present" ); | 
| 3564 |     case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash: | 
| 3565 |         return QStringLiteral("Path component starts with '//' and authority is absent" ); | 
| 3566 |     case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash: | 
| 3567 |         return QStringLiteral("Relative URL's path component contains ':' before any '/'" ); | 
| 3568 |     } | 
| 3569 |  | 
| 3570 |     Q_UNREACHABLE_RETURN(QString()); | 
| 3571 | } | 
| 3572 |  | 
| 3573 | static inline void appendComponentIfPresent(QString &msg, bool present, const char *componentName, | 
| 3574 |                                             const QString &component) | 
| 3575 | { | 
| 3576 |     if (present) | 
| 3577 |         msg += QLatin1StringView(componentName) % u'"' % component % "\","_L1 ; | 
| 3578 | } | 
| 3579 |  | 
| 3580 | /*! | 
| 3581 |     \since 4.2 | 
| 3582 |  | 
| 3583 |     Returns an error message if the last operation that modified this QUrl | 
| 3584 |     object ran into a parsing error. If no error was detected, this function | 
| 3585 |     returns an empty string and isValid() returns \c true. | 
| 3586 |  | 
| 3587 |     The error message returned by this function is technical in nature and may | 
| 3588 |     not be understood by end users. It is mostly useful to developers trying to | 
| 3589 |     understand why QUrl will not accept some input. | 
| 3590 |  | 
| 3591 |     \sa QUrl::ParsingMode | 
| 3592 | */ | 
| 3593 | QString QUrl::errorString() const | 
| 3594 | { | 
| 3595 |     QString msg; | 
| 3596 |     if (!d) | 
| 3597 |         return msg; | 
| 3598 |  | 
| 3599 |     QString errorSource; | 
| 3600 |     qsizetype errorPosition = 0; | 
| 3601 |     QUrlPrivate::ErrorCode errorCode = d->validityError(source: &errorSource, position: &errorPosition); | 
| 3602 |     if (errorCode == QUrlPrivate::NoError) | 
| 3603 |         return msg; | 
| 3604 |  | 
| 3605 |     msg += errorMessage(errorCode, errorSource, errorPosition); | 
| 3606 |     msg += "; source was \""_L1 ; | 
| 3607 |     msg += errorSource; | 
| 3608 |     msg += "\";"_L1 ; | 
| 3609 |     appendComponentIfPresent(msg, present: d->sectionIsPresent & QUrlPrivate::Scheme, | 
| 3610 |                              componentName: " scheme = " , component: d->scheme); | 
| 3611 |     appendComponentIfPresent(msg, present: d->sectionIsPresent & QUrlPrivate::UserInfo, | 
| 3612 |                              componentName: " userinfo = " , component: userInfo()); | 
| 3613 |     appendComponentIfPresent(msg, present: d->sectionIsPresent & QUrlPrivate::Host, | 
| 3614 |                              componentName: " host = " , component: d->host); | 
| 3615 |     appendComponentIfPresent(msg, present: d->port != -1, | 
| 3616 |                              componentName: " port = " , component: QString::number(d->port)); | 
| 3617 |     appendComponentIfPresent(msg, present: !d->path.isEmpty(), | 
| 3618 |                              componentName: " path = " , component: d->path); | 
| 3619 |     appendComponentIfPresent(msg, present: d->sectionIsPresent & QUrlPrivate::Query, | 
| 3620 |                              componentName: " query = " , component: d->query); | 
| 3621 |     appendComponentIfPresent(msg, present: d->sectionIsPresent & QUrlPrivate::Fragment, | 
| 3622 |                              componentName: " fragment = " , component: d->fragment); | 
| 3623 |     if (msg.endsWith(c: u',')) | 
| 3624 |         msg.chop(n: 1); | 
| 3625 |     return msg; | 
| 3626 | } | 
| 3627 |  | 
| 3628 | /*! | 
| 3629 |     \since 5.1 | 
| 3630 |  | 
| 3631 |     Converts a list of \a urls into a list of QString objects, using toString(\a options). | 
| 3632 | */ | 
| 3633 | QStringList QUrl::toStringList(const QList<QUrl> &urls, FormattingOptions options) | 
| 3634 | { | 
| 3635 |     QStringList lst; | 
| 3636 |     lst.reserve(asize: urls.size()); | 
| 3637 |     for (const QUrl &url : urls) | 
| 3638 |         lst.append(t: url.toString(options)); | 
| 3639 |     return lst; | 
| 3640 |  | 
| 3641 | } | 
| 3642 |  | 
| 3643 | /*! | 
| 3644 |     \since 5.1 | 
| 3645 |  | 
| 3646 |     Converts a list of strings representing \a urls into a list of urls, using QUrl(str, \a mode). | 
| 3647 |     Note that this means all strings must be urls, not for instance local paths. | 
| 3648 | */ | 
| 3649 | QList<QUrl> QUrl::fromStringList(const QStringList &urls, ParsingMode mode) | 
| 3650 | { | 
| 3651 |     QList<QUrl> lst; | 
| 3652 |     lst.reserve(asize: urls.size()); | 
| 3653 |     for (const QString &str : urls) | 
| 3654 |         lst.append(t: QUrl(str, mode)); | 
| 3655 |     return lst; | 
| 3656 | } | 
| 3657 |  | 
| 3658 | /*! | 
| 3659 |     \typedef QUrl::DataPtr | 
| 3660 |     \internal | 
| 3661 | */ | 
| 3662 |  | 
| 3663 | /*! | 
| 3664 |     \fn DataPtr &QUrl::data_ptr() | 
| 3665 |     \internal | 
| 3666 | */ | 
| 3667 |  | 
| 3668 | /*! | 
| 3669 |     \fn size_t qHash(const QUrl &key, size_t seed) | 
| 3670 |     \qhashold{QHash} | 
| 3671 |     \since 5.0 | 
| 3672 | */ | 
| 3673 | size_t qHash(const QUrl &url, size_t seed) noexcept | 
| 3674 | { | 
| 3675 |     if (!url.d) | 
| 3676 |         return qHash(key: -1, seed); // the hash of an unset port (-1) | 
| 3677 |  | 
| 3678 |     return qHash(key: url.d->scheme) ^ | 
| 3679 |             qHash(key: url.d->userName) ^ | 
| 3680 |             qHash(key: url.d->password) ^ | 
| 3681 |             qHash(key: url.d->host) ^ | 
| 3682 |             qHash(key: url.d->port, seed) ^ | 
| 3683 |             qHash(key: url.d->path) ^ | 
| 3684 |             qHash(key: url.d->query) ^ | 
| 3685 |             qHash(key: url.d->fragment); | 
| 3686 | } | 
| 3687 |  | 
| 3688 | static QUrl adjustFtpPath(QUrl url) | 
| 3689 | { | 
| 3690 |     if (url.scheme() == ftpScheme()) { | 
| 3691 |         QString path = url.path(options: QUrl::PrettyDecoded); | 
| 3692 |         if (path.startsWith(s: "//"_L1 )) | 
| 3693 |             url.setPath(path: "/%2F"_L1  + QStringView{path}.mid(pos: 2), mode: QUrl::TolerantMode); | 
| 3694 |     } | 
| 3695 |     return url; | 
| 3696 | } | 
| 3697 |  | 
| 3698 | static bool isIp6(const QString &text) | 
| 3699 | { | 
| 3700 |     QIPAddressUtils::IPv6Address address; | 
| 3701 |     return !text.isEmpty() && QIPAddressUtils::parseIp6(address, begin: text.begin(), end: text.end()) == nullptr; | 
| 3702 | } | 
| 3703 |  | 
| 3704 | /*! | 
| 3705 |     Returns a valid URL from a user supplied \a userInput string if one can be | 
| 3706 |     deduced. In the case that is not possible, an invalid QUrl() is returned. | 
| 3707 |  | 
| 3708 |     This allows the user to input a URL or a local file path in the form of a plain | 
| 3709 |     string. This string can be manually typed into a location bar, obtained from | 
| 3710 |     the clipboard, or passed in via command line arguments. | 
| 3711 |  | 
| 3712 |     When the string is not already a valid URL, a best guess is performed, | 
| 3713 |     making various assumptions. | 
| 3714 |  | 
| 3715 |     In the case the string corresponds to a valid file path on the system, | 
| 3716 |     a file:// URL is constructed, using QUrl::fromLocalFile(). | 
| 3717 |  | 
| 3718 |     If that is not the case, an attempt is made to turn the string into a | 
| 3719 |     http:// or ftp:// URL. The latter in the case the string starts with | 
| 3720 |     'ftp'. The result is then passed through QUrl's tolerant parser, and | 
| 3721 |     in the case or success, a valid QUrl is returned, or else a QUrl(). | 
| 3722 |  | 
| 3723 |     \section1 Examples: | 
| 3724 |  | 
| 3725 |     \list | 
| 3726 |     \li qt-project.org becomes http://qt-project.org | 
| 3727 |     \li ftp.qt-project.org becomes ftp://ftp.qt-project.org | 
| 3728 |     \li hostname becomes http://hostname | 
| 3729 |     \li /home/user/test.html becomes file:///home/user/test.html | 
| 3730 |     \endlist | 
| 3731 |  | 
| 3732 |     In order to be able to handle relative paths, this method takes an optional | 
| 3733 |     \a workingDirectory path. This is especially useful when handling command | 
| 3734 |     line arguments. | 
| 3735 |     If \a workingDirectory is empty, no handling of relative paths will be done. | 
| 3736 |  | 
| 3737 |     By default, an input string that looks like a relative path will only be treated | 
| 3738 |     as such if the file actually exists in the given working directory. | 
| 3739 |     If the application can handle files that don't exist yet, it should pass the | 
| 3740 |     flag AssumeLocalFile in \a options. | 
| 3741 |  | 
| 3742 |     \since 5.4 | 
| 3743 | */ | 
| 3744 | QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirectory, | 
| 3745 |                          UserInputResolutionOptions options) | 
| 3746 | { | 
| 3747 |     QString trimmedString = userInput.trimmed(); | 
| 3748 |  | 
| 3749 |     if (trimmedString.isEmpty()) | 
| 3750 |         return QUrl(); | 
| 3751 |  | 
| 3752 |     // Check for IPv6 addresses, since a path starting with ":" is absolute (a resource) | 
| 3753 |     // and IPv6 addresses can start with "c:" too | 
| 3754 |     if (isIp6(text: trimmedString)) { | 
| 3755 |         QUrl url; | 
| 3756 |         url.setHost(host: trimmedString); | 
| 3757 |         url.setScheme(QStringLiteral("http" )); | 
| 3758 |         return url; | 
| 3759 |     } | 
| 3760 |  | 
| 3761 |     const QUrl url = QUrl(trimmedString, QUrl::TolerantMode); | 
| 3762 |  | 
| 3763 |     // Check for a relative path | 
| 3764 |     if (!workingDirectory.isEmpty()) { | 
| 3765 |         const QFileInfo fileInfo(QDir(workingDirectory), userInput); | 
| 3766 |         if (fileInfo.exists()) | 
| 3767 |             return QUrl::fromLocalFile(localFile: fileInfo.absoluteFilePath()); | 
| 3768 |  | 
| 3769 |         // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes) | 
| 3770 |         if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(path: userInput)) | 
| 3771 |             return QUrl::fromLocalFile(localFile: fileInfo.absoluteFilePath()); | 
| 3772 |     } | 
| 3773 |  | 
| 3774 |     // Check first for files, since on Windows drive letters can be interpreted as schemes | 
| 3775 |     if (QDir::isAbsolutePath(path: trimmedString)) | 
| 3776 |         return QUrl::fromLocalFile(localFile: trimmedString); | 
| 3777 |  | 
| 3778 |     QUrl urlPrepended = QUrl("http://"_L1  + trimmedString, QUrl::TolerantMode); | 
| 3779 |  | 
| 3780 |     // Check the most common case of a valid url with a scheme | 
| 3781 |     // We check if the port would be valid by adding the scheme to handle the case host:port | 
| 3782 |     // where the host would be interpreted as the scheme | 
| 3783 |     if (url.isValid() | 
| 3784 |         && !url.scheme().isEmpty() | 
| 3785 |         && urlPrepended.port() == -1) | 
| 3786 |         return adjustFtpPath(url); | 
| 3787 |  | 
| 3788 |     // Else, try the prepended one and adjust the scheme from the host name | 
| 3789 |     if (urlPrepended.isValid() && (!urlPrepended.host().isEmpty() || !urlPrepended.path().isEmpty())) { | 
| 3790 |         qsizetype dotIndex = trimmedString.indexOf(c: u'.'); | 
| 3791 |         const QStringView hostscheme = QStringView{trimmedString}.left(n: dotIndex); | 
| 3792 |         if (hostscheme.compare(other: ftpScheme(), cs: Qt::CaseInsensitive) == 0) | 
| 3793 |             urlPrepended.setScheme(ftpScheme()); | 
| 3794 |         return adjustFtpPath(url: urlPrepended); | 
| 3795 |     } | 
| 3796 |  | 
| 3797 |     return QUrl(); | 
| 3798 | } | 
| 3799 |  | 
| 3800 | QT_END_NAMESPACE | 
| 3801 |  |