source: vendor/trolltech/current/src/kernel/qurl.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

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