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

kdecore

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

kdecore

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

kdecore

Skip menu "kdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdecore by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |