kdecore Library API Documentation

kurl.cpp

00001 /* 00002 Copyright (C) 1999 Torben Weis <weis@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 /* 00021 * The currently active RFC for URL/URIs is RFC3986 00022 * Previous (and now deprecated) RFCs are RFC1738 and RFC2396 00023 */ 00024 00025 #include "kurl.h" 00026 00027 #ifndef KDE_QT_ONLY 00028 #include <kdebug.h> 00029 #include <kglobal.h> 00030 #include <kidna.h> 00031 #include <kprotocolinfo.h> 00032 #endif 00033 00034 #include <stdio.h> 00035 #include <assert.h> 00036 #include <ctype.h> 00037 #include <stdlib.h> 00038 #include <unistd.h> 00039 00040 #include <qurl.h> 00041 #include <qdir.h> 00042 #include <qstringlist.h> 00043 #include <qregexp.h> 00044 #include <qstylesheet.h> 00045 #include <qmap.h> 00046 #include <qtextcodec.h> 00047 #include <qmutex.h> 00048 00049 #ifdef Q_WS_WIN 00050 # define KURL_ROOTDIR_PATH "C:/" 00051 #else 00052 # define KURL_ROOTDIR_PATH "/" 00053 #endif 00054 00055 static const QString fileProt = "file"; 00056 00057 static QTextCodec * codecForHint( int encoding_hint /* not 0 ! */ ) 00058 { 00059 return QTextCodec::codecForMib( encoding_hint ); 00060 } 00061 00062 // encoding_offset: 00063 // 0 encode both @ and / 00064 // 1 encode @ but not / 00065 // 2 encode neither @ or / 00066 static QString encode( const QString& segment, int encoding_offset, int encoding_hint ) 00067 { 00068 const char *encode_string = "/@<>#\"&%?={}|^~[]\'`\\:+"; 00069 encode_string += encoding_offset; 00070 00071 QCString local; 00072 if (encoding_hint==0) 00073 local = segment.local8Bit(); 00074 else 00075 { 00076 QTextCodec * textCodec = codecForHint( encoding_hint ); 00077 if (!textCodec) 00078 local = segment.local8Bit(); 00079 else 00080 local = textCodec->fromUnicode( segment ); 00081 } 00082 00083 int old_length = local.length(); 00084 00085 if ( !old_length ) 00086 return segment.isNull() ? QString::null : QString(""); // differentiate null and empty 00087 00088 // a worst case approximation 00089 QChar *new_segment = new QChar[ old_length * 3 + 1 ]; 00090 int new_length = 0; 00091 00092 for ( int i = 0; i < old_length; i++ ) 00093 { 00094 // 'unsave' and 'reserved' characters 00095 // according to RFC 1738, 00096 // 2.2. URL Character Encoding Issues (pp. 3-4) 00097 // WABA: Added non-ascii 00098 unsigned char character = local[i]; 00099 if ( (character <= 32) || (character >= 127) || 00100 strchr(encode_string, character) ) 00101 { 00102 new_segment[ new_length++ ] = '%'; 00103 00104 unsigned int c = character / 16; 00105 c += (c > 9) ? ('A' - 10) : '0'; 00106 new_segment[ new_length++ ] = c; 00107 00108 c = character % 16; 00109 c += (c > 9) ? ('A' - 10) : '0'; 00110 new_segment[ new_length++ ] = c; 00111 00112 } 00113 else 00114 new_segment[ new_length++ ] = local[i]; 00115 } 00116 00117 QString result = QString(new_segment, new_length); 00118 delete [] new_segment; 00119 return result; 00120 } 00121 00122 static QString encodeHost( const QString& segment, bool encode_slash, int encoding_hint ) 00123 { 00124 // Hostnames are encoded differently 00125 // we use the IDNA transformation instead 00126 00127 // Note: when merging qt-addon, use QResolver::domainToAscii here 00128 #ifndef KDE_QT_ONLY 00129 Q_UNUSED( encode_slash ); 00130 Q_UNUSED( encoding_hint ); 00131 QString host = KIDNA::toAscii(segment); 00132 if (host.isEmpty()) 00133 return segment; 00134 return host; 00135 #else 00136 return encode(segment, encode_slash ? 0 : 1, encoding_hint); 00137 #endif 00138 } 00139 00140 static int hex2int( unsigned int _char ) 00141 { 00142 if ( _char >= 'A' && _char <='F') 00143 return _char - 'A' + 10; 00144 if ( _char >= 'a' && _char <='f') 00145 return _char - 'a' + 10; 00146 if ( _char >= '0' && _char <='9') 00147 return _char - '0'; 00148 return -1; 00149 } 00150 00151 // WABA: The result of lazy_encode isn't usable for a URL which 00152 // needs to satisfies RFC requirements. However, the following 00153 // operation will make it usable again: 00154 // encode(decode(...)) 00155 // 00156 // As a result one can see that url.prettyURL() does not result in 00157 // a RFC compliant URL but that the following sequence does: 00158 // KURL(url.prettyURL()).url() 00159 00160 00161 static QString lazy_encode( const QString& segment, bool encodeAt=true ) 00162 { 00163 int old_length = segment.length(); 00164 00165 if ( !old_length ) 00166 return QString::null; 00167 00168 // a worst case approximation 00169 QChar *new_segment = new QChar[ old_length * 3 + 1 ]; 00170 int new_length = 0; 00171 00172 for ( int i = 0; i < old_length; i++ ) 00173 { 00174 unsigned int character = segment[i].unicode(); // Don't use latin1() 00175 // It returns 0 for non-latin1 values 00176 // Small set of really ambiguous chars 00177 if ((character < 32) || // Low ASCII 00178 ((character == '%') && // The escape character itself 00179 (i+2 < old_length) && // But only if part of a valid escape sequence! 00180 (hex2int(segment[i+1].unicode())!= -1) && 00181 (hex2int(segment[i+2].unicode())!= -1)) || 00182 (character == '?') || // Start of query delimiter 00183 ((character == '@') && encodeAt) || // Username delimiter 00184 (character == '#') || // Start of reference delimiter 00185 ((character == 32) && (i+1 == old_length))) // A trailing space 00186 { 00187 new_segment[ new_length++ ] = '%'; 00188 00189 unsigned int c = character / 16; 00190 c += (c > 9) ? ('A' - 10) : '0'; 00191 new_segment[ new_length++ ] = c; 00192 00193 c = character % 16; 00194 c += (c > 9) ? ('A' - 10) : '0'; 00195 new_segment[ new_length++ ] = c; 00196 } 00197 else 00198 new_segment[ new_length++ ] = segment[i]; 00199 } 00200 00201 QString result = QString(new_segment, new_length); 00202 delete [] new_segment; 00203 return result; 00204 } 00205 00206 static void decode( const QString& segment, QString &decoded, QString &encoded, int encoding_hint=0, bool updateDecoded = true ) 00207 { 00208 decoded = QString::null; 00209 encoded = segment; 00210 00211 int old_length = segment.length(); 00212 if ( !old_length ) 00213 return; 00214 00215 QTextCodec *textCodec = 0; 00216 if (encoding_hint) 00217 textCodec = codecForHint( encoding_hint ); 00218 00219 if (!textCodec) 00220 textCodec = QTextCodec::codecForLocale(); 00221 00222 QCString csegment = textCodec->fromUnicode(segment); 00223 // Check if everything went ok 00224 if (textCodec->toUnicode(csegment) != segment) 00225 { 00226 // Uh oh 00227 textCodec = codecForHint( 106 ); // Fall back to utf-8 00228 csegment = textCodec->fromUnicode(segment); 00229 } 00230 old_length = csegment.length(); 00231 00232 int new_length = 0; 00233 int new_length2 = 0; 00234 00235 // make a copy of the old one 00236 char *new_segment = new char[ old_length + 1 ]; 00237 QChar *new_usegment = new QChar[ old_length * 3 + 1 ]; 00238 00239 int i = 0; 00240 while( i < old_length ) 00241 { 00242 bool bReencode = false; 00243 unsigned char character = csegment[ i++ ]; 00244 if ((character <= ' ') || (character > 127)) 00245 bReencode = true; 00246 00247 new_usegment [ new_length2++ ] = character; 00248 if (character == '%' ) 00249 { 00250 int a = i+1 < old_length ? hex2int( csegment[i] ) : -1; 00251 int b = i+1 < old_length ? hex2int( csegment[i+1] ) : -1; 00252 if ((a == -1) || (b == -1)) // Only replace if sequence is valid 00253 { 00254 // Contains stray %, make sure to re-encode! 00255 bReencode = true; 00256 } 00257 else 00258 { 00259 // Valid %xx sequence 00260 character = a * 16 + b; // Replace with value of %dd 00261 if (!character && updateDecoded) 00262 break; // Stop at %00 00263 00264 new_usegment [ new_length2++ ] = (unsigned char) csegment[i++]; 00265 new_usegment [ new_length2++ ] = (unsigned char) csegment[i++]; 00266 } 00267 } 00268 if (bReencode) 00269 { 00270 new_length2--; 00271 new_usegment [ new_length2++ ] = '%'; 00272 00273 unsigned int c = character / 16; 00274 c += (c > 9) ? ('A' - 10) : '0'; 00275 new_usegment[ new_length2++ ] = c; 00276 00277 c = character % 16; 00278 c += (c > 9) ? ('A' - 10) : '0'; 00279 new_usegment[ new_length2++ ] = c; 00280 } 00281 00282 new_segment [ new_length++ ] = character; 00283 } 00284 new_segment [ new_length ] = 0; 00285 00286 encoded = QString( new_usegment, new_length2); 00287 00288 // Encoding specified 00289 if (updateDecoded) 00290 { 00291 QByteArray array; 00292 array.setRawData(new_segment, new_length); 00293 decoded = textCodec->toUnicode( array, new_length ); 00294 array.resetRawData(new_segment, new_length); 00295 QCString validate = textCodec->fromUnicode(decoded); 00296 00297 if (strcmp(validate.data(), new_segment) != 0) 00298 { 00299 decoded = QString::fromLocal8Bit(new_segment, new_length); 00300 } 00301 } 00302 00303 delete [] new_segment; 00304 delete [] new_usegment; 00305 } 00306 00307 static QString decode(const QString &segment, int encoding_hint = 0) 00308 { 00309 QString result; 00310 QString tmp; 00311 decode(segment, result, tmp, encoding_hint); 00312 return result; 00313 } 00314 00315 static QString cleanpath(const QString &_path, bool cleanDirSeparator, bool decodeDots) 00316 { 00317 if (_path.isEmpty()) return QString::null; 00318 00319 if (QDir::isRelativePath(_path)) 00320 return _path; // Don't mangle mailto-style URLs 00321 00322 QString path = _path; 00323 00324 int len = path.length(); 00325 00326 if (decodeDots) 00327 { 00328 #ifndef KDE_QT_ONLY 00329 static const QString &encodedDot = KGlobal::staticQString("%2e"); 00330 #else 00331 QString encodedDot("%2e"); 00332 #endif 00333 if (path.find(encodedDot, 0, false) != -1) 00334 { 00335 #ifndef KDE_QT_ONLY 00336 static const QString &encodedDOT = KGlobal::staticQString("%2E"); // Uppercase! 00337 #else 00338 QString encodedDOT("%2E"); 00339 #endif 00340 path.replace(encodedDot, "."); 00341 path.replace(encodedDOT, "."); 00342 len = path.length(); 00343 } 00344 } 00345 00346 bool slash = (len && path[len-1] == '/') || 00347 (len > 1 && path[len-2] == '/' && path[len-1] == '.'); 00348 00349 // The following code cleans up directory path much like 00350 // QDir::cleanDirPath() except it can be made to ignore multiple 00351 // directory separators by setting the flag to false. That fixes 00352 // bug# 15044, mail.altavista.com and other similar brain-dead server 00353 // implementations that do not follow what has been specified in 00354 // RFC 2396!! (dA) 00355 QString result; 00356 int cdUp, orig_pos, pos; 00357 00358 cdUp = 0; 00359 pos = orig_pos = len; 00360 while ( pos && (pos = path.findRev('/',--pos)) != -1 ) 00361 { 00362 len = orig_pos - pos - 1; 00363 if ( len == 2 && path[pos+1] == '.' && path[pos+2] == '.' ) 00364 cdUp++; 00365 else 00366 { 00367 // Ignore any occurrences of '.' 00368 // This includes entries that simply do not make sense like /..../ 00369 if ( (len || !cleanDirSeparator) && 00370 (len != 1 || path[pos+1] != '.' ) ) 00371 { 00372 if ( !cdUp ) 00373 result.prepend(path.mid(pos, len+1)); 00374 else 00375 cdUp--; 00376 } 00377 } 00378 orig_pos = pos; 00379 } 00380 00381 #ifdef Q_WS_WIN // prepend drive letter if exists (js) 00382 if (orig_pos >= 2 && isalpha(path[0].latin1()) && path[1]==':') { 00383 result.prepend(QString(path[0])+":"); 00384 } 00385 #endif 00386 00387 if ( result.isEmpty() ) 00388 result = KURL_ROOTDIR_PATH; 00389 else if ( slash && result[result.length()-1] != '/' ) 00390 result.append('/'); 00391 00392 return result; 00393 } 00394 00395 bool KURL::isRelativeURL(const QString &_url) 00396 { 00397 int len = _url.length(); 00398 if (!len) return true; // Very short relative URL. 00399 const QChar *str = _url.unicode(); 00400 00401 // Absolute URL must start with alpha-character 00402 if (!isalpha(str[0].latin1())) 00403 return true; // Relative URL 00404 00405 for(int i = 1; i < len; i++) 00406 { 00407 char c = str[i].latin1(); // Note: non-latin1 chars return 0! 00408 if (c == ':') 00409 return false; // Absolute URL 00410 00411 // Protocol part may only contain alpha, digit, + or - 00412 if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-')) 00413 return true; // Relative URL 00414 } 00415 // URL did not contain ':' 00416 return true; // Relative URL 00417 } 00418 00419 KURL::List::List(const KURL &url) 00420 { 00421 append( url ); 00422 } 00423 00424 KURL::List::List(const QStringList &list) 00425 { 00426 for (QStringList::ConstIterator it = list.begin(); 00427 it != list.end(); 00428 it++) 00429 { 00430 append( KURL(*it) ); 00431 } 00432 } 00433 00434 QStringList KURL::List::toStringList() const 00435 { 00436 QStringList lst; 00437 for( KURL::List::ConstIterator it = begin(); 00438 it != end(); 00439 it++) 00440 { 00441 lst.append( (*it).url() ); 00442 } 00443 return lst; 00444 } 00445 00446 00447 KURL::KURL() 00448 { 00449 reset(); 00450 } 00451 00452 KURL::~KURL() 00453 { 00454 } 00455 00456 00457 KURL::KURL( const QString &url, int encoding_hint ) 00458 { 00459 reset(); 00460 parse( url, encoding_hint ); 00461 } 00462 00463 KURL::KURL( const char * url, int encoding_hint ) 00464 { 00465 reset(); 00466 parse( QString::fromLatin1(url), encoding_hint ); 00467 } 00468 00469 KURL::KURL( const QCString& url, int encoding_hint ) 00470 { 00471 reset(); 00472 parse( QString::fromLatin1(url), encoding_hint ); 00473 } 00474 00475 KURL::KURL( const KURL& _u ) 00476 { 00477 *this = _u; 00478 } 00479 00480 QDataStream & operator<< (QDataStream & s, const KURL & a) 00481 { 00482 QString QueryForWire=a.m_strQuery_encoded; 00483 if (!a.m_strQuery_encoded.isNull()) 00484 QueryForWire.prepend("?"); 00485 00486 s << a.m_strProtocol << a.m_strUser << a.m_strPass << a.m_strHost 00487 << a.m_strPath << a.m_strPath_encoded << QueryForWire << a.m_strRef_encoded 00488 << Q_INT8(a.m_bIsMalformed ? 1 : 0) << a.m_iPort; 00489 return s; 00490 } 00491 00492 QDataStream & operator>> (QDataStream & s, KURL & a) 00493 { 00494 Q_INT8 malf; 00495 QString QueryFromWire; 00496 s >> a.m_strProtocol >> a.m_strUser >> a.m_strPass >> a.m_strHost 00497 >> a.m_strPath >> a.m_strPath_encoded >> QueryFromWire >> a.m_strRef_encoded 00498 >> malf >> a.m_iPort; 00499 a.m_bIsMalformed = (malf != 0); 00500 00501 if ( QueryFromWire.isNull() ) 00502 a.m_strQuery_encoded = QString::null; 00503 else if ( QueryFromWire.length() == 1 ) // empty query 00504 a.m_strQuery_encoded = ""; 00505 else 00506 a.m_strQuery_encoded = QueryFromWire.mid(1); 00507 00508 a.m_iUriMode = KURL::uriModeForProtocol( a.m_strProtocol ); 00509 00510 return s; 00511 } 00512 00513 #ifndef QT_NO_NETWORKPROTOCOL 00514 KURL::KURL( const QUrl &u ) 00515 { 00516 *this = u; 00517 } 00518 #endif 00519 00520 KURL::KURL( const KURL& _u, const QString& _rel_url, int encoding_hint ) 00521 { 00522 if (_u.hasSubURL()) // Operate on the last suburl, not the first 00523 { 00524 KURL::List lst = split( _u ); 00525 KURL u(lst.last(), _rel_url, encoding_hint); 00526 lst.remove( lst.last() ); 00527 lst.append( u ); 00528 *this = join( lst ); 00529 return; 00530 } 00531 // WORKAROUND THE RFC 1606 LOOPHOLE THAT ALLOWS 00532 // http:/index.html AS A VALID SYNTAX FOR RELATIVE 00533 // URLS. ( RFC 2396 section 5.2 item # 3 ) 00534 QString rUrl = _rel_url; 00535 int len = _u.m_strProtocol.length(); 00536 if ( !_u.m_strHost.isEmpty() && !rUrl.isEmpty() && 00537 rUrl.find( _u.m_strProtocol, 0, false ) == 0 && 00538 rUrl[len] == ':' && (rUrl[len+1] != '/' || 00539 (rUrl[len+1] == '/' && rUrl[len+2] != '/')) ) 00540 { 00541 rUrl.remove( 0, rUrl.find( ':' ) + 1 ); 00542 } 00543 00544 if ( rUrl.isEmpty() ) 00545 { 00546 *this = _u; 00547 } 00548 else if ( rUrl[0] == '#' ) 00549 { 00550 *this = _u; 00551 m_strRef_encoded = rUrl.mid(1); 00552 QString ref = decode(rUrl.mid(1), encoding_hint); 00553 if ( m_strRef_encoded.isNull() ) 00554 m_strRef_encoded = ""; // we know there was an (empty) html ref, we saw the '#' 00555 } 00556 else if ( isRelativeURL( rUrl) ) 00557 { 00558 *this = _u; 00559 m_strQuery_encoded = QString::null; 00560 m_strRef_encoded = QString::null; 00561 if ( rUrl[0] == '/') 00562 { 00563 if ((rUrl.length() > 1) && (rUrl[1] == '/')) 00564 { 00565 m_strHost = QString::null; 00566 // File protocol returns file:/// without host, strip // from rUrl 00567 if (_u.m_strProtocol == fileProt) 00568 rUrl.remove(0, 2); 00569 } 00570 m_strPath = QString::null; 00571 m_strPath_encoded = QString::null; 00572 } 00573 else if ( rUrl[0] != '?' ) 00574 { 00575 int pos = m_strPath.findRev( '/' ); 00576 if (pos >= 0) 00577 m_strPath.truncate(pos); 00578 m_strPath += '/'; 00579 if (!m_strPath_encoded.isEmpty()) 00580 { 00581 pos = m_strPath_encoded.findRev( '/' ); 00582 if (pos >= 0) 00583 m_strPath_encoded.truncate(pos); 00584 m_strPath_encoded += '/'; 00585 } 00586 } 00587 else 00588 { 00589 if ( m_strPath.isEmpty() ) 00590 m_strPath = '/'; 00591 } 00592 KURL tmp( url() + rUrl, encoding_hint); 00593 *this = tmp; 00594 cleanPath(false); 00595 } 00596 else 00597 { 00598 KURL tmp( rUrl, encoding_hint); 00599 *this = tmp; 00600 // Preserve userinfo if applicable. 00601 if (!_u.m_strUser.isEmpty() && m_strUser.isEmpty() && (_u.m_strHost == m_strHost) && (_u.m_strProtocol == m_strProtocol)) 00602 { 00603 m_strUser = _u.m_strUser; 00604 m_strPass = _u.m_strPass; 00605 } 00606 cleanPath(false); 00607 } 00608 } 00609 00610 void KURL::reset() 00611 { 00612 m_strProtocol = QString::null; 00613 m_strUser = QString::null; 00614 m_strPass = QString::null; 00615 m_strHost = QString::null; 00616 m_strPath = QString::null; 00617 m_strPath_encoded = QString::null; 00618 m_strQuery_encoded = QString::null; 00619 m_strRef_encoded = QString::null; 00620 m_bIsMalformed = true; 00621 m_iPort = 0; 00622 m_iUriMode = Auto; 00623 } 00624 00625 bool KURL::isEmpty() const 00626 { 00627 return (m_strPath.isEmpty() && m_strProtocol.isEmpty()); 00628 } 00629 00630 void KURL::parse( const QString& _url, int encoding_hint ) 00631 { 00632 if ( _url.isEmpty() || m_iUriMode == Invalid ) 00633 { 00634 m_strProtocol = _url; 00635 m_iUriMode = Invalid; 00636 return; 00637 } 00638 00639 const QChar* buf = _url.unicode(); 00640 const QChar* orig = buf; 00641 uint len = _url.length(); 00642 uint pos = 0; 00643 00644 // Node 1: Accept alpha or slash 00645 QChar x = buf[pos++]; 00646 #ifdef Q_WS_WIN 00647 /* win32: accept <letter>: or <letter>:/ or <letter>:\ */ 00648 const bool alpha = isalpha((int)x); 00649 if (alpha && len<2) 00650 goto NodeErr; 00651 if (alpha && buf[pos]==':' && (len==2 || (len>2 && (buf[pos+1]=='/' || buf[pos+1]=='\\')))) 00652 #else 00653 if ( x == '/' ) 00654 #endif 00655 { 00656 // A slash means we immediately proceed to parse it as a file URL. 00657 m_iUriMode = URL; 00658 m_strProtocol = fileProt; 00659 parseURL( _url, encoding_hint ); 00660 return; 00661 } 00662 if ( !isalpha( (int)x ) ) 00663 goto NodeErr; 00664 00665 // Node 2: Accept any amount of (alpha|digit|'+'|'-') 00666 // '.' is not currently accepted, because current KURL may be confused. 00667 // Proceed with :// :/ or : 00668 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) || 00669 buf[pos] == '+' || buf[pos] == '-')) pos++; 00670 00671 if (pos < len && buf[pos] == ':' ) 00672 { 00673 m_strProtocol = QString( orig, pos ).lower(); 00674 if ( m_iUriMode == Auto ) 00675 m_iUriMode = uriModeForProtocol( m_strProtocol ); 00676 // Proceed to correct parse function. 00677 switch ( m_iUriMode ) 00678 { 00679 case RawURI: 00680 parseRawURI( _url ); 00681 return; 00682 case Mailto: 00683 parseMailto( _url ); 00684 return; 00685 case URL: 00686 parseURL( _url, encoding_hint ); 00687 return; 00688 default: 00689 // Unknown URI mode results in an invalid URI. 00690 break; 00691 } 00692 } 00693 00694 NodeErr: 00695 reset(); 00696 m_strProtocol = _url; 00697 m_iUriMode = Invalid; 00698 } 00699 00700 void KURL::parseRawURI( const QString& _url, int encoding_hint ) 00701 { 00702 uint len = _url.length(); 00703 const QChar* buf = _url.unicode(); 00704 00705 uint pos = 0; 00706 00707 // Accept any amount of (alpha|digit|'+'|'-') 00708 // '.' is not currently accepted, because current KURL may be confused. 00709 // Proceed with : 00710 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) || 00711 buf[pos] == '+' || buf[pos] == '-')) pos++; 00712 00713 // Note that m_strProtocol is already set here, so we just skip over the protocol. 00714 if (pos < len && buf[pos] == ':' ) 00715 pos++; 00716 else { // can't happen, the caller checked all this already 00717 reset(); 00718 m_strProtocol = _url; 00719 m_iUriMode = Invalid; 00720 return; 00721 } 00722 00723 if ( pos == len ) // can't happen, the caller checked this already 00724 m_strPath = QString::null; 00725 else 00726 m_strPath = decode( QString( buf + pos, len - pos ), encoding_hint ); 00727 00728 m_bIsMalformed = false; 00729 00730 return; 00731 } 00732 00733 void KURL::parseMailto( const QString& _url, int encoding_hint ) 00734 { 00735 parseURL( _url, encoding_hint); 00736 if ( m_bIsMalformed ) 00737 return; 00738 QRegExp mailre("(.+@)(.+)"); 00739 if ( mailre.exactMatch( m_strPath ) ) 00740 { 00741 #ifndef KDE_QT_ONLY 00742 QString host = KIDNA::toUnicode( mailre.cap( 2 ) ); 00743 if (host.isEmpty()) 00744 host = mailre.cap( 2 ).lower(); 00745 #else 00746 QString host = mailre.cap( 2 ).lower(); 00747 #endif 00748 m_strPath = mailre.cap( 1 ) + host; 00749 } 00750 } 00751 00752 void KURL::parseURL( const QString& _url, int encoding_hint ) 00753 { 00754 QString port; 00755 bool badHostName = false; 00756 int start = 0; 00757 uint len = _url.length(); 00758 const QChar* buf = _url.unicode(); 00759 00760 QChar delim; 00761 QString tmp; 00762 00763 uint pos = 0; 00764 00765 // Node 1: Accept alpha or slash 00766 QChar x = buf[pos++]; 00767 #ifdef Q_WS_WIN 00768 /* win32: accept <letter>: or <letter>:/ or <letter>:\ */ 00769 const bool alpha = isalpha((int)x); 00770 if (alpha && len<2) 00771 goto NodeErr; 00772 if (alpha && buf[pos]==':' && (len==2 || (len>2 && (buf[pos+1]=='/' || buf[pos+1]=='\\')))) 00773 #else 00774 if ( x == '/' ) 00775 #endif 00776 goto Node9; 00777 if ( !isalpha( (int)x ) ) 00778 goto NodeErr; 00779 00780 // Node 2: Accept any amount of (alpha|digit|'+'|'-') 00781 // '.' is not currently accepted, because current KURL may be confused. 00782 // Proceed with :// :/ or : 00783 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) || 00784 buf[pos] == '+' || buf[pos] == '-')) pos++; 00785 00786 // Note that m_strProtocol is already set here, so we just skip over the protocol. 00787 if ( pos+2 < len && buf[pos] == ':' && buf[pos+1] == '/' && buf[pos+2] == '/' ) 00788 { 00789 pos += 3; 00790 } 00791 else if (pos+1 < len && buf[pos] == ':' ) // Need to always compare length()-1 otherwise KURL passes "http:" as legal!! 00792 { 00793 pos++; 00794 start = pos; 00795 goto Node9; 00796 } 00797 else 00798 goto NodeErr; 00799 00800 //Node 3: We need at least one character here 00801 if ( pos == len ) 00802 goto NodeErr; 00803 start = pos; 00804 00805 // Node 4: Accept any amount of characters. 00806 if (buf[pos] == '[') // An IPv6 host follows. 00807 goto Node8; 00808 // Terminate on / or @ or ? or # or " or ; or < 00809 x = buf[pos]; 00810 while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') ) 00811 { 00812 if ((x == '\"') || (x == ';') || (x == '<')) 00813 badHostName = true; 00814 if (++pos == len) 00815 break; 00816 x = buf[pos]; 00817 } 00818 if ( pos == len ) 00819 { 00820 if (badHostName) 00821 goto NodeErr; 00822 00823 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00824 goto NodeOk; 00825 } 00826 if ( x == '@' ) 00827 { 00828 m_strUser = decode(QString( buf + start, pos - start ), encoding_hint); 00829 pos++; 00830 goto Node7; 00831 } 00832 else if ( (x == '/') || (x == '?') || (x == '#')) 00833 { 00834 if (badHostName) 00835 goto NodeErr; 00836 00837 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00838 start = pos; 00839 goto Node9; 00840 } 00841 else if ( x != ':' ) 00842 goto NodeErr; 00843 m_strUser = decode(QString( buf + start, pos - start ), encoding_hint); 00844 pos++; 00845 00846 // Node 5: We need at least one character 00847 if ( pos == len ) 00848 goto NodeErr; 00849 start = pos++; 00850 00851 // Node 6: Read everything until @, /, ? or # 00852 while( (pos < len) && 00853 (buf[pos] != '@') && 00854 (buf[pos] != '/') && 00855 (buf[pos] != '?') && 00856 (buf[pos] != '#')) pos++; 00857 // If we now have a '@' the ':' seperates user and password. 00858 // Otherwise it seperates host and port. 00859 if ( (pos == len) || (buf[pos] != '@') ) 00860 { 00861 // Ok the : was used to separate host and port 00862 if (badHostName) 00863 goto NodeErr; 00864 setHost(m_strUser); 00865 m_strUser = QString::null; 00866 QString tmp( buf + start, pos - start ); 00867 char *endptr; 00868 m_iPort = (unsigned short int)strtol(tmp.ascii(), &endptr, 10); 00869 if ((pos == len) && (strlen(endptr) == 0)) 00870 goto NodeOk; 00871 // there is more after the digits 00872 pos -= strlen(endptr); 00873 if ((buf[pos] != '@') && 00874 (buf[pos] != '/') && 00875 (buf[pos] != '?') && 00876 (buf[pos] != '#')) 00877 goto NodeErr; 00878 00879 start = pos; 00880 goto Node9; 00881 } 00882 m_strPass = decode(QString( buf + start, pos - start), encoding_hint); 00883 pos++; 00884 00885 // Node 7: We need at least one character 00886 Node7: 00887 if ( pos == len ) 00888 goto NodeErr; 00889 00890 Node8: 00891 if (buf[pos] == '[') 00892 { 00893 // IPv6 address 00894 start = ++pos; // Skip '[' 00895 00896 if (pos == len) 00897 { 00898 badHostName = true; 00899 goto NodeErr; 00900 } 00901 // Node 8a: Read everything until ] or terminate 00902 badHostName = false; 00903 x = buf[pos]; 00904 while( (x != ']') ) 00905 { 00906 if ((x == '\"') || (x == ';') || (x == '<')) 00907 badHostName = true; 00908 if (++pos == len) 00909 { 00910 badHostName = true; 00911 break; 00912 } 00913 x = buf[pos]; 00914 } 00915 if (badHostName) 00916 goto NodeErr; 00917 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00918 if (pos < len) pos++; // Skip ']' 00919 if (pos == len) 00920 goto NodeOk; 00921 } 00922 else 00923 { 00924 // Non IPv6 address, with a user 00925 start = pos; 00926 00927 // Node 8b: Read everything until / : or terminate 00928 badHostName = false; 00929 x = buf[pos]; 00930 while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') ) 00931 { 00932 if ((x == '\"') || (x == ';') || (x == '<')) 00933 badHostName = true; 00934 if (++pos == len) 00935 break; 00936 x = buf[pos]; 00937 } 00938 if (badHostName) 00939 goto NodeErr; 00940 if ( pos == len ) 00941 { 00942 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00943 goto NodeOk; 00944 } 00945 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00946 } 00947 x = buf[pos]; 00948 if ( x == '/' || x == '#' || x == '?' ) 00949 { 00950 start = pos; 00951 goto Node9; 00952 } 00953 else if ( x != ':' ) 00954 goto NodeErr; 00955 pos++; 00956 00957 // Node 8c: Accept at least one digit 00958 if ( pos == len ) 00959 goto NodeErr; 00960 start = pos; 00961 if ( !isdigit( buf[pos++] ) ) 00962 goto NodeErr; 00963 00964 // Node 8d: Accept any amount of digits 00965 while( pos < len && isdigit( buf[pos] ) ) pos++; 00966 port = QString( buf + start, pos - start ); 00967 m_iPort = port.toUShort(); 00968 if ( pos == len ) 00969 goto NodeOk; 00970 start = pos; 00971 00972 Node9: // parse path until query or reference reached 00973 00974 while( pos < len && buf[pos] != '#' && buf[pos]!='?' ) pos++; 00975 00976 tmp = QString( buf + start, pos - start ); 00977 //kdDebug(126)<<" setting encoded path to:"<<tmp<<endl; 00978 setEncodedPath( tmp, encoding_hint ); 00979 00980 if ( pos == len ) 00981 goto NodeOk; 00982 00983 //Node10: // parse query or reference depending on what comes first 00984 delim = (buf[pos++]=='#'?'?':'#'); 00985 00986 start = pos; 00987 00988 while(pos < len && buf[pos]!=delim ) pos++; 00989 00990 tmp = QString(buf + start, pos - start); 00991 if (delim=='#') 00992 _setQuery(tmp, encoding_hint); 00993 else 00994 m_strRef_encoded = tmp; 00995 00996 if (pos == len) 00997 goto NodeOk; 00998 00999 //Node11: // feed the rest into the remaining variable 01000 tmp = QString( buf + pos + 1, len - pos - 1); 01001 if (delim == '#') 01002 m_strRef_encoded = tmp; 01003 else 01004 _setQuery(tmp, encoding_hint); 01005 01006 NodeOk: 01007 //kdDebug(126)<<"parsing finished. m_strProtocol="<<m_strProtocol<<" m_strHost="<<m_strHost<<" m_strPath="<<m_strPath<<endl; 01008 m_bIsMalformed = false; // Valid URL 01009 01010 //kdDebug()<<"Prot="<<m_strProtocol<<"\nUser="<<m_strUser<<"\nPass="<<m_strPass<<"\nHost="<<m_strHost<<"\nPath="<<m_strPath<<"\nQuery="<<m_strQuery_encoded<<"\nRef="<<m_strRef_encoded<<"\nPort="<<m_iPort<<endl; 01011 if (m_strProtocol.isEmpty()) 01012 { 01013 m_iUriMode = URL; 01014 m_strProtocol = fileProt; 01015 } 01016 return; 01017 01018 NodeErr: 01019 // kdDebug(126) << "KURL couldn't parse URL \"" << _url << "\"" << endl; 01020 reset(); 01021 m_strProtocol = _url; 01022 m_iUriMode = Invalid; 01023 } 01024 01025 KURL& KURL::operator=( const QString& _url ) 01026 { 01027 reset(); 01028 parse( _url ); 01029 01030 return *this; 01031 } 01032 01033 KURL& KURL::operator=( const char * _url ) 01034 { 01035 reset(); 01036 parse( QString::fromLatin1(_url) ); 01037 01038 return *this; 01039 } 01040 01041 #ifndef QT_NO_NETWORKPROTOCOL 01042 KURL& KURL::operator=( const QUrl & u ) 01043 { 01044 m_strProtocol = u.protocol(); 01045 m_iUriMode = Auto; 01046 m_strUser = u.user(); 01047 m_strPass = u.password(); 01048 m_strHost = u.host(); 01049 m_strPath = u.path( false ); 01050 m_strPath_encoded = QString::null; 01051 m_strQuery_encoded = u.query(); 01052 m_strRef_encoded = u.ref(); 01053 m_bIsMalformed = !u.isValid(); 01054 m_iPort = u.port(); 01055 01056 return *this; 01057 } 01058 #endif 01059 01060 KURL& KURL::operator=( const KURL& _u ) 01061 { 01062 m_strProtocol = _u.m_strProtocol; 01063 m_strUser = _u.m_strUser; 01064 m_strPass = _u.m_strPass; 01065 m_strHost = _u.m_strHost; 01066 m_strPath = _u.m_strPath; 01067 m_strPath_encoded = _u.m_strPath_encoded; 01068 m_strQuery_encoded = _u.m_strQuery_encoded; 01069 m_strRef_encoded = _u.m_strRef_encoded; 01070 m_bIsMalformed = _u.m_bIsMalformed; 01071 m_iPort = _u.m_iPort; 01072 m_iUriMode = _u.m_iUriMode; 01073 01074 return *this; 01075 } 01076 01077 bool KURL::operator<( const KURL& _u) const 01078 { 01079 int i; 01080 if (!_u.isValid()) 01081 { 01082 if (!isValid()) 01083 { 01084 i = m_strProtocol.compare(_u.m_strProtocol); 01085 return (i < 0); 01086 } 01087 return false; 01088 } 01089 if (!isValid()) 01090 return true; 01091 01092 i = m_strProtocol.compare(_u.m_strProtocol); 01093 if (i) return (i < 0); 01094 01095 i = m_strHost.compare(_u.m_strHost); 01096 if (i) return (i < 0); 01097 01098 if (m_iPort != _u.m_iPort) return (m_iPort < _u.m_iPort); 01099 01100 i = m_strPath.compare(_u.m_strPath); 01101 if (i) return (i < 0); 01102 01103 i = m_strQuery_encoded.compare(_u.m_strQuery_encoded); 01104 if (i) return (i < 0); 01105 01106 i = m_strRef_encoded.compare(_u.m_strRef_encoded); 01107 if (i) return (i < 0); 01108 01109 i = m_strUser.compare(_u.m_strUser); 01110 if (i) return (i < 0); 01111 01112 i = m_strPass.compare(_u.m_strPass); 01113 if (i) return (i < 0); 01114 01115 return false; 01116 } 01117 01118 bool KURL::operator==( const KURL& _u ) const 01119 { 01120 if ( !isValid() || !_u.isValid() ) 01121 return false; 01122 01123 if ( m_strProtocol == _u.m_strProtocol && 01124 m_strUser == _u.m_strUser && 01125 m_strPass == _u.m_strPass && 01126 m_strHost == _u.m_strHost && 01127 m_strPath == _u.m_strPath && 01128 // The encoded path may be null, but the URLs are still equal (David) 01129 ( m_strPath_encoded.isNull() || _u.m_strPath_encoded.isNull() || 01130 m_strPath_encoded == _u.m_strPath_encoded ) && 01131 m_strQuery_encoded == _u.m_strQuery_encoded && 01132 m_strRef_encoded == _u.m_strRef_encoded && 01133 m_iPort == _u.m_iPort ) 01134 { 01135 return true; 01136 } 01137 01138 return false; 01139 } 01140 01141 bool KURL::operator==( const QString& _u ) const 01142 { 01143 KURL u( _u ); 01144 return ( *this == u ); 01145 } 01146 01147 bool KURL::cmp( const KURL &u, bool ignore_trailing ) const 01148 { 01149 return equals( u, ignore_trailing ); 01150 } 01151 01152 bool KURL::equals( const KURL &_u, bool ignore_trailing ) const 01153 { 01154 if ( !isValid() || !_u.isValid() ) 01155 return false; 01156 01157 if ( ignore_trailing ) 01158 { 01159 QString path1 = path(1); 01160 QString path2 = _u.path(1); 01161 if ( path1 != path2 ) 01162 return false; 01163 01164 if ( m_strProtocol == _u.m_strProtocol && 01165 m_strUser == _u.m_strUser && 01166 m_strPass == _u.m_strPass && 01167 m_strHost == _u.m_strHost && 01168 m_strQuery_encoded == _u.m_strQuery_encoded && 01169 m_strRef_encoded == _u.m_strRef_encoded && 01170 m_iPort == _u.m_iPort ) 01171 return true; 01172 01173 return false; 01174 } 01175 01176 return ( *this == _u ); 01177 } 01178 01179 bool KURL::isParentOf( const KURL& _u ) const 01180 { 01181 if ( !isValid() || !_u.isValid() ) 01182 return false; 01183 01184 if ( m_strProtocol == _u.m_strProtocol && 01185 m_strUser == _u.m_strUser && 01186 m_strPass == _u.m_strPass && 01187 m_strHost == _u.m_strHost && 01188 m_strQuery_encoded == _u.m_strQuery_encoded && 01189 m_strRef_encoded == _u.m_strRef_encoded && 01190 m_iPort == _u.m_iPort ) 01191 { 01192 if ( path().isEmpty() || _u.path().isEmpty() ) 01193 return false; // can't work with implicit paths 01194 01195 QString p1( cleanpath( path(), true, false ) ); 01196 if ( p1[p1.length()-1] != '/' ) 01197 p1 += '/'; 01198 QString p2( cleanpath( _u.path(), true, false ) ); 01199 if ( p2[p2.length()-1] != '/' ) 01200 p2 += '/'; 01201 01202 //kdDebug(126) << "p1=" << p1 << endl; 01203 //kdDebug(126) << "p2=" << p2 << endl; 01204 //kdDebug(126) << "p1.length()=" << p1.length() << endl; 01205 //kdDebug(126) << "p2.left(!$)=" << p2.left( p1.length() ) << endl; 01206 return p2.startsWith( p1 ); 01207 } 01208 return false; 01209 } 01210 01211 void KURL::setFileName( const QString& _txt ) 01212 { 01213 m_strRef_encoded = QString::null; 01214 int i = 0; 01215 while( _txt[i] == '/' ) ++i; 01216 QString tmp; 01217 if ( i ) 01218 tmp = _txt.mid( i ); 01219 else 01220 tmp = _txt; 01221 01222 QString path = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded; 01223 if ( path.isEmpty() ) 01224 path = "/"; 01225 else 01226 { 01227 int lastSlash = path.findRev( '/' ); 01228 if ( lastSlash == -1) 01229 { 01230 // The first character is not a '/' ??? 01231 // This looks strange ... 01232 path = "/"; 01233 } 01234 else if ( path.right(1) != "/" ) 01235 path.truncate( lastSlash+1 ); // keep the "/" 01236 } 01237 if (m_strPath_encoded.isEmpty()) 01238 { 01239 path += tmp; 01240 setPath( path ); 01241 } 01242 else 01243 { 01244 path += encode_string(tmp); 01245 setEncodedPath( path ); 01246 } 01247 cleanPath(); 01248 } 01249 01250 void KURL::cleanPath( bool cleanDirSeparator ) // taken from the old KURL 01251 { 01252 if (m_iUriMode != URL) return; 01253 m_strPath = cleanpath(m_strPath, cleanDirSeparator, false); 01254 // WABA: Is this safe when "/../" is encoded with %? 01255 m_strPath_encoded = cleanpath(m_strPath_encoded, cleanDirSeparator, true); 01256 } 01257 01258 static QString trailingSlash( int _trailing, const QString &path ) 01259 { 01260 QString result = path; 01261 01262 if ( _trailing == 0 ) 01263 return result; 01264 else if ( _trailing == 1 ) 01265 { 01266 int len = result.length(); 01267 if ( (len == 0) || (result[ len - 1 ] != '/') ) 01268 result += "/"; 01269 return result; 01270 } 01271 else if ( _trailing == -1 ) 01272 { 01273 if ( result == "/" ) 01274 return result; 01275 int len = result.length(); 01276 if ( (len != 0) && (result[ len - 1 ] == '/') ) 01277 result.truncate( len - 1 ); 01278 return result; 01279 } 01280 else { 01281 assert( 0 ); 01282 return QString::null; 01283 } 01284 } 01285 01286 void KURL::adjustPath( int _trailing ) 01287 { 01288 if (!m_strPath_encoded.isEmpty()) 01289 { 01290 m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded ); 01291 } 01292 m_strPath = trailingSlash( _trailing, m_strPath ); 01293 } 01294 01295 01296 QString KURL::encodedPathAndQuery( int _trailing, bool _no_empty_path, int encoding_hint ) const 01297 { 01298 QString tmp; 01299 if (!m_strPath_encoded.isEmpty() && encoding_hint == 0) 01300 { 01301 tmp = trailingSlash( _trailing, m_strPath_encoded ); 01302 } 01303 else 01304 { 01305 tmp = path( _trailing ); 01306 if ( _no_empty_path && tmp.isEmpty() ) 01307 tmp = "/"; 01308 if (m_iUriMode == Mailto) 01309 { 01310 tmp = encode( tmp, 2, encoding_hint ); 01311 } 01312 else 01313 { 01314 tmp = encode( tmp, 1, encoding_hint ); 01315 } 01316 } 01317 01318 // TODO apply encoding_hint to the query 01319 if (!m_strQuery_encoded.isNull()) 01320 tmp += '?' + m_strQuery_encoded; 01321 return tmp; 01322 } 01323 01324 void KURL::setEncodedPath( const QString& _txt, int encoding_hint ) 01325 { 01326 m_strPath_encoded = _txt; 01327 01328 decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint ); 01329 // Throw away encoding for local files, makes file-operations faster. 01330 if (m_strProtocol == fileProt) 01331 m_strPath_encoded = QString::null; 01332 01333 if ( m_iUriMode == Auto ) 01334 m_iUriMode = URL; 01335 } 01336 01337 01338 void KURL::setEncodedPathAndQuery( const QString& _txt, int encoding_hint ) 01339 { 01340 int pos = _txt.find( '?' ); 01341 if ( pos == -1 ) 01342 { 01343 setEncodedPath(_txt, encoding_hint); 01344 m_strQuery_encoded = QString::null; 01345 } 01346 else 01347 { 01348 setEncodedPath(_txt.left( pos ), encoding_hint); 01349 _setQuery(_txt.right(_txt.length() - pos - 1), encoding_hint); 01350 } 01351 } 01352 01353 QString KURL::path( int _trailing ) const 01354 { 01355 return trailingSlash( _trailing, path() ); 01356 } 01357 01358 bool KURL::isLocalFile() const 01359 { 01360 if ( (m_strProtocol != fileProt ) || hasSubURL() ) 01361 return false; 01362 01363 if (m_strHost.isEmpty() || (m_strHost == "localhost")) 01364 return true; 01365 01366 char hostname[ 256 ]; 01367 hostname[ 0 ] = '\0'; 01368 if (!gethostname( hostname, 255 )) 01369 hostname[sizeof(hostname)-1] = '\0'; 01370 01371 for(char *p = hostname; *p; p++) 01372 *p = tolower(*p); 01373 01374 return (m_strHost == hostname); 01375 } 01376 01377 void KURL::setFileEncoding(const QString &encoding) 01378 { 01379 if (!isLocalFile()) 01380 return; 01381 01382 QString q = query(); 01383 01384 if (!q.isEmpty() && (q[0] == '?')) 01385 q = q.mid(1); 01386 01387 QStringList args = QStringList::split('&', q); 01388 for(QStringList::Iterator it = args.begin(); 01389 it != args.end();) 01390 { 01391 QString s = decode_string(*it); 01392 if (s.startsWith("charset=")) 01393 it = args.erase(it); 01394 else 01395 ++it; 01396 } 01397 if (!encoding.isEmpty()) 01398 args.append("charset="+encode_string(encoding)); 01399 01400 if (args.isEmpty()) 01401 _setQuery(QString::null); 01402 else 01403 _setQuery(args.join("&")); 01404 } 01405 01406 QString KURL::fileEncoding() const 01407 { 01408 if (!isLocalFile()) 01409 return QString::null; 01410 01411 QString q = query(); 01412 01413 if (q.isEmpty()) 01414 return QString::null; 01415 01416 if (q[0] == '?') 01417 q = q.mid(1); 01418 01419 QStringList args = QStringList::split('&', q); 01420 for(QStringList::ConstIterator it = args.begin(); 01421 it != args.end(); 01422 ++it) 01423 { 01424 QString s = decode_string(*it); 01425 if (s.startsWith("charset=")) 01426 return s.mid(8); 01427 } 01428 return QString::null; 01429 } 01430 01431 bool KURL::hasSubURL() const 01432 { 01433 if ( m_strProtocol.isEmpty() || m_bIsMalformed ) 01434 return false; 01435 if (m_strRef_encoded.isEmpty()) 01436 return false; 01437 if (m_strRef_encoded.startsWith("gzip:")) 01438 return true; 01439 if (m_strRef_encoded.startsWith("bzip:")) 01440 return true; 01441 if (m_strRef_encoded.startsWith("bzip2:")) 01442 return true; 01443 if (m_strRef_encoded.startsWith("tar:")) 01444 return true; 01445 if (m_strRef_encoded.startsWith("ar:")) 01446 return true; 01447 if (m_strRef_encoded.startsWith("zip:")) 01448 return true; 01449 if ( m_strProtocol == "error" ) // anything that starts with error: has suburls 01450 return true; 01451 return false; 01452 } 01453 01454 QString KURL::url( int _trailing, int encoding_hint ) const 01455 { 01456 if( m_bIsMalformed ) 01457 { 01458 // Return the whole url even when the url is 01459 // malformed. Under such conditions the url 01460 // is stored in m_strProtocol. 01461 return m_strProtocol; 01462 } 01463 01464 QString u = m_strProtocol; 01465 if (!u.isEmpty()) 01466 u += ":"; 01467 01468 if ( hasHost() || (m_strProtocol == fileProt) ) 01469 { 01470 u += "//"; 01471 if ( hasUser() ) 01472 { 01473 u += encode(m_strUser, 0, encoding_hint); 01474 if ( hasPass() ) 01475 { 01476 u += ":"; 01477 u += encode(m_strPass, 0, encoding_hint); 01478 } 01479 u += "@"; 01480 } 01481 if ( m_iUriMode == URL ) 01482 { 01483 bool IPv6 = (m_strHost.find(':') != -1); 01484 if (IPv6) 01485 u += '[' + m_strHost + ']'; 01486 else 01487 u += encodeHost(m_strHost, true, encoding_hint); 01488 if ( m_iPort != 0 ) { 01489 QString buffer; 01490 buffer.sprintf( ":%u", m_iPort ); 01491 u += buffer; 01492 } 01493 } 01494 else 01495 { 01496 u += m_strHost; 01497 } 01498 } 01499 01500 if ( m_iUriMode == URL || m_iUriMode == Mailto ) 01501 u += encodedPathAndQuery( _trailing, false, encoding_hint ); 01502 else 01503 u += m_strPath; 01504 01505 if ( hasRef() ) 01506 { 01507 u += "#"; 01508 u += m_strRef_encoded; 01509 } 01510 01511 return u; 01512 } 01513 01514 QString KURL::prettyURL( int _trailing ) const 01515 { 01516 if( m_bIsMalformed ) 01517 { 01518 // Return the whole url even when the url is 01519 // malformed. Under such conditions the url 01520 // is stored in m_strProtocol. 01521 return m_strProtocol; 01522 } 01523 01524 QString u = m_strProtocol; 01525 if (!u.isEmpty()) 01526 u += ":"; 01527 01528 if ( hasHost() || (m_strProtocol == fileProt) ) 01529 { 01530 u += "//"; 01531 if ( hasUser() ) 01532 { 01533 u += lazy_encode(m_strUser); 01534 // Don't show password! 01535 u += "@"; 01536 } 01537 if ( m_iUriMode == URL ) 01538 { 01539 bool IPv6 = (m_strHost.find(':') != -1); 01540 if (IPv6) 01541 { 01542 u += '[' + m_strHost + ']'; 01543 } 01544 else 01545 { 01546 u += lazy_encode(m_strHost); 01547 } 01548 } 01549 else 01550 { 01551 u += lazy_encode(m_strHost); 01552 } 01553 if ( m_iPort != 0 ) { 01554 QString buffer; 01555 buffer.sprintf( ":%u", m_iPort ); 01556 u += buffer; 01557 } 01558 } 01559 01560 if (m_iUriMode == Mailto) 01561 { 01562 u += lazy_encode( m_strPath, false ); 01563 } 01564 else 01565 { 01566 u += trailingSlash( _trailing, lazy_encode( m_strPath ) ); 01567 } 01568 01569 if (!m_strQuery_encoded.isNull()) 01570 u += '?' + m_strQuery_encoded; 01571 01572 if ( hasRef() ) 01573 { 01574 u += "#"; 01575 u += m_strRef_encoded; 01576 } 01577 01578 return u; 01579 } 01580 01581 QString KURL::prettyURL( int _trailing, AdjustementFlags _flags) const 01582 { 01583 QString u = prettyURL(_trailing); 01584 if (_flags & StripFileProtocol && u.startsWith("file://")) { 01585 u.remove(0, 7); 01586 #ifdef Q_WS_WIN 01587 return QDir::convertSeparators(u); 01588 #endif 01589 } 01590 return u; 01591 } 01592 01593 QString KURL::pathOrURL() const 01594 { 01595 if ( isLocalFile() && m_strRef_encoded.isNull() && m_strQuery_encoded.isNull() ) { 01596 return path(); 01597 } else { 01598 return prettyURL(); 01599 } 01600 } 01601 01602 QString KURL::htmlURL() const 01603 { 01604 return QStyleSheet::escape(prettyURL()); 01605 } 01606 01607 KURL::List KURL::split( const KURL& _url ) 01608 { 01609 QString ref; 01610 KURL::List lst; 01611 KURL url = _url; 01612 01613 while(true) 01614 { 01615 KURL u = url; 01616 u.m_strRef_encoded = QString::null; 01617 lst.append(u); 01618 if (url.hasSubURL()) 01619 { 01620 url = KURL(url.m_strRef_encoded); 01621 } 01622 else 01623 { 01624 ref = url.m_strRef_encoded; 01625 break; 01626 } 01627 } 01628 01629 // Set HTML ref in all URLs. 01630 KURL::List::Iterator it; 01631 for( it = lst.begin() ; it != lst.end(); ++it ) 01632 { 01633 (*it).m_strRef_encoded = ref; 01634 } 01635 01636 return lst; 01637 } 01638 01639 KURL::List KURL::split( const QString& _url ) 01640 { 01641 return split(KURL(_url)); 01642 } 01643 01644 KURL KURL::join( const KURL::List & lst ) 01645 { 01646 if (lst.isEmpty()) return KURL(); 01647 KURL tmp; 01648 01649 KURL::List::ConstIterator first = lst.fromLast(); 01650 for( KURL::List::ConstIterator it = first; it != lst.end(); --it ) 01651 { 01652 KURL u(*it); 01653 if (it != first) 01654 { 01655 if (!u.m_strRef_encoded) u.m_strRef_encoded = tmp.url(); 01656 else u.m_strRef_encoded += "#" + tmp.url(); // Support more than one suburl thingy 01657 } 01658 tmp = u; 01659 } 01660 01661 return tmp; 01662 } 01663 01664 QString KURL::fileName( bool _strip_trailing_slash ) const 01665 { 01666 QString fname; 01667 if (hasSubURL()) { // If we have a suburl, then return the filename from there 01668 KURL::List list = KURL::split(*this); 01669 KURL::List::Iterator it = list.fromLast(); 01670 return (*it).fileName(_strip_trailing_slash); 01671 } 01672 const QString &path = m_strPath; 01673 01674 int len = path.length(); 01675 if ( len == 0 ) 01676 return fname; 01677 01678 if ( _strip_trailing_slash ) 01679 { 01680 while ( len >= 1 && path[ len - 1 ] == '/' ) 01681 len--; 01682 } 01683 else if ( path[ len - 1 ] == '/' ) 01684 return fname; 01685 01686 // Does the path only consist of '/' characters ? 01687 if ( len == 1 && path[ 0 ] == '/' ) 01688 return fname; 01689 01690 // Skip last n slashes 01691 int n = 1; 01692 if (!m_strPath_encoded.isEmpty()) 01693 { 01694 // This is hairy, we need the last unencoded slash. 01695 // Count in the encoded string how many encoded slashes follow the last 01696 // unencoded one. 01697 int i = m_strPath_encoded.findRev( '/', len - 1 ); 01698 QString fileName_encoded = m_strPath_encoded.mid(i+1); 01699 n += fileName_encoded.contains("%2f", false); 01700 } 01701 int i = len; 01702 do { 01703 i = path.findRev( '/', i - 1 ); 01704 } 01705 while (--n && (i > 0)); 01706 01707 // If ( i == -1 ) => the first character is not a '/' 01708 // So it's some URL like file:blah.tgz, return the whole path 01709 if ( i == -1 ) { 01710 if ( len == (int)path.length() ) 01711 fname = path; 01712 else 01713 // Might get here if _strip_trailing_slash is true 01714 fname = path.left( len ); 01715 } 01716 else 01717 { 01718 fname = path.mid( i + 1, len - i - 1 ); // TO CHECK 01719 } 01720 return fname; 01721 } 01722 01723 void KURL::addPath( const QString& _txt ) 01724 { 01725 if (hasSubURL()) 01726 { 01727 KURL::List lst = split( *this ); 01728 KURL &u = lst.last(); 01729 u.addPath(_txt); 01730 *this = join( lst ); 01731 return; 01732 } 01733 01734 m_strPath_encoded = QString::null; 01735 01736 if ( _txt.isEmpty() ) 01737 return; 01738 01739 int i = 0; 01740 int len = m_strPath.length(); 01741 // Add the trailing '/' if it is missing 01742 if ( _txt[0] != '/' && ( len == 0 || m_strPath[ len - 1 ] != '/' ) ) 01743 m_strPath += "/"; 01744 01745 // No double '/' characters 01746 i = 0; 01747 if ( len != 0 && m_strPath[ len - 1 ] == '/' ) 01748 { 01749 while( _txt[i] == '/' ) 01750 ++i; 01751 } 01752 01753 m_strPath += _txt.mid( i ); 01754 } 01755 01756 QString KURL::directory( bool _strip_trailing_slash_from_result, 01757 bool _ignore_trailing_slash_in_path ) const 01758 { 01759 QString result = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded; 01760 if ( _ignore_trailing_slash_in_path ) 01761 result = trailingSlash( -1, result ); 01762 01763 if ( result.isEmpty() || result == "/" ) 01764 return result; 01765 01766 int i = result.findRev( "/" ); 01767 // If ( i == -1 ) => the first character is not a '/' 01768 // So it's some URL like file:blah.tgz, with no path 01769 if ( i == -1 ) 01770 return QString::null; 01771 01772 if ( i == 0 ) 01773 { 01774 result = "/"; 01775 return result; 01776 } 01777 01778 if ( _strip_trailing_slash_from_result ) 01779 result = result.left( i ); 01780 else 01781 result = result.left( i + 1 ); 01782 01783 if (!m_strPath_encoded.isEmpty()) 01784 result = decode(result); 01785 01786 return result; 01787 } 01788 01789 01790 bool KURL::cd( const QString& _dir ) 01791 { 01792 if ( _dir.isEmpty() || m_bIsMalformed ) 01793 return false; 01794 01795 if (hasSubURL()) 01796 { 01797 KURL::List lst = split( *this ); 01798 KURL &u = lst.last(); 01799 u.cd(_dir); 01800 *this = join( lst ); 01801 return true; 01802 } 01803 01804 // absolute path ? 01805 if ( _dir[0] == '/' ) 01806 { 01807 m_strPath_encoded = QString::null; 01808 m_strPath = _dir; 01809 setHTMLRef( QString::null ); 01810 m_strQuery_encoded = QString::null; 01811 return true; 01812 } 01813 01814 // Users home directory on the local disk ? 01815 if ( ( _dir[0] == '~' ) && ( m_strProtocol == fileProt )) 01816 { 01817 m_strPath_encoded = QString::null; 01818 m_strPath = QDir::homeDirPath(); 01819 m_strPath += "/"; 01820 m_strPath += _dir.right(m_strPath.length() - 1); 01821 setHTMLRef( QString::null ); 01822 m_strQuery_encoded = QString::null; 01823 return true; 01824 } 01825 01826 // relative path 01827 // we always work on the past of the first url. 01828 // Sub URLs are not touched. 01829 01830 // append '/' if necessary 01831 QString p = path(1); 01832 p += _dir; 01833 p = cleanpath( p, true, false ); 01834 setPath( p ); 01835 01836 setHTMLRef( QString::null ); 01837 m_strQuery_encoded = QString::null; 01838 01839 return true; 01840 } 01841 01842 KURL KURL::upURL( ) const 01843 { 01844 if (!query().isEmpty()) 01845 { 01846 KURL u(*this); 01847 u._setQuery(QString::null); 01848 return u; 01849 }; 01850 01851 if (!hasSubURL()) 01852 { 01853 KURL u(*this); 01854 u.cd("../"); 01855 return u; 01856 } 01857 01858 // We have a subURL. 01859 KURL::List lst = split( *this ); 01860 if (lst.isEmpty()) 01861 return KURL(); // Huh? 01862 while (true) 01863 { 01864 KURL &u = lst.last(); 01865 QString old = u.path(); 01866 u.cd("../"); 01867 if (u.path() != old) 01868 break; // Finshed. 01869 if (lst.count() == 1) 01870 break; // Finished. 01871 lst.remove(lst.fromLast()); 01872 } 01873 return join( lst ); 01874 } 01875 01876 QString KURL::htmlRef() const 01877 { 01878 if ( !hasSubURL() ) 01879 { 01880 return decode( ref() ); 01881 } 01882 01883 List lst = split( *this ); 01884 return decode( (*lst.begin()).ref() ); 01885 } 01886 01887 QString KURL::encodedHtmlRef() const 01888 { 01889 if ( !hasSubURL() ) 01890 { 01891 return ref(); 01892 } 01893 01894 List lst = split( *this ); 01895 return (*lst.begin()).ref(); 01896 } 01897 01898 void KURL::setHTMLRef( const QString& _ref ) 01899 { 01900 if ( !hasSubURL() ) 01901 { 01902 m_strRef_encoded = encode( _ref, 0, 0 /*?*/); 01903 return; 01904 } 01905 01906 List lst = split( *this ); 01907 01908 (*lst.begin()).setRef( encode( _ref, 0, 0 /*?*/) ); 01909 01910 *this = join( lst ); 01911 } 01912 01913 bool KURL::hasHTMLRef() const 01914 { 01915 if ( !hasSubURL() ) 01916 { 01917 return hasRef(); 01918 } 01919 01920 List lst = split( *this ); 01921 return (*lst.begin()).hasRef(); 01922 } 01923 01924 void 01925 KURL::setProtocol( const QString& _txt ) 01926 { 01927 m_strProtocol = _txt; 01928 if ( m_iUriMode == Auto ) m_iUriMode = uriModeForProtocol( m_strProtocol ); 01929 m_bIsMalformed = false; 01930 } 01931 01932 void 01933 KURL::setUser( const QString& _txt ) 01934 { 01935 m_strUser = _txt; 01936 } 01937 01938 void 01939 KURL::setPass( const QString& _txt ) 01940 { 01941 m_strPass = _txt; 01942 } 01943 01944 void 01945 KURL::setHost( const QString& _txt ) 01946 { 01947 if ( m_iUriMode == Auto ) 01948 m_iUriMode = URL; 01949 switch ( m_iUriMode ) 01950 { 01951 case URL: 01952 #ifndef KDE_QT_ONLY 01953 m_strHost = KIDNA::toUnicode(_txt); 01954 if (m_strHost.isEmpty()) 01955 m_strHost = _txt.lower(); // Probably an invalid hostname, but... 01956 #else 01957 m_strHost = _txt.lower(); 01958 #endif 01959 break; 01960 default: 01961 m_strHost = _txt; 01962 break; 01963 } 01964 } 01965 01966 void 01967 KURL::setPort( unsigned short int _p ) 01968 { 01969 m_iPort = _p; 01970 } 01971 01972 void KURL::setPath( const QString & path ) 01973 { 01974 if (isEmpty()) 01975 m_bIsMalformed = false; 01976 if (m_strProtocol.isEmpty()) 01977 { 01978 m_strProtocol = fileProt; 01979 } 01980 m_strPath = path; 01981 m_strPath_encoded = QString::null; 01982 if ( m_iUriMode == Auto ) 01983 m_iUriMode = URL; 01984 } 01985 01986 void KURL::setDirectory( const QString &dir) 01987 { 01988 if ( dir.endsWith("/")) 01989 setPath(dir); 01990 else 01991 setPath(dir+"/"); 01992 } 01993 01994 void KURL::setQuery( const QString &_txt, int encoding_hint) 01995 { 01996 if (_txt[0] == '?') 01997 _setQuery( _txt.mid(1), encoding_hint ); 01998 else 01999 _setQuery( _txt, encoding_hint ); 02000 } 02001 02002 // This is a private function that expects a query without '?' 02003 void KURL::_setQuery( const QString &_txt, int encoding_hint) 02004 { 02005 m_strQuery_encoded = _txt; 02006 if (!_txt.length()) 02007 return; 02008 02009 int l = m_strQuery_encoded.length(); 02010 int i = 0; 02011 QString result; 02012 while (i < l) 02013 { 02014 int s = i; 02015 // Re-encode. Break encoded string up according to the reserved 02016 // characters '&:;=/?' and re-encode part by part. 02017 while(i < l) 02018 { 02019 char c = m_strQuery_encoded[i].latin1(); 02020 if ((c == '&') || (c == ':') || (c == ';') || 02021 (c == '=') || (c == '/') || (c == '?')) 02022 break; 02023 i++; 02024 } 02025 if (i > s) 02026 { 02027 QString tmp = m_strQuery_encoded.mid(s, i-s); 02028 QString newTmp; 02029 decode( tmp, newTmp, tmp, encoding_hint, false ); 02030 result += tmp; 02031 } 02032 if (i < l) 02033 { 02034 result += m_strQuery_encoded[i]; 02035 i++; 02036 } 02037 } 02038 m_strQuery_encoded = result; 02039 } 02040 02041 QString KURL::query() const 02042 { 02043 if (m_strQuery_encoded.isNull()) 02044 return QString::null; 02045 return '?'+m_strQuery_encoded; 02046 } 02047 02048 QString KURL::decode_string(const QString &str, int encoding_hint) 02049 { 02050 return decode(str, encoding_hint); 02051 } 02052 02053 QString KURL::encode_string(const QString &str, int encoding_hint) 02054 { 02055 return encode(str, 1, encoding_hint); 02056 } 02057 02058 QString KURL::encode_string_no_slash(const QString &str, int encoding_hint) 02059 { 02060 return encode(str, 0, encoding_hint); 02061 } 02062 02063 bool urlcmp( const QString& _url1, const QString& _url2 ) 02064 { 02065 // Both empty ? 02066 if ( _url1.isEmpty() && _url2.isEmpty() ) 02067 return true; 02068 // Only one empty ? 02069 if ( _url1.isEmpty() || _url2.isEmpty() ) 02070 return false; 02071 02072 KURL::List list1 = KURL::split( _url1 ); 02073 KURL::List list2 = KURL::split( _url2 ); 02074 02075 // Malformed ? 02076 if ( list1.isEmpty() || list2.isEmpty() ) 02077 return false; 02078 02079 return ( list1 == list2 ); 02080 } 02081 02082 bool urlcmp( const QString& _url1, const QString& _url2, bool _ignore_trailing, bool _ignore_ref ) 02083 { 02084 // Both empty ? 02085 if ( _url1.isEmpty() && _url2.isEmpty() ) 02086 return true; 02087 // Only one empty ? 02088 if ( _url1.isEmpty() || _url2.isEmpty() ) 02089 return false; 02090 02091 KURL::List list1 = KURL::split( _url1 ); 02092 KURL::List list2 = KURL::split( _url2 ); 02093 02094 // Malformed ? 02095 if ( list1.isEmpty() || list2.isEmpty() ) 02096 return false; 02097 02098 unsigned int size = list1.count(); 02099 if ( list2.count() != size ) 02100 return false; 02101 02102 if ( _ignore_ref ) 02103 { 02104 (*list1.begin()).setRef(QString::null); 02105 (*list2.begin()).setRef(QString::null); 02106 } 02107 02108 KURL::List::Iterator it1 = list1.begin(); 02109 KURL::List::Iterator it2 = list2.begin(); 02110 for( ; it1 != list1.end() ; ++it1, ++it2 ) 02111 if ( !(*it1).equals( *it2, _ignore_trailing ) ) 02112 return false; 02113 02114 return true; 02115 } 02116 02117 QMap< QString, QString > KURL::queryItems( int options ) const { 02118 return queryItems(options, 0); 02119 } 02120 02121 QMap< QString, QString > KURL::queryItems( int options, int encoding_hint ) const { 02122 if ( m_strQuery_encoded.isEmpty() ) 02123 return QMap<QString,QString>(); 02124 02125 QMap< QString, QString > result; 02126 QStringList items = QStringList::split( '&', m_strQuery_encoded ); 02127 for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) { 02128 int equal_pos = (*it).find( '=' ); 02129 if ( equal_pos > 0 ) { // = is not the first char... 02130 QString name = (*it).left( equal_pos ); 02131 if ( options & CaseInsensitiveKeys ) 02132 name = name.lower(); 02133 QString value = (*it).mid( equal_pos + 1 ); 02134 if ( value.isEmpty() ) 02135 result.insert( name, QString::fromLatin1("") ); 02136 else { 02137 // ### why is decoding name not necessary? 02138 value.replace( '+', ' ' ); // + in queries means space 02139 result.insert( name, decode_string( value, encoding_hint ) ); 02140 } 02141 } else if ( equal_pos < 0 ) { // no = 02142 QString name = (*it); 02143 if ( options & CaseInsensitiveKeys ) 02144 name = name.lower(); 02145 result.insert( name, QString::null ); 02146 } 02147 } 02148 02149 return result; 02150 } 02151 02152 QString KURL::queryItem( const QString& _item ) const 02153 { 02154 return queryItem( _item, 0 ); 02155 } 02156 02157 QString KURL::queryItem( const QString& _item, int encoding_hint ) const 02158 { 02159 QString item = _item + '='; 02160 if ( m_strQuery_encoded.length() <= 1 ) 02161 return QString::null; 02162 02163 QStringList items = QStringList::split( '&', m_strQuery_encoded ); 02164 unsigned int _len = item.length(); 02165 for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it ) 02166 { 02167 if ( (*it).startsWith( item ) ) 02168 { 02169 if ( (*it).length() > _len ) 02170 { 02171 QString str = (*it).mid( _len ); 02172 str.replace( '+', ' ' ); // + in queries means space. 02173 return decode_string( str, encoding_hint ); 02174 } 02175 else // empty value 02176 return QString::fromLatin1(""); 02177 } 02178 } 02179 02180 return QString::null; 02181 } 02182 02183 void KURL::removeQueryItem( const QString& _item ) 02184 { 02185 QString item = _item + '='; 02186 if ( m_strQuery_encoded.length() <= 1 ) 02187 return; 02188 02189 QStringList items = QStringList::split( '&', m_strQuery_encoded ); 02190 for ( QStringList::Iterator it = items.begin(); it != items.end(); ) 02191 { 02192 if ( (*it).startsWith( item ) || (*it == _item) ) 02193 { 02194 QStringList::Iterator deleteIt = it; 02195 ++it; 02196 items.remove(deleteIt); 02197 } 02198 else 02199 { 02200 ++it; 02201 } 02202 } 02203 m_strQuery_encoded = items.join( "&" ); 02204 } 02205 02206 void KURL::addQueryItem( const QString& _item, const QString& _value, int encoding_hint ) 02207 { 02208 QString item = _item + '='; 02209 QString value = encode( _value, 0, encoding_hint ); 02210 02211 if (!m_strQuery_encoded.isEmpty()) 02212 m_strQuery_encoded += '&'; 02213 m_strQuery_encoded += item + value; 02214 } 02215 02216 // static 02217 KURL KURL::fromPathOrURL( const QString& text ) 02218 { 02219 if ( text.isEmpty() ) 02220 return KURL(); 02221 02222 KURL url; 02223 if (!QDir::isRelativePath(text)) 02224 url.setPath( text ); 02225 else 02226 url = text; 02227 02228 return url; 02229 } 02230 02231 static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent) 02232 { 02233 QString _base_dir(QDir::cleanDirPath(base_dir)); 02234 QString _path(QDir::cleanDirPath(path.isEmpty() || (path[0] != '/') ? _base_dir+"/"+path : path)); 02235 02236 if (_base_dir.isEmpty()) 02237 return _path; 02238 02239 if (_base_dir[_base_dir.length()-1] != '/') 02240 _base_dir.append('/'); 02241 02242 QStringList list1 = QStringList::split('/', _base_dir); 02243 QStringList list2 = QStringList::split('/', _path); 02244 02245 // Find where they meet 02246 uint level = 0; 02247 uint maxLevel = QMIN(list1.count(), list2.count()); 02248 while((level < maxLevel) && (list1[level] == list2[level])) level++; 02249 02250 QString result; 02251 // Need to go down out of the first path to the common branch. 02252 for(uint i = level; i < list1.count(); i++) 02253 result.append("../"); 02254 02255 // Now up up from the common branch to the second path. 02256 for(uint i = level; i < list2.count(); i++) 02257 result.append(list2[i]).append("/"); 02258 02259 if ((level < list2.count()) && (path[path.length()-1] != '/')) 02260 result.truncate(result.length()-1); 02261 02262 isParent = (level == list1.count()); 02263 02264 return result; 02265 } 02266 02267 QString KURL::relativePath(const QString &base_dir, const QString &path, bool *isParent) 02268 { 02269 bool parent = false; 02270 QString result = _relativePath(base_dir, path, parent); 02271 if (parent) 02272 result.prepend("./"); 02273 02274 if (isParent) 02275 *isParent = parent; 02276 02277 return result; 02278 } 02279 02280 02281 QString KURL::relativeURL(const KURL &base_url, const KURL &url, int encoding_hint) 02282 { 02283 if ((url.protocol() != base_url.protocol()) || 02284 (url.host() != base_url.host()) || 02285 (url.port() && url.port() != base_url.port()) || 02286 (url.hasUser() && url.user() != base_url.user()) || 02287 (url.hasPass() && url.pass() != base_url.pass())) 02288 { 02289 return url.url(0, encoding_hint); 02290 } 02291 02292 QString relURL; 02293 02294 if ((base_url.path() != url.path()) || (base_url.query() != url.query())) 02295 { 02296 bool dummy; 02297 QString basePath = base_url.directory(false, false); 02298 relURL = encode( _relativePath(basePath, url.path(), dummy), 1, encoding_hint); 02299 relURL += url.query(); 02300 } 02301 02302 if ( url.hasRef() ) 02303 { 02304 relURL += "#"; 02305 relURL += url.ref(); 02306 } 02307 02308 if ( relURL.isEmpty() ) 02309 return "./"; 02310 02311 return relURL; 02312 } 02313 02314 int KURL::uriMode() const 02315 { 02316 return m_iUriMode; 02317 } 02318 02319 KURL::URIMode KURL::uriModeForProtocol(const QString& protocol) 02320 { 02321 #ifndef KDE_QT_ONLY 02322 KURL::URIMode mode = Auto; 02323 if (protocol == fileProt) 02324 return URL; 02325 if (KGlobal::_instance) 02326 mode = KProtocolInfo::uriParseMode(protocol); 02327 if (mode == Auto ) { 02328 #else 02329 KURL::URIMode mode = Auto; 02330 #endif 02331 if ( protocol == "ed2k" || protocol == "sig2dat" || protocol == "slsk" || protocol == "data" ) mode = RawURI; 02332 else if ( protocol == "mailto" ) mode = Mailto; 02333 else mode = URL; 02334 #ifndef KDE_QT_ONLY 02335 } 02336 #endif 02337 return mode; 02338 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Apr 14 00:03:34 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003