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 KURL tmp( url() + rUrl, encoding_hint);
00601 *this = tmp;
00602 cleanPath(false);
00603 }
00604 else
00605 {
00606 KURL tmp( rUrl, encoding_hint);
00607 *this = tmp;
00608
00609 if (!_u.m_strUser.isEmpty() && m_strUser.isEmpty() && (_u.m_strHost == m_strHost) && (_u.m_strProtocol == m_strProtocol))
00610 {
00611 m_strUser = _u.m_strUser;
00612 m_strPass = _u.m_strPass;
00613 }
00614 cleanPath(false);
00615 }
00616 }
00617
00618 void KURL::reset()
00619 {
00620 m_strProtocol = QString::null;
00621 m_strUser = QString::null;
00622 m_strPass = QString::null;
00623 m_strHost = QString::null;
00624 m_strPath = QString::null;
00625 m_strPath_encoded = QString::null;
00626 m_strQuery_encoded = QString::null;
00627 m_strRef_encoded = QString::null;
00628 m_bIsMalformed = true;
00629 m_iPort = 0;
00630 m_iUriMode = Auto;
00631 }
00632
00633 bool KURL::isEmpty() const
00634 {
00635 return (m_strPath.isEmpty() && m_strProtocol.isEmpty());
00636 }
00637
00638 void KURL::parse( const QString& _url, int encoding_hint )
00639 {
00640 if ( _url.isEmpty() || m_iUriMode == Invalid )
00641 {
00642 m_strProtocol = _url;
00643 m_iUriMode = Invalid;
00644 return;
00645 }
00646
00647 const QChar* buf = _url.unicode();
00648 const QChar* orig = buf;
00649 uint len = _url.length();
00650 uint pos = 0;
00651
00652
00653 QChar x = buf[pos++];
00654 #ifdef Q_WS_WIN
00655
00656 const bool alpha = isalpha((int)x);
00657 if (alpha && len<2)
00658 goto NodeErr;
00659 if (alpha && buf[pos]==':' && (len==2 || (len>2 && (buf[pos+1]=='/' || buf[pos+1]=='\\'))))
00660 #else
00661 if ( x == '/' )
00662 #endif
00663 {
00664
00665 m_iUriMode = URL;
00666 m_strProtocol = fileProt;
00667 parseURL( _url, encoding_hint );
00668 return;
00669 }
00670 if ( !isalpha( (int)x ) )
00671 goto NodeErr;
00672
00673
00674
00675
00676 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
00677 buf[pos] == '+' || buf[pos] == '-')) pos++;
00678
00679 if (pos < len && buf[pos] == ':' )
00680 {
00681 m_strProtocol = QString( orig, pos ).lower();
00682 if ( m_iUriMode == Auto )
00683 m_iUriMode = uriModeForProtocol( m_strProtocol );
00684
00685 switch ( m_iUriMode )
00686 {
00687 case RawURI:
00688 parseRawURI( _url );
00689 return;
00690 case Mailto:
00691 parseMailto( _url );
00692 return;
00693 case URL:
00694 parseURL( _url, encoding_hint );
00695 return;
00696 default:
00697
00698 break;
00699 }
00700 }
00701
00702 NodeErr:
00703 reset();
00704 m_strProtocol = _url;
00705 m_iUriMode = Invalid;
00706 }
00707
00708 void KURL::parseRawURI( const QString& _url, int encoding_hint )
00709 {
00710 uint len = _url.length();
00711 const QChar* buf = _url.unicode();
00712
00713 uint pos = 0;
00714
00715
00716
00717
00718 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
00719 buf[pos] == '+' || buf[pos] == '-')) pos++;
00720
00721
00722 if (pos < len && buf[pos] == ':' )
00723 pos++;
00724 else {
00725 reset();
00726 m_strProtocol = _url;
00727 m_iUriMode = Invalid;
00728 return;
00729 }
00730
00731 if ( pos == len )
00732 m_strPath = QString::null;
00733 else
00734 m_strPath = decode( QString( buf + pos, len - pos ), encoding_hint, true );
00735
00736 m_bIsMalformed = false;
00737
00738 return;
00739 }
00740
00741 void KURL::parseMailto( const QString& _url, int encoding_hint )
00742 {
00743 parseURL( _url, encoding_hint);
00744 if ( m_bIsMalformed )
00745 return;
00746 QRegExp mailre("(.+@)(.+)");
00747 if ( mailre.exactMatch( m_strPath ) )
00748 {
00749 #ifndef KDE_QT_ONLY
00750 QString host = KIDNA::toUnicode( mailre.cap( 2 ) );
00751 if (host.isEmpty())
00752 host = mailre.cap( 2 ).lower();
00753 #else
00754 QString host = mailre.cap( 2 ).lower();
00755 #endif
00756 m_strPath = mailre.cap( 1 ) + host;
00757 }
00758 }
00759
00760 void KURL::parseURL( const QString& _url, int encoding_hint )
00761 {
00762 QString port;
00763 bool badHostName = false;
00764 int start = 0;
00765 uint len = _url.length();
00766 const QChar* buf = _url.unicode();
00767
00768 QChar delim;
00769 QString tmp;
00770
00771 uint pos = 0;
00772
00773
00774 QChar x = buf[pos++];
00775 #ifdef Q_WS_WIN
00776
00777 const bool alpha = isalpha((int)x);
00778 if (alpha && len<2)
00779 goto NodeErr;
00780 if (alpha && buf[pos]==':' && (len==2 || (len>2 && (buf[pos+1]=='/' || buf[pos+1]=='\\'))))
00781 #else
00782 if ( x == '/' )
00783 #endif
00784 goto Node9;
00785 if ( !isalpha( (int)x ) )
00786 goto NodeErr;
00787
00788
00789
00790
00791 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
00792 buf[pos] == '+' || buf[pos] == '-')) pos++;
00793
00794
00795 if ( pos+2 < len && buf[pos] == ':' && buf[pos+1] == '/' && buf[pos+2] == '/' )
00796 {
00797 pos += 3;
00798 }
00799 else if (pos+1 < len && buf[pos] == ':' )
00800 {
00801 pos++;
00802 start = pos;
00803 goto Node9;
00804 }
00805 else
00806 goto NodeErr;
00807
00808
00809 if ( pos == len )
00810 goto NodeErr;
00811 start = pos;
00812
00813
00814 if (buf[pos] == '[')
00815 goto Node8;
00816
00817 x = buf[pos];
00818 while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') )
00819 {
00820 if ((x == '\"') || (x == ';') || (x == '<'))
00821 badHostName = true;
00822 if (++pos == len)
00823 break;
00824 x = buf[pos];
00825 }
00826 if ( pos == len )
00827 {
00828 if (badHostName)
00829 goto NodeErr;
00830
00831 setHost(decode(QString( buf + start, pos - start ), encoding_hint));
00832 goto NodeOk;
00833 }
00834 if ( x == '@' )
00835 {
00836 m_strUser = decode(QString( buf + start, pos - start ), encoding_hint);
00837 pos++;
00838 goto Node7;
00839 }
00840 else if ( (x == '/') || (x == '?') || (x == '#'))
00841 {
00842 if (badHostName)
00843 goto NodeErr;
00844
00845 setHost(decode(QString( buf + start, pos - start ), encoding_hint));
00846 start = pos;
00847 goto Node9;
00848 }
00849 else if ( x != ':' )
00850 goto NodeErr;
00851 m_strUser = decode(QString( buf + start, pos - start ), encoding_hint);
00852 pos++;
00853
00854
00855 if ( pos == len )
00856 goto NodeErr;
00857 start = pos++;
00858
00859
00860 while( (pos < len) &&
00861 (buf[pos] != '@') &&
00862 (buf[pos] != '/') &&
00863 (buf[pos] != '?') &&
00864 (buf[pos] != '#')) pos++;
00865
00866
00867 if ( (pos == len) || (buf[pos] != '@') )
00868 {
00869
00870 if (badHostName)
00871 goto NodeErr;
00872 setHost(m_strUser);
00873 m_strUser = QString::null;
00874 QString tmp( buf + start, pos - start );
00875 char *endptr;
00876 m_iPort = (unsigned short int)strtol(tmp.ascii(), &endptr, 10);
00877 if ((pos == len) && (strlen(endptr) == 0))
00878 goto NodeOk;
00879
00880 pos -= strlen(endptr);
00881 if ((buf[pos] != '@') &&
00882 (buf[pos] != '/') &&
00883 (buf[pos] != '?') &&
00884 (buf[pos] != '#'))
00885 goto NodeErr;
00886
00887 start = pos;
00888 goto Node9;
00889 }
00890 m_strPass = decode(QString( buf + start, pos - start), encoding_hint);
00891 pos++;
00892
00893
00894 Node7:
00895 if ( pos == len )
00896 goto NodeErr;
00897
00898 Node8:
00899 if (buf[pos] == '[')
00900 {
00901
00902 start = ++pos;
00903
00904 if (pos == len)
00905 {
00906 badHostName = true;
00907 goto NodeErr;
00908 }
00909
00910 badHostName = false;
00911 x = buf[pos];
00912 while( (x != ']') )
00913 {
00914 if ((x == '\"') || (x == ';') || (x == '<'))
00915 badHostName = true;
00916 if (++pos == len)
00917 {
00918 badHostName = true;
00919 break;
00920 }
00921 x = buf[pos];
00922 }
00923 if (badHostName)
00924 goto NodeErr;
00925 setHost(decode(QString( buf + start, pos - start ), encoding_hint));
00926 if (pos < len) pos++;
00927 if (pos == len)
00928 goto NodeOk;
00929 }
00930 else
00931 {
00932
00933 start = pos;
00934
00935
00936 badHostName = false;
00937 x = buf[pos];
00938 while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') )
00939 {
00940 if ((x == '\"') || (x == ';') || (x == '<'))
00941 badHostName = true;
00942 if (++pos == len)
00943 break;
00944 x = buf[pos];
00945 }
00946 if (badHostName)
00947 goto NodeErr;
00948 if ( pos == len )
00949 {
00950 setHost(decode(QString( buf + start, pos - start ), encoding_hint));
00951 goto NodeOk;
00952 }
00953 setHost(decode(QString( buf + start, pos - start ), encoding_hint));
00954 }
00955 x = buf[pos];
00956 if ( x == '/' || x == '#' || x == '?' )
00957 {
00958 start = pos;
00959 goto Node9;
00960 }
00961 else if ( x != ':' )
00962 goto NodeErr;
00963 pos++;
00964
00965
00966 if ( pos == len )
00967 goto NodeErr;
00968 start = pos;
00969 if ( !isdigit( buf[pos++] ) )
00970 goto NodeErr;
00971
00972
00973 while( pos < len && isdigit( buf[pos] ) ) pos++;
00974 port = QString( buf + start, pos - start );
00975 m_iPort = port.toUShort();
00976 if ( pos == len )
00977 goto NodeOk;
00978 start = pos;
00979
00980 Node9:
00981
00982 while( pos < len && buf[pos] != '#' && buf[pos]!='?' ) pos++;
00983
00984 tmp = QString( buf + start, pos - start );
00985
00986 setEncodedPath( tmp, encoding_hint );
00987
00988 if ( pos == len )
00989 goto NodeOk;
00990
00991
00992 delim = (buf[pos++]=='#'?'?':'#');
00993
00994 start = pos;
00995
00996 while(pos < len && buf[pos]!=delim ) pos++;
00997
00998 tmp = QString(buf + start, pos - start);
00999 if (delim=='#')
01000 _setQuery(tmp, encoding_hint);
01001 else
01002 m_strRef_encoded = tmp;
01003
01004 if (pos == len)
01005 goto NodeOk;
01006
01007
01008 tmp = QString( buf + pos + 1, len - pos - 1);
01009 if (delim == '#')
01010 m_strRef_encoded = tmp;
01011 else
01012 _setQuery(tmp, encoding_hint);
01013
01014 NodeOk:
01015
01016 m_bIsMalformed = false;
01017
01018
01019 if (m_strProtocol.isEmpty())
01020 {
01021 m_iUriMode = URL;
01022 m_strProtocol = fileProt;
01023 }
01024 return;
01025
01026 NodeErr:
01027
01028 reset();
01029 m_strProtocol = _url;
01030 m_iUriMode = Invalid;
01031 }
01032
01033 KURL& KURL::operator=( const QString& _url )
01034 {
01035 reset();
01036 parse( _url );
01037
01038 return *this;
01039 }
01040
01041 KURL& KURL::operator=( const char * _url )
01042 {
01043 reset();
01044 parse( QString::fromLatin1(_url) );
01045
01046 return *this;
01047 }
01048
01049 #ifndef QT_NO_NETWORKPROTOCOL
01050 KURL& KURL::operator=( const QUrl & u )
01051 {
01052 m_strProtocol = u.protocol();
01053 m_iUriMode = Auto;
01054 m_strUser = u.user();
01055 m_strPass = u.password();
01056 m_strHost = u.host();
01057 m_strPath = u.path( false );
01058 m_strPath_encoded = QString::null;
01059 m_strQuery_encoded = u.query();
01060 m_strRef_encoded = u.ref();
01061 m_bIsMalformed = !u.isValid();
01062 m_iPort = u.port();
01063
01064 return *this;
01065 }
01066 #endif
01067
01068 KURL& KURL::operator=( const KURL& _u )
01069 {
01070 m_strProtocol = _u.m_strProtocol;
01071 m_strUser = _u.m_strUser;
01072 m_strPass = _u.m_strPass;
01073 m_strHost = _u.m_strHost;
01074 m_strPath = _u.m_strPath;
01075 m_strPath_encoded = _u.m_strPath_encoded;
01076 m_strQuery_encoded = _u.m_strQuery_encoded;
01077 m_strRef_encoded = _u.m_strRef_encoded;
01078 m_bIsMalformed = _u.m_bIsMalformed;
01079 m_iPort = _u.m_iPort;
01080 m_iUriMode = _u.m_iUriMode;
01081
01082 return *this;
01083 }
01084
01085 bool KURL::operator<( const KURL& _u) const
01086 {
01087 int i;
01088 if (!_u.isValid())
01089 {
01090 if (!isValid())
01091 {
01092 i = m_strProtocol.compare(_u.m_strProtocol);
01093 return (i < 0);
01094 }
01095 return false;
01096 }
01097 if (!isValid())
01098 return true;
01099
01100 i = m_strProtocol.compare(_u.m_strProtocol);
01101 if (i) return (i < 0);
01102
01103 i = m_strHost.compare(_u.m_strHost);
01104 if (i) return (i < 0);
01105
01106 if (m_iPort != _u.m_iPort) return (m_iPort < _u.m_iPort);
01107
01108 i = m_strPath.compare(_u.m_strPath);
01109 if (i) return (i < 0);
01110
01111 i = m_strQuery_encoded.compare(_u.m_strQuery_encoded);
01112 if (i) return (i < 0);
01113
01114 i = m_strRef_encoded.compare(_u.m_strRef_encoded);
01115 if (i) return (i < 0);
01116
01117 i = m_strUser.compare(_u.m_strUser);
01118 if (i) return (i < 0);
01119
01120 i = m_strPass.compare(_u.m_strPass);
01121 if (i) return (i < 0);
01122
01123 return false;
01124 }
01125
01126 bool KURL::operator==( const KURL& _u ) const
01127 {
01128 if ( !isValid() || !_u.isValid() )
01129 return false;
01130
01131 if ( m_strProtocol == _u.m_strProtocol &&
01132 m_strUser == _u.m_strUser &&
01133 m_strPass == _u.m_strPass &&
01134 m_strHost == _u.m_strHost &&
01135 m_strPath == _u.m_strPath &&
01136
01137 ( m_strPath_encoded.isNull() || _u.m_strPath_encoded.isNull() ||
01138 m_strPath_encoded == _u.m_strPath_encoded ) &&
01139 m_strQuery_encoded == _u.m_strQuery_encoded &&
01140 m_strRef_encoded == _u.m_strRef_encoded &&
01141 m_iPort == _u.m_iPort )
01142 {
01143 return true;
01144 }
01145
01146 return false;
01147 }
01148
01149 bool KURL::operator==( const QString& _u ) const
01150 {
01151 KURL u( _u );
01152 return ( *this == u );
01153 }
01154
01155 bool KURL::cmp( const KURL &u, bool ignore_trailing ) const
01156 {
01157 return equals( u, ignore_trailing );
01158 }
01159
01160 bool KURL::equals( const KURL &_u, bool ignore_trailing ) const
01161 {
01162 if ( !isValid() || !_u.isValid() )
01163 return false;
01164
01165 if ( ignore_trailing )
01166 {
01167 QString path1 = path(1);
01168 QString path2 = _u.path(1);
01169 if ( path1 != path2 )
01170 return false;
01171
01172 if ( m_strProtocol == _u.m_strProtocol &&
01173 m_strUser == _u.m_strUser &&
01174 m_strPass == _u.m_strPass &&
01175 m_strHost == _u.m_strHost &&
01176 m_strQuery_encoded == _u.m_strQuery_encoded &&
01177 m_strRef_encoded == _u.m_strRef_encoded &&
01178 m_iPort == _u.m_iPort )
01179 return true;
01180
01181 return false;
01182 }
01183
01184 return ( *this == _u );
01185 }
01186
01187 bool KURL::isParentOf( const KURL& _u ) const
01188 {
01189 if ( !isValid() || !_u.isValid() )
01190 return false;
01191
01192 if ( m_strProtocol == _u.m_strProtocol &&
01193 m_strUser == _u.m_strUser &&
01194 m_strPass == _u.m_strPass &&
01195 m_strHost == _u.m_strHost &&
01196 m_strQuery_encoded == _u.m_strQuery_encoded &&
01197 m_strRef_encoded == _u.m_strRef_encoded &&
01198 m_iPort == _u.m_iPort )
01199 {
01200 if ( path().isEmpty() || _u.path().isEmpty() )
01201 return false;
01202
01203 QString p1( cleanpath( path(), true, false ) );
01204 if ( p1[p1.length()-1] != '/' )
01205 p1 += '/';
01206 QString p2( cleanpath( _u.path(), true, false ) );
01207 if ( p2[p2.length()-1] != '/' )
01208 p2 += '/';
01209
01210
01211
01212
01213
01214 return p2.startsWith( p1 );
01215 }
01216 return false;
01217 }
01218
01219 void KURL::setFileName( const QString& _txt )
01220 {
01221 m_strRef_encoded = QString::null;
01222 int i = 0;
01223 while( _txt[i] == '/' ) ++i;
01224 QString tmp;
01225 if ( i )
01226 tmp = _txt.mid( i );
01227 else
01228 tmp = _txt;
01229
01230 QString path = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded;
01231 if ( path.isEmpty() )
01232 path = "/";
01233 else
01234 {
01235 int lastSlash = path.findRev( '/' );
01236 if ( lastSlash == -1)
01237 {
01238
01239
01240 path = "/";
01241 }
01242 else if ( path.right(1) != "/" )
01243 path.truncate( lastSlash+1 );
01244 }
01245 if (m_strPath_encoded.isEmpty())
01246 {
01247 path += tmp;
01248 setPath( path );
01249 }
01250 else
01251 {
01252 path += encode_string(tmp);
01253 setEncodedPath( path );
01254 }
01255 cleanPath();
01256 }
01257
01258 void KURL::cleanPath( bool cleanDirSeparator )
01259 {
01260 if (m_iUriMode != URL) return;
01261 m_strPath = cleanpath(m_strPath, cleanDirSeparator, false);
01262
01263 m_strPath_encoded = cleanpath(m_strPath_encoded, cleanDirSeparator, true);
01264 }
01265
01266 static QString trailingSlash( int _trailing, const QString &path )
01267 {
01268 QString result = path;
01269
01270 if ( _trailing == 0 )
01271 return result;
01272 else if ( _trailing == 1 )
01273 {
01274 int len = result.length();
01275 if ( (len == 0) || (result[ len - 1 ] != '/') )
01276 result += "/";
01277 return result;
01278 }
01279 else if ( _trailing == -1 )
01280 {
01281 if ( result == "/" )
01282 return result;
01283 int len = result.length();
01284 while (len > 1 && result[ len - 1 ] == '/')
01285 {
01286 len--;
01287 }
01288 result.truncate( len );
01289 return result;
01290 }
01291 else {
01292 assert( 0 );
01293 return QString::null;
01294 }
01295 }
01296
01297 void KURL::adjustPath( int _trailing )
01298 {
01299 if (!m_strPath_encoded.isEmpty())
01300 {
01301 m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded );
01302 }
01303 m_strPath = trailingSlash( _trailing, m_strPath );
01304 }
01305
01306
01307 QString KURL::encodedPathAndQuery( int _trailing, bool _no_empty_path, int encoding_hint ) const
01308 {
01309 QString tmp;
01310 if (!m_strPath_encoded.isEmpty() && encoding_hint == 0)
01311 {
01312 tmp = trailingSlash( _trailing, m_strPath_encoded );
01313 }
01314 else
01315 {
01316 tmp = path( _trailing );
01317 if ( _no_empty_path && tmp.isEmpty() )
01318 tmp = "/";
01319 if (m_iUriMode == Mailto)
01320 {
01321 tmp = encode( tmp, 2, encoding_hint );
01322 }
01323 else
01324 {
01325 tmp = encode( tmp, 1, encoding_hint );
01326 }
01327 }
01328
01329
01330 if (!m_strQuery_encoded.isNull())
01331 tmp += '?' + m_strQuery_encoded;
01332 return tmp;
01333 }
01334
01335 void KURL::setEncodedPath( const QString& _txt, int encoding_hint )
01336 {
01337 m_strPath_encoded = _txt;
01338
01339 decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint );
01340
01341 if (m_strProtocol == fileProt)
01342 m_strPath_encoded = QString::null;
01343
01344 if ( m_iUriMode == Auto )
01345 m_iUriMode = URL;
01346 }
01347
01348
01349 void KURL::setEncodedPathAndQuery( const QString& _txt, int encoding_hint )
01350 {
01351 int pos = _txt.find( '?' );
01352 if ( pos == -1 )
01353 {
01354 setEncodedPath(_txt, encoding_hint);
01355 m_strQuery_encoded = QString::null;
01356 }
01357 else
01358 {
01359 setEncodedPath(_txt.left( pos ), encoding_hint);
01360 _setQuery(_txt.right(_txt.length() - pos - 1), encoding_hint);
01361 }
01362 }
01363
01364 QString KURL::path( int _trailing ) const
01365 {
01366 return trailingSlash( _trailing, path() );
01367 }
01368
01369 bool KURL::isLocalFile() const
01370 {
01371 if ( (m_strProtocol != fileProt ) || hasSubURL() )
01372 return false;
01373
01374 if (m_strHost.isEmpty() || (m_strHost == "localhost"))
01375 return true;
01376
01377 char hostname[ 256 ];
01378 hostname[ 0 ] = '\0';
01379 if (!gethostname( hostname, 255 ))
01380 hostname[sizeof(hostname)-1] = '\0';
01381
01382 for(char *p = hostname; *p; p++)
01383 *p = tolower(*p);
01384
01385 return (m_strHost == hostname);
01386 }
01387
01388 void KURL::setFileEncoding(const QString &encoding)
01389 {
01390 if (!isLocalFile())
01391 return;
01392
01393 QString q = query();
01394
01395 if (!q.isEmpty() && (q[0] == '?'))
01396 q = q.mid(1);
01397
01398 QStringList args = QStringList::split('&', q);
01399 for(QStringList::Iterator it = args.begin();
01400 it != args.end();)
01401 {
01402 QString s = decode_string(*it);
01403 if (s.startsWith("charset="))
01404 it = args.erase(it);
01405 else
01406 ++it;
01407 }
01408 if (!encoding.isEmpty())
01409 args.append("charset="+encode_string(encoding));
01410
01411 if (args.isEmpty())
01412 _setQuery(QString::null);
01413 else
01414 _setQuery(args.join("&"));
01415 }
01416
01417 QString KURL::fileEncoding() const
01418 {
01419 if (!isLocalFile())
01420 return QString::null;
01421
01422 QString q = query();
01423
01424 if (q.isEmpty())
01425 return QString::null;
01426
01427 if (q[0] == '?')
01428 q = q.mid(1);
01429
01430 QStringList args = QStringList::split('&', q);
01431 for(QStringList::ConstIterator it = args.begin();
01432 it != args.end();
01433 ++it)
01434 {
01435 QString s = decode_string(*it);
01436 if (s.startsWith("charset="))
01437 return s.mid(8);
01438 }
01439 return QString::null;
01440 }
01441
01442 bool KURL::hasSubURL() const
01443 {
01444 if ( m_strProtocol.isEmpty() || m_bIsMalformed )
01445 return false;
01446 if (m_strRef_encoded.isEmpty())
01447 return false;
01448 if (m_strRef_encoded.startsWith("gzip:"))
01449 return true;
01450 if (m_strRef_encoded.startsWith("bzip:"))
01451 return true;
01452 if (m_strRef_encoded.startsWith("bzip2:"))
01453 return true;
01454 if (m_strRef_encoded.startsWith("tar:"))
01455 return true;
01456 if (m_strRef_encoded.startsWith("ar:"))
01457 return true;
01458 if (m_strRef_encoded.startsWith("zip:"))
01459 return true;
01460 if ( m_strProtocol == "error" )
01461 return true;
01462 return false;
01463 }
01464
01465 QString KURL::url( int _trailing, int encoding_hint ) const
01466 {
01467 if( m_bIsMalformed )
01468 {
01469
01470
01471
01472 return m_strProtocol;
01473 }
01474
01475 QString u = m_strProtocol;
01476 if (!u.isEmpty())
01477 u += ":";
01478
01479 if ( hasHost() || (m_strProtocol == fileProt) )
01480 {
01481 u += "//";
01482 if ( hasUser() )
01483 {
01484 u += encode(m_strUser, 0, encoding_hint);
01485 if ( hasPass() )
01486 {
01487 u += ":";
01488 u += encode(m_strPass, 0, encoding_hint);
01489 }
01490 u += "@";
01491 }
01492 if ( m_iUriMode == URL )
01493 {
01494 bool IPv6 = (m_strHost.find(':') != -1);
01495 if (IPv6)
01496 u += '[' + m_strHost + ']';
01497 else
01498 u += encodeHost(m_strHost, true, encoding_hint);
01499 if ( m_iPort != 0 ) {
01500 QString buffer;
01501 buffer.sprintf( ":%u", m_iPort );
01502 u += buffer;
01503 }
01504 }
01505 else
01506 {
01507 u += m_strHost;
01508 }
01509 }
01510
01511 if ( m_iUriMode == URL || m_iUriMode == Mailto )
01512 u += encodedPathAndQuery( _trailing, false, encoding_hint );
01513 else
01514 u += encode( m_strPath, 21, encoding_hint, true );
01515
01516 if ( hasRef() )
01517 {
01518 u += "#";
01519 u += m_strRef_encoded;
01520 }
01521
01522 return u;
01523 }
01524
01525 QString KURL::prettyURL( int _trailing ) const
01526 {
01527 if( m_bIsMalformed )
01528 {
01529
01530
01531
01532 return m_strProtocol;
01533 }
01534
01535 QString u = m_strProtocol;
01536 if (!u.isEmpty())
01537 u += ":";
01538
01539 if ( hasHost() || (m_strProtocol == fileProt) )
01540 {
01541 u += "//";
01542 if ( hasUser() )
01543 {
01544 QString s = m_strUser;
01545 #ifndef KDE_QT_ONLY
01546
01547 if (!hasPass())
01548 s = KStringHandler::csqueeze(s, 16);
01549 #endif
01550 u += encode(s, 0, 0);
01551
01552 u += "@";
01553 }
01554 if ( m_iUriMode == URL )
01555 {
01556 bool IPv6 = (m_strHost.find(':') != -1);
01557 if (IPv6)
01558 {
01559 u += '[' + m_strHost + ']';
01560 }
01561 else
01562 {
01563 u += lazy_encode(m_strHost);
01564 }
01565 }
01566 else
01567 {
01568 u += lazy_encode(m_strHost);
01569 }
01570 if ( m_iPort != 0 ) {
01571 QString buffer;
01572 buffer.sprintf( ":%u", m_iPort );
01573 u += buffer;
01574 }
01575 }
01576
01577 if (m_iUriMode == Mailto)
01578 {
01579 u += lazy_encode( m_strPath, false );
01580 }
01581 else
01582 {
01583 u += trailingSlash( _trailing, lazy_encode( m_strPath ) );
01584 }
01585
01586 if (!m_strQuery_encoded.isNull())
01587 u += '?' + m_strQuery_encoded;
01588
01589 if ( hasRef() )
01590 {
01591 u += "#";
01592 u += m_strRef_encoded;
01593 }
01594
01595 return u;
01596 }
01597
01598 QString KURL::prettyURL( int _trailing, AdjustementFlags _flags) const
01599 {
01600 QString u = prettyURL(_trailing);
01601 if (_flags & StripFileProtocol && u.startsWith("file://")) {
01602 u.remove(0, 7);
01603 #ifdef Q_WS_WIN
01604 return QDir::convertSeparators(u);
01605 #endif
01606 }
01607 return u;
01608 }
01609
01610 QString KURL::pathOrURL() const
01611 {
01612 if ( isLocalFile() && m_strRef_encoded.isNull() && m_strQuery_encoded.isNull() ) {
01613 return path();
01614 } else {
01615 return prettyURL();
01616 }
01617 }
01618
01619 QString KURL::htmlURL() const
01620 {
01621 return QStyleSheet::escape(prettyURL());
01622 }
01623
01624 KURL::List KURL::split( const KURL& _url )
01625 {
01626 QString ref;
01627 KURL::List lst;
01628 KURL url = _url;
01629
01630 while(true)
01631 {
01632 KURL u = url;
01633 u.m_strRef_encoded = QString::null;
01634 lst.append(u);
01635 if (url.hasSubURL())
01636 {
01637 url = KURL(url.m_strRef_encoded);
01638 }
01639 else
01640 {
01641 ref = url.m_strRef_encoded;
01642 break;
01643 }
01644 }
01645
01646
01647 KURL::List::Iterator it;
01648 for( it = lst.begin() ; it != lst.end(); ++it )
01649 {
01650 (*it).m_strRef_encoded = ref;
01651 }
01652
01653 return lst;
01654 }
01655
01656 KURL::List KURL::split( const QString& _url )
01657 {
01658 return split(KURL(_url));
01659 }
01660
01661 KURL KURL::join( const KURL::List & lst )
01662 {
01663 if (lst.isEmpty()) return KURL();
01664 KURL tmp;
01665
01666 KURL::List::ConstIterator first = lst.fromLast();
01667 for( KURL::List::ConstIterator it = first; it != lst.end(); --it )
01668 {
01669 KURL u(*it);
01670 if (it != first)
01671 {
01672 if (!u.m_strRef_encoded) u.m_strRef_encoded = tmp.url();
01673 else u.m_strRef_encoded += "#" + tmp.url();
01674 }
01675 tmp = u;
01676 }
01677
01678 return tmp;
01679 }
01680
01681 QString KURL::fileName( bool _strip_trailing_slash ) const
01682 {
01683 QString fname;
01684 if (hasSubURL()) {
01685 KURL::List list = KURL::split(*this);
01686 KURL::List::Iterator it = list.fromLast();
01687 return (*it).fileName(_strip_trailing_slash);
01688 }
01689 const QString &path = m_strPath;
01690
01691 int len = path.length();
01692 if ( len == 0 )
01693 return fname;
01694
01695 if ( _strip_trailing_slash )
01696 {
01697 while ( len >= 1 && path[ len - 1 ] == '/' )
01698 len--;
01699 }
01700 else if ( path[ len - 1 ] == '/' )
01701 return fname;
01702
01703
01704 if ( len == 1 && path[ 0 ] == '/' )
01705 return fname;
01706
01707
01708 int n = 1;
01709 if (!m_strPath_encoded.isEmpty())
01710 {
01711
01712
01713
01714 int i = m_strPath_encoded.findRev( '/', len - 1 );
01715 QString fileName_encoded = m_strPath_encoded.mid(i+1);
01716 n += fileName_encoded.contains("%2f", false);
01717 }
01718 int i = len;
01719 do {
01720 i = path.findRev( '/', i - 1 );
01721 }
01722 while (--n && (i > 0));
01723
01724
01725
01726 if ( i == -1 ) {
01727 if ( len == (int)path.length() )
01728 fname = path;
01729 else
01730
01731 fname = path.left( len );
01732 }
01733 else
01734 {
01735 fname = path.mid( i + 1, len - i - 1 );
01736 }
01737 return fname;
01738 }
01739
01740 void KURL::addPath( const QString& _txt )
01741 {
01742 if (hasSubURL())
01743 {
01744 KURL::List lst = split( *this );
01745 KURL &u = lst.last();
01746 u.addPath(_txt);
01747 *this = join( lst );
01748 return;
01749 }
01750
01751 m_strPath_encoded = QString::null;
01752
01753 if ( _txt.isEmpty() )
01754 return;
01755
01756 int i = 0;
01757 int len = m_strPath.length();
01758
01759 if ( _txt[0] != '/' && ( len == 0 || m_strPath[ len - 1 ] != '/' ) )
01760 m_strPath += "/";
01761
01762
01763 i = 0;
01764 if ( len != 0 && m_strPath[ len - 1 ] == '/' )
01765 {
01766 while( _txt[i] == '/' )
01767 ++i;
01768 }
01769
01770 m_strPath += _txt.mid( i );
01771 }
01772
01773 QString KURL::directory( bool _strip_trailing_slash_from_result,
01774 bool _ignore_trailing_slash_in_path ) const
01775 {
01776 QString result = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded;
01777 if ( _ignore_trailing_slash_in_path )
01778 result = trailingSlash( -1, result );
01779
01780 if ( result.isEmpty() || result == "/" )
01781 return result;
01782
01783 int i = result.findRev( "/" );
01784
01785
01786 if ( i == -1 )
01787 return QString::null;
01788
01789 if ( i == 0 )
01790 {
01791 result = "/";
01792 return result;
01793 }
01794
01795 if ( _strip_trailing_slash_from_result )
01796 result = result.left( i );
01797 else
01798 result = result.left( i + 1 );
01799
01800 if (!m_strPath_encoded.isEmpty())
01801 result = decode(result);
01802
01803 return result;
01804 }
01805
01806
01807 bool KURL::cd( const QString& _dir )
01808 {
01809 if ( _dir.isEmpty() || m_bIsMalformed )
01810 return false;
01811
01812 if (hasSubURL())
01813 {
01814 KURL::List lst = split( *this );
01815 KURL &u = lst.last();
01816 u.cd(_dir);
01817 *this = join( lst );
01818 return true;
01819 }
01820
01821
01822 if ( _dir[0] == '/' )
01823 {
01824 m_strPath_encoded = QString::null;
01825 m_strPath = _dir;
01826 setHTMLRef( QString::null );
01827 m_strQuery_encoded = QString::null;
01828 return true;
01829 }
01830
01831
01832 if ( ( _dir[0] == '~' ) && ( m_strProtocol == fileProt ))
01833 {
01834 m_strPath_encoded = QString::null;
01835 m_strPath = QDir::homeDirPath();
01836 m_strPath += "/";
01837 m_strPath += _dir.right(m_strPath.length() - 1);
01838 setHTMLRef( QString::null );
01839 m_strQuery_encoded = QString::null;
01840 return true;
01841 }
01842
01843
01844
01845
01846
01847
01848 QString p = path(1);
01849 p += _dir;
01850 p = cleanpath( p, true, false );
01851 setPath( p );
01852
01853 setHTMLRef( QString::null );
01854 m_strQuery_encoded = QString::null;
01855
01856 return true;
01857 }
01858
01859 KURL KURL::upURL( ) const
01860 {
01861 if (!query().isEmpty())
01862 {
01863 KURL u(*this);
01864 u._setQuery(QString::null);
01865 return u;
01866 };
01867
01868 if (!hasSubURL())
01869 {
01870 KURL u(*this);
01871
01872 u.cd("../");
01873
01874 return u;
01875 }
01876
01877
01878 KURL::List lst = split( *this );
01879 if (lst.isEmpty())
01880 return KURL();
01881 while (true)
01882 {
01883 KURL &u = lst.last();
01884 QString old = u.path();
01885 u.cd("../");
01886 if (u.path() != old)
01887 break;
01888 if (lst.count() == 1)
01889 break;
01890 lst.remove(lst.fromLast());
01891 }
01892 return join( lst );
01893 }
01894
01895 QString KURL::htmlRef() const
01896 {
01897 if ( !hasSubURL() )
01898 {
01899 return decode( ref() );
01900 }
01901
01902 List lst = split( *this );
01903 return decode( (*lst.begin()).ref() );
01904 }
01905
01906 QString KURL::encodedHtmlRef() const
01907 {
01908 if ( !hasSubURL() )
01909 {
01910 return ref();
01911 }
01912
01913 List lst = split( *this );
01914 return (*lst.begin()).ref();
01915 }
01916
01917 void KURL::setHTMLRef( const QString& _ref )
01918 {
01919 if ( !hasSubURL() )
01920 {
01921 m_strRef_encoded = encode( _ref, 0, 0 );
01922 return;
01923 }
01924
01925 List lst = split( *this );
01926
01927 (*lst.begin()).setRef( encode( _ref, 0, 0 ) );
01928
01929 *this = join( lst );
01930 }
01931
01932 bool KURL::hasHTMLRef() const
01933 {
01934 if ( !hasSubURL() )
01935 {
01936 return hasRef();
01937 }
01938
01939 List lst = split( *this );
01940 return (*lst.begin()).hasRef();
01941 }
01942
01943 void
01944 KURL::setProtocol( const QString& _txt )
01945 {
01946 m_strProtocol = _txt;
01947 if ( m_iUriMode == Auto ) m_iUriMode = uriModeForProtocol( m_strProtocol );
01948 m_bIsMalformed = false;
01949 }
01950
01951 void
01952 KURL::setUser( const QString& _txt )
01953 {
01954 if ( _txt.isEmpty() )
01955 m_strUser = QString::null;
01956 else
01957 m_strUser = _txt;
01958 }
01959
01960 void
01961 KURL::setPass( const QString& _txt )
01962 {
01963 if ( _txt.isEmpty() )
01964 m_strPass = QString::null;
01965 else
01966 m_strPass = _txt;
01967 }
01968
01969 void
01970 KURL::setHost( const QString& _txt )
01971 {
01972 if ( m_iUriMode == Auto )
01973 m_iUriMode = URL;
01974 switch ( m_iUriMode )
01975 {
01976 case URL:
01977 #ifndef KDE_QT_ONLY
01978 m_strHost = KIDNA::toUnicode(_txt);
01979 if (m_strHost.isEmpty())
01980 m_strHost = _txt.lower();
01981 #else
01982 m_strHost = _txt.lower();
01983 #endif
01984 break;
01985 default:
01986 m_strHost = _txt;
01987 break;
01988 }
01989 }
01990
01991 void
01992 KURL::setPort( unsigned short int _p )
01993 {
01994 m_iPort = _p;
01995 }
01996
01997 void KURL::setPath( const QString & path )
01998 {
01999 if (isEmpty())
02000 m_bIsMalformed = false;
02001 if (m_strProtocol.isEmpty())
02002 {
02003 m_strProtocol = fileProt;
02004 }
02005 m_strPath = path;
02006 m_strPath_encoded = QString::null;
02007 if ( m_iUriMode == Auto )
02008 m_iUriMode = URL;
02009 }
02010
02011 void KURL::setDirectory( const QString &dir)
02012 {
02013 if ( dir.endsWith("/"))
02014 setPath(dir);
02015 else
02016 setPath(dir+"/");
02017 }
02018
02019 void KURL::setQuery( const QString &_txt, int encoding_hint)
02020 {
02021 if (_txt[0] == '?')
02022 _setQuery( _txt.length() > 1 ? _txt.mid(1) : "" , encoding_hint );
02023 else
02024 _setQuery( _txt, encoding_hint );
02025 }
02026
02027
02028 void KURL::_setQuery( const QString &_txt, int encoding_hint)
02029 {
02030 m_strQuery_encoded = _txt;
02031 if (!_txt.length())
02032 return;
02033
02034 int l = m_strQuery_encoded.length();
02035 int i = 0;
02036 QString result;
02037 while (i < l)
02038 {
02039 int s = i;
02040
02041
02042 while(i < l)
02043 {
02044 char c = m_strQuery_encoded[i].latin1();
02045 if ((c == '&') || (c == ':') || (c == ';') ||
02046 (c == '=') || (c == '/') || (c == '?'))
02047 break;
02048 i++;
02049 }
02050 if (i > s)
02051 {
02052 QString tmp = m_strQuery_encoded.mid(s, i-s);
02053 QString newTmp;
02054 decode( tmp, newTmp, tmp, encoding_hint, false );
02055 result += tmp;
02056 }
02057 if (i < l)
02058 {
02059 result += m_strQuery_encoded[i];
02060 i++;
02061 }
02062 }
02063 m_strQuery_encoded = result;
02064 }
02065
02066 QString KURL::query() const
02067 {
02068 if (m_strQuery_encoded.isNull())
02069 return QString::null;
02070 return '?'+m_strQuery_encoded;
02071 }
02072
02073 QString KURL::decode_string(const QString &str, int encoding_hint)
02074 {
02075 return decode(str, encoding_hint);
02076 }
02077
02078 QString KURL::encode_string(const QString &str, int encoding_hint)
02079 {
02080 return encode(str, 1, encoding_hint);
02081 }
02082
02083 QString KURL::encode_string_no_slash(const QString &str, int encoding_hint)
02084 {
02085 return encode(str, 0, encoding_hint);
02086 }
02087
02088 bool urlcmp( const QString& _url1, const QString& _url2 )
02089 {
02090
02091 if ( _url1.isEmpty() && _url2.isEmpty() )
02092 return true;
02093
02094 if ( _url1.isEmpty() || _url2.isEmpty() )
02095 return false;
02096
02097 KURL::List list1 = KURL::split( _url1 );
02098 KURL::List list2 = KURL::split( _url2 );
02099
02100
02101 if ( list1.isEmpty() || list2.isEmpty() )
02102 return false;
02103
02104 return ( list1 == list2 );
02105 }
02106
02107 bool urlcmp( const QString& _url1, const QString& _url2, bool _ignore_trailing, bool _ignore_ref )
02108 {
02109
02110 if ( _url1.isEmpty() && _url2.isEmpty() )
02111 return true;
02112
02113 if ( _url1.isEmpty() || _url2.isEmpty() )
02114 return false;
02115
02116 KURL::List list1 = KURL::split( _url1 );
02117 KURL::List list2 = KURL::split( _url2 );
02118
02119
02120 if ( list1.isEmpty() || list2.isEmpty() )
02121 return false;
02122
02123 unsigned int size = list1.count();
02124 if ( list2.count() != size )
02125 return false;
02126
02127 if ( _ignore_ref )
02128 {
02129 (*list1.begin()).setRef(QString::null);
02130 (*list2.begin()).setRef(QString::null);
02131 }
02132
02133 KURL::List::Iterator it1 = list1.begin();
02134 KURL::List::Iterator it2 = list2.begin();
02135 for( ; it1 != list1.end() ; ++it1, ++it2 )
02136 if ( !(*it1).equals( *it2, _ignore_trailing ) )
02137 return false;
02138
02139 return true;
02140 }
02141
02142 QMap< QString, QString > KURL::queryItems( int options ) const {
02143 return queryItems(options, 0);
02144 }
02145
02146 QMap< QString, QString > KURL::queryItems( int options, int encoding_hint ) const {
02147 if ( m_strQuery_encoded.isEmpty() )
02148 return QMap<QString,QString>();
02149
02150 QMap< QString, QString > result;
02151 QStringList items = QStringList::split( '&', m_strQuery_encoded );
02152 for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
02153 int equal_pos = (*it).find( '=' );
02154 if ( equal_pos > 0 ) {
02155 QString name = (*it).left( equal_pos );
02156 if ( options & CaseInsensitiveKeys )
02157 name = name.lower();
02158 QString value = (*it).mid( equal_pos + 1 );
02159 if ( value.isEmpty() )
02160 result.insert( name, QString::fromLatin1("") );
02161 else {
02162
02163 value.replace( '+', ' ' );
02164 result.insert( name, decode_string( value, encoding_hint ) );
02165 }
02166 } else if ( equal_pos < 0 ) {
02167 QString name = (*it);
02168 if ( options & CaseInsensitiveKeys )
02169 name = name.lower();
02170 result.insert( name, QString::null );
02171 }
02172 }
02173
02174 return result;
02175 }
02176
02177 QString KURL::queryItem( const QString& _item ) const
02178 {
02179 return queryItem( _item, 0 );
02180 }
02181
02182 QString KURL::queryItem( const QString& _item, int encoding_hint ) const
02183 {
02184 QString item = _item + '=';
02185 if ( m_strQuery_encoded.length() <= 1 )
02186 return QString::null;
02187
02188 QStringList items = QStringList::split( '&', m_strQuery_encoded );
02189 unsigned int _len = item.length();
02190 for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it )
02191 {
02192 if ( (*it).startsWith( item ) )
02193 {
02194 if ( (*it).length() > _len )
02195 {
02196 QString str = (*it).mid( _len );
02197 str.replace( '+', ' ' );
02198 return decode_string( str, encoding_hint );
02199 }
02200 else
02201 return QString::fromLatin1("");
02202 }
02203 }
02204
02205 return QString::null;
02206 }
02207
02208 void KURL::removeQueryItem( const QString& _item )
02209 {
02210 QString item = _item + '=';
02211 if ( m_strQuery_encoded.length() <= 1 )
02212 return;
02213
02214 QStringList items = QStringList::split( '&', m_strQuery_encoded );
02215 for ( QStringList::Iterator it = items.begin(); it != items.end(); )
02216 {
02217 if ( (*it).startsWith( item ) || (*it == _item) )
02218 {
02219 QStringList::Iterator deleteIt = it;
02220 ++it;
02221 items.remove(deleteIt);
02222 }
02223 else
02224 {
02225 ++it;
02226 }
02227 }
02228 m_strQuery_encoded = items.join( "&" );
02229 }
02230
02231 void KURL::addQueryItem( const QString& _item, const QString& _value, int encoding_hint )
02232 {
02233 QString item = _item + '=';
02234 QString value = encode( _value, 0, encoding_hint );
02235
02236 if (!m_strQuery_encoded.isEmpty())
02237 m_strQuery_encoded += '&';
02238 m_strQuery_encoded += item + value;
02239 }
02240
02241
02242 KURL KURL::fromPathOrURL( const QString& text )
02243 {
02244 if ( text.isEmpty() )
02245 return KURL();
02246
02247 KURL url;
02248 if (!QDir::isRelativePath(text))
02249 url.setPath( text );
02250 else
02251 url = text;
02252
02253 return url;
02254 }
02255
02256 static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent)
02257 {
02258 QString _base_dir(QDir::cleanDirPath(base_dir));
02259 QString _path(QDir::cleanDirPath(path.isEmpty() || (path[0] != '/') ? _base_dir+"/"+path : path));
02260
02261 if (_base_dir.isEmpty())
02262 return _path;
02263
02264 if (_base_dir[_base_dir.length()-1] != '/')
02265 _base_dir.append('/');
02266
02267 QStringList list1 = QStringList::split('/', _base_dir);
02268 QStringList list2 = QStringList::split('/', _path);
02269
02270
02271 uint level = 0;
02272 uint maxLevel = QMIN(list1.count(), list2.count());
02273 while((level < maxLevel) && (list1[level] == list2[level])) level++;
02274
02275 QString result;
02276
02277 for(uint i = level; i < list1.count(); i++)
02278 result.append("../");
02279
02280
02281 for(uint i = level; i < list2.count(); i++)
02282 result.append(list2[i]).append("/");
02283
02284 if ((level < list2.count()) && (path[path.length()-1] != '/'))
02285 result.truncate(result.length()-1);
02286
02287 isParent = (level == list1.count());
02288
02289 return result;
02290 }
02291
02292 QString KURL::relativePath(const QString &base_dir, const QString &path, bool *isParent)
02293 {
02294 bool parent = false;
02295 QString result = _relativePath(base_dir, path, parent);
02296 if (parent)
02297 result.prepend("./");
02298
02299 if (isParent)
02300 *isParent = parent;
02301
02302 return result;
02303 }
02304
02305
02306 QString KURL::relativeURL(const KURL &base_url, const KURL &url, int encoding_hint)
02307 {
02308 if ((url.protocol() != base_url.protocol()) ||
02309 (url.host() != base_url.host()) ||
02310 (url.port() && url.port() != base_url.port()) ||
02311 (url.hasUser() && url.user() != base_url.user()) ||
02312 (url.hasPass() && url.pass() != base_url.pass()))
02313 {
02314 return url.url(0, encoding_hint);
02315 }
02316
02317 QString relURL;
02318
02319 if ((base_url.path() != url.path()) || (base_url.query() != url.query()))
02320 {
02321 bool dummy;
02322 QString basePath = base_url.directory(false, false);
02323 relURL = encode( _relativePath(basePath, url.path(), dummy), 1, encoding_hint);
02324 relURL += url.query();
02325 }
02326
02327 if ( url.hasRef() )
02328 {
02329 relURL += "#";
02330 relURL += url.ref();
02331 }
02332
02333 if ( relURL.isEmpty() )
02334 return "./";
02335
02336 return relURL;
02337 }
02338
02339 int KURL::uriMode() const
02340 {
02341 return m_iUriMode;
02342 }
02343
02344 KURL::URIMode KURL::uriModeForProtocol(const QString& protocol)
02345 {
02346 #ifndef KDE_QT_ONLY
02347 KURL::URIMode mode = Auto;
02348 if (protocol == fileProt)
02349 return URL;
02350 if (KGlobal::_instance)
02351 mode = KProtocolInfo::uriParseMode(protocol);
02352 if (mode == Auto ) {
02353 #else
02354 KURL::URIMode mode = Auto;
02355 #endif
02356 if ( protocol == "ed2k" || protocol == "sig2dat" || protocol == "slsk" || protocol == "data" ) mode = RawURI;
02357 else if ( protocol == "mailto" ) mode = Mailto;
02358 else mode = URL;
02359 #ifndef KDE_QT_ONLY
02360 }
02361 #endif
02362 return mode;
02363 }