• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

kurl.cpp

00001 /*
00002     Copyright (C) 1999 Torben Weis <weis@kde.org>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, USA.
00018 */
00019 
00020 /*
00021  * The currently active RFC for URL/URIs is RFC3986
00022  * Previous (and now deprecated) RFCs are RFC1738 and RFC2396
00023  */
00024 
00025 #include "kurl.h"
00026 
00027 // KDE_QT_ONLY is first used for dcop/client (e.g. marshalling)
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 /* not 0 ! */ )
00059 {
00060     return TQTextCodec::codecForMib( encoding_hint );
00061 }
00062 
00063 // encoding_offset:
00064 // 0 encode both @ and /
00065 // 1 encode @ but not /
00066 // 2 encode neither @ or /
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(""); // differentiate null and empty
00088 
00089   // a worst case approximation
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     // 'unsave' and 'reserved' characters
00096     // according to RFC 1738,
00097     // 2.2. URL Character Encoding Issues (pp. 3-4)
00098     // WABA: Added non-ascii
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   // Hostnames are encoded differently
00126   // we use the IDNA transformation instead
00127 
00128   // Note: when merging qt-addon, use QResolver::domainToAscii here
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 // WABA: The result of lazy_encode isn't usable for a URL which
00153 // needs to satisfies RFC requirements. However, the following
00154 // operation will make it usable again:
00155 //      encode(decode(...))
00156 //
00157 // As a result one can see that url.prettyURL() does not result in
00158 // a RFC compliant URL but that the following sequence does:
00159 //      KURL(url.prettyURL()).url()
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   // a worst case approximation
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(); // Don't use latin1()
00176                                                    // It returns 0 for non-latin1 values
00177     // Small set of really ambiguous chars
00178     if ((character < 32) ||  // Low ASCII
00179         ((character == '%') && // The escape character itself
00180            (i+2 < old_length) && // But only if part of a valid escape sequence!
00181           (hex2int(segment[i+1].unicode())!= -1) &&
00182           (hex2int(segment[i+2].unicode())!= -1)) ||
00183         (character == '?') || // Start of query delimiter
00184         ((character == '@') && encodeAt) || // Username delimiter
00185         (character == '#') || // Start of reference delimiter
00186         ((character == 32) && (i+1 == old_length || segment[i+1] == (TQChar)' '))) // A trailing space
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   // Check if everything went ok
00225   if (textCodec->toUnicode(csegment) != segment)
00226   {
00227       // Uh oh
00228       textCodec = codecForHint( 106 ); // Fall back to utf-8
00229       csegment = textCodec->fromUnicode(segment);
00230   }
00231   old_length = csegment.length();
00232 
00233   int new_length = 0;
00234   int new_length2 = 0;
00235 
00236   // make a copy of the old one
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)) // Only replace if sequence is valid
00254       {
00255          // Contains stray %, make sure to re-encode!
00256          bReencode = true;
00257       }
00258       else
00259       {
00260          // Valid %xx sequence
00261          character = a * 16 + b; // Replace with value of %dd
00262          if (!isRawURI && !character && updateDecoded)
00263             break; // Stop at %00
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   // Encoding specified
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; // Don't mangle mailto-style URLs
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"); // Uppercase!
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   // The following code cleans up directory path much like
00358   // TQDir::cleanDirPath() except it can be made to ignore multiple
00359   // directory separators by setting the flag to false.  That fixes
00360   // bug# 15044, mail.altavista.com and other similar brain-dead server
00361   // implementations that do not follow what has been specified in
00362   // RFC 2396!! (dA)
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       // Ignore any occurrences of '.'
00376       // This includes entries that simply do not make sense like /..../
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; // Very short relative URL.
00413   const TQChar *str = _url.unicode();
00414 
00415   // Absolute URL must start with alpha-character
00416   if (!isalpha(str[0].latin1()))
00417      return true; // Relative URL
00418 
00419   for(int i = 1; i < len; i++)
00420   {
00421      char c = str[i].latin1(); // Note: non-latin1 chars return 0!
00422      if (c == ':')
00423         return false; // Absolute URL
00424 
00425      // Protocol part may only contain alpha, digit, + or -
00426      if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-'))
00427         return true; // Relative URL
00428   }
00429   // URL did not contain ':'
00430   return true; // Relative URL
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 ) // empty query
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()) // Operate on the last suburl, not the first
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   // WORKAROUND THE RFC 1606 LOOPHOLE THAT ALLOWS
00560   // http:/index.html AS A VALID SYNTAX FOR RELATIVE
00561   // URLS. ( RFC 2396 section 5.2 item # 3 )
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 = ""; // we know there was an (empty) html ref, we saw the '#'
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            // File protocol returns file:/// without host, strip // from rUrl
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     // Preserve userinfo if applicable.
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     // Node 1: Accept alpha or slash
00672     TQChar x = buf[pos++];
00673 #ifdef Q_WS_WIN
00674     /* win32: accept <letter>: or <letter>:/ or <letter>:\ */
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     // A slash means we immediately proceed to parse it as a file URL.
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     // Node 2: Accept any amount of (alpha|digit|'+'|'-')
00693     // '.' is not currently accepted, because current KURL may be confused.
00694     // Proceed with :// :/ or :
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     // Proceed to correct parse function.
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         // Unknown URI mode results in an invalid URI.
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     // Accept any amount of (alpha|digit|'+'|'-')
00735     // '.' is not currently accepted, because current KURL may be confused.
00736     // Proceed with :
00737     while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
00738              buf[pos] == (TQChar)'+' || buf[pos] == (TQChar)'-')) pos++;
00739 
00740     // Note that m_strProtocol is already set here, so we just skip over the protocol.
00741     if (pos < len && buf[pos] == (TQChar)':' )
00742     pos++;
00743     else { // can't happen, the caller checked all this already
00744     reset();
00745     m_strProtocol = _url;
00746     m_iUriMode = Invalid;
00747     return;
00748     }
00749 
00750     if ( pos == len ) // can't happen, the caller checked this already
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   // Node 1: Accept alpha or slash
00793   TQChar x = buf[pos++];
00794 #ifdef Q_WS_WIN
00795   /* win32: accept <letter>: or <letter>:/ or <letter>:\ */
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   // Node 2: Accept any amount of (alpha|digit|'+'|'-')
00808   // '.' is not currently accepted, because current KURL may be confused.
00809   // Proceed with :// :/ or :
00810   while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) ||
00811           buf[pos] == (TQChar)'+' || buf[pos] == (TQChar)'-')) pos++;
00812 
00813   // Note that m_strProtocol is already set here, so we just skip over the protocol.
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)':' ) // Need to always compare length()-1 otherwise KURL passes "http:" as legal!!
00819     {
00820       pos++;
00821       start = pos;
00822       goto Node9;
00823     }
00824   else
00825     goto NodeErr;
00826 
00827   //Node 3: We need at least one character here
00828   if ( pos == len )
00829       goto NodeErr;
00830   start = pos;
00831 
00832   // Node 4: Accept any amount of characters.
00833   if (buf[pos] == (TQChar)'[')     // An IPv6 host follows.
00834       goto Node8;
00835   // Terminate on / or @ or ? or # or " or ; or <
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   // Node 5: We need at least one character
00874   if ( pos == len )
00875     goto NodeErr;
00876   start = pos++;
00877 
00878   // Node 6: Read everything until @, /, ? or #
00879   while( (pos < len) &&
00880         (buf[pos] != (TQChar)'@') &&
00881         (buf[pos] != (TQChar)'/') &&
00882         (buf[pos] != (TQChar)'?') &&
00883         (buf[pos] != (TQChar)'#')) pos++;
00884   // If we now have a '@' the ':' seperates user and password.
00885   // Otherwise it seperates host and port.
00886   if ( (pos == len) || (buf[pos] != (TQChar)'@') )
00887     {
00888       // Ok the : was used to separate host and port
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       // there is more after the digits
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   // Node 7: We need at least one character
00913  Node7:
00914   if ( pos == len )
00915     goto NodeErr;
00916 
00917  Node8:
00918   if (buf[pos] == (TQChar)'[')
00919   {
00920     // IPv6 address
00921     start = ++pos; // Skip '['
00922 
00923     if (pos == len)
00924     {
00925        badHostName = true;
00926        goto NodeErr;
00927     }
00928     // Node 8a: Read everything until ] or terminate
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++; // Skip ']'
00946     if (pos == len)
00947        goto NodeOk;
00948   }
00949   else
00950   {
00951     // Non IPv6 address, with a user
00952     start = pos;
00953 
00954     // Node 8b: Read everything until / : or terminate
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   // Node 8c: Accept at least one digit
00985   if ( pos == len )
00986     goto NodeErr;
00987   start = pos;
00988   if ( !isdigit( buf[pos++] ) )
00989     goto NodeErr;
00990 
00991   // Node 8d: Accept any amount of digits
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: // parse path until query or reference reached
01000 
01001   while( pos < len && buf[pos] != (TQChar)'#' && buf[pos]!=(TQChar)'?' ) pos++;
01002 
01003   tmp = TQString( buf + start, pos - start );
01004   //kdDebug(126)<<" setting encoded path to:"<<tmp<<endl;
01005   setEncodedPath( tmp, encoding_hint );
01006 
01007   if ( pos == len )
01008       goto NodeOk;
01009 
01010  //Node10: // parse query or reference depending on what comes first
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  //Node11: // feed the rest into the remaining variable
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   //kdDebug(126)<<"parsing finished. m_strProtocol="<<m_strProtocol<<" m_strHost="<<m_strHost<<" m_strPath="<<m_strPath<<endl;
01035   m_bIsMalformed = false; // Valid URL
01036 
01037   //kdDebug()<<"Prot="<<m_strProtocol<<"\nUser="<<m_strUser<<"\nPass="<<m_strPass<<"\nHost="<<m_strHost<<"\nPath="<<m_strPath<<"\nQuery="<<m_strQuery_encoded<<"\nRef="<<m_strRef_encoded<<"\nPort="<<m_iPort<<endl;
01038   if (m_strProtocol.isEmpty())
01039   {
01040     m_iUriMode = URL;
01041     m_strProtocol = fileProt;
01042   }
01043   return;
01044 
01045  NodeErr:
01046 //  kdDebug(126) << "KURL couldn't parse URL \"" << _url << "\"" << endl;
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        // The encoded path may be null, but the URLs are still equal (David)
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; // can't work with implicit paths
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     //kdDebug(126) << "p1=" << p1 << endl;
01241     //kdDebug(126) << "p2=" << p2 << endl;
01242     //kdDebug(126) << "p1.length()=" << p1.length() << endl;
01243     //kdDebug(126) << "p2.left(!$)=" << p2.left( p1.length() ) << endl;
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       // The first character is not a '/' ???
01269       // This looks strange ...
01270       path = "/";
01271     }
01272     else if ( path.right(1) != "/" )
01273       path.truncate( lastSlash+1 ); // keep the "/"
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 ) // taken from the old KURL
01289 {
01290   if (m_iUriMode != URL) return;
01291   m_strPath = cleanpath(m_strPath, cleanDirSeparator, false);
01292   // WABA: Is this safe when "/../" is encoded with %?
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   // TODO apply encoding_hint to the query
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   // Throw away encoding for local files, makes file-operations faster.
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" ) // anything that starts with error: has suburls
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     // Return the whole url even when the url is
01504     // malformed.  Under such conditions the url
01505     // is stored in m_strProtocol.
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     // Return the whole url even when the url is
01564     // malformed.  Under such conditions the url
01565     // is stored in m_strProtocol.
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       // Don't show password!
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   // Set HTML ref in all URLs.
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(); // Support more than one suburl thingy
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()) { // If we have a suburl, then return the filename from there
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   // Does the path only consist of '/' characters ?
01732   if ( len == 1 && path[ 0 ] == TQChar('/') )
01733     return fname;
01734 
01735   // Skip last n slashes
01736   int n = 1;
01737   if (!m_strPath_encoded.isEmpty())
01738   {
01739      // This is hairy, we need the last unencoded slash.
01740      // Count in the encoded string how many encoded slashes follow the last
01741      // unencoded one.
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   // If ( i == -1 ) => the first character is not a '/'
01753   // So it's some URL like file:blah.tgz, return the whole path
01754   if ( i == -1 ) {
01755     if ( len == (int)path.length() )
01756       fname = path;
01757     else
01758       // Might get here if _strip_trailing_slash is true
01759       fname = path.left( len );
01760   }
01761   else
01762   {
01763      fname = path.mid( i + 1, len - i - 1 ); // TO CHECK
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   // Add the trailing '/' if it is missing
01787   if ( _txt[0] != (TQChar)'/' && ( len == 0 || m_strPath[ len - 1 ] != (TQChar)'/' ) )
01788     m_strPath += "/";
01789 
01790   // No double '/' characters
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   // If ( i == -1 ) => the first character is not a '/'
01813   // So it's some URL like file:blah.tgz, with no path
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   // absolute path ?
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   // Users home directory on the local disk ?
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   // relative path
01872   // we always work on the past of the first url.
01873   // Sub URLs are not touched.
01874 
01875   // append '/' if necessary
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   // We have a subURL.
01906   KURL::List lst = split( *this );
01907   if (lst.isEmpty())
01908       return KURL(); // Huh?
01909   while (true)
01910   {
01911      KURL &u = lst.last();
01912      TQString old = u.path();
01913      u.cd("../");
01914      if (u.path() != old)
01915          break; // Finshed.
01916      if (lst.count() == 1)
01917          break; // Finished.
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(); // Probably an invalid hostname, but...
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) : "" /*empty, not null*/, encoding_hint );
02051    else
02052       _setQuery( _txt, encoding_hint );
02053 }
02054 
02055 // This is a private function that expects a query without '?'
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       // Re-encode. Break encoded string up according to the reserved
02069       // characters '&:;=/?' and re-encode part by part.
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   // Both empty ?
02119   if ( _url1.isEmpty() && _url2.isEmpty() )
02120     return true;
02121   // Only one empty ?
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   // Malformed ?
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   // Both empty ?
02138   if ( _url1.isEmpty() && _url2.isEmpty() )
02139     return true;
02140   // Only one empty ?
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   // Malformed ?
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 ) { // = is not the first char...
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     // ### why is decoding name not necessary?
02191     value.replace( '+', ' ' ); // + in queries means space
02192     result.insert( name, decode_string( value, encoding_hint ) );
02193       }
02194     } else if ( equal_pos < 0 ) { // no =
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( '+', ' ' ); // + in queries means space.
02226         return decode_string( str, encoding_hint );
02227       }
02228       else // empty value
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 // static
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    // Find where they meet
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    // Need to go down out of the first path to the common branch.
02305    for(uint i = level; i < list1.count(); i++)
02306       result.append("../");
02307 
02308    // Now up up from the common branch to the second path.
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 }

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.7.1
This website is maintained by Timothy Pearson.