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