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