src/qt3support/network/q3url.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "q3url.h"
       
    43 
       
    44 #ifndef QT_NO_URL
       
    45 
       
    46 #include "q3cstring.h"
       
    47 #include "qdir.h"
       
    48 
       
    49 QT_BEGIN_NAMESPACE
       
    50 
       
    51 // used by q3filedialog.cpp
       
    52 bool qt_resolve_symlinks = true;
       
    53 
       
    54 class Q3UrlPrivate
       
    55 {
       
    56 public:
       
    57     QString protocol;
       
    58     QString user;
       
    59     QString pass;
       
    60     QString host;
       
    61     QString path, cleanPath;
       
    62     QString refEncoded;
       
    63     QString queryEncoded;
       
    64     bool isValid;
       
    65     int port;
       
    66     bool cleanPathDirty;
       
    67 };
       
    68 
       
    69 /*!
       
    70     Replaces backslashes with slashes and removes multiple occurrences
       
    71     of slashes or backslashes if \c allowMultiple is false.
       
    72 */
       
    73 
       
    74 static void slashify( QString& s, bool allowMultiple = true )
       
    75 {
       
    76     bool justHadSlash = false;
       
    77     for ( int i = 0; i < (int)s.length(); i++ ) {
       
    78 	if ( !allowMultiple && justHadSlash &&
       
    79 	     ( s[ i ] == QLatin1Char('/') || s[ i ] == QLatin1Char('\\') ) ) {
       
    80 	    s.remove( i, 1 );
       
    81 	    --i;
       
    82 	    continue;
       
    83 	}
       
    84 	if ( s[ i ] == QLatin1Char('\\') )
       
    85 	    s[ i ] = QLatin1Char('/');
       
    86 #if defined (Q_WS_MAC9)
       
    87 	if ( s[ i ] == QLatin1Char(':') && (i == (int)s.length()-1 || s[ i + 1 ] != QLatin1Char('/') ) ) //mac colon's go away, unless after a protocol
       
    88 		s[ i ] = QLatin1Char('/');
       
    89 #endif
       
    90 	if ( s[ i ] == QLatin1Char('/') )
       
    91 	    justHadSlash = true;
       
    92 	else
       
    93 	    justHadSlash = false;
       
    94     }
       
    95 }
       
    96 
       
    97 
       
    98 
       
    99 /*!
       
   100     \class Q3Url
       
   101     \brief The Q3Url class provides a URL parser and simplifies working with URLs.
       
   102 
       
   103     \compat
       
   104 
       
   105     The Q3Url class is provided for simple work with URLs. It can
       
   106     parse, decode, encode, etc.
       
   107 
       
   108     Q3Url works with the decoded path and encoded query in turn.
       
   109 
       
   110     Example:
       
   111 
       
   112     <tt>http://example.com:80/cgi-bin/test%20me.pl?cmd=Hello%20you</tt>
       
   113 
       
   114     \table
       
   115     \header \i Function	    \i Returns
       
   116     \row \i \l protocol()   \i "http"
       
   117     \row \i \l host()	    \i "example.com"
       
   118     \row \i \l port()	    \i 80
       
   119     \row \i \l path()	    \i "/cgi-bin/test&nbsp;me.pl"
       
   120     \row \i \l fileName()   \i "test&nbsp;me.pl"
       
   121     \row \i \l query()	    \i "cmd=Hello%20you"
       
   122     \endtable
       
   123 
       
   124     Example:
       
   125 
       
   126     <tt>http://qt.nokia.com/doc/qdockarea.html#lines</tt>
       
   127 
       
   128     \table
       
   129     \header \i Function	    \i Returns
       
   130     \row \i \l protocol()   \i "http"
       
   131     \row \i \l host()	    \i "qt.nokia.com"
       
   132     \row \i \l fileName()   \i "doc/qdockarea.html"
       
   133     \row \i \l ref()	    \i "lines"
       
   134     \endtable
       
   135 
       
   136     The individual parts of a URL can be set with setProtocol(),
       
   137     setHost(), setPort(), setPath(), setFileName(), setRef() and
       
   138     setQuery(). A URL could contain, for example, an ftp address which
       
   139     requires a user name and password; these can be set with setUser()
       
   140     and setPassword().
       
   141 
       
   142     Because path is always encoded internally you must not use "%00"
       
   143     in the path, although this is okay (but not recommended) for the
       
   144     query.
       
   145 
       
   146     Q3Url is normally used like this:
       
   147 
       
   148     \snippet doc/src/snippets/code/src_qt3support_network_q3url.cpp 0
       
   149 
       
   150     You can then access and manipulate the various parts of the URL.
       
   151 
       
   152     To make it easy to work with Q3Urls and QStrings, Q3Url implements
       
   153     the necessary cast and assignment operators so you can do
       
   154     following:
       
   155 
       
   156     \snippet doc/src/snippets/code/src_qt3support_network_q3url.cpp 1
       
   157 
       
   158     Use the static functions, encode() and decode() to encode or
       
   159     decode a URL in a string. (They operate on the string in-place.)
       
   160     The isRelativeUrl() static function returns true if the given
       
   161     string is a relative URL.
       
   162 
       
   163     If you want to use a URL to work on a hierarchical structure (e.g.
       
   164     a local or remote filesystem), you might want to use the subclass
       
   165     Q3UrlOperator.
       
   166 
       
   167     \sa Q3UrlOperator
       
   168 */
       
   169 
       
   170 
       
   171 /*!
       
   172     Constructs an empty URL that is invalid.
       
   173 */
       
   174 
       
   175 Q3Url::Q3Url()
       
   176 {
       
   177     d = new Q3UrlPrivate;
       
   178     d->isValid = false;
       
   179     d->port = -1;
       
   180     d->cleanPathDirty = true;
       
   181 }
       
   182 
       
   183 /*!
       
   184     Constructs a URL by parsing the string \a url.
       
   185 
       
   186     If you pass a string like "/home/qt", the "file" protocol is
       
   187     assumed.
       
   188 */
       
   189 
       
   190 Q3Url::Q3Url( const QString& url )
       
   191 {
       
   192     d = new Q3UrlPrivate;
       
   193     d->protocol = QLatin1String("file");
       
   194     d->port = -1;
       
   195     parse( url );
       
   196 }
       
   197 
       
   198 /*!
       
   199     Copy constructor. Copies the data of \a url.
       
   200 */
       
   201 
       
   202 Q3Url::Q3Url( const Q3Url& url )
       
   203 {
       
   204     d = new Q3UrlPrivate;
       
   205     *d = *url.d;
       
   206 }
       
   207 
       
   208 /*!
       
   209     Returns true if \a url is relative; otherwise returns false.
       
   210 */
       
   211 
       
   212 bool Q3Url::isRelativeUrl( const QString &url )
       
   213 {
       
   214     int colon = url.find( QLatin1Char(':') );
       
   215     int slash = url.find( QLatin1Char('/') );
       
   216 
       
   217     return ( slash != 0 && ( colon == -1 || ( slash != -1 && colon > slash ) ) );
       
   218 }
       
   219 
       
   220 /*!
       
   221     Constructs an URL taking \a url as the base (context) and
       
   222     \a relUrl as a relative URL to \a url. If \a relUrl is not relative,
       
   223     \a relUrl is taken as the new URL.
       
   224 
       
   225     For example, the path of
       
   226     \snippet doc/src/snippets/code/src_qt3support_network_q3url.cpp 2
       
   227     will be "/qt/srource/qt-2.1.0.tar.gz".
       
   228 
       
   229     On the other hand,
       
   230     \snippet doc/src/snippets/code/src_qt3support_network_q3url.cpp 3
       
   231     will result in a new URL, "ftp://ftp.qt.nokia.com/usr/local",
       
   232     because "/usr/local" isn't relative.
       
   233 
       
   234     Similarly,
       
   235     \snippet doc/src/snippets/code/src_qt3support_network_q3url.cpp 4
       
   236     will result in a new URL, with "/usr/local" as the path
       
   237     and "file" as the protocol.
       
   238 
       
   239     Normally it is expected that the path of \a url points to a
       
   240     directory, even if the path has no slash at the end. But if you
       
   241     want the constructor to handle the last part of the path as a file
       
   242     name if there is no slash at the end, and to let it be replaced by
       
   243     the file name of \a relUrl (if it contains one), set \a checkSlash
       
   244     to true.
       
   245 */
       
   246 
       
   247 Q3Url::Q3Url( const Q3Url& url, const QString& relUrl, bool checkSlash )
       
   248 {
       
   249     d = new Q3UrlPrivate;
       
   250     QString rel = relUrl;
       
   251     slashify( rel );
       
   252 
       
   253     Q3Url urlTmp( url );
       
   254     if ( !urlTmp.isValid() ) {
       
   255 	urlTmp.reset();
       
   256     }
       
   257     if ( isRelativeUrl( rel ) ) {
       
   258 	if ( rel[ 0 ] == QLatin1Char('#') ) {
       
   259 	    *this = urlTmp;
       
   260 	    rel.remove( (uint)0, 1 );
       
   261 	    decode( rel );
       
   262 	    setRef( rel );
       
   263 	} else if ( rel[ 0 ] == QLatin1Char('?') ) {
       
   264 	    *this = urlTmp;
       
   265 	    rel.remove( (uint)0, 1 );
       
   266 	    setQuery( rel );
       
   267 	} else {
       
   268 	    decode( rel );
       
   269 	    *this = urlTmp;
       
   270 	    setRef( QString() );
       
   271 	    if ( checkSlash && d->cleanPath[(int)path().length()-1] != QLatin1Char('/') ) {
       
   272 		if ( isRelativeUrl( path() ) )
       
   273 		    setEncodedPathAndQuery( rel );
       
   274 		else
       
   275 		    setFileName( rel );
       
   276 	    } else {
       
   277 		QString p = urlTmp.path();
       
   278 		if ( p.isEmpty() ) {
       
   279 		    // allow URLs like "file:foo"
       
   280 		    if ( !d->host.isEmpty() && !d->user.isEmpty() && !d->pass.isEmpty() )
       
   281 			p = QLatin1String("/");
       
   282 		}
       
   283 		if ( !p.isEmpty() && !p.endsWith(QLatin1Char('/')) )
       
   284 		    p += QLatin1Char('/');
       
   285 		p += rel;
       
   286 		d->path = p;
       
   287 		d->cleanPathDirty = true;
       
   288 	    }
       
   289 	}
       
   290     } else {
       
   291 	if ( rel[ 0 ] == QChar( QLatin1Char('/') ) ) {
       
   292 	    *this = urlTmp;
       
   293 	    setEncodedPathAndQuery( rel );
       
   294 	} else {
       
   295 	    *this = rel;
       
   296 	}
       
   297     }
       
   298 }
       
   299 
       
   300 /*!
       
   301     Destructor.
       
   302 */
       
   303 
       
   304 Q3Url::~Q3Url()
       
   305 {
       
   306     delete d;
       
   307     d = 0;
       
   308 }
       
   309 
       
   310 /*!
       
   311     Returns the protocol of the URL. Typically, "file", "http", "ftp",
       
   312     etc.
       
   313 
       
   314     \sa setProtocol()
       
   315 */
       
   316 
       
   317 QString Q3Url::protocol() const
       
   318 {
       
   319     return d->protocol;
       
   320 }
       
   321 
       
   322 /*!
       
   323     Sets the protocol of the URL to \a protocol. Typically, "file",
       
   324     "http", "ftp", etc.
       
   325 
       
   326     \sa protocol()
       
   327 */
       
   328 
       
   329 void Q3Url::setProtocol( const QString& protocol )
       
   330 {
       
   331     d->protocol = protocol;
       
   332     if ( hasHost() )
       
   333 	d->isValid = true;
       
   334 }
       
   335 
       
   336 /*!
       
   337     Returns the username of the URL.
       
   338 
       
   339     \sa setUser() setPassword()
       
   340 */
       
   341 
       
   342 QString Q3Url::user() const
       
   343 {
       
   344     return  d->user;
       
   345 }
       
   346 
       
   347 /*!
       
   348     Sets the username of the URL to \a user.
       
   349 
       
   350     \sa user() setPassword()
       
   351 */
       
   352 
       
   353 void Q3Url::setUser( const QString& user )
       
   354 {
       
   355     d->user = user;
       
   356 }
       
   357 
       
   358 /*!
       
   359     Returns true if the URL contains a username; otherwise returns
       
   360     false.
       
   361 
       
   362     \sa setUser() setPassword()
       
   363 */
       
   364 
       
   365 bool Q3Url::hasUser() const
       
   366 {
       
   367     return !d->user.isEmpty();
       
   368 }
       
   369 
       
   370 /*!
       
   371     Returns the password of the URL.
       
   372 
       
   373     \warning Passwords passed in URLs are normally \e insecure; this
       
   374     is due to the mechanism, not because of Qt.
       
   375 
       
   376     \sa setPassword() setUser()
       
   377 */
       
   378 
       
   379 QString Q3Url::password() const
       
   380 {
       
   381     return d->pass;
       
   382 }
       
   383 
       
   384 /*!
       
   385     Sets the password of the URL to \a pass.
       
   386 
       
   387     \warning Passwords passed in URLs are normally \e insecure; this
       
   388     is due to the mechanism, not because of Qt.
       
   389 
       
   390     \sa password() setUser()
       
   391 */
       
   392 
       
   393 void Q3Url::setPassword( const QString& pass )
       
   394 {
       
   395     d->pass = pass;
       
   396 }
       
   397 
       
   398 /*!
       
   399     Returns true if the URL contains a password; otherwise returns
       
   400     false.
       
   401 
       
   402     \warning Passwords passed in URLs are normally \e insecure; this
       
   403     is due to the mechanism, not because of Qt.
       
   404 
       
   405     \sa setPassword() setUser()
       
   406 */
       
   407 
       
   408 bool Q3Url::hasPassword() const
       
   409 {
       
   410     return !d->pass.isEmpty();
       
   411 }
       
   412 
       
   413 /*!
       
   414     Returns the hostname of the URL.
       
   415 
       
   416     \sa setHost() hasHost()
       
   417 */
       
   418 
       
   419 QString Q3Url::host() const
       
   420 {
       
   421     return d->host;
       
   422 }
       
   423 
       
   424 /*!
       
   425     Sets the hostname of the URL to \a host.
       
   426 
       
   427     \sa host() hasHost()
       
   428 */
       
   429 
       
   430 void Q3Url::setHost( const QString& host )
       
   431 {
       
   432     d->host = host;
       
   433     if ( !d->protocol.isNull() && d->protocol != QLatin1String("file") )
       
   434 	d->isValid = true;
       
   435 }
       
   436 
       
   437 /*!
       
   438     Returns true if the URL contains a hostname; otherwise returns
       
   439     false.
       
   440 
       
   441     \sa setHost()
       
   442 */
       
   443 
       
   444 bool Q3Url::hasHost() const
       
   445 {
       
   446     return !d->host.isEmpty();
       
   447 }
       
   448 
       
   449 /*!
       
   450     Returns the port of the URL or -1 if no port has been set.
       
   451 
       
   452     \sa setPort()
       
   453 */
       
   454 
       
   455 int Q3Url::port() const
       
   456 {
       
   457     return d->port;
       
   458 }
       
   459 
       
   460 /*!
       
   461     Sets the port of the URL to \a port.
       
   462 
       
   463     \sa port()
       
   464 */
       
   465 
       
   466 void Q3Url::setPort( int port )
       
   467 {
       
   468     d->port = port;
       
   469 }
       
   470 
       
   471 /*!
       
   472     Returns true if the URL contains a port; otherwise returns false.
       
   473 
       
   474     \sa setPort()
       
   475 */
       
   476 
       
   477 bool Q3Url::hasPort() const
       
   478 {
       
   479     return d->port >= 0;
       
   480 }
       
   481 
       
   482 /*!
       
   483     Sets the path of the URL to \a path.
       
   484 
       
   485     \sa path() hasPath()
       
   486 */
       
   487 
       
   488 void Q3Url::setPath( const QString& path )
       
   489 {
       
   490     d->path = path;
       
   491     slashify( d->path );
       
   492     d->cleanPathDirty = true;
       
   493     d->isValid = true;
       
   494 }
       
   495 
       
   496 /*!
       
   497     Returns true if the URL contains a path; otherwise returns false.
       
   498 
       
   499     \sa path() setPath()
       
   500 */
       
   501 
       
   502 bool Q3Url::hasPath() const
       
   503 {
       
   504     return !d->path.isEmpty();
       
   505 }
       
   506 
       
   507 /*!
       
   508     Sets the query of the URL to \a txt. \a txt must be encoded.
       
   509 
       
   510     \sa query() encode()
       
   511 */
       
   512 
       
   513 void Q3Url::setQuery( const QString& txt )
       
   514 {
       
   515     d->queryEncoded = txt;
       
   516 }
       
   517 
       
   518 /*!
       
   519     Returns the (encoded) query of the URL.
       
   520 
       
   521     \sa setQuery() decode()
       
   522 */
       
   523 
       
   524 QString Q3Url::query() const
       
   525 {
       
   526     return d->queryEncoded;
       
   527 }
       
   528 
       
   529 /*!
       
   530     Returns the (encoded) reference of the URL.
       
   531 
       
   532     \sa setRef() hasRef() decode()
       
   533 */
       
   534 
       
   535 QString Q3Url::ref() const
       
   536 {
       
   537     return d->refEncoded;
       
   538 }
       
   539 
       
   540 /*!
       
   541     Sets the reference of the URL to \a txt. \a txt must be encoded.
       
   542 
       
   543     \sa ref() hasRef() encode()
       
   544 */
       
   545 
       
   546 void Q3Url::setRef( const QString& txt )
       
   547 {
       
   548     d->refEncoded = txt;
       
   549 }
       
   550 
       
   551 /*!
       
   552     Returns true if the URL has a reference; otherwise returns false.
       
   553 
       
   554     \sa setRef()
       
   555 */
       
   556 
       
   557 bool Q3Url::hasRef() const
       
   558 {
       
   559     return !d->refEncoded.isEmpty();
       
   560 }
       
   561 
       
   562 /*!
       
   563     Returns true if the URL is valid; otherwise returns false. A URL
       
   564     is invalid if it cannot be parsed, for example.
       
   565 */
       
   566 
       
   567 bool Q3Url::isValid() const
       
   568 {
       
   569     return d->isValid;
       
   570 }
       
   571 
       
   572 /*!
       
   573     Resets all parts of the URL to their default values and
       
   574     invalidates it.
       
   575 */
       
   576 
       
   577 void Q3Url::reset()
       
   578 {
       
   579     d->protocol = QLatin1String("file");
       
   580     d->user = QLatin1String("");
       
   581     d->pass = QLatin1String("");
       
   582     d->host = QLatin1String("");
       
   583     d->path = QLatin1String("");
       
   584     d->queryEncoded = QLatin1String("");
       
   585     d->refEncoded = QLatin1String("");
       
   586     d->isValid = true;
       
   587     d->port = -1;
       
   588     d->cleanPathDirty = true;
       
   589 }
       
   590 
       
   591 /*!
       
   592     Parses the \a url. Returns true on success; otherwise returns false.
       
   593 */
       
   594 
       
   595 bool Q3Url::parse( const QString& url )
       
   596 {
       
   597     QString url_( url );
       
   598     slashify( url_ );
       
   599 
       
   600     if ( url_.isEmpty() ) {
       
   601 	d->isValid = false;
       
   602 	return false;
       
   603     }
       
   604 
       
   605     d->cleanPathDirty = true;
       
   606     d->isValid = true;
       
   607     QString oldProtocol = d->protocol;
       
   608     d->protocol.clear();
       
   609 
       
   610     const int Init	= 0;
       
   611     const int Protocol	= 1;
       
   612     const int Separator1= 2; // :
       
   613     const int Separator2= 3; // :/
       
   614     const int Separator3= 4; // :// or more slashes
       
   615     const int User	= 5;
       
   616     const int Pass	= 6;
       
   617     const int Host	= 7;
       
   618     const int Path	= 8;
       
   619     const int Ref	= 9;
       
   620     const int Query	= 10;
       
   621     const int Port	= 11;
       
   622     const int Done	= 12;
       
   623 
       
   624     const int InputAlpha= 1;
       
   625     const int InputDigit= 2;
       
   626     const int InputSlash= 3;
       
   627     const int InputColon= 4;
       
   628     const int InputAt	= 5;
       
   629     const int InputHash = 6;
       
   630     const int InputQuery= 7;
       
   631 
       
   632     static uchar table[ 12 ][ 8 ] = {
       
   633      /* None       InputAlpha  InputDigit  InputSlash  InputColon  InputAt     InputHash   InputQuery */
       
   634 	{ 0,       Protocol,   0,          Path,       0,          0,          0,          0,         }, // Init
       
   635 	{ 0,       Protocol,   Protocol,   0,          Separator1, 0,          0,          0,         }, // Protocol
       
   636 	{ 0,       Path,       Path,       Separator2, 0,          0,          0,          0,         }, // Separator1
       
   637 	{ 0,       Path,       Path,       Separator3, 0,          0,          0,          0,         }, // Separator2
       
   638 	{ 0,       User,       User,       Separator3, Pass,       Host,       0,          0,         }, // Separator3
       
   639 	{ 0,       User,       User,       User,       Pass,       Host,       User,       User,      }, // User
       
   640 	{ 0,       Pass,       Pass,       Pass,       Pass,       Host,       Pass,       Pass,      }, // Pass
       
   641 	{ 0,       Host,       Host,       Path,       Port,       Host,       Ref,        Query,     }, // Host
       
   642 	{ 0,       Path,       Path,       Path,       Path,       Path,       Ref,        Query,     }, // Path
       
   643 	{ 0,       Ref,        Ref,        Ref,        Ref,        Ref,        Ref,        Query,     }, // Ref
       
   644 	{ 0,       Query,      Query,      Query,      Query,      Query,      Query,      Query,     }, // Query
       
   645 	{ 0,       0,          Port,       Path,       0,          0,          0,          0,         }  // Port
       
   646     };
       
   647 
       
   648     bool relPath = false;
       
   649 
       
   650     relPath = false;
       
   651     bool forceRel = false;
       
   652 
       
   653     // If ':' is at pos 1, we have only one letter
       
   654     // before that separator => that's a drive letter!
       
   655     if ( url_.length() >= 2 && url_[1] == QLatin1Char(':') )
       
   656 	relPath = forceRel = true;
       
   657 
       
   658     int hasNoHost = -1;
       
   659     int cs = url_.find( QLatin1String(":/") );
       
   660     if ( cs != -1 ) // if a protocol is there, find out if there is a host or directly the path after it
       
   661 	hasNoHost = url_.find( QLatin1String("///"), cs );
       
   662     table[ 4 ][ 1 ] = User;
       
   663     table[ 4 ][ 2 ] = User;
       
   664     if ( cs == -1 || forceRel ) { // we have a relative file
       
   665 	if ( url.find( QLatin1Char(':') ) == -1 || forceRel ) {
       
   666 	    table[ 0 ][ 1 ] = Path;
       
   667 	    // Filenames may also begin with a digit
       
   668 	    table[ 0 ][ 2 ] = Path;
       
   669 	} else {
       
   670 	    table[ 0 ][ 1 ] = Protocol;
       
   671 	}
       
   672 	relPath = true;
       
   673     } else { // some checking
       
   674 	table[ 0 ][ 1 ] = Protocol;
       
   675 
       
   676 	// find the part between the protocol and the path as the meaning
       
   677 	// of that part is dependent on some chars
       
   678 	++cs;
       
   679 	while ( url_[ cs ] == QLatin1Char('/') )
       
   680 	    ++cs;
       
   681 	int slash = url_.find( QLatin1Char('/'), cs );
       
   682 	if ( slash == -1 )
       
   683 	    slash = url_.length() - 1;
       
   684 	QString tmp = url_.mid( cs, slash - cs + 1 );
       
   685 
       
   686 	if ( !tmp.isEmpty() ) { // if this part exists
       
   687 
       
   688 	    // look for the @ in this part
       
   689 	    int at = tmp.find( QLatin1Char('@') );
       
   690 	    if ( at != -1 )
       
   691 		at += cs;
       
   692 	    // we have no @, which means host[:port], so directly
       
   693 	    // after the protocol the host starts, or if the protocol
       
   694 	    // is file or there were more than 2 slashes, it is the
       
   695 	    // path
       
   696 	    if ( at == -1 ) {
       
   697 		if ( url_.left( 4 ) == QLatin1String("file") || hasNoHost != -1 )
       
   698 		    table[ 4 ][ 1 ] = Path;
       
   699 		else
       
   700 		    table[ 4 ][ 1 ] = Host;
       
   701 		table[ 4 ][ 2 ] = table[ 4 ][ 1 ];
       
   702 	    }
       
   703 	}
       
   704     }
       
   705 
       
   706     int state = Init; // parse state
       
   707     int input; // input token
       
   708 
       
   709     QChar c = url_[ 0 ];
       
   710     int i = 0;
       
   711     QString port;
       
   712 
       
   713     for ( ;; ) {
       
   714 	switch ( c.latin1() ) {
       
   715 	case '?':
       
   716 	    input = InputQuery;
       
   717 	    break;
       
   718 	case '#':
       
   719 	    input = InputHash;
       
   720 	    break;
       
   721 	case '@':
       
   722 	    input = InputAt;
       
   723 	    break;
       
   724 	case ':':
       
   725 	    input = InputColon;
       
   726 	    break;
       
   727 	case '/':
       
   728 	    input = InputSlash;
       
   729 	    break;
       
   730 	case '1': case '2': case '3': case '4': case '5':
       
   731 	case '6': case '7': case '8': case '9': case '0':
       
   732 	    input = InputDigit;
       
   733 	    break;
       
   734 	default:
       
   735 	    input = InputAlpha;
       
   736 	}
       
   737 
       
   738 	state = table[ state ][ input ];
       
   739 
       
   740 	switch ( state ) {
       
   741 	case Protocol:
       
   742 	    d->protocol += c;
       
   743 	    break;
       
   744 	case User:
       
   745 	    d->user += c;
       
   746 	    break;
       
   747 	case Pass:
       
   748 	    d->pass += c;
       
   749 	    break;
       
   750 	case Host:
       
   751 	    d->host += c;
       
   752 	    break;
       
   753 	case Path:
       
   754 	    d->path += c;
       
   755 	    break;
       
   756 	case Ref:
       
   757 	    d->refEncoded += c;
       
   758 	    break;
       
   759 	case Query:
       
   760 	    d->queryEncoded += c;
       
   761 	    break;
       
   762 	case Port:
       
   763 	    port += c;
       
   764 	    break;
       
   765 	default:
       
   766 	    break;
       
   767 	}
       
   768 
       
   769 	++i;
       
   770 	if ( i > (int)url_.length() - 1 || state == Done || state == 0 )
       
   771 	    break;
       
   772 	c = url_[ i ];
       
   773 
       
   774     }
       
   775 
       
   776     if ( !port.isEmpty() ) {
       
   777 	port.remove( (uint)0, 1 );
       
   778 	d->port = port.toInt();
       
   779     }
       
   780 
       
   781     // error
       
   782     if ( i < (int)url_.length() - 1 ) {
       
   783 	d->isValid = false;
       
   784 	return false;
       
   785     }
       
   786 
       
   787 
       
   788     if ( d->protocol.isEmpty() )
       
   789 	d->protocol = oldProtocol;
       
   790 
       
   791     if ( d->path.isEmpty() )
       
   792 	d->path = QLatin1String("/");
       
   793 
       
   794     // hack for windows
       
   795     if ( d->path.length() == 2 && d->path[ 1 ] == QLatin1Char(':') )
       
   796 	d->path += QLatin1Char('/');
       
   797 
       
   798     // #### do some corrections, should be done nicer too
       
   799     if ( !d->pass.isEmpty() ) {
       
   800 	if ( d->pass[ 0 ] == QLatin1Char(':') )
       
   801 	    d->pass.remove( (uint)0, 1 );
       
   802 	decode( d->pass );
       
   803     }
       
   804     if ( !d->user.isEmpty() ) {
       
   805 	decode( d->user );
       
   806     }
       
   807     if ( !d->path.isEmpty() ) {
       
   808 	if ( d->path[ 0 ] == QLatin1Char('@') || d->path[ 0 ] == QLatin1Char(':') )
       
   809 	    d->path.remove( (uint)0, 1 );
       
   810 	if ( d->path[ 0 ] != QLatin1Char('/') && !relPath && d->path[ 1 ] != QLatin1Char(':') )
       
   811 	    d->path.prepend( QLatin1Char('/') );
       
   812     }
       
   813     if ( !d->refEncoded.isEmpty() && d->refEncoded[ 0 ] == QLatin1Char('#') )
       
   814 	d->refEncoded.remove( (uint)0, 1 );
       
   815     if ( !d->queryEncoded.isEmpty() && d->queryEncoded[ 0 ] == QLatin1Char('?') )
       
   816 	d->queryEncoded.remove( (uint)0, 1 );
       
   817     if ( !d->host.isEmpty() && d->host[ 0 ] == QLatin1Char('@') )
       
   818 	d->host.remove( (uint)0, 1 );
       
   819 
       
   820 #if defined(Q_OS_WIN32)
       
   821     // hack for windows file://machine/path syntax
       
   822     if ( d->protocol == QLatin1String("file") ) {
       
   823 	if ( url.startsWith(QLatin1String("file://")) &&
       
   824 	     d->path.length() > 1 && d->path[ 1 ] != QLatin1Char(':') )
       
   825 		 d->path.prepend( QLatin1Char('/') );
       
   826     }
       
   827 #endif
       
   828 
       
   829     decode( d->path );
       
   830     d->cleanPathDirty = true;
       
   831 
       
   832 #if 0
       
   833     qDebug( "URL: %s", url.latin1() );
       
   834     qDebug( "protocol: %s", d->protocol.latin1() );
       
   835     qDebug( "user: %s", d->user.latin1() );
       
   836     qDebug( "pass: %s", d->pass.latin1() );
       
   837     qDebug( "host: %s", d->host.latin1() );
       
   838     qDebug( "path: %s", path().latin1() );
       
   839     qDebug( "ref: %s", d->refEncoded.latin1() );
       
   840     qDebug( "query: %s", d->queryEncoded.latin1() );
       
   841     qDebug( "port: %d\n\n----------------------------\n\n", d->port );
       
   842 #endif
       
   843 
       
   844     return true;
       
   845 }
       
   846 
       
   847 /*!
       
   848     \overload
       
   849 
       
   850     Parses \a url and assigns the resulting data to this class.
       
   851 
       
   852     If you pass a string like "/home/qt" the "file" protocol will be
       
   853     assumed.
       
   854 */
       
   855 
       
   856 Q3Url& Q3Url::operator=( const QString& url )
       
   857 {
       
   858     reset();
       
   859     parse( url );
       
   860 
       
   861     return *this;
       
   862 }
       
   863 
       
   864 /*!
       
   865     Assigns the data of \a url to this class.
       
   866 */
       
   867 
       
   868 Q3Url& Q3Url::operator=( const Q3Url& url )
       
   869 {
       
   870     *d = *url.d;
       
   871     return *this;
       
   872 }
       
   873 
       
   874 /*!
       
   875     Compares this URL with \a url and returns true if they are equal;
       
   876     otherwise returns false.
       
   877 */
       
   878 
       
   879 bool Q3Url::operator==( const Q3Url& url ) const
       
   880 {
       
   881     if ( !isValid() || !url.isValid() )
       
   882 	return false;
       
   883 
       
   884     if ( d->protocol == url.d->protocol &&
       
   885 	 d->user == url.d->user &&
       
   886 	 d->pass == url.d->pass &&
       
   887 	 d->host == url.d->host &&
       
   888 	 d->path == url.d->path &&
       
   889 	 d->queryEncoded == url.d->queryEncoded &&
       
   890 	 d->refEncoded == url.d->refEncoded &&
       
   891 	 d->isValid == url.d->isValid &&
       
   892 	 d->port == url.d->port )
       
   893 	return true;
       
   894 
       
   895     return false;
       
   896 }
       
   897 
       
   898 /*!
       
   899     \overload
       
   900 
       
   901     Compares this URL with \a url. \a url is parsed first. Returns
       
   902     true if \a url is equal to this url; otherwise returns false.
       
   903 */
       
   904 
       
   905 bool Q3Url::operator==( const QString& url ) const
       
   906 {
       
   907     Q3Url u( url );
       
   908     return ( *this == u );
       
   909 }
       
   910 
       
   911 /*!
       
   912     Sets the file name of the URL to \a name. If this URL contains a
       
   913     fileName(), the original file name is replaced by \a name.
       
   914 
       
   915     See the documentation of fileName() for a more detailed discussion
       
   916     of what is handled as file name and what is handled as a directory
       
   917     path.
       
   918 
       
   919     \sa fileName()
       
   920 */
       
   921 
       
   922 void Q3Url::setFileName( const QString& name )
       
   923 {
       
   924     QString fn( name );
       
   925     slashify( fn );
       
   926 
       
   927     while ( fn[ 0 ] == QLatin1Char( '/' ) )
       
   928 	fn.remove( (uint)0, 1 );
       
   929 
       
   930     QString p;
       
   931     if ( path().isEmpty() ) {
       
   932 	p = QLatin1String("/");
       
   933     } else {
       
   934 	p = path();
       
   935 	int slash = p.findRev( QLatin1Char( '/' ) );
       
   936 	if ( slash == -1 ) {
       
   937 	    p = QLatin1String("/");
       
   938 	} else if ( p[ (int)p.length() - 1 ] != QLatin1Char( '/' ) ) {
       
   939 	    p.truncate( slash + 1 );
       
   940 	}
       
   941     }
       
   942 
       
   943     p += fn;
       
   944     if ( !d->queryEncoded.isEmpty() )
       
   945 	p += QLatin1Char('?') + d->queryEncoded;
       
   946     setEncodedPathAndQuery( p );
       
   947 }
       
   948 
       
   949 /*!
       
   950     Returns the encoded path and query.
       
   951 
       
   952     \sa decode()
       
   953 */
       
   954 
       
   955 QString Q3Url::encodedPathAndQuery()
       
   956 {
       
   957     QString p = path();
       
   958     if ( p.isEmpty() )
       
   959 	p = QLatin1String("/");
       
   960 
       
   961     encode( p );
       
   962 
       
   963     if ( !d->queryEncoded.isEmpty() ) {
       
   964 	p += QLatin1Char('?');
       
   965 	p += d->queryEncoded;
       
   966     }
       
   967 
       
   968     return p;
       
   969 }
       
   970 
       
   971 /*!
       
   972     Parses \a pathAndQuery for a path and query and sets those values.
       
   973     The whole string must be encoded.
       
   974 
       
   975     \sa encode()
       
   976 */
       
   977 
       
   978 void Q3Url::setEncodedPathAndQuery( const QString& pathAndQuery )
       
   979 {
       
   980     d->cleanPathDirty = true;
       
   981     int pos = pathAndQuery.find( QLatin1Char('?') );
       
   982     if ( pos == -1 ) {
       
   983 	d->path = pathAndQuery;
       
   984 	d->queryEncoded = QLatin1String("");
       
   985     } else {
       
   986 	d->path = pathAndQuery.left( pos );
       
   987 	d->queryEncoded = pathAndQuery.mid( pos + 1 );
       
   988     }
       
   989 
       
   990     decode( d->path );
       
   991     d->cleanPathDirty = true;
       
   992 }
       
   993 
       
   994 /*!
       
   995     Returns the path of the URL. If \a correct is true, the path is
       
   996     cleaned (deals with too many or too few slashes, cleans things
       
   997     like "/../..", etc). Otherwise path() returns exactly the path
       
   998     that was parsed or set.
       
   999 
       
  1000     \sa setPath() hasPath()
       
  1001 */
       
  1002 QString Q3Url::path( bool correct ) const
       
  1003 {
       
  1004     if ( !correct )
       
  1005 	return d->path;
       
  1006 
       
  1007     if ( d->cleanPathDirty ) {
       
  1008 	bool check = true;
       
  1009 	if ( QDir::isRelativePath( d->path ) ) {
       
  1010 	    d->cleanPath = d->path;
       
  1011 	} else if ( isLocalFile() ) {
       
  1012 #if defined(Q_OS_WIN32)
       
  1013 	    // hack for stuff like \\machine\path and //machine/path on windows
       
  1014 	    if ( ( d->path.startsWith(QLatin1Char('/')) || d->path.startsWith(QLatin1Char('\\')) ) &&
       
  1015 		 d->path.length() > 1 ) {
       
  1016 		d->cleanPath = d->path;
       
  1017 		bool share = (d->cleanPath[0] == QLatin1Char('\\') && d->cleanPath[1] == QLatin1Char('\\')) ||
       
  1018 		             (d->cleanPath[0] == QLatin1Char('/') && d->cleanPath[1] == QLatin1Char('/'));
       
  1019 		slashify( d->cleanPath, false );
       
  1020 		d->cleanPath = QDir::cleanDirPath( d->cleanPath );
       
  1021 		if ( share ) {
       
  1022 		    check = false;
       
  1023 		    while (d->cleanPath.at(0) != QLatin1Char('/') || d->cleanPath.at(1) != QLatin1Char('/'))
       
  1024 			d->cleanPath.prepend(QLatin1Char('/'));
       
  1025 		}
       
  1026 	    }
       
  1027 #endif
       
  1028 	    if ( check ) {
       
  1029 		QFileInfo fi( d->path );
       
  1030 		if ( !fi.exists() )
       
  1031 		    d->cleanPath = d->path;
       
  1032 		else if ( fi.isDir() ) {
       
  1033                     QString canPath = QDir( d->path ).canonicalPath();
       
  1034                     QString dir;
       
  1035                     if ( qt_resolve_symlinks && !canPath.isNull() )
       
  1036                        dir = QDir::cleanDirPath( canPath );
       
  1037                     else
       
  1038                        dir = QDir::cleanDirPath( QDir( d->path ).absPath() );
       
  1039                     dir += QLatin1Char('/');
       
  1040 		    if ( dir == QLatin1String("//") )
       
  1041 			d->cleanPath = QLatin1String("/");
       
  1042 		    else
       
  1043 			d->cleanPath = dir;
       
  1044 		} else {
       
  1045 		    QString p =
       
  1046 			QDir::cleanDirPath( (qt_resolve_symlinks ?
       
  1047 					    fi.dir().canonicalPath() :
       
  1048 					    fi.dir().absPath()) );
       
  1049 		    d->cleanPath = p + QLatin1Char('/') + fi.fileName();
       
  1050 		}
       
  1051 	    }
       
  1052 	} else {
       
  1053 		d->cleanPath = QDir::cleanDirPath( d->path );
       
  1054 	    if ( d->path.length() > 1 && d->path.endsWith(QLatin1Char('/')) )
       
  1055     		d->cleanPath += QLatin1Char('/');
       
  1056 	}
       
  1057 
       
  1058 	if ( check )
       
  1059 	    slashify( d->cleanPath, false );
       
  1060 	d->cleanPathDirty = false;
       
  1061     }
       
  1062 
       
  1063     return d->cleanPath;
       
  1064 }
       
  1065 
       
  1066 /*!
       
  1067     Returns true if the URL is a local file; otherwise returns false.
       
  1068 */
       
  1069 
       
  1070 bool Q3Url::isLocalFile() const
       
  1071 {
       
  1072     return d->protocol == QLatin1String("file");
       
  1073 }
       
  1074 
       
  1075 /*!
       
  1076     Returns the file name of the URL. If the path of the URL doesn't
       
  1077     have a slash at the end, the part between the last slash and the
       
  1078     end of the path string is considered to be the file name. If the
       
  1079     path has a slash at the end, an empty string is returned here.
       
  1080 
       
  1081     \sa setFileName()
       
  1082 */
       
  1083 
       
  1084 QString Q3Url::fileName() const
       
  1085 {
       
  1086     if ( d->path.isEmpty() || d->path.endsWith( QLatin1Char('/') )
       
  1087 #ifdef Q_WS_WIN
       
  1088 	|| d->path.endsWith( QLatin1Char('\\') )
       
  1089 #endif
       
  1090 	)
       
  1091 	return QString();
       
  1092 
       
  1093     return QFileInfo( d->path ).fileName();
       
  1094 }
       
  1095 
       
  1096 /*!
       
  1097     Adds the path \a pa to the path of the URL.
       
  1098 
       
  1099     \sa setPath() hasPath()
       
  1100 */
       
  1101 
       
  1102 void Q3Url::addPath( const QString& pa )
       
  1103 {
       
  1104     if ( pa.isEmpty() )
       
  1105 	return;
       
  1106 
       
  1107     QString p( pa );
       
  1108     slashify( p );
       
  1109 
       
  1110     if ( path().isEmpty() ) {
       
  1111 	if ( p[ 0 ] != QLatin1Char( '/' ) )
       
  1112 	    d->path = QLatin1Char('/') + p;
       
  1113 	else
       
  1114 	    d->path = p;
       
  1115     } else {
       
  1116 	if ( p[ 0 ] != QLatin1Char( '/' ) && d->path[ (int)d->path.length() - 1 ] != QLatin1Char('/') )
       
  1117 	    d->path += QLatin1Char('/') + p;
       
  1118 	else
       
  1119 	    d->path += p;
       
  1120     }
       
  1121     d->cleanPathDirty = true;
       
  1122 }
       
  1123 
       
  1124 /*!
       
  1125     Returns the directory path of the URL. This is the part of the
       
  1126     path of the URL without the fileName(). See the documentation of
       
  1127     fileName() for a discussion of what is handled as file name and
       
  1128     what is handled as directory path.
       
  1129 
       
  1130     \sa setPath() hasPath()
       
  1131 */
       
  1132 
       
  1133 QString Q3Url::dirPath() const
       
  1134 {
       
  1135     if ( path().isEmpty() )
       
  1136 	return QString();
       
  1137 
       
  1138     QString s = path();
       
  1139     int pos = s.findRev( QLatin1Char('/') );
       
  1140     if ( pos == -1 ) {
       
  1141 	return QString::fromLatin1( "." );
       
  1142     } else {
       
  1143 	if ( pos == 0 )
       
  1144 	    return QString::fromLatin1( "/" );
       
  1145 	return s.left( pos );
       
  1146     }
       
  1147 }
       
  1148 
       
  1149 /*!
       
  1150     Encodes the \a url in-place into UTF-8.  For example
       
  1151 
       
  1152     \snippet doc/src/snippets/code/src_qt3support_network_q3url.cpp 5
       
  1153 
       
  1154   \sa decode()
       
  1155 */
       
  1156 
       
  1157 void Q3Url::encode( QString& url )
       
  1158 {
       
  1159     if ( url.isEmpty() )
       
  1160 	return;
       
  1161 
       
  1162     Q3CString curl = url.utf8();
       
  1163     int oldlen = curl.length();
       
  1164 
       
  1165     const Q3CString special( "+<>#@\"&%$:,;?={}|^~[]\'`\\ \n\t\r" );
       
  1166     QString newUrl;
       
  1167     int newlen = 0;
       
  1168 
       
  1169     for ( int i = 0; i < oldlen ;++i ) {
       
  1170 	uchar inCh = (uchar)curl[ i ];
       
  1171 
       
  1172 	if ( inCh >= 128 || special.contains(inCh) ) {
       
  1173 	    newUrl[ newlen++ ] = QLatin1Char( '%' );
       
  1174 
       
  1175 	    ushort c = inCh / 16;
       
  1176 	    c += c > 9 ? 'A' - 10 : '0';
       
  1177 	    newUrl[ newlen++ ] = c;
       
  1178 
       
  1179 	    c = inCh % 16;
       
  1180 	    c += c > 9 ? 'A' - 10 : '0';
       
  1181 	    newUrl[ newlen++ ] = c;
       
  1182 	} else {
       
  1183 	    newUrl[ newlen++ ] = inCh;
       
  1184 	}
       
  1185     }
       
  1186 
       
  1187     url = newUrl;
       
  1188 }
       
  1189 
       
  1190 static uchar hex_to_int( uchar c )
       
  1191 {
       
  1192     if ( c >= 'A' && c <= 'F' )
       
  1193 	return c - 'A' + 10;
       
  1194     if ( c >= 'a' && c <= 'f')
       
  1195 	return c - 'a' + 10;
       
  1196     if ( c >= '0' && c <= '9')
       
  1197 	return c - '0';
       
  1198     return 0;
       
  1199 }
       
  1200 
       
  1201 /*!
       
  1202     Decodes the \a url in-place into UTF-8.  For example
       
  1203 
       
  1204     \snippet doc/src/snippets/code/src_qt3support_network_q3url.cpp 6
       
  1205 
       
  1206     \sa encode()
       
  1207 */
       
  1208 
       
  1209 void Q3Url::decode( QString& url )
       
  1210 {
       
  1211     if ( url.isEmpty() )
       
  1212 	return;
       
  1213 
       
  1214     int newlen = 0;
       
  1215     Q3CString curl = url.utf8();
       
  1216     int oldlen = curl.length();
       
  1217 
       
  1218     Q3CString newUrl(oldlen);
       
  1219 
       
  1220     int i = 0;
       
  1221     while ( i < oldlen ) {
       
  1222 	uchar c = (uchar)curl[ i++ ];
       
  1223 	if ( c == '%' && i <= oldlen - 2 ) {
       
  1224 	    c = hex_to_int( (uchar)curl[ i ] ) * 16 + hex_to_int( (uchar)curl[ i + 1 ] );
       
  1225 	    i += 2;
       
  1226 	}
       
  1227 	newUrl [ newlen++ ] = c;
       
  1228     }
       
  1229     newUrl.truncate( newlen );
       
  1230 
       
  1231     url = QString::fromUtf8(newUrl.data());
       
  1232 }
       
  1233 
       
  1234 
       
  1235 /*!
       
  1236     Composes a string version of the URL and returns it. If \a
       
  1237     encodedPath is true the path in the returned string is encoded. If
       
  1238     \a forcePrependProtocol is true and \a encodedPath looks like a
       
  1239     local filename, the "file:/" protocol is also prepended.
       
  1240 
       
  1241     \sa encode() decode()
       
  1242 */
       
  1243 
       
  1244 QString Q3Url::toString( bool encodedPath, bool forcePrependProtocol ) const
       
  1245 {
       
  1246     QString res, p = path();
       
  1247     if ( encodedPath )
       
  1248 	encode( p );
       
  1249 
       
  1250     if ( isLocalFile() ) {
       
  1251 	if ( forcePrependProtocol )
       
  1252 	    res = d->protocol + QLatin1Char(':') + p;
       
  1253 	else
       
  1254 	    res = p;
       
  1255     } else if ( d->protocol == QLatin1String("mailto") ) {
       
  1256 	res = d->protocol + QLatin1Char(':') + p;
       
  1257     } else {
       
  1258 	res = d->protocol + QLatin1String("://");
       
  1259 	if ( !d->user.isEmpty() || !d->pass.isEmpty() ) {
       
  1260 	    QString tmp;
       
  1261 	    if ( !d->user.isEmpty() ) {
       
  1262 		tmp = d->user;
       
  1263 		encode( tmp );
       
  1264 		res += tmp;
       
  1265 	    }
       
  1266 	    if ( !d->pass.isEmpty() ) {
       
  1267 		tmp = d->pass;
       
  1268 		encode( tmp );
       
  1269 		res += QLatin1Char(':') + tmp;
       
  1270 	    }
       
  1271 	    res += QLatin1Char('@');
       
  1272 	}
       
  1273 	res += d->host;
       
  1274 	if ( d->port != -1 )
       
  1275         res += QLatin1Char(':') + QString::number( d->port );
       
  1276 	if ( !p.isEmpty() ) {
       
  1277 	    if ( !d->host.isEmpty() && p[0]!= QLatin1Char( '/' ) )
       
  1278 		res += QLatin1Char('/');
       
  1279 	    res += p;
       
  1280 	}
       
  1281     }
       
  1282 
       
  1283     if ( !d->refEncoded.isEmpty() )
       
  1284 	res += QLatin1Char('#') + d->refEncoded;
       
  1285     if ( !d->queryEncoded.isEmpty() )
       
  1286 	res += QLatin1Char('?') + d->queryEncoded;
       
  1287 
       
  1288     return res;
       
  1289 }
       
  1290 
       
  1291 /*!
       
  1292     Composes a string version of the URL and returns it.
       
  1293 
       
  1294     \sa Q3Url::toString()
       
  1295 */
       
  1296 
       
  1297 Q3Url::operator QString() const
       
  1298 {
       
  1299     return toString();
       
  1300 }
       
  1301 
       
  1302 /*!
       
  1303     Changes the directory to one directory up. This function always returns
       
  1304     true.
       
  1305 
       
  1306     \sa setPath()
       
  1307 */
       
  1308 
       
  1309 bool Q3Url::cdUp()
       
  1310 {
       
  1311     d->path += QLatin1String("/..");
       
  1312     d->cleanPathDirty = true;
       
  1313     return true;
       
  1314 }
       
  1315 
       
  1316 QT_END_NAMESPACE
       
  1317 
       
  1318 #endif // QT_NO_URL