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