00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00022
00023
00024
00025
00026
00027
00028 #include "kurl.h"
00029
00030 #include <kdebug.h>
00031 #include <kglobal.h>
00032 #include <kshell.h>
00033 #include <kstringhandler.h>
00034
00035 #include <stdio.h>
00036 #include <assert.h>
00037 #include <ctype.h>
00038 #include <stdlib.h>
00039 #include <unistd.h>
00040
00041 #include <QtCore/QDir>
00042 #include <QtCore/QMutableStringListIterator>
00043 #include <QtCore/QRegExp>
00044 #include <QtCore/QMimeData>
00045 #include <QtCore/QTextCodec>
00046
00047 #ifdef DEBUG_KURL
00048 static int kurlDebugArea() { static int s_area = KDebug::registerArea("kdecore (KUrl)"); return s_area; }
00049 #endif
00050
00051 static QString cleanpath( const QString &_path, bool cleanDirSeparator, bool decodeDots )
00052 {
00053 if (_path.isEmpty())
00054 return QString();
00055
00056 if (QFileInfo(_path).isRelative())
00057 return _path;
00058
00059 QString path = _path;
00060
00061 int len = path.length();
00062
00063 if (decodeDots)
00064 {
00065 static const QString &encodedDot = KGlobal::staticQString("%2e");
00066 if (path.indexOf(encodedDot, 0, Qt::CaseInsensitive) != -1)
00067 {
00068 static const QString &encodedDOT = KGlobal::staticQString("%2E");
00069 path.replace(encodedDot, ".");
00070 path.replace(encodedDOT, ".");
00071 len = path.length();
00072 }
00073 }
00074
00075 bool slash = (len && path[len-1] == QLatin1Char('/')) ||
00076 (len > 1 && path[len-2] == QLatin1Char('/') && path[len-1] == QLatin1Char('.'));
00077
00078
00079
00080
00081
00082
00083
00084 QString result;
00085 int cdUp, orig_pos, pos;
00086
00087 cdUp = 0;
00088 pos = orig_pos = len;
00089 while ( pos && (pos = path.lastIndexOf(QLatin1Char('/'),--pos)) != -1 )
00090 {
00091 len = orig_pos - pos - 1;
00092 if ( len == 2 && path[pos+1] == '.' && path[pos+2] == '.' )
00093 cdUp++;
00094 else
00095 {
00096
00097
00098 if ( (len || !cleanDirSeparator) &&
00099 (len != 1 || path[pos+1] != '.' ) )
00100 {
00101 if ( !cdUp )
00102 result.prepend(path.mid(pos, len+1));
00103 else
00104 cdUp--;
00105 }
00106 }
00107 orig_pos = pos;
00108 }
00109
00110 #ifdef Q_WS_WIN // prepend drive letter if exists (js)
00111 if (orig_pos >= 2 && path[0].isLetter() && path[1] == QLatin1Char(':') ) {
00112 result.prepend(QString(path[0]) + QLatin1Char(':') );
00113 }
00114 #endif
00115
00116 if ( result.isEmpty() )
00117 result = '/';
00118 else if ( slash && result[result.length()-1] != QLatin1Char('/') )
00119 result.append(QChar('/'));
00120
00121 return result;
00122 }
00123
00124 #ifdef Q_WS_WIN
00125
00126
00127 #define IS_DRIVE_OR_DOUBLESLASH(isletter, char1, char2, colon, slash) \
00128 ((isletter && char2 == colon) || (char1 == slash && char2 == slash))
00129
00130
00131
00132
00133 static QString removeSlashOrFilePrefix(const QString& str)
00134 {
00135
00136 const int len = str.length();
00137 if (str[0]=='f') {
00138 if ( len > 10 && str.startsWith( QLatin1String( "file:///" ) )
00139 && IS_DRIVE_OR_DOUBLESLASH(str[8].isLetter(), str[8], str[9], QLatin1Char(':'), QLatin1Char('/')) )
00140 return QUrl::fromPercentEncoding( str.toLatin1() ).mid(8);
00141 else if ( len > 9 && str.startsWith( QLatin1String( "file://" ) )
00142 && IS_DRIVE_OR_DOUBLESLASH(str[7].isLetter(), str[7], str[8], QLatin1Char(':'), QLatin1Char('/')) )
00143 return QUrl::fromPercentEncoding( str.toLatin1() ).mid(7);
00144 else if ( len > 8 && str.startsWith( QLatin1String( "file:/" ) )
00145 && IS_DRIVE_OR_DOUBLESLASH(str[6].isLetter(), str[6], str[7], QLatin1Char(':'), QLatin1Char('/')) )
00146 return QUrl::fromPercentEncoding( str.toLatin1() ).mid(6);
00147 }
00148
00149
00150
00151 if ( len > 2 && str[0] == QLatin1Char('/')
00152 && IS_DRIVE_OR_DOUBLESLASH(str[1].isLetter(), str[1], str[2], QLatin1Char(':'), QLatin1Char('/')) )
00153 return str.mid(1);
00154
00155 else if ( len >= 2 && IS_DRIVE_OR_DOUBLESLASH(str[0].isLetter(), str[0], str[1], QLatin1Char(':'), QLatin1Char('/')) )
00156 return str;
00157 return QString();
00158 }
00159 #endif
00160
00161 bool KUrl::isRelativeUrl(const QString &_url)
00162 {
00163 int len = _url.length();
00164 if (!len) return true;
00165 const QChar *str = _url.unicode();
00166
00167
00168 if (!isalpha(str[0].toLatin1()))
00169 return true;
00170
00171 for(int i = 1; i < len; i++)
00172 {
00173 char c = str[i].toLatin1();
00174 if (c == ':')
00175 return false;
00176
00177
00178 if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-'))
00179 return true;
00180 }
00181
00182 return true;
00183 }
00184
00185 KUrl::List::List(const KUrl &url)
00186 {
00187 append( url );
00188 }
00189
00190 KUrl::List::List(const QList<KUrl> &list)
00191 : QList<KUrl>(list)
00192 {
00193 }
00194
00195 KUrl::List::List(const QStringList &list)
00196 {
00197 for (QStringList::ConstIterator it = list.begin();
00198 it != list.end();
00199 ++it)
00200 {
00201 append( KUrl(*it) );
00202 }
00203 }
00204
00205 QStringList KUrl::List::toStringList() const
00206 {
00207 QStringList lst;
00208 for( KUrl::List::ConstIterator it = begin();
00209 it != end();
00210 ++it)
00211 {
00212 lst.append( (*it).url() );
00213 }
00214 return lst;
00215 }
00216
00217 static QByteArray uriListData(const KUrl::List& urls)
00218 {
00219 QList<QByteArray> urlStringList;
00220 KUrl::List::ConstIterator uit = urls.constBegin();
00221 const KUrl::List::ConstIterator uEnd = urls.constEnd();
00222 for (; uit != uEnd ; ++uit) {
00223
00224
00225 urlStringList.append((*uit).toMimeDataString().toLatin1());
00226 }
00227
00228 QByteArray uriListData;
00229 for (int i = 0, n = urlStringList.count(); i < n; ++i) {
00230 uriListData += urlStringList.at(i);
00231 if (i < n-1)
00232 uriListData += "\r\n";
00233 }
00234 return uriListData;
00235 }
00236
00237 static const char* s_kdeUriListMime = "application/x-kde4-urilist";
00238
00239 void KUrl::List::populateMimeData( QMimeData* mimeData,
00240 const KUrl::MetaDataMap& metaData,
00241 MimeDataFlags flags ) const
00242 {
00243 mimeData->setData("text/uri-list", uriListData(*this));
00244
00245 if ( ( flags & KUrl::NoTextExport ) == 0 )
00246 {
00247 QStringList prettyURLsList;
00248 KUrl::List::ConstIterator uit = constBegin();
00249 const KUrl::List::ConstIterator uEnd = constEnd();
00250 for ( ; uit != uEnd ; ++uit ) {
00251 QString prettyURL = (*uit).prettyUrl();
00252 if ( (*uit).protocol() == "mailto" ) {
00253 prettyURL = (*uit).path();
00254 }
00255 prettyURLsList.append( prettyURL );
00256 }
00257
00258 QByteArray plainTextData = prettyURLsList.join( "\n" ).toLocal8Bit();
00259 if( count() > 1 )
00260 plainTextData.append( "\n" );
00261 mimeData->setData( "text/plain", plainTextData );
00262 }
00263
00264 if ( !metaData.isEmpty() )
00265 {
00266 QByteArray metaDataData;
00267 for( KUrl::MetaDataMap::const_iterator it = metaData.begin(); it != metaData.end(); ++it )
00268 {
00269 metaDataData += it.key().toUtf8();
00270 metaDataData += "$@@$";
00271 metaDataData += it.value().toUtf8();
00272 metaDataData += "$@@$";
00273 }
00274 mimeData->setData( "application/x-kio-metadata", metaDataData );
00275 }
00276 }
00277
00278
00279 void KUrl::List::populateMimeData(const KUrl::List& mostLocalUrls,
00280 QMimeData* mimeData,
00281 const KUrl::MetaDataMap& metaData,
00282 MimeDataFlags flags) const
00283 {
00284
00285 mostLocalUrls.populateMimeData(mimeData, metaData, flags);
00286
00287 mimeData->setData(s_kdeUriListMime, uriListData(*this));
00288 }
00289
00290 bool KUrl::List::canDecode( const QMimeData *mimeData )
00291 {
00292 return mimeData->hasFormat("text/uri-list") ||
00293 mimeData->hasFormat(s_kdeUriListMime);
00294 }
00295
00296 QStringList KUrl::List::mimeDataTypes()
00297 {
00298 return QStringList() << s_kdeUriListMime << "text/uri-list";
00299 }
00300
00301
00302 KUrl::List KUrl::List::fromMimeData(const QMimeData *mimeData,
00303 DecodeOptions decodeOptions,
00304 KUrl::MetaDataMap* metaData)
00305 {
00306
00307 KUrl::List uris;
00308 const char* firstMimeType = s_kdeUriListMime;
00309 const char* secondMimeType = "text/uri-list";
00310 if (decodeOptions == PreferLocalUrls) {
00311 qSwap(firstMimeType, secondMimeType);
00312 }
00313 QByteArray payload = mimeData->data(firstMimeType);
00314 if (payload.isEmpty())
00315 payload = mimeData->data(secondMimeType);
00316 if ( !payload.isEmpty() ) {
00317 int c = 0;
00318 const char* d = payload.data();
00319 while ( c < payload.size() && d[c] ) {
00320 int f = c;
00321
00322 while (c < payload.size() && d[c] && d[c]!='\r'
00323 && d[c] != '\n')
00324 c++;
00325 QByteArray s( d+f, c-f );
00326 if ( s[0] != '#' )
00327 uris.append( KUrl::fromMimeDataByteArray( s ) );
00328
00329 while ( c < payload.size() && d[c] &&
00330 ( d[c] == '\n' || d[c] == '\r' ) )
00331 ++c;
00332 }
00333 }
00334 if ( metaData )
00335 {
00336 const QByteArray metaDataPayload = mimeData->data( "application/x-kio-metadata" );
00337 if ( !metaDataPayload.isEmpty() )
00338 {
00339 QString str = QString::fromUtf8( metaDataPayload );
00340 Q_ASSERT( str.endsWith( "$@@$" ) );
00341 str.truncate( str.length() - 4 );
00342 const QStringList lst = str.split( "$@@$" );
00343 QStringList::ConstIterator it = lst.begin();
00344 bool readingKey = true;
00345 QString key;
00346 for ( ; it != lst.end(); ++it ) {
00347 if ( readingKey )
00348 key = *it;
00349 else
00350 metaData->insert( key, *it );
00351 readingKey = !readingKey;
00352 }
00353 Q_ASSERT( readingKey );
00354 }
00355 }
00356
00357 return uris;
00358 }
00359
00360 KUrl::List KUrl::List::fromMimeData( const QMimeData *mimeData, KUrl::MetaDataMap* metaData )
00361 {
00362 return fromMimeData(mimeData, PreferKdeUrls, metaData);
00363 }
00364
00365 KUrl::List::operator QVariant() const
00366 {
00367 return qVariantFromValue(*this);
00368 }
00369
00371
00372 KUrl::KUrl()
00373 : QUrl(), d(0)
00374 {
00375 }
00376
00377 KUrl::~KUrl()
00378 {
00379 }
00380
00381
00382 KUrl::KUrl( const QString &str )
00383 : QUrl(), d(0)
00384 {
00385 if ( !str.isEmpty() ) {
00386 #ifdef Q_WS_WIN
00387 #ifdef DEBUG_KURL
00388 kDebug(kurlDebugArea()) << "KUrl::KUrl ( const QString &str = " << str.toAscii().data() << " )";
00389 #endif
00390 QString pathToSet;
00391
00392
00393 if (!str.startsWith(QLatin1String("file://")))
00394 pathToSet = removeSlashOrFilePrefix( QDir::fromNativeSeparators(str) );
00395 if ( !pathToSet.isEmpty() ) {
00396
00397
00398 int index = pathToSet.lastIndexOf('?');
00399 if (index == -1)
00400 setPath( pathToSet );
00401 else {
00402 setPath( pathToSet.left( index ) );
00403 _setQuery( pathToSet.mid( index + 1 ) );
00404 }
00405 return;
00406 }
00407 #endif
00408 if ( str[0] == QLatin1Char('/') || str[0] == QLatin1Char('~') )
00409 setPath( str );
00410 else {
00411 _setEncodedUrl( str.toUtf8() );
00412 }
00413 }
00414 }
00415
00416 KUrl::KUrl( const char * str )
00417 : QUrl(), d(0)
00418 {
00419 #ifdef Q_WS_WIN
00420
00421 #define IS_LETTER(c) \
00422 ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
00423
00424
00425 #define IS_SLASH_AND_DRIVE_OR_DOUBLESLASH_0 \
00426 ( str[0] == '/' && IS_DRIVE_OR_DOUBLESLASH(IS_LETTER(str[1]), str[1], str[2], ':', '/') )
00427
00428
00429 #define IS_DRIVE_OR_DOUBLESLASH_0 \
00430 ( IS_DRIVE_OR_DOUBLESLASH(IS_LETTER(str[0]), str[0], str[1], ':', '/') )
00431
00432 #if defined(DEBUG_KURL)
00433 kDebug(kurlDebugArea()) << "KUrl::KUrl " << " " << str;
00434 #endif
00435 if ( str && str[0] && str[1] && str[2] ) {
00436 if ( IS_SLASH_AND_DRIVE_OR_DOUBLESLASH_0 )
00437 setPath( QString::fromUtf8( str+1 ) );
00438 else if ( IS_DRIVE_OR_DOUBLESLASH_0 )
00439 setPath( QString::fromUtf8( str ) );
00440 }
00441 #endif
00442 if ( str && str[0] ) {
00443 if ( str[0] == '/' || str[0] == '~' )
00444 setPath( QString::fromUtf8( str ) );
00445 else
00446 _setEncodedUrl( str );
00447 }
00448 }
00449
00450 KUrl::KUrl( const QByteArray& str )
00451 : QUrl(), d(0)
00452 {
00453 if ( !str.isEmpty() ) {
00454 #ifdef Q_WS_WIN
00455 #ifdef DEBUG_KURL
00456 kDebug(kurlDebugArea()) << "KUrl::KUrl " << " " << str.data();
00457 #endif
00458 if ( IS_SLASH_AND_DRIVE_OR_DOUBLESLASH_0 )
00459 setPath( QString::fromUtf8( str.mid( 1 ) ) );
00460 else if ( IS_DRIVE_OR_DOUBLESLASH_0 )
00461 setPath( QString::fromUtf8( str ) );
00462 #else
00463 if ( str[0] == '/' || str[0] == '~' )
00464 setPath( QString::fromUtf8( str ) );
00465 #endif
00466 else
00467 _setEncodedUrl( str );
00468 }
00469 }
00470
00471 KUrl::KUrl( const KUrl& _u )
00472 : QUrl( _u ), d(0)
00473 {
00474 #if defined(Q_WS_WIN) && defined(DEBUG_KURL)
00475 kDebug(kurlDebugArea()) << "KUrl::KUrl(KUrl) " << " path " << _u.path() << " toLocalFile " << _u.toLocalFile();
00476 #endif
00477 }
00478
00479 KUrl::KUrl( const QUrl &u )
00480 : QUrl( u ), d(0)
00481 {
00482 #if defined(Q_WS_WIN) && defined(DEBUG_KURL)
00483 kDebug(kurlDebugArea()) << "KUrl::KUrl(Qurl) " << " path " << u.path() << " toLocalFile " << u.toLocalFile();
00484 #endif
00485 }
00486
00487 KUrl::KUrl( const KUrl& _u, const QString& _rel_url )
00488 : QUrl(), d(0)
00489 {
00490 #if defined(Q_WS_WIN) && defined(DEBUG_KURL)
00491 kDebug(kurlDebugArea()) << "KUrl::KUrl(KUrl,QString rel_url) " << " path " << _u.path() << " toLocalFile " << _u.toLocalFile();
00492 #endif
00493 #if 0
00494 if (_u.hasSubUrl())
00495 {
00496 KUrl::List lst = split( _u );
00497 KUrl u(lst.last(), _rel_url);
00498 lst.erase( --lst.end() );
00499 lst.append( u );
00500 *this = join( lst );
00501 return;
00502 }
00503 #endif
00504 QString rUrl = _rel_url;
00505
00506
00507
00508
00509 int len = _u.scheme().length();
00510 if ( !_u.host().isEmpty() && !rUrl.isEmpty() &&
00511 rUrl.indexOf( _u.scheme(), 0, Qt::CaseInsensitive ) == 0 &&
00512 rUrl[len] == ':' && (rUrl[len+1] != QLatin1Char('/') ||
00513 (rUrl[len+1] == '/' && rUrl[len+2] != QLatin1Char('/'))) )
00514 {
00515 rUrl.remove( 0, rUrl.indexOf( ':' ) + 1 );
00516 }
00517
00518
00519 if ( rUrl.isEmpty() )
00520 {
00521 *this = _u;
00522 }
00523 else if ( rUrl[0] == '#' )
00524 {
00525 *this = _u;
00526 QString strRef_encoded = rUrl.mid(1);
00527 if ( strRef_encoded.isNull() )
00528 strRef_encoded = "";
00529 setFragment( strRef_encoded );
00530 }
00531 else if ( isRelativeUrl( rUrl ) )
00532 {
00533 *this = _u;
00534 setFragment( QString() );
00535 setEncodedQuery( QByteArray() );
00536 QString strPath = path();
00537 if ( rUrl[0] == QLatin1Char('/') )
00538 {
00539 if ((rUrl.length() > 1) && (rUrl[1] == QLatin1Char('/')))
00540 {
00541 setHost( QString() );
00542 setPort( -1 );
00543
00544 if ( _u.isLocalFile() )
00545 rUrl.remove(0, 2);
00546 }
00547 strPath.clear();
00548 }
00549 else if ( rUrl[0] != '?' )
00550 {
00551 int pos = strPath.lastIndexOf( QLatin1Char('/') );
00552 if (pos >= 0)
00553 strPath.truncate(pos);
00554 strPath += QLatin1Char('/');
00555 }
00556 else
00557 {
00558 if ( strPath.isEmpty() )
00559 strPath = QLatin1Char('/');
00560 }
00561 setPath( strPath );
00562
00563 KUrl tmp( url() + rUrl);
00564
00565 *this = tmp;
00566 cleanPath(KeepDirSeparators);
00567 }
00568 else
00569 {
00570 KUrl tmp( rUrl );
00571
00572 *this = tmp;
00573
00574 if (!_u.userInfo().isEmpty() && userInfo().isEmpty()
00575 && (_u.host() == host()) && (_u.scheme() == scheme()))
00576 {
00577 setUserInfo( _u.userInfo() );
00578 }
00579 cleanPath(KeepDirSeparators);
00580 }
00581 }
00582
00583 KUrl& KUrl::operator=( const KUrl& _u )
00584 {
00585 QUrl::operator=( _u );
00586 return *this;
00587 }
00588
00589 bool KUrl::operator==( const KUrl& _u ) const
00590 {
00591 return QUrl::operator==( _u );
00592 }
00593
00594 bool KUrl::operator==( const QString& _u ) const
00595 {
00596 KUrl u( _u );
00597 return ( *this == u );
00598 }
00599
00600 KUrl::operator QVariant() const
00601 {
00602 return qVariantFromValue(*this);
00603 }
00604
00605 bool KUrl::cmp( const KUrl &u, bool ignore_trailing ) const
00606 {
00607 return equals( u, ignore_trailing ? CompareWithoutTrailingSlash : EqualsOptions(0) );
00608 }
00609
00610 bool KUrl::equals( const KUrl &_u, const EqualsOptions& options ) const
00611 {
00612 if ( !isValid() || !_u.isValid() )
00613 return false;
00614
00615 if ( options & CompareWithoutTrailingSlash || options & CompareWithoutFragment )
00616 {
00617 QString path1 = path((options & CompareWithoutTrailingSlash) ? RemoveTrailingSlash : LeaveTrailingSlash);
00618 QString path2 = _u.path((options & CompareWithoutTrailingSlash) ? RemoveTrailingSlash : LeaveTrailingSlash);
00619 #ifdef Q_WS_WIN
00620 const bool bLocal1 = isLocalFile();
00621 const bool bLocal2 = _u.isLocalFile();
00622 if ( !bLocal1 && bLocal2 || bLocal1 && !bLocal2 )
00623 return false;
00624
00625 if ( bLocal1 && bLocal2 && 0 != QString::compare( path1, path2, Qt::CaseInsensitive ) )
00626 return false;
00627 #endif
00628 if ( path1 != path2 )
00629 return false;
00630
00631 if ( scheme() == _u.scheme() &&
00632 authority() == _u.authority() &&
00633 encodedQuery() == _u.encodedQuery() &&
00634 (fragment() == _u.fragment() || options & CompareWithoutFragment ) )
00635 return true;
00636
00637 return false;
00638 }
00639
00640 return ( *this == _u );
00641 }
00642
00643 QString KUrl::protocol() const
00644 {
00645 return scheme().toLower();
00646 }
00647
00648 void KUrl::setProtocol( const QString& proto )
00649 {
00650 setScheme( proto );
00651 }
00652
00653 QString KUrl::user() const
00654 {
00655 return userName();
00656 }
00657
00658 void KUrl::setUser( const QString& user )
00659 {
00660 setUserName( user );
00661 }
00662
00663 bool KUrl::hasUser() const
00664 {
00665 return !userName().isEmpty();
00666 }
00667
00668 QString KUrl::pass() const
00669 {
00670 return password();
00671 }
00672
00673 void KUrl::setPass( const QString& pass )
00674 {
00675 setPassword( pass );
00676 }
00677
00678 bool KUrl::hasPass() const
00679 {
00680 return !password().isEmpty();
00681 }
00682
00683 bool KUrl::hasHost() const
00684 {
00685 return !host().isEmpty();
00686 }
00687
00688 bool KUrl::hasPath() const
00689 {
00690 return !path().isEmpty();
00691 }
00692
00693 KUrl KUrl::fromPath( const QString& text )
00694 {
00695 KUrl u;
00696 u.setPath( text );
00697 return u;
00698 }
00699
00700 void KUrl::setFileName( const QString& _txt )
00701 {
00702 setFragment( QString() );
00703 int i = 0;
00704 while( i < _txt.length() && _txt[i] == QLatin1Char('/') )
00705 ++i;
00706 QString tmp = i ? _txt.mid( i ) : _txt;
00707
00708 QString path = this->path();
00709 if ( path.isEmpty() )
00710 #ifdef Q_OS_WIN
00711 path = isLocalFile() ? QDir::rootPath() : QLatin1String("/");
00712 #else
00713 path = QDir::rootPath();
00714 #endif
00715 else
00716 {
00717 int lastSlash = path.lastIndexOf( QLatin1Char('/') );
00718 if ( lastSlash == -1)
00719 path.clear();
00720 else if ( !path.endsWith( QLatin1Char('/') ) )
00721 path.truncate( lastSlash+1 );
00722 }
00723
00724 path += tmp;
00725 setPath( path );
00726
00727 cleanPath();
00728 }
00729
00730 void KUrl::cleanPath( const CleanPathOption& options )
00731 {
00732
00733 const QString newPath = cleanpath(path(), !(options & KeepDirSeparators), false);
00734 if ( path() != newPath )
00735 setPath( newPath );
00736
00737
00738 }
00739
00740 static QString trailingSlash( KUrl::AdjustPathOption trailing, const QString &path )
00741 {
00742 if ( trailing == KUrl::LeaveTrailingSlash ) {
00743 return path;
00744 }
00745
00746 QString result = path;
00747
00748 if ( trailing == KUrl::AddTrailingSlash )
00749 {
00750 int len = result.length();
00751 if ( (len == 0) || (result[ len - 1 ] != QLatin1Char('/')) )
00752 result += QLatin1Char('/');
00753 return result;
00754 }
00755 else if ( trailing == KUrl::RemoveTrailingSlash )
00756 {
00757 if ( result == QLatin1String("/") )
00758 return result;
00759 int len = result.length();
00760 while (len > 1 && result[ len - 1 ] == QLatin1Char('/'))
00761 {
00762 len--;
00763 }
00764 result.truncate( len );
00765 return result;
00766 }
00767 else {
00768 assert( 0 );
00769 return result;
00770 }
00771 }
00772
00773 void KUrl::adjustPath( AdjustPathOption trailing )
00774 {
00775 #if 0
00776 if (!m_strPath_encoded.isEmpty())
00777 {
00778 m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded );
00779 }
00780 #endif
00781 const QString newPath = trailingSlash( trailing, path() );
00782 if ( path() != newPath )
00783 setPath( newPath );
00784 }
00785
00786
00787 QString KUrl::encodedPathAndQuery( AdjustPathOption trailing , const EncodedPathAndQueryOptions &options) const
00788 {
00789 QString encodedPath;
00790 #ifdef Q_OS_WIN
00791
00792 if (isLocalFile()) {
00793
00794 encodedPath = trailingSlash(trailing, QUrl::toLocalFile());
00795 encodedPath = QString::fromLatin1(QUrl::toPercentEncoding(encodedPath, "!$&'()*+,;=:@/"));
00796 } else {
00797 encodedPath = trailingSlash(trailing, QUrl::encodedPath());
00798 }
00799 #else
00800 encodedPath = trailingSlash(trailing, QUrl::encodedPath());
00801 #endif
00802
00803 if ((options & AvoidEmptyPath) && encodedPath.isEmpty()) {
00804 encodedPath.append('/');
00805 }
00806
00807 if (hasQuery()) {
00808 return encodedPath + '?' + encodedQuery();
00809 } else {
00810 return encodedPath;
00811 }
00812 }
00813
00814 #if 0
00815 void KUrl::setEncodedPath( const QString& _txt, int encoding_hint )
00816 {
00817 m_strPath_encoded = _txt;
00818
00819 decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint );
00820
00821 if (m_strProtocol == "file")
00822 m_strPath_encoded.clear();
00823
00824 if ( m_iUriMode == Auto )
00825 m_iUriMode = URL;
00826 }
00827 #endif
00828
00829 void KUrl::setEncodedPathAndQuery( const QString& _txt )
00830 {
00831 int pos = _txt.indexOf( '?' );
00832 if ( pos == -1 )
00833 {
00834 setPath( QUrl::fromPercentEncoding( _txt.toLatin1() ) );
00835 setEncodedQuery( QByteArray() );
00836 }
00837 else
00838 {
00839 setPath( QUrl::fromPercentEncoding( _txt.toLatin1() ).left( pos ) );
00840 _setQuery( _txt.right( _txt.length() - pos - 1 ) );
00841 }
00842 }
00843
00844 QString KUrl::path( AdjustPathOption trailing ) const
00845 {
00846 #ifdef Q_WS_WIN
00847 kWarning() << (isLocalFile() ? "converted to local file - the related call should be converted to toLocalFile()" : "") << QUrl::path();
00848 return trailingSlash( trailing, isLocalFile() ? QUrl::toLocalFile() : QUrl::path() );
00849 #else
00850 return trailingSlash( trailing, QUrl::path() );
00851 #endif
00852 }
00853
00854 QString KUrl::toLocalFile( AdjustPathOption trailing ) const
00855 {
00856 if (hasHost() && isLocalFile()) {
00857 KUrl urlWithoutHost(*this);
00858 urlWithoutHost.setHost(QString());
00859 return trailingSlash(trailing, urlWithoutHost.toLocalFile());
00860 }
00861 return trailingSlash(trailing, QUrl::toLocalFile());
00862 }
00863
00864 inline static bool hasSubUrl( const QUrl& url );
00865
00866 static inline bool isLocalFile( const QUrl& url )
00867 {
00868 if ( ( url.scheme() != QLatin1String("file") ) || hasSubUrl( url ) )
00869 return false;
00870
00871 if (url.host().isEmpty() || (url.host() == QLatin1String("localhost")))
00872 return true;
00873
00874 char hostname[ 256 ];
00875 hostname[ 0 ] = '\0';
00876 if (!gethostname( hostname, 255 ))
00877 hostname[sizeof(hostname)-1] = '\0';
00878
00879 for(char *p = hostname; *p; p++)
00880 *p = tolower(*p);
00881
00882 return (url.host() == QString::fromLatin1( hostname ));
00883 }
00884
00885 bool KUrl::isLocalFile() const
00886 {
00887 return ::isLocalFile( *this );
00888 }
00889
00890 void KUrl::setFileEncoding(const QString &encoding)
00891 {
00892 if (!isLocalFile())
00893 return;
00894
00895 QString q = query();
00896
00897 if (!q.isEmpty() && (q[0] == '?'))
00898 q = q.mid(1);
00899
00900 QStringList args = q.split('&', QString::SkipEmptyParts);
00901 for(QStringList::Iterator it = args.begin();
00902 it != args.end();)
00903 {
00904 QString s = QUrl::fromPercentEncoding( (*it).toLatin1() );
00905 if (s.startsWith("charset="))
00906 it = args.erase(it);
00907 else
00908 ++it;
00909 }
00910 if (!encoding.isEmpty())
00911 args.append("charset=" + QUrl::toPercentEncoding(encoding));
00912
00913 if (args.isEmpty())
00914 _setQuery(QString());
00915 else
00916 _setQuery(args.join("&"));
00917 }
00918
00919 QString KUrl::fileEncoding() const
00920 {
00921 if (!isLocalFile())
00922 return QString();
00923
00924 QString q = query();
00925
00926 if (q.isEmpty())
00927 return QString();
00928
00929 if (q[0] == '?')
00930 q = q.mid(1);
00931
00932 const QStringList args = q.split('&', QString::SkipEmptyParts);
00933 for(QStringList::ConstIterator it = args.begin();
00934 it != args.end();
00935 ++it)
00936 {
00937 QString s = QUrl::fromPercentEncoding((*it).toLatin1());
00938 if (s.startsWith("charset="))
00939 return s.mid(8);
00940 }
00941 return QString();
00942 }
00943
00944 inline static bool hasSubUrl( const QUrl& url )
00945 {
00946
00947
00948 if ( url.scheme().isEmpty() )
00949 return false;
00950 const QByteArray ref( url.fragment().toLatin1() );
00951 if (ref.isEmpty())
00952 return false;
00953 switch ( ref.data()[0] ) {
00954 case 'g':
00955 if ( ref.startsWith("gzip:") )
00956 return true;
00957 break;
00958 case 'b':
00959 if ( ref.startsWith("bzip:") || ref.startsWith("bzip2:") )
00960 return true;
00961 break;
00962 case 'l':
00963 if ( ref.startsWith("lzma:") )
00964 return true;
00965 break;
00966 case 'x':
00967 if ( ref.startsWith("xz:") )
00968 return true;
00969 break;
00970 case 't':
00971 if ( ref.startsWith("tar:") )
00972 return true;
00973 break;
00974 case 'a':
00975 if ( ref.startsWith("ar:") )
00976 return true;
00977 break;
00978 case 'z':
00979 if ( ref.startsWith("zip:") )
00980 return true;
00981 break;
00982 default:
00983 break;
00984 }
00985 if ( url.scheme() == "error" )
00986 return true;
00987 return false;
00988 }
00989
00990 bool KUrl::hasSubUrl() const
00991 {
00992 return ::hasSubUrl( *this );
00993 }
00994
00995 QString KUrl::url( AdjustPathOption trailing ) const
00996 {
00997 if (QString::compare(scheme(), QLatin1String("mailto"), Qt::CaseInsensitive) == 0) {
00998
00999 return prettyUrl(trailing);
01000 }
01001 if ( trailing == AddTrailingSlash && !path().endsWith( QLatin1Char('/') ) ) {
01002
01003
01004
01005 QUrl newUrl( *this );
01006 newUrl.setPath( path() + QLatin1Char('/') );
01007 return QString::fromLatin1(newUrl.toEncoded());
01008 }
01009 else if ( trailing == RemoveTrailingSlash && path() == "/" ) {
01010 return QLatin1String(toEncoded(None));
01011 }
01012 return QString::fromLatin1(toEncoded(trailing == RemoveTrailingSlash ? StripTrailingSlash : None));
01013 }
01014
01015 static QString toPrettyPercentEncoding(const QString &input, bool forFragment)
01016 {
01017 QString result;
01018 for (int i = 0; i < input.length(); ++i) {
01019 QChar c = input.at(i);
01020 register ushort u = c.unicode();
01021 if (u < 0x20
01022 || (!forFragment && u == '?')
01023 || u == '#' || u == '%'
01024 || (u == ' ' && (i+1 == input.length() || input.at(i+1) == ' '))) {
01025 static const char hexdigits[] = "0123456789ABCDEF";
01026 result += QLatin1Char('%');
01027 result += QLatin1Char(hexdigits[(u & 0xf0) >> 4]);
01028 result += QLatin1Char(hexdigits[u & 0xf]);
01029 } else {
01030 result += c;
01031 }
01032 }
01033
01034 return result;
01035 }
01036
01037 QString KUrl::prettyUrl( AdjustPathOption trailing ) const
01038 {
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048 QString result = scheme();
01049 if (!result.isEmpty())
01050 {
01051 if(!authority().isEmpty() || result == QLatin1String("file"))
01052 result += QLatin1String("://");
01053 else
01054 result += QLatin1String(":");
01055 }
01056
01057 QString tmp = userName();
01058 if (!tmp.isEmpty()) {
01059 result += QUrl::toPercentEncoding(tmp);
01060 result += QLatin1Char('@');
01061 }
01062
01063
01064 tmp = host();
01065 if (tmp.contains(':'))
01066 result += QLatin1Char('[') + tmp + QLatin1Char(']');
01067 else
01068 result += tmp;
01069
01070 if (port() != -1) {
01071 result += QLatin1Char(':');
01072 result += QString::number(port());
01073 }
01074
01075 tmp = path();
01076 result += toPrettyPercentEncoding(tmp, false);
01077
01078
01079 if (trailing == AddTrailingSlash && !tmp.endsWith(QLatin1Char('/')))
01080 result += QLatin1Char('/');
01081 else if (trailing == RemoveTrailingSlash && tmp.length() > 1 && tmp.endsWith(QLatin1Char('/')))
01082 result.chop(1);
01083
01084 if (hasQuery()) {
01085 result += QLatin1Char('?');
01086 result += QUrl::fromPercentEncoding(encodedQuery());
01087 }
01088
01089 if (hasFragment()) {
01090 result += QLatin1Char('#');
01091 result += toPrettyPercentEncoding(fragment(), true);
01092 }
01093
01094 return result;
01095 }
01096
01097 #if 0
01098 QString KUrl::prettyUrl( int _trailing, AdjustementFlags _flags) const
01099 {
01100 QString u = prettyUrl(_trailing);
01101 if (_flags & StripFileProtocol && u.startsWith("file://")) {
01102 u.remove(0, 7);
01103 #ifdef Q_WS_WIN
01104 return QDir::convertSeparators(u);
01105 #endif
01106 }
01107 return u;
01108 }
01109 #endif
01110
01111 QString KUrl::pathOrUrl() const
01112 {
01113 return pathOrUrl(LeaveTrailingSlash);
01114 }
01115
01116 QString KUrl::pathOrUrl(AdjustPathOption trailing) const
01117 {
01118 if ( isLocalFile() && fragment().isNull() && encodedQuery().isNull() ) {
01119 return toLocalFile(trailing);
01120 } else {
01121 return prettyUrl(trailing);
01122 }
01123 }
01124
01125
01126 QString KUrl::toMimeDataString() const
01127 {
01128 if ( isLocalFile() )
01129 {
01130 #if 1
01131 return url();
01132 #else
01133
01134
01135
01136 const QString s = url( 0, KGlobal::locale()->fileEncodingMib() );
01137 if( !s.startsWith( QLatin1String ( "file://" ) ))
01138 {
01139 char hostname[257];
01140 if ( gethostname( hostname, 255 ) == 0 )
01141 {
01142 hostname[256] = '\0';
01143 return QString( "file://" ) + hostname + s.mid( 5 );
01144 }
01145 }
01146 #endif
01147 }
01148
01149 if (hasPass()) {
01150 KUrl safeUrl(*this);
01151 safeUrl.setPassword(QString());
01152 return safeUrl.url();
01153 }
01154 return url();
01155 }
01156
01157 KUrl KUrl::fromMimeDataByteArray( const QByteArray& str )
01158 {
01159 if ( str.startsWith( "file:" ) )
01160 return KUrl( str );
01161
01162 return KUrl( str );
01163 }
01164
01165 KUrl::List KUrl::split( const KUrl& _url )
01166 {
01167 QString ref;
01168 bool hasRef;
01169 KUrl::List lst;
01170 KUrl url = _url;
01171
01172 while(true)
01173 {
01174 KUrl u = url;
01175 u.setFragment( QString() );
01176 lst.append(u);
01177 if (url.hasSubUrl())
01178 {
01179 url = KUrl(url.fragment());
01180 }
01181 else
01182 {
01183 ref = url.fragment();
01184 hasRef = url.hasFragment();
01185 break;
01186 }
01187 }
01188
01189 if ( hasRef )
01190 {
01191
01192 KUrl::List::Iterator it;
01193 for( it = lst.begin() ; it != lst.end(); ++it )
01194 {
01195 (*it).setFragment( ref );
01196 }
01197 }
01198
01199 return lst;
01200 }
01201
01202 KUrl::List KUrl::split( const QString& _url )
01203 {
01204 return split(KUrl(_url));
01205 }
01206
01207 KUrl KUrl::join( const KUrl::List & lst )
01208 {
01209 if (lst.isEmpty()) return KUrl();
01210 KUrl tmp;
01211
01212 bool first = true;
01213 QListIterator<KUrl> it(lst);
01214 it.toBack();
01215 while (it.hasPrevious())
01216 {
01217 KUrl u(it.previous());
01218 if (!first) {
01219 u.setEncodedFragment(tmp.url().toLatin1() );
01220 }
01221 tmp = u;
01222
01223 first = false;
01224 }
01225
01226 return tmp;
01227 }
01228
01229 QString KUrl::fileName( const DirectoryOptions& options ) const
01230 {
01231 Q_ASSERT( options != 0 );
01232 QString fname;
01233 if (hasSubUrl()) {
01234 KUrl::List list = KUrl::split(*this);
01235 return list.last().fileName(options);
01236 }
01237 const QString path = this->path();
01238
01239 int len = path.length();
01240 if ( len == 0 )
01241 return fname;
01242
01243 if (!(options & ObeyTrailingSlash) )
01244 {
01245 while ( len >= 1 && path[ len - 1 ] == QLatin1Char('/') )
01246 len--;
01247 }
01248 else if ( path[ len - 1 ] == QLatin1Char('/') )
01249 return fname;
01250
01251
01252 if ( len == 1 && path[ 0 ] == QLatin1Char('/') )
01253 return fname;
01254
01255
01256 int n = 1;
01257 #if 0
01258 if (!m_strPath_encoded.isEmpty())
01259 {
01260
01261
01262
01263 int i = m_strPath_encoded.lastIndexOf( QLatin1Char('/'), len - 1 );
01264 QString fileName_encoded = m_strPath_encoded.mid(i+1);
01265 n += fileName_encoded.count("%2f", Qt::CaseInsensitive);
01266 }
01267 #endif
01268 int i = len;
01269 do {
01270 i = path.lastIndexOf( QLatin1Char('/'), i - 1 );
01271 }
01272 while (--n && (i > 0));
01273
01274
01275
01276 if ( i == -1 ) {
01277 if ( len == (int)path.length() )
01278 fname = path;
01279 else
01280
01281 fname = path.left( len );
01282 }
01283 else
01284 {
01285 fname = path.mid( i + 1, len - i - 1 );
01286 }
01287 return fname;
01288 }
01289
01290 void KUrl::addPath( const QString& _txt )
01291 {
01292 if (hasSubUrl())
01293 {
01294 KUrl::List lst = split( *this );
01295 KUrl &u = lst.last();
01296 u.addPath(_txt);
01297 *this = join( lst );
01298 return;
01299 }
01300
01301
01302
01303 if ( _txt.isEmpty() )
01304 return;
01305
01306 QString strPath = path();
01307 int i = 0;
01308 int len = strPath.length();
01309
01310 if ( _txt[0] != QLatin1Char('/') && ( len == 0 || strPath[ len - 1 ] != QLatin1Char('/') ) )
01311 strPath += QLatin1Char('/');
01312
01313
01314 i = 0;
01315 const int _txtlen = _txt.length();
01316 if ( strPath.endsWith( QLatin1Char('/') ) )
01317 {
01318 while ( ( i < _txtlen ) && ( _txt[i] == QLatin1Char('/') ) )
01319 ++i;
01320 }
01321
01322 setPath( strPath + _txt.mid( i ) );
01323
01324 }
01325
01326 QString KUrl::directory( const DirectoryOptions& options ) const
01327 {
01328 Q_ASSERT( options != 0 );
01329 QString result = path();
01330 if ( !(options & ObeyTrailingSlash) )
01331 result = trailingSlash( RemoveTrailingSlash, result );
01332
01333 if ( result.isEmpty() || result == QLatin1String ( "/" ) )
01334 return result;
01335
01336 int i = result.lastIndexOf( '/' );
01337
01338
01339 if ( i == -1 )
01340 return QString();
01341
01342 if ( i == 0 )
01343 {
01344 return QLatin1String( "/" );
01345 }
01346
01347 #ifdef Q_WS_WIN
01348 if ( i == 2 && result[1] == QLatin1Char(':') )
01349 {
01350 return result.left(3);
01351 }
01352 #endif
01353
01354 if ( options & AppendTrailingSlash )
01355 result = result.left( i + 1 );
01356 else
01357 result = result.left( i );
01358
01359
01360
01361
01362 return result;
01363 }
01364
01365
01366 bool KUrl::cd( const QString& _dir )
01367 {
01368 if ( _dir.isEmpty() || !isValid() )
01369 return false;
01370
01371 if (hasSubUrl())
01372 {
01373 KUrl::List lst = split( *this );
01374 KUrl &u = lst.last();
01375 u.cd(_dir);
01376 *this = join( lst );
01377 return true;
01378 }
01379
01380
01381 #ifdef Q_OS_WIN
01382 if ( !QFileInfo(_dir).isRelative() )
01383 #else
01384 if ( _dir[0] == QLatin1Char('/') )
01385 #endif
01386 {
01387
01388 setPath( _dir );
01389 setHTMLRef( QString() );
01390 setEncodedQuery( QByteArray() );
01391 return true;
01392 }
01393
01394
01395 if ( ( _dir[0] == '~' ) && ( scheme() == QLatin1String ( "file" ) ))
01396 {
01397
01398 QString strPath = QDir::homePath();
01399 strPath += QLatin1Char('/');
01400 strPath += _dir.right( strPath.length() - 1 );
01401 setPath( strPath );
01402 setHTMLRef( QString() );
01403 setEncodedQuery( QByteArray() );
01404 return true;
01405 }
01406
01407
01408
01409
01410
01411
01412 QString p = path(AddTrailingSlash);
01413 p += _dir;
01414 p = cleanpath( p, true, false );
01415 setPath( p );
01416
01417 setHTMLRef( QString() );
01418 setEncodedQuery( QByteArray() );
01419
01420 return true;
01421 }
01422
01423 KUrl KUrl::upUrl( ) const
01424 {
01425 if (!isValid() || isRelative())
01426 return KUrl();
01427
01428 if (!encodedQuery().isEmpty())
01429 {
01430 KUrl u(*this);
01431 u.setEncodedQuery(QByteArray());
01432 return u;
01433 }
01434
01435 if (!hasSubUrl())
01436 {
01437 KUrl u(*this);
01438
01439 u.cd("../");
01440
01441 return u;
01442 }
01443
01444
01445 KUrl::List lst = split( *this );
01446 if (lst.isEmpty())
01447 return KUrl();
01448 while (true)
01449 {
01450 KUrl &u = lst.last();
01451 const QString old = u.path();
01452 u.cd("../");
01453 if (u.path() != old)
01454 break;
01455 if (lst.count() == 1)
01456 break;
01457 lst.removeLast();
01458 }
01459 return join( lst );
01460 }
01461
01462 QString KUrl::htmlRef() const
01463 {
01464 if ( !hasSubUrl() )
01465 {
01466 return QUrl::fromPercentEncoding( ref().toLatin1() );
01467 }
01468
01469 List lst = split( *this );
01470 return QUrl::fromPercentEncoding( (*lst.begin()).ref().toLatin1() );
01471 }
01472
01473 QString KUrl::encodedHtmlRef() const
01474 {
01475 if ( !hasSubUrl() )
01476 {
01477 return ref();
01478 }
01479
01480 List lst = split( *this );
01481 return (*lst.begin()).ref();
01482 }
01483
01484 void KUrl::setHTMLRef( const QString& _ref )
01485 {
01486 if ( !hasSubUrl() )
01487 {
01488 setFragment( _ref );
01489 return;
01490 }
01491
01492 List lst = split( *this );
01493
01494 (*lst.begin()).setFragment( _ref );
01495
01496 *this = join( lst );
01497 }
01498
01499 bool KUrl::hasHTMLRef() const
01500 {
01501 if ( !hasSubUrl() )
01502 {
01503 return hasRef();
01504 }
01505
01506 List lst = split( *this );
01507 return (*lst.begin()).hasRef();
01508 }
01509
01510 void KUrl::setDirectory( const QString &dir)
01511 {
01512 if ( dir.endsWith(QLatin1Char('/')))
01513 setPath(dir);
01514 else
01515 setPath(dir + QLatin1Char('/'));
01516 }
01517
01518 void KUrl::setQuery( const QString &_txt )
01519 {
01520 if (!_txt.isEmpty() && _txt[0] == '?')
01521 _setQuery( _txt.length() > 1 ? _txt.mid(1) : "" );
01522 else
01523 _setQuery( _txt );
01524 }
01525
01526 void KUrl::_setQuery( const QString& query )
01527 {
01528 if ( query.isNull() ) {
01529 setEncodedQuery( QByteArray() );
01530 } else if ( query.isEmpty() ) {
01531 setEncodedQuery( "" );
01532 } else {
01533 setEncodedQuery( query.toLatin1() );
01534 }
01535 }
01536
01537 QString KUrl::query() const
01538 {
01539 if (!hasQuery()) {
01540 return QString();
01541 }
01542 return QString( QChar( '?' ) ) + QString::fromAscii( encodedQuery() );
01543 }
01544
01545 void KUrl::_setEncodedUrl(const QByteArray& url)
01546 {
01547 setEncodedUrl(url, QUrl::TolerantMode);
01548 if (!isValid())
01549 setUrl(url, QUrl::TolerantMode);
01550 }
01551
01552 bool urlcmp( const QString& _url1, const QString& _url2 )
01553 {
01554 return QUrl( _url1, QUrl::TolerantMode ) == QUrl( _url2, QUrl::TolerantMode );
01555 #if 0
01556
01557 if ( _url1.isEmpty() && _url2.isEmpty() )
01558 return true;
01559
01560 if ( _url1.isEmpty() || _url2.isEmpty() )
01561 return false;
01562
01563 KUrl::List list1 = KUrl::split( _url1 );
01564 KUrl::List list2 = KUrl::split( _url2 );
01565
01566
01567 if ( list1.isEmpty() || list2.isEmpty() )
01568 return false;
01569
01570 return ( list1 == list2 );
01571 #endif
01572 }
01573
01574 bool urlcmp( const QString& _url1, const QString& _url2, const KUrl::EqualsOptions& _options )
01575 {
01576 QUrl u1( _url1 );
01577 QUrl u2( _url2 );
01578 QUrl::FormattingOptions options = QUrl::None;
01579 if ( _options & KUrl::CompareWithoutTrailingSlash )
01580 options |= QUrl::StripTrailingSlash;
01581 if ( _options & KUrl::CompareWithoutFragment )
01582 options |= QUrl::RemoveFragment;
01583 #ifdef Q_WS_WIN
01584 if ( ::isLocalFile( u1 ) && ::isLocalFile( u2 ) )
01585 return 0 == QString::compare( u1.toString( options ), u2.toString( options ), Qt::CaseInsensitive );
01586 #endif
01587 return u1.toString( options ) == u2.toString( options );
01588
01589 #if 0
01590
01591 if ( _url1.isEmpty() && _url2.isEmpty() )
01592 return true;
01593
01594 if ( _url1.isEmpty() || _url2.isEmpty() )
01595 return false;
01596
01597 KUrl::List list1 = KUrl::split( _url1 );
01598 KUrl::List list2 = KUrl::split( _url2 );
01599
01600
01601 if ( list1.isEmpty() || list2.isEmpty() )
01602 return false;
01603
01604 int size = list1.count();
01605 if ( list2.count() != size )
01606 return false;
01607
01608 if ( _ignore_ref )
01609 {
01610 (*list1.begin()).setRef(QString());
01611 (*list2.begin()).setRef(QString());
01612 }
01613
01614 KUrl::List::Iterator it1 = list1.begin();
01615 KUrl::List::Iterator it2 = list2.begin();
01616 for( ; it1 != list1.end() ; ++it1, ++it2 )
01617 if ( !(*it1).equals( *it2, _ignore_trailing ) )
01618 return false;
01619 return true;
01620 #endif
01621 }
01622
01623
01624 KUrl KUrl::fromPathOrUrl( const QString& text )
01625 {
01626 KUrl url;
01627 if ( !text.isEmpty() )
01628 {
01629 if (!QDir::isRelativePath(text) || text[0] == '~')
01630 url.setPath( text );
01631 else
01632 url = KUrl( text );
01633 }
01634
01635 return url;
01636 }
01637
01638 static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent)
01639 {
01640 QString _base_dir(QDir::cleanPath(base_dir));
01641 QString _path(QDir::cleanPath(path.isEmpty() || (path[0] != QLatin1Char('/')) ? _base_dir+'/'+path : path));
01642
01643 if (_base_dir.isEmpty())
01644 return _path;
01645
01646 if (_base_dir[_base_dir.length()-1] != QLatin1Char('/'))
01647 _base_dir.append(QLatin1Char('/') );
01648
01649 const QStringList list1 = _base_dir.split(QLatin1Char('/'), QString::SkipEmptyParts);
01650 const QStringList list2 = _path.split(QLatin1Char('/'), QString::SkipEmptyParts);
01651
01652
01653 int level = 0;
01654 int maxLevel = qMin(list1.count(), list2.count());
01655 while((level < maxLevel) && (list1[level] == list2[level])) level++;
01656
01657 QString result;
01658
01659 for(int i = level; i < list1.count(); i++)
01660 result.append("../");
01661
01662
01663 for(int i = level; i < list2.count(); i++)
01664 result.append(list2[i]).append("/");
01665
01666 if ((level < list2.count()) && (path[path.length()-1] != QLatin1Char('/')))
01667 result.truncate(result.length()-1);
01668
01669 isParent = (level == list1.count());
01670
01671 return result;
01672 }
01673
01674 QString KUrl::relativePath(const QString &base_dir, const QString &path, bool *isParent)
01675 {
01676 bool parent = false;
01677 QString result = _relativePath(base_dir, path, parent);
01678 if (parent)
01679 result.prepend("./");
01680
01681 if (isParent)
01682 *isParent = parent;
01683
01684 return result;
01685 }
01686
01687
01688 QString KUrl::relativeUrl(const KUrl &base_url, const KUrl &url)
01689 {
01690 if ((url.protocol() != base_url.protocol()) ||
01691 (url.host() != base_url.host()) ||
01692 (url.port() && url.port() != base_url.port()) ||
01693 (url.hasUser() && url.user() != base_url.user()) ||
01694 (url.hasPass() && url.pass() != base_url.pass()))
01695 {
01696 return url.url();
01697 }
01698
01699 QString relURL;
01700
01701 if ((base_url.path() != url.path()) || (base_url.query() != url.query()))
01702 {
01703 bool dummy;
01704 QString basePath = base_url.directory(KUrl::ObeyTrailingSlash);
01705 relURL = _relativePath(basePath, url.path(), dummy);
01706 relURL += url.query();
01707 }
01708
01709 if ( url.hasRef() )
01710 {
01711 relURL += '#';
01712 relURL += url.ref();
01713 }
01714
01715 if ( relURL.isEmpty() )
01716 return "./";
01717
01718 return relURL;
01719 }
01720
01721 void KUrl::setPath( const QString& _path )
01722 {
01723 #if defined(Q_WS_WIN) && defined(DEBUG_KURL)
01724 kDebug(kurlDebugArea()) << "KUrl::setPath " << " " << _path.toAscii().data();
01725 #endif
01726 if ( scheme().isEmpty() )
01727 setScheme( QLatin1String( "file" ) );
01728 QString path = KShell::tildeExpand( _path );
01729 #ifdef Q_WS_WIN
01730 const int len = path.length();
01731 if( len == 2 && IS_LETTER(path[0]) && path[1] == QLatin1Char(':') )
01732 path += QLatin1Char('/');
01733
01734
01735
01736 else
01737 if( len > 0 && path[0] != QLatin1Char('/') && scheme() == QLatin1String( "file" ) )
01738 path = QLatin1Char('/') + path;
01739 #endif
01740 QUrl::setPath( path );
01741 }
01742
01743 #if 0 // this would be if we didn't decode '+' into ' '
01744 QMap< QString, QString > KUrl::queryItems( int options ) const {
01745 QMap< QString, QString > result;
01746 const QList<QPair<QString, QString> > items = QUrl::queryItems();
01747 QPair<QString, QString> item;
01748 Q_FOREACH( item, items ) {
01749 result.insert( options & CaseInsensitiveKeys ? item.first.toLower() : item.first, item.second );
01750 }
01751 return result;
01752 }
01753 #endif
01754
01755 QMap< QString, QString > KUrl::queryItems( const QueryItemsOptions &options ) const {
01756 const QString strQueryEncoded = encodedQuery();
01757 if ( strQueryEncoded.isEmpty() )
01758 return QMap<QString,QString>();
01759
01760 QMap< QString, QString > result;
01761 const QStringList items = strQueryEncoded.split( '&', QString::SkipEmptyParts );
01762 for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
01763 const int equal_pos = (*it).indexOf( '=' );
01764 if ( equal_pos > 0 ) {
01765 QString name = (*it).left( equal_pos );
01766 if ( options & CaseInsensitiveKeys )
01767 name = name.toLower();
01768 QString value = (*it).mid( equal_pos + 1 );
01769 if ( value.isEmpty() )
01770 result.insert( name, QString::fromLatin1("") );
01771 else {
01772
01773 value.replace( '+', ' ' );
01774 result.insert( name, QUrl::fromPercentEncoding( value.toLatin1() ) );
01775 }
01776 } else if ( equal_pos < 0 ) {
01777 QString name = (*it);
01778 if ( options & CaseInsensitiveKeys )
01779 name = name.toLower();
01780 result.insert( name, QString() );
01781 }
01782 }
01783
01784 return result;
01785 }
01786
01787 QString KUrl::queryItem( const QString& _item ) const
01788 {
01789 const QString strQueryEncoded = encodedQuery();
01790 const QString item = _item + '=';
01791 if ( strQueryEncoded.length() <= 1 )
01792 return QString();
01793
01794 const QStringList items = strQueryEncoded.split( '&', QString::SkipEmptyParts );
01795 const int _len = item.length();
01796 for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it )
01797 {
01798 if ( (*it).startsWith( item ) )
01799 {
01800 if ( (*it).length() > _len )
01801 {
01802 QString str = (*it).mid( _len );
01803 str.replace( '+', ' ' );
01804 return QUrl::fromPercentEncoding( str.toLatin1() );
01805 }
01806 else
01807 return QString::fromLatin1("");
01808 }
01809 }
01810
01811 return QString();
01812 }
01813
01814 void KUrl::addQueryItem( const QString& _item, const QString& _value )
01815 {
01816 QString item = _item + '=';
01817 QString value = QUrl::toPercentEncoding( _value );
01818
01819 QString strQueryEncoded = encodedQuery();
01820 if (!strQueryEncoded.isEmpty())
01821 strQueryEncoded += '&';
01822 strQueryEncoded += item + value;
01823 setEncodedQuery( strQueryEncoded.toLatin1() );
01824 }
01825
01826 void KUrl::populateMimeData( QMimeData* mimeData,
01827 const MetaDataMap& metaData,
01828 MimeDataFlags flags ) const
01829 {
01830 KUrl::List lst( *this );
01831 lst.populateMimeData( mimeData, metaData, flags );
01832 }
01833
01834 bool KUrl::hasRef() const
01835 {
01836 return hasFragment();
01837 }
01838
01839 void KUrl::setRef( const QString& fragment )
01840 {
01841 if ( fragment.isNull() )
01842 setFragment( fragment );
01843 else
01844 setFragment( QUrl::fromPercentEncoding( fragment.toLatin1() ) );
01845 }
01846
01847 QString KUrl::ref() const
01848 {
01849 if ( fragment().isNull() )
01850 return QString();
01851 else
01852 return QString::fromLatin1( QUrl::toPercentEncoding( fragment() ) );
01853 }
01854
01855 bool KUrl::isParentOf( const KUrl& u ) const
01856 {
01857 return QUrl::isParentOf( u ) || equals( u, CompareWithoutTrailingSlash );
01858 }
01859
01860 uint qHash(const KUrl& kurl)
01861 {
01862
01863
01864
01865 return qHash(kurl.protocol()) ^ qHash(kurl.path()) ^ qHash(kurl.fragment()) ^ qHash(kurl.query());
01866 }