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