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