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