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