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 return trailingSlash( trailing, QUrl::path() );
00843 }
00844
00845 QString KUrl::toLocalFile( AdjustPathOption trailing ) const
00846 {
00847 return trailingSlash( trailing, QUrl::toLocalFile() );
00848 }
00849
00850 inline static bool hasSubUrl( const QUrl& url );
00851
00852 static inline bool isLocalFile( const QUrl& url )
00853 {
00854 if ( ( url.scheme() != QLatin1String("file") ) || hasSubUrl( url ) )
00855 return false;
00856
00857 if (url.host().isEmpty() || (url.host() == QLatin1String("localhost")))
00858 return true;
00859
00860 char hostname[ 256 ];
00861 hostname[ 0 ] = '\0';
00862 if (!gethostname( hostname, 255 ))
00863 hostname[sizeof(hostname)-1] = '\0';
00864
00865 for(char *p = hostname; *p; p++)
00866 *p = tolower(*p);
00867
00868 return (url.host() == QString::fromLatin1( hostname ));
00869 }
00870
00871 bool KUrl::isLocalFile() const
00872 {
00873 return ::isLocalFile( *this );
00874 }
00875
00876 void KUrl::setFileEncoding(const QString &encoding)
00877 {
00878 if (!isLocalFile())
00879 return;
00880
00881 QString q = query();
00882
00883 if (!q.isEmpty() && (q[0] == '?'))
00884 q = q.mid(1);
00885
00886 QStringList args = q.split('&', QString::SkipEmptyParts);
00887 for(QStringList::Iterator it = args.begin();
00888 it != args.end();)
00889 {
00890 QString s = QUrl::fromPercentEncoding( (*it).toLatin1() );
00891 if (s.startsWith("charset="))
00892 it = args.erase(it);
00893 else
00894 ++it;
00895 }
00896 if (!encoding.isEmpty())
00897 args.append("charset=" + QUrl::toPercentEncoding(encoding));
00898
00899 if (args.isEmpty())
00900 _setQuery(QString());
00901 else
00902 _setQuery(args.join("&"));
00903 }
00904
00905 QString KUrl::fileEncoding() const
00906 {
00907 if (!isLocalFile())
00908 return QString();
00909
00910 QString q = query();
00911
00912 if (q.isEmpty())
00913 return QString();
00914
00915 if (q[0] == '?')
00916 q = q.mid(1);
00917
00918 const QStringList args = q.split('&', QString::SkipEmptyParts);
00919 for(QStringList::ConstIterator it = args.begin();
00920 it != args.end();
00921 ++it)
00922 {
00923 QString s = QUrl::fromPercentEncoding((*it).toLatin1());
00924 if (s.startsWith("charset="))
00925 return s.mid(8);
00926 }
00927 return QString();
00928 }
00929
00930 inline static bool hasSubUrl( const QUrl& url )
00931 {
00932
00933
00934 if ( url.scheme().isEmpty() )
00935 return false;
00936 const QByteArray ref( url.fragment().toLatin1() );
00937 if (ref.isEmpty())
00938 return false;
00939 switch ( ref.data()[0] ) {
00940 case 'g':
00941 if ( ref.startsWith("gzip:") )
00942 return true;
00943 break;
00944 case 'b':
00945 if ( ref.startsWith("bzip:") || ref.startsWith("bzip2:") )
00946 return true;
00947 break;
00948 case 'l':
00949 if ( ref.startsWith("lzma:") )
00950 return true;
00951 break;
00952 case 'x':
00953 if ( ref.startsWith("xz:") )
00954 return true;
00955 break;
00956 case 't':
00957 if ( ref.startsWith("tar:") )
00958 return true;
00959 break;
00960 case 'a':
00961 if ( ref.startsWith("ar:") )
00962 return true;
00963 break;
00964 case 'z':
00965 if ( ref.startsWith("zip:") )
00966 return true;
00967 break;
00968 default:
00969 break;
00970 }
00971 if ( url.scheme() == "error" )
00972 return true;
00973 return false;
00974 }
00975
00976 bool KUrl::hasSubUrl() const
00977 {
00978 return ::hasSubUrl( *this );
00979 }
00980
00981 QString KUrl::url( AdjustPathOption trailing ) const
00982 {
00983 if (QString::compare(scheme(), QLatin1String("mailto"), Qt::CaseInsensitive) == 0) {
00984
00985 return prettyUrl(trailing);
00986 }
00987 if ( trailing == AddTrailingSlash && !path().endsWith( QLatin1Char('/') ) ) {
00988
00989
00990
00991 QUrl newUrl( *this );
00992 newUrl.setPath( path() + QLatin1Char('/') );
00993 return QString::fromLatin1(newUrl.toEncoded());
00994 }
00995 else if ( trailing == RemoveTrailingSlash && path() == "/" ) {
00996 return QLatin1String(toEncoded(None));
00997 }
00998 return QString::fromLatin1(toEncoded(trailing == RemoveTrailingSlash ? StripTrailingSlash : None));
00999 }
01000
01001 static QString toPrettyPercentEncoding(const QString &input, bool forFragment)
01002 {
01003 QString result;
01004 for (int i = 0; i < input.length(); ++i) {
01005 QChar c = input.at(i);
01006 register ushort u = c.unicode();
01007 if (u < 0x20
01008 || (!forFragment && u == '?')
01009 || u == '#' || u == '%'
01010 || (u == ' ' && (i+1 == input.length() || input.at(i+1) == ' '))) {
01011 static const char hexdigits[] = "0123456789ABCDEF";
01012 result += QLatin1Char('%');
01013 result += QLatin1Char(hexdigits[(u & 0xf0) >> 4]);
01014 result += QLatin1Char(hexdigits[u & 0xf]);
01015 } else {
01016 result += c;
01017 }
01018 }
01019
01020 return result;
01021 }
01022
01023 QString KUrl::prettyUrl( AdjustPathOption trailing ) const
01024 {
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034 QString result = scheme();
01035 if (!result.isEmpty())
01036 {
01037 if(!authority().isEmpty() || result == QLatin1String("file"))
01038 result += QLatin1String("://");
01039 else
01040 result += QLatin1String(":");
01041 }
01042
01043 QString tmp = userName();
01044 if (!tmp.isEmpty()) {
01045 result += QUrl::toPercentEncoding(tmp);
01046 result += QLatin1Char('@');
01047 }
01048
01049
01050 tmp = host();
01051 if (tmp.contains(':'))
01052 result += QLatin1Char('[') + tmp + QLatin1Char(']');
01053 else
01054 result += tmp;
01055
01056 if (port() != -1) {
01057 result += QLatin1Char(':');
01058 result += QString::number(port());
01059 }
01060
01061 tmp = path();
01062 result += toPrettyPercentEncoding(tmp, false);
01063
01064
01065 if (trailing == AddTrailingSlash && !tmp.endsWith(QLatin1Char('/')))
01066 result += QLatin1Char('/');
01067 else if (trailing == RemoveTrailingSlash && tmp.length() > 1 && tmp.endsWith(QLatin1Char('/')))
01068 result.chop(1);
01069
01070 if (hasQuery()) {
01071 result += QLatin1Char('?');
01072 result += QUrl::fromPercentEncoding(encodedQuery());
01073 }
01074
01075 if (hasFragment()) {
01076 result += QLatin1Char('#');
01077 result += toPrettyPercentEncoding(fragment(), true);
01078 }
01079
01080 return result;
01081 }
01082
01083 #if 0
01084 QString KUrl::prettyUrl( int _trailing, AdjustementFlags _flags) const
01085 {
01086 QString u = prettyUrl(_trailing);
01087 if (_flags & StripFileProtocol && u.startsWith("file://")) {
01088 u.remove(0, 7);
01089 #ifdef Q_WS_WIN
01090 return QDir::convertSeparators(u);
01091 #endif
01092 }
01093 return u;
01094 }
01095 #endif
01096
01097 QString KUrl::pathOrUrl() const
01098 {
01099 return pathOrUrl(LeaveTrailingSlash);
01100 }
01101
01102 QString KUrl::pathOrUrl(AdjustPathOption trailing) const
01103 {
01104 if ( isLocalFile() && fragment().isNull() && encodedQuery().isNull() ) {
01105 return toLocalFile(trailing);
01106 } else {
01107 return prettyUrl(trailing);
01108 }
01109 }
01110
01111
01112 QString KUrl::toMimeDataString() const
01113 {
01114 if ( isLocalFile() )
01115 {
01116 #if 1
01117 return url();
01118 #else
01119
01120
01121
01122 const QString s = url( 0, KGlobal::locale()->fileEncodingMib() );
01123 if( !s.startsWith( QLatin1String ( "file://" ) ))
01124 {
01125 char hostname[257];
01126 if ( gethostname( hostname, 255 ) == 0 )
01127 {
01128 hostname[256] = '\0';
01129 return QString( "file://" ) + hostname + s.mid( 5 );
01130 }
01131 }
01132 #endif
01133 }
01134
01135 if (hasPass()) {
01136 KUrl safeUrl(*this);
01137 safeUrl.setPassword(QString());
01138 return safeUrl.url();
01139 }
01140 return url();
01141 }
01142
01143 KUrl KUrl::fromMimeDataByteArray( const QByteArray& str )
01144 {
01145 if ( str.startsWith( "file:" ) )
01146 return KUrl( str );
01147
01148 return KUrl( str );
01149 }
01150
01151 KUrl::List KUrl::split( const KUrl& _url )
01152 {
01153 QString ref;
01154 bool hasRef;
01155 KUrl::List lst;
01156 KUrl url = _url;
01157
01158 while(true)
01159 {
01160 KUrl u = url;
01161 u.setFragment( QString() );
01162 lst.append(u);
01163 if (url.hasSubUrl())
01164 {
01165 url = KUrl(url.fragment());
01166 }
01167 else
01168 {
01169 ref = url.fragment();
01170 hasRef = url.hasFragment();
01171 break;
01172 }
01173 }
01174
01175 if ( hasRef )
01176 {
01177
01178 KUrl::List::Iterator it;
01179 for( it = lst.begin() ; it != lst.end(); ++it )
01180 {
01181 (*it).setFragment( ref );
01182 }
01183 }
01184
01185 return lst;
01186 }
01187
01188 KUrl::List KUrl::split( const QString& _url )
01189 {
01190 return split(KUrl(_url));
01191 }
01192
01193 KUrl KUrl::join( const KUrl::List & lst )
01194 {
01195 if (lst.isEmpty()) return KUrl();
01196 KUrl tmp;
01197
01198 bool first = true;
01199 QListIterator<KUrl> it(lst);
01200 it.toBack();
01201 while (it.hasPrevious())
01202 {
01203 KUrl u(it.previous());
01204 if (!first) {
01205 u.setEncodedFragment(tmp.url().toLatin1() );
01206 }
01207 tmp = u;
01208
01209 first = false;
01210 }
01211
01212 return tmp;
01213 }
01214
01215 QString KUrl::fileName( const DirectoryOptions& options ) const
01216 {
01217 Q_ASSERT( options != 0 );
01218 QString fname;
01219 if (hasSubUrl()) {
01220 KUrl::List list = KUrl::split(*this);
01221 return list.last().fileName(options);
01222 }
01223 const QString path = this->path();
01224
01225 int len = path.length();
01226 if ( len == 0 )
01227 return fname;
01228
01229 if (!(options & ObeyTrailingSlash) )
01230 {
01231 while ( len >= 1 && path[ len - 1 ] == QLatin1Char('/') )
01232 len--;
01233 }
01234 else if ( path[ len - 1 ] == QLatin1Char('/') )
01235 return fname;
01236
01237
01238 if ( len == 1 && path[ 0 ] == QLatin1Char('/') )
01239 return fname;
01240
01241
01242 int n = 1;
01243 #if 0
01244 if (!m_strPath_encoded.isEmpty())
01245 {
01246
01247
01248
01249 int i = m_strPath_encoded.lastIndexOf( QLatin1Char('/'), len - 1 );
01250 QString fileName_encoded = m_strPath_encoded.mid(i+1);
01251 n += fileName_encoded.count("%2f", Qt::CaseInsensitive);
01252 }
01253 #endif
01254 int i = len;
01255 do {
01256 i = path.lastIndexOf( QLatin1Char('/'), i - 1 );
01257 }
01258 while (--n && (i > 0));
01259
01260
01261
01262 if ( i == -1 ) {
01263 if ( len == (int)path.length() )
01264 fname = path;
01265 else
01266
01267 fname = path.left( len );
01268 }
01269 else
01270 {
01271 fname = path.mid( i + 1, len - i - 1 );
01272 }
01273 return fname;
01274 }
01275
01276 void KUrl::addPath( const QString& _txt )
01277 {
01278 if (hasSubUrl())
01279 {
01280 KUrl::List lst = split( *this );
01281 KUrl &u = lst.last();
01282 u.addPath(_txt);
01283 *this = join( lst );
01284 return;
01285 }
01286
01287
01288
01289 if ( _txt.isEmpty() )
01290 return;
01291
01292 QString strPath = path();
01293 int i = 0;
01294 int len = strPath.length();
01295
01296 if ( _txt[0] != QLatin1Char('/') && ( len == 0 || strPath[ len - 1 ] != QLatin1Char('/') ) )
01297 strPath += QLatin1Char('/');
01298
01299
01300 i = 0;
01301 const int _txtlen = _txt.length();
01302 if ( strPath.endsWith( QLatin1Char('/') ) )
01303 {
01304 while ( ( i < _txtlen ) && ( _txt[i] == QLatin1Char('/') ) )
01305 ++i;
01306 }
01307
01308 setPath( strPath + _txt.mid( i ) );
01309
01310 }
01311
01312 QString KUrl::directory( const DirectoryOptions& options ) const
01313 {
01314 Q_ASSERT( options != 0 );
01315 QString result = path();
01316 if ( !(options & ObeyTrailingSlash) )
01317 result = trailingSlash( RemoveTrailingSlash, result );
01318
01319 if ( result.isEmpty() || result == QLatin1String ( "/" ) )
01320 return result;
01321
01322 int i = result.lastIndexOf( '/' );
01323
01324
01325 if ( i == -1 )
01326 return QString();
01327
01328 if ( i == 0 )
01329 {
01330 return QLatin1String( "/" );
01331 }
01332
01333 #ifdef Q_WS_WIN
01334 if ( i == 2 && result[1] == QLatin1Char(':') )
01335 {
01336 return result.left(3);
01337 }
01338 #endif
01339
01340 if ( options & AppendTrailingSlash )
01341 result = result.left( i + 1 );
01342 else
01343 result = result.left( i );
01344
01345
01346
01347
01348 return result;
01349 }
01350
01351
01352 bool KUrl::cd( const QString& _dir )
01353 {
01354 if ( _dir.isEmpty() || !isValid() )
01355 return false;
01356
01357 if (hasSubUrl())
01358 {
01359 KUrl::List lst = split( *this );
01360 KUrl &u = lst.last();
01361 u.cd(_dir);
01362 *this = join( lst );
01363 return true;
01364 }
01365
01366
01367 #ifdef Q_OS_WIN
01368 if ( !QFileInfo(_dir).isRelative() )
01369 #else
01370 if ( _dir[0] == QLatin1Char('/') )
01371 #endif
01372 {
01373
01374 setPath( _dir );
01375 setHTMLRef( QString() );
01376 setEncodedQuery( QByteArray() );
01377 return true;
01378 }
01379
01380
01381 if ( ( _dir[0] == '~' ) && ( scheme() == QLatin1String ( "file" ) ))
01382 {
01383
01384 QString strPath = QDir::homePath();
01385 strPath += QLatin1Char('/');
01386 strPath += _dir.right( strPath.length() - 1 );
01387 setPath( strPath );
01388 setHTMLRef( QString() );
01389 setEncodedQuery( QByteArray() );
01390 return true;
01391 }
01392
01393
01394
01395
01396
01397
01398 QString p = path(AddTrailingSlash);
01399 p += _dir;
01400 p = cleanpath( p, true, false );
01401 setPath( p );
01402
01403 setHTMLRef( QString() );
01404 setEncodedQuery( QByteArray() );
01405
01406 return true;
01407 }
01408
01409 KUrl KUrl::upUrl( ) const
01410 {
01411 if (!isValid() || isRelative())
01412 return KUrl();
01413
01414 if (!encodedQuery().isEmpty())
01415 {
01416 KUrl u(*this);
01417 u.setEncodedQuery(QByteArray());
01418 return u;
01419 }
01420
01421 if (!hasSubUrl())
01422 {
01423 KUrl u(*this);
01424
01425 u.cd("../");
01426
01427 return u;
01428 }
01429
01430
01431 KUrl::List lst = split( *this );
01432 if (lst.isEmpty())
01433 return KUrl();
01434 while (true)
01435 {
01436 KUrl &u = lst.last();
01437 const QString old = u.path();
01438 u.cd("../");
01439 if (u.path() != old)
01440 break;
01441 if (lst.count() == 1)
01442 break;
01443 lst.removeLast();
01444 }
01445 return join( lst );
01446 }
01447
01448 QString KUrl::htmlRef() const
01449 {
01450 if ( !hasSubUrl() )
01451 {
01452 return QUrl::fromPercentEncoding( ref().toLatin1() );
01453 }
01454
01455 List lst = split( *this );
01456 return QUrl::fromPercentEncoding( (*lst.begin()).ref().toLatin1() );
01457 }
01458
01459 QString KUrl::encodedHtmlRef() const
01460 {
01461 if ( !hasSubUrl() )
01462 {
01463 return ref();
01464 }
01465
01466 List lst = split( *this );
01467 return (*lst.begin()).ref();
01468 }
01469
01470 void KUrl::setHTMLRef( const QString& _ref )
01471 {
01472 if ( !hasSubUrl() )
01473 {
01474 setFragment( _ref );
01475 return;
01476 }
01477
01478 List lst = split( *this );
01479
01480 (*lst.begin()).setFragment( _ref );
01481
01482 *this = join( lst );
01483 }
01484
01485 bool KUrl::hasHTMLRef() const
01486 {
01487 if ( !hasSubUrl() )
01488 {
01489 return hasRef();
01490 }
01491
01492 List lst = split( *this );
01493 return (*lst.begin()).hasRef();
01494 }
01495
01496 void KUrl::setDirectory( const QString &dir)
01497 {
01498 if ( dir.endsWith(QLatin1Char('/')))
01499 setPath(dir);
01500 else
01501 setPath(dir + QLatin1Char('/'));
01502 }
01503
01504 void KUrl::setQuery( const QString &_txt )
01505 {
01506 if (!_txt.isEmpty() && _txt[0] == '?')
01507 _setQuery( _txt.length() > 1 ? _txt.mid(1) : "" );
01508 else
01509 _setQuery( _txt );
01510 }
01511
01512 void KUrl::_setQuery( const QString& query )
01513 {
01514 if ( query.isNull() ) {
01515 setEncodedQuery( QByteArray() );
01516 } else if ( query.isEmpty() ) {
01517 setEncodedQuery( "" );
01518 } else {
01519 setEncodedQuery( query.toLatin1() );
01520 }
01521 }
01522
01523 QString KUrl::query() const
01524 {
01525 if (!hasQuery()) {
01526 return QString();
01527 }
01528 return QString( QChar( '?' ) ) + QString::fromAscii( encodedQuery() );
01529 }
01530
01531 void KUrl::_setEncodedUrl(const QByteArray& url)
01532 {
01533 setEncodedUrl(url, QUrl::TolerantMode);
01534 if (!isValid())
01535 setUrl(url, QUrl::TolerantMode);
01536 }
01537
01538 bool urlcmp( const QString& _url1, const QString& _url2 )
01539 {
01540 return QUrl( _url1, QUrl::TolerantMode ) == QUrl( _url2, QUrl::TolerantMode );
01541 #if 0
01542
01543 if ( _url1.isEmpty() && _url2.isEmpty() )
01544 return true;
01545
01546 if ( _url1.isEmpty() || _url2.isEmpty() )
01547 return false;
01548
01549 KUrl::List list1 = KUrl::split( _url1 );
01550 KUrl::List list2 = KUrl::split( _url2 );
01551
01552
01553 if ( list1.isEmpty() || list2.isEmpty() )
01554 return false;
01555
01556 return ( list1 == list2 );
01557 #endif
01558 }
01559
01560 bool urlcmp( const QString& _url1, const QString& _url2, const KUrl::EqualsOptions& _options )
01561 {
01562 QUrl u1( _url1 );
01563 QUrl u2( _url2 );
01564 QUrl::FormattingOptions options = QUrl::None;
01565 if ( _options & KUrl::CompareWithoutTrailingSlash )
01566 options |= QUrl::StripTrailingSlash;
01567 if ( _options & KUrl::CompareWithoutFragment )
01568 options |= QUrl::RemoveFragment;
01569 #ifdef Q_WS_WIN
01570 if ( ::isLocalFile( u1 ) && ::isLocalFile( u2 ) )
01571 return 0 == QString::compare( u1.toString( options ), u2.toString( options ), Qt::CaseInsensitive );
01572 #endif
01573 return u1.toString( options ) == u2.toString( options );
01574
01575 #if 0
01576
01577 if ( _url1.isEmpty() && _url2.isEmpty() )
01578 return true;
01579
01580 if ( _url1.isEmpty() || _url2.isEmpty() )
01581 return false;
01582
01583 KUrl::List list1 = KUrl::split( _url1 );
01584 KUrl::List list2 = KUrl::split( _url2 );
01585
01586
01587 if ( list1.isEmpty() || list2.isEmpty() )
01588 return false;
01589
01590 int size = list1.count();
01591 if ( list2.count() != size )
01592 return false;
01593
01594 if ( _ignore_ref )
01595 {
01596 (*list1.begin()).setRef(QString());
01597 (*list2.begin()).setRef(QString());
01598 }
01599
01600 KUrl::List::Iterator it1 = list1.begin();
01601 KUrl::List::Iterator it2 = list2.begin();
01602 for( ; it1 != list1.end() ; ++it1, ++it2 )
01603 if ( !(*it1).equals( *it2, _ignore_trailing ) )
01604 return false;
01605 return true;
01606 #endif
01607 }
01608
01609
01610 KUrl KUrl::fromPathOrUrl( const QString& text )
01611 {
01612 KUrl url;
01613 if ( !text.isEmpty() )
01614 {
01615 if (!QDir::isRelativePath(text) || text[0] == '~')
01616 url.setPath( text );
01617 else
01618 url = KUrl( text );
01619 }
01620
01621 return url;
01622 }
01623
01624 static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent)
01625 {
01626 QString _base_dir(QDir::cleanPath(base_dir));
01627 QString _path(QDir::cleanPath(path.isEmpty() || (path[0] != QLatin1Char('/')) ? _base_dir+'/'+path : path));
01628
01629 if (_base_dir.isEmpty())
01630 return _path;
01631
01632 if (_base_dir[_base_dir.length()-1] != QLatin1Char('/'))
01633 _base_dir.append(QLatin1Char('/') );
01634
01635 const QStringList list1 = _base_dir.split(QLatin1Char('/'), QString::SkipEmptyParts);
01636 const QStringList list2 = _path.split(QLatin1Char('/'), QString::SkipEmptyParts);
01637
01638
01639 int level = 0;
01640 int maxLevel = qMin(list1.count(), list2.count());
01641 while((level < maxLevel) && (list1[level] == list2[level])) level++;
01642
01643 QString result;
01644
01645 for(int i = level; i < list1.count(); i++)
01646 result.append("../");
01647
01648
01649 for(int i = level; i < list2.count(); i++)
01650 result.append(list2[i]).append("/");
01651
01652 if ((level < list2.count()) && (path[path.length()-1] != QLatin1Char('/')))
01653 result.truncate(result.length()-1);
01654
01655 isParent = (level == list1.count());
01656
01657 return result;
01658 }
01659
01660 QString KUrl::relativePath(const QString &base_dir, const QString &path, bool *isParent)
01661 {
01662 bool parent = false;
01663 QString result = _relativePath(base_dir, path, parent);
01664 if (parent)
01665 result.prepend("./");
01666
01667 if (isParent)
01668 *isParent = parent;
01669
01670 return result;
01671 }
01672
01673
01674 QString KUrl::relativeUrl(const KUrl &base_url, const KUrl &url)
01675 {
01676 if ((url.protocol() != base_url.protocol()) ||
01677 (url.host() != base_url.host()) ||
01678 (url.port() && url.port() != base_url.port()) ||
01679 (url.hasUser() && url.user() != base_url.user()) ||
01680 (url.hasPass() && url.pass() != base_url.pass()))
01681 {
01682 return url.url();
01683 }
01684
01685 QString relURL;
01686
01687 if ((base_url.path() != url.path()) || (base_url.query() != url.query()))
01688 {
01689 bool dummy;
01690 QString basePath = base_url.directory(KUrl::ObeyTrailingSlash);
01691 relURL = _relativePath(basePath, url.path(), dummy);
01692 relURL += url.query();
01693 }
01694
01695 if ( url.hasRef() )
01696 {
01697 relURL += '#';
01698 relURL += url.ref();
01699 }
01700
01701 if ( relURL.isEmpty() )
01702 return "./";
01703
01704 return relURL;
01705 }
01706
01707 void KUrl::setPath( const QString& _path )
01708 {
01709 #if defined(Q_WS_WIN) && defined(DEBUG_KURL)
01710 kDebug(126) << "KUrl::setPath " << " " << _path.toAscii().data();
01711 #endif
01712 if ( scheme().isEmpty() )
01713 setScheme( QLatin1String( "file" ) );
01714 QString path = KShell::tildeExpand( _path );
01715 #ifdef Q_WS_WIN
01716 const int len = path.length();
01717 if( len == 2 && IS_LETTER(path[0]) && path[1] == QLatin1Char(':') )
01718 path += QLatin1Char('/');
01719
01720
01721
01722 else
01723 if( len > 0 && path[0] != QLatin1Char('/') && scheme() == QLatin1String( "file" ) )
01724 path = QLatin1Char('/') + path;
01725 #endif
01726 QUrl::setPath( path );
01727 }
01728
01729 #if 0 // this would be if we didn't decode '+' into ' '
01730 QMap< QString, QString > KUrl::queryItems( int options ) const {
01731 QMap< QString, QString > result;
01732 const QList<QPair<QString, QString> > items = QUrl::queryItems();
01733 QPair<QString, QString> item;
01734 Q_FOREACH( item, items ) {
01735 result.insert( options & CaseInsensitiveKeys ? item.first.toLower() : item.first, item.second );
01736 }
01737 return result;
01738 }
01739 #endif
01740
01741 QMap< QString, QString > KUrl::queryItems( const QueryItemsOptions &options ) const {
01742 const QString strQueryEncoded = encodedQuery();
01743 if ( strQueryEncoded.isEmpty() )
01744 return QMap<QString,QString>();
01745
01746 QMap< QString, QString > result;
01747 const QStringList items = strQueryEncoded.split( '&', QString::SkipEmptyParts );
01748 for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
01749 const int equal_pos = (*it).indexOf( '=' );
01750 if ( equal_pos > 0 ) {
01751 QString name = (*it).left( equal_pos );
01752 if ( options & CaseInsensitiveKeys )
01753 name = name.toLower();
01754 QString value = (*it).mid( equal_pos + 1 );
01755 if ( value.isEmpty() )
01756 result.insert( name, QString::fromLatin1("") );
01757 else {
01758
01759 value.replace( '+', ' ' );
01760 result.insert( name, QUrl::fromPercentEncoding( value.toLatin1() ) );
01761 }
01762 } else if ( equal_pos < 0 ) {
01763 QString name = (*it);
01764 if ( options & CaseInsensitiveKeys )
01765 name = name.toLower();
01766 result.insert( name, QString() );
01767 }
01768 }
01769
01770 return result;
01771 }
01772
01773 QString KUrl::queryItem( const QString& _item ) const
01774 {
01775 const QString strQueryEncoded = encodedQuery();
01776 const QString item = _item + '=';
01777 if ( strQueryEncoded.length() <= 1 )
01778 return QString();
01779
01780 const QStringList items = strQueryEncoded.split( '&', QString::SkipEmptyParts );
01781 const int _len = item.length();
01782 for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it )
01783 {
01784 if ( (*it).startsWith( item ) )
01785 {
01786 if ( (*it).length() > _len )
01787 {
01788 QString str = (*it).mid( _len );
01789 str.replace( '+', ' ' );
01790 return QUrl::fromPercentEncoding( str.toLatin1() );
01791 }
01792 else
01793 return QString::fromLatin1("");
01794 }
01795 }
01796
01797 return QString();
01798 }
01799
01800 void KUrl::addQueryItem( const QString& _item, const QString& _value )
01801 {
01802 QString item = _item + '=';
01803 QString value = QUrl::toPercentEncoding( _value );
01804
01805 QString strQueryEncoded = encodedQuery();
01806 if (!strQueryEncoded.isEmpty())
01807 strQueryEncoded += '&';
01808 strQueryEncoded += item + value;
01809 setEncodedQuery( strQueryEncoded.toLatin1() );
01810 }
01811
01812 void KUrl::populateMimeData( QMimeData* mimeData,
01813 const MetaDataMap& metaData,
01814 MimeDataFlags flags ) const
01815 {
01816 KUrl::List lst( *this );
01817 lst.populateMimeData( mimeData, metaData, flags );
01818 }
01819
01820 bool KUrl::hasRef() const
01821 {
01822 return hasFragment();
01823 }
01824
01825 void KUrl::setRef( const QString& fragment )
01826 {
01827 if ( fragment.isNull() )
01828 setFragment( fragment );
01829 else
01830 setFragment( QUrl::fromPercentEncoding( fragment.toLatin1() ) );
01831 }
01832
01833 QString KUrl::ref() const
01834 {
01835 if ( fragment().isNull() )
01836 return QString();
01837 else
01838 return QString::fromLatin1( QUrl::toPercentEncoding( fragment() ) );
01839 }
01840
01841 bool KUrl::isParentOf( const KUrl& u ) const
01842 {
01843 return QUrl::isParentOf( u ) || equals( u, CompareWithoutTrailingSlash );
01844 }
01845
01846 uint qHash(const KUrl& kurl)
01847 {
01848
01849
01850
01851 return qHash(kurl.protocol()) ^ qHash(kurl.path()) ^ qHash(kurl.fragment()) ^ qHash(kurl.query());
01852 }