~ubuntu-branches/ubuntu/gutsy/kde4libs/gutsy

« back to all changes in this revision

Viewing changes to kdecore/kurl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-02-21 11:00:12 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070221110012-6kw8khr9knv6lmg1
Tags: 3.80.3-0ubuntu1
New upstream unstable release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// -*- c-basic-offset: 2 -*-
2
 
/*
3
 
    Copyright (C) 1999 Torben Weis <weis@kde.org>
4
 
    Copyright (C) 2005-2006 David Faure <faure@kde.org>
5
 
 
6
 
    This library is free software; you can redistribute it and/or
7
 
    modify it under the terms of the GNU Library General Public
8
 
    License as published by the Free Software Foundation; either
9
 
    version 2 of the License, or (at your option) any later version.
10
 
 
11
 
    This library is distributed in the hope that it will be useful,
12
 
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 
    Library General Public License for more details.
15
 
 
16
 
    You should have received a copy of the GNU Library General Public License
17
 
    along with this library; see the file COPYING.LIB.  If not, write to
18
 
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19
 
    Boston, MA 02110-1301, USA.
20
 
*/
21
 
 
22
 
/// KDE4 TODO: maybe we should use QUrl::resolved()
23
 
 
24
 
/*
25
 
 * The currently active RFC for URL/URIs is RFC3986
26
 
 * Previous (and now deprecated) RFCs are RFC1738 and RFC2396
27
 
 */
28
 
 
29
 
#include "kurl.h"
30
 
 
31
 
// KDE_QT_ONLY is first used for dcop/client (e.g. marshalling)
32
 
#ifndef KDE_QT_ONLY
33
 
#include <kdebug.h>
34
 
#include <kglobal.h>
35
 
#include <kshell.h>
36
 
#endif
37
 
 
38
 
#include <stdio.h>
39
 
#include <assert.h>
40
 
#include <ctype.h>
41
 
#include <stdlib.h>
42
 
#include <unistd.h>
43
 
 
44
 
#include <qdir.h>
45
 
#include <qstringlist.h>
46
 
#include <qregexp.h>
47
 
#include <qmimedata.h>
48
 
#include <qtextcodec.h>
49
 
 
50
 
static QString cleanpath( const QString &_path, bool cleanDirSeparator, bool decodeDots )
51
 
{
52
 
  if (_path.isEmpty()) return QString();
53
 
 
54
 
  if (QDir::isRelativePath(_path))
55
 
     return _path; // Don't mangle mailto-style URLs
56
 
 
57
 
  QString path = _path;
58
 
 
59
 
  int len = path.length();
60
 
 
61
 
  if (decodeDots)
62
 
  {
63
 
#ifndef KDE_QT_ONLY
64
 
     static const QString &encodedDot = KGlobal::staticQString("%2e");
65
 
#else
66
 
     QString encodedDot("%2e");
67
 
#endif
68
 
     if (path.indexOf(encodedDot, 0, Qt::CaseInsensitive) != -1)
69
 
     {
70
 
#ifndef KDE_QT_ONLY
71
 
        static const QString &encodedDOT = KGlobal::staticQString("%2E"); // Uppercase!
72
 
#else
73
 
        QString encodedDOT("%2E");
74
 
#endif
75
 
        path.replace(encodedDot, ".");
76
 
        path.replace(encodedDOT, ".");
77
 
        len = path.length();
78
 
     }
79
 
  }
80
 
 
81
 
  bool slash = (len && path[len-1] == QLatin1Char('/')) ||
82
 
               (len > 1 && path[len-2] == QLatin1Char('/') && path[len-1] == QLatin1Char('.'));
83
 
 
84
 
  // The following code cleans up directory path much like
85
 
  // QDir::cleanPath() except it can be made to ignore multiple
86
 
  // directory separators by setting the flag to false.  That fixes
87
 
  // bug# 15044, mail.altavista.com and other similar brain-dead server
88
 
  // implementations that do not follow what has been specified in
89
 
  // RFC 2396!! (dA)
90
 
  QString result;
91
 
  int cdUp, orig_pos, pos;
92
 
 
93
 
  cdUp = 0;
94
 
  pos = orig_pos = len;
95
 
  while ( pos && (pos = path.lastIndexOf(QLatin1Char('/'),--pos)) != -1 )
96
 
  {
97
 
    len = orig_pos - pos - 1;
98
 
    if ( len == 2 && path[pos+1] == '.' && path[pos+2] == '.' )
99
 
      cdUp++;
100
 
    else
101
 
    {
102
 
      // Ignore any occurrences of '.'
103
 
      // This includes entries that simply do not make sense like /..../
104
 
      if ( (len || !cleanDirSeparator) &&
105
 
           (len != 1 || path[pos+1] != '.' ) )
106
 
      {
107
 
          if ( !cdUp )
108
 
              result.prepend(path.mid(pos, len+1));
109
 
          else
110
 
              cdUp--;
111
 
      }
112
 
    }
113
 
    orig_pos = pos;
114
 
  }
115
 
 
116
 
#ifdef Q_WS_WIN // prepend drive letter if exists (js)
117
 
  if (orig_pos >= 2 && isalpha(path[0].toLatin1()) && path[1]==':') {
118
 
    result.prepend(QString(path[0])+':');
119
 
  }
120
 
#endif
121
 
 
122
 
  if ( result.isEmpty() )
123
 
    result = '/';
124
 
  else if ( slash && result[result.length()-1] != QLatin1Char('/') )
125
 
       result.append(QChar('/'));
126
 
 
127
 
  return result;
128
 
}
129
 
 
130
 
bool KUrl::isRelativeUrl(const QString &_url)
131
 
{
132
 
#if 0
133
 
  // would this work?
134
 
  return QUrl( _url ).isRelative();
135
 
#endif
136
 
  int len = _url.length();
137
 
  if (!len) return true; // Very short relative URL.
138
 
  const QChar *str = _url.unicode();
139
 
 
140
 
  // Absolute URL must start with alpha-character
141
 
  if (!isalpha(str[0].toLatin1()))
142
 
     return true; // Relative URL
143
 
 
144
 
  for(int i = 1; i < len; i++)
145
 
  {
146
 
     char c = str[i].toLatin1(); // Note: non-latin1 chars return 0!
147
 
     if (c == ':')
148
 
        return false; // Absolute URL
149
 
 
150
 
     // Protocol part may only contain alpha, digit, + or -
151
 
     if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-'))
152
 
        return true; // Relative URL
153
 
  }
154
 
  // URL did not contain ':'
155
 
  return true; // Relative URL
156
 
}
157
 
 
158
 
KUrl::List::List(const KUrl &url)
159
 
{
160
 
    append( url );
161
 
}
162
 
 
163
 
KUrl::List::List(const QStringList &list)
164
 
{
165
 
  for (QStringList::ConstIterator it = list.begin();
166
 
       it != list.end();
167
 
       it++)
168
 
    {
169
 
      append( KUrl(*it) );
170
 
    }
171
 
}
172
 
 
173
 
QStringList KUrl::List::toStringList() const
174
 
{
175
 
  QStringList lst;
176
 
   for( KUrl::List::ConstIterator it = begin();
177
 
        it != end();
178
 
        it++)
179
 
   {
180
 
      lst.append( (*it).url() );
181
 
   }
182
 
   return lst;
183
 
}
184
 
 
185
 
 
186
 
void KUrl::List::populateMimeData( QMimeData* mimeData,
187
 
                                   const KUrl::MetaDataMap& metaData,
188
 
                                   MimeDataFlags flags ) const
189
 
{
190
 
    QList<QByteArray> urlStringList;
191
 
    KUrl::List::ConstIterator uit = begin();
192
 
    const KUrl::List::ConstIterator uEnd = end();
193
 
    for ( ; uit != uEnd ; ++uit )
194
 
    {
195
 
        // Get each URL encoded in utf8 - and since we get it in escaped
196
 
        // form on top of that, .toLatin1() is fine.
197
 
        urlStringList.append( (*uit).toMimeDataString().toLatin1() );
198
 
    }
199
 
 
200
 
    QByteArray uriListData;
201
 
    for ( QList<QByteArray>::const_iterator it = urlStringList.begin(), end = urlStringList.end()
202
 
                                                 ; it != end ; ++it ) {
203
 
        uriListData += (*it);
204
 
        uriListData += "\r\n";
205
 
    }
206
 
    mimeData->setData( "text/uri-list", uriListData );
207
 
 
208
 
    if ( ( flags & KUrl::NoTextExport ) == 0 )
209
 
    {
210
 
        QStringList prettyURLsList;
211
 
        for ( uit = begin(); uit != uEnd ; ++uit )
212
 
            prettyURLsList.append( (*uit).prettyUrl() );
213
 
 
214
 
        QByteArray plainTextData = prettyURLsList.join( "\n" ).toLocal8Bit();
215
 
        if( count() > 1 ) // terminate last line, unless it's the only line
216
 
            plainTextData.append( "\n" );
217
 
        mimeData->setData( "text/plain", plainTextData );
218
 
    }
219
 
 
220
 
    if ( !metaData.isEmpty() )
221
 
    {
222
 
        QByteArray metaDataData; // :)
223
 
        for( KUrl::MetaDataMap::const_iterator it = metaData.begin(); it != metaData.end(); ++it )
224
 
        {
225
 
            metaDataData += it.key().toUtf8();
226
 
            metaDataData += "$@@$";
227
 
            metaDataData += it.value().toUtf8();
228
 
            metaDataData += "$@@$";
229
 
        }
230
 
        mimeData->setData( "application/x-kio-metadata", metaDataData );
231
 
    }
232
 
}
233
 
 
234
 
bool KUrl::List::canDecode( const QMimeData *mimeData )
235
 
{
236
 
    return mimeData->hasFormat( "text/uri-list" ) || mimeData->hasFormat( "application/x-kde-urilist" );
237
 
}
238
 
 
239
 
QStringList KUrl::List::mimeDataTypes()
240
 
{
241
 
    return QStringList()<<( "application/x-kde-urilist" )<<( "text/uri-list" );
242
 
}
243
 
 
244
 
KUrl::List KUrl::List::fromMimeData( const QMimeData *mimeData, KUrl::MetaDataMap* metaData )
245
 
{
246
 
    KUrl::List uris;
247
 
    // x-kde-urilist is the same format as text/uri-list, but contains
248
 
    // KDE-aware urls, like media:/ and system:/, whereas text/uri-list is resolved to
249
 
    // local files. So we look at it first for decoding, but we let apps set it when encoding.
250
 
    QByteArray payload = mimeData->data( "application/x-kde-urilist" );
251
 
    if ( payload.isEmpty() )
252
 
        payload = mimeData->data( "text/uri-list" );
253
 
    if ( !payload.isEmpty() ) {
254
 
        int c = 0;
255
 
        const char* d = payload.data();
256
 
        while ( c < payload.size() && d[c] ) {
257
 
            int f = c;
258
 
            // Find line end
259
 
            while (c < payload.size() && d[c] && d[c]!='\r'
260
 
                   && d[c] != '\n')
261
 
                c++;
262
 
            QByteArray s( d+f, c-f );
263
 
            if ( s[0] != '#' ) // non-comment?
264
 
                uris.append( KUrl::fromMimeDataByteArray( s ) );
265
 
            // Skip junk
266
 
            while ( c < payload.size() && d[c] &&
267
 
                    ( d[c] == '\n' || d[c] == '\r' ) )
268
 
                ++c;
269
 
        }
270
 
    }
271
 
    if ( metaData )
272
 
    {
273
 
        const QByteArray metaDataPayload = mimeData->data( "application/x-kio-metadata" );
274
 
        if ( !metaDataPayload.isEmpty() )
275
 
        {
276
 
            QString str = QString::fromUtf8( metaDataPayload );
277
 
            Q_ASSERT( str.endsWith( "$@@$" ) );
278
 
            str.truncate( str.length() - 4 );
279
 
            const QStringList lst = str.split( "$@@$" );
280
 
            QStringList::ConstIterator it = lst.begin();
281
 
            bool readingKey = true; // true, then false, then true, etc.
282
 
            QString key;
283
 
            for ( ; it != lst.end(); ++it ) {
284
 
                if ( readingKey )
285
 
                    key = *it;
286
 
                else
287
 
                    metaData->insert( key, *it );
288
 
                readingKey = !readingKey;
289
 
            }
290
 
            Q_ASSERT( readingKey ); // an odd number of items would be, well, odd ;-)
291
 
        }
292
 
    }
293
 
 
294
 
    return uris;
295
 
}
296
 
 
297
 
////
298
 
 
299
 
KUrl::KUrl()
300
 
    : QUrl(), d(0)
301
 
{
302
 
}
303
 
 
304
 
KUrl::~KUrl()
305
 
{
306
 
}
307
 
 
308
 
 
309
 
KUrl::KUrl( const QString &str )
310
 
  : QUrl(), d(0)
311
 
{
312
 
  if ( !str.isEmpty() ) {
313
 
    if ( str[0] == QLatin1Char('/') || str[0] == QLatin1Char('~') )
314
 
      setPath( str );
315
 
    else
316
 
      setEncodedUrl( str.toUtf8(), QUrl::TolerantMode );
317
 
  }
318
 
}
319
 
 
320
 
KUrl::KUrl( const char * str )
321
 
  : QUrl(), d(0)
322
 
{
323
 
  if ( str ) {
324
 
    if ( str[0] == '/' || str[0] == '~' )
325
 
      setPath( QString::fromUtf8( str ) );
326
 
    else
327
 
      setEncodedUrl( str, QUrl::TolerantMode );
328
 
  }
329
 
}
330
 
 
331
 
KUrl::KUrl( const QByteArray& str )
332
 
   : QUrl(), d(0)
333
 
{
334
 
  if ( !str.isEmpty() ) {
335
 
    if ( str[0] == '/' || str[0] == '~' )
336
 
      setPath( QString::fromUtf8( str ) );
337
 
    else
338
 
      setEncodedUrl( str, QUrl::TolerantMode );
339
 
  }
340
 
}
341
 
 
342
 
KUrl::KUrl( const KUrl& _u )
343
 
    : QUrl( _u ), d(0)
344
 
{
345
 
}
346
 
 
347
 
KUrl::KUrl( const QUrl &u )
348
 
    : QUrl( u ), d(0)
349
 
{
350
 
}
351
 
 
352
 
KUrl::KUrl( const KUrl& _u, const QString& _rel_url )
353
 
   : QUrl(), d(0)
354
 
{
355
 
#if 0
356
 
  if (_u.hasSubUrl()) // Operate on the last suburl, not the first
357
 
  {
358
 
    KUrl::List lst = split( _u );
359
 
    KUrl u(lst.last(), _rel_url);
360
 
    lst.erase( --lst.end() );
361
 
    lst.append( u );
362
 
    *this = join( lst );
363
 
    return;
364
 
  }
365
 
#endif
366
 
  QString rUrl = _rel_url;
367
 
 
368
 
  // WORKAROUND THE RFC 1606 LOOPHOLE THAT ALLOWS
369
 
  // http:/index.html AS A VALID SYNTAX FOR RELATIVE
370
 
  // URLS. ( RFC 2396 section 5.2 item # 3 )
371
 
  int len = _u.scheme().length();
372
 
  if ( !_u.host().isEmpty() && !rUrl.isEmpty() &&
373
 
       rUrl.indexOf( _u.scheme(), 0, Qt::CaseInsensitive ) == 0 &&
374
 
       rUrl[len] == ':' && (rUrl[len+1] != QLatin1Char('/') ||
375
 
       (rUrl[len+1] == '/' && rUrl[len+2] != QLatin1Char('/'))) )
376
 
  {
377
 
    rUrl.remove( 0, rUrl.indexOf( ':' ) + 1 );
378
 
  }
379
 
 
380
 
 
381
 
  if ( rUrl.isEmpty() )
382
 
  {
383
 
    *this = _u;
384
 
  }
385
 
  else if ( rUrl[0] == '#' )
386
 
  {
387
 
    *this = _u;
388
 
    QString strRef_encoded = rUrl.mid(1);
389
 
    if ( strRef_encoded.isNull() )
390
 
        strRef_encoded = ""; // we know there was an (empty) html ref, we saw the '#'
391
 
    setFragment( strRef_encoded );
392
 
  }
393
 
  else if ( isRelativeUrl( rUrl ) )
394
 
  {
395
 
    *this = _u;
396
 
    setFragment( QString() );
397
 
    setEncodedQuery( QByteArray() );
398
 
    QString strPath = path();
399
 
    if ( rUrl[0] == QLatin1Char('/') )
400
 
    {
401
 
        if ((rUrl.length() > 1) && (rUrl[1] == QLatin1Char('/')))
402
 
        {
403
 
            setHost( QString() );
404
 
            setPort( -1 );
405
 
            // File protocol returns file:/// without host, strip // from rUrl
406
 
            if ( _u.isLocalFile() )
407
 
                rUrl.remove(0, 2);
408
 
        }
409
 
        strPath.clear();
410
 
    }
411
 
    else if ( rUrl[0] != '?' )
412
 
    {
413
 
       int pos = strPath.lastIndexOf( QLatin1Char('/') );
414
 
       if (pos >= 0)
415
 
          strPath.truncate(pos);
416
 
       strPath += QLatin1Char('/');
417
 
    }
418
 
    else
419
 
    {
420
 
       if ( strPath.isEmpty() )
421
 
          strPath = QLatin1Char('/');
422
 
    }
423
 
    setPath( strPath );
424
 
    //kDebug(126) << "url()=" << url() << " rUrl=" << rUrl << endl;
425
 
    KUrl tmp( url() + rUrl);
426
 
    //kDebug(126) << "assigning tmp=" << tmp.url() << endl;
427
 
    *this = tmp;
428
 
    cleanPath(KeepDirSeparators);
429
 
  }
430
 
  else
431
 
  {
432
 
    KUrl tmp( rUrl );
433
 
    //kDebug(126) << "not relative; assigning tmp=" << tmp.url() << endl;
434
 
    *this = tmp;
435
 
    // Preserve userinfo if applicable.
436
 
    if (!_u.userInfo().isEmpty() && userInfo().isEmpty()
437
 
        && (_u.host() == host()) && (_u.scheme() == scheme()))
438
 
    {
439
 
       setUserInfo( _u.userInfo() );
440
 
    }
441
 
    cleanPath(KeepDirSeparators);
442
 
  }
443
 
}
444
 
 
445
 
bool KUrl::operator==( const KUrl& _u ) const
446
 
{
447
 
  if ( !isValid() || !_u.isValid() )
448
 
    return false;
449
 
  return QUrl::operator==( _u );;
450
 
}
451
 
 
452
 
bool KUrl::operator==( const QString& _u ) const
453
 
{
454
 
  KUrl u( _u );
455
 
  return ( *this == u );
456
 
}
457
 
 
458
 
bool KUrl::cmp( const KUrl &u, bool ignore_trailing ) const
459
 
{
460
 
  return equals( u, ignore_trailing ? CompareWithoutTrailingSlash : EqualsOptions(0) );
461
 
}
462
 
 
463
 
bool KUrl::equals( const KUrl &_u, const EqualsOptions& options ) const
464
 
{
465
 
  if ( !isValid() || !_u.isValid() )
466
 
    return false;
467
 
 
468
 
  if ( options & CompareWithoutTrailingSlash || options & CompareWithoutFragment )
469
 
  {
470
 
    QString path1 = path((options & CompareWithoutTrailingSlash) ? RemoveTrailingSlash : LeaveTrailingSlash);
471
 
    QString path2 = _u.path((options & CompareWithoutTrailingSlash) ? RemoveTrailingSlash : LeaveTrailingSlash);
472
 
    if ( path1 != path2 )
473
 
      return false;
474
 
 
475
 
    if ( scheme() == _u.scheme() &&
476
 
         authority() == _u.authority() && // user+pass+host+port
477
 
         encodedQuery() == _u.encodedQuery() &&
478
 
         (fragment() == _u.fragment() || options & CompareWithoutFragment )    )
479
 
      return true;
480
 
 
481
 
    return false;
482
 
  }
483
 
 
484
 
  return ( *this == _u );
485
 
}
486
 
 
487
 
void KUrl::setFileName( const QString& _txt )
488
 
{
489
 
  setFragment( QString() );
490
 
  int i = 0;
491
 
  while( i < _txt.length() && _txt[i] == QLatin1Char('/') )
492
 
      ++i;
493
 
  QString tmp = i ? _txt.mid( i ) : _txt;
494
 
 
495
 
  //QString path = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded;
496
 
  QString path = this->path();
497
 
  if ( path.isEmpty() )
498
 
    path = "/";
499
 
  else
500
 
  {
501
 
    int lastSlash = path.lastIndexOf( QLatin1Char('/') );
502
 
    if ( lastSlash == -1)
503
 
    {
504
 
      // The first character is not a '/' ???
505
 
      // This looks strange ...
506
 
      path = QLatin1Char('/');
507
 
    }
508
 
    else if ( !path.endsWith( QLatin1Char('/') ) )
509
 
      path.truncate( lastSlash+1 ); // keep the "/"
510
 
  }
511
 
#if 0
512
 
  if (m_strPath_encoded.isEmpty())
513
 
#endif
514
 
  {
515
 
     path += tmp;
516
 
     setPath( path );
517
 
  }
518
 
#if 0
519
 
  else
520
 
  {
521
 
     path += encode_string(tmp);
522
 
     setEncodedPath( path );
523
 
  }
524
 
#endif
525
 
  cleanPath();
526
 
}
527
 
 
528
 
void KUrl::cleanPath( const CleanPathOption& options )
529
 
{
530
 
  //if (m_iUriMode != URL) return;
531
 
  const QString newPath = cleanpath(path(), !(options & KeepDirSeparators), false);
532
 
  if ( path() != newPath )
533
 
      setPath( newPath );
534
 
  // WABA: Is this safe when "/../" is encoded with %?
535
 
  //m_strPath_encoded = cleanpath(m_strPath_encoded, cleanDirSeparator, true);
536
 
}
537
 
 
538
 
static QString trailingSlash( KUrl::AdjustPathOption trailing, const QString &path )
539
 
{
540
 
  QString result = path;
541
 
 
542
 
  if ( trailing == KUrl::LeaveTrailingSlash )
543
 
    return result;
544
 
  else if ( trailing == KUrl::AddTrailingSlash )
545
 
  {
546
 
    int len = result.length();
547
 
    if ( (len == 0) || (result[ len - 1 ] != QLatin1Char('/')) )
548
 
      result += QLatin1Char('/');
549
 
    return result;
550
 
  }
551
 
  else if ( trailing == KUrl::RemoveTrailingSlash )
552
 
  {
553
 
    if ( result == "/" )
554
 
      return result;
555
 
    int len = result.length();
556
 
    while (len > 1 && result[ len - 1 ] == QLatin1Char('/'))
557
 
    {
558
 
      len--;
559
 
    }
560
 
    result.truncate( len );
561
 
    return result;
562
 
  }
563
 
  else {
564
 
    assert( 0 );
565
 
    return result;
566
 
  }
567
 
}
568
 
 
569
 
void KUrl::adjustPath( AdjustPathOption trailing )
570
 
{
571
 
#if 0
572
 
  if (!m_strPath_encoded.isEmpty())
573
 
  {
574
 
     m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded );
575
 
  }
576
 
#endif
577
 
  const QString newPath = trailingSlash( trailing, path() );
578
 
  if ( path() != newPath )
579
 
      setPath( newPath );
580
 
}
581
 
 
582
 
 
583
 
QString KUrl::encodedPathAndQuery( AdjustPathOption trailing , const EncodedPathAndQueryOptions &options) const
584
 
{
585
 
  QString tmp;
586
 
#if 0
587
 
  if (!m_strPath_encoded.isEmpty())
588
 
  {
589
 
     tmp = trailingSlash( _trailing, m_strPath_encoded );
590
 
  }
591
 
  else
592
 
#endif
593
 
  {
594
 
     tmp = path( trailing );
595
 
     if ( (options & AvoidEmptyPath) && tmp.isEmpty() )
596
 
        tmp = "/";
597
 
#if 0
598
 
     if (m_iUriMode == Mailto)
599
 
     {
600
 
       tmp = encode( tmp, 2 ); // encode neither @ nor /
601
 
     }
602
 
     else
603
 
     {
604
 
       tmp = encode( tmp, 1 ); // encode @ but not /
605
 
     }
606
 
#endif
607
 
     // The list of chars to exclude comes from QUrlPrivate::toEncoded
608
 
     tmp = QString::fromLatin1( QUrl::toPercentEncoding( tmp, "!$&'()*+,;=:@/" ) );
609
 
  }
610
 
 
611
 
#if defined( QT_KDE_QT_COPY ) || QT_VERSION >= 0x040200
612
 
  if (hasQuery())
613
 
#else
614
 
  if (!query().isEmpty())
615
 
#endif
616
 
  {
617
 
      tmp += query(); // includes the '?'
618
 
  }
619
 
  return tmp;
620
 
}
621
 
 
622
 
#if 0
623
 
void KUrl::setEncodedPath( const QString& _txt, int encoding_hint )
624
 
{
625
 
  m_strPath_encoded = _txt;
626
 
 
627
 
  decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint );
628
 
  // Throw away encoding for local files, makes file-operations faster.
629
 
  if (m_strProtocol == "file")
630
 
     m_strPath_encoded.clear();
631
 
 
632
 
  if ( m_iUriMode == Auto )
633
 
    m_iUriMode = URL;
634
 
}
635
 
#endif
636
 
 
637
 
void KUrl::setEncodedPathAndQuery( const QString& _txt )
638
 
{
639
 
  int pos = _txt.indexOf( '?' );
640
 
  if ( pos == -1 )
641
 
  {
642
 
    setPath( QUrl::fromPercentEncoding( _txt.toLatin1() ) );
643
 
    setEncodedQuery( QByteArray() );
644
 
  }
645
 
  else
646
 
  {
647
 
    setPath( QUrl::fromPercentEncoding( _txt.toLatin1() ).left( pos ) );
648
 
    _setQuery( _txt.right( _txt.length() - pos - 1 ) );
649
 
  }
650
 
}
651
 
 
652
 
QString KUrl::path( AdjustPathOption trailing ) const
653
 
{
654
 
  return trailingSlash( trailing, path() );
655
 
}
656
 
 
657
 
bool KUrl::isLocalFile() const
658
 
{
659
 
  if ( ( scheme() != "file" ) || hasSubUrl() )
660
 
     return false;
661
 
 
662
 
  if (host().isEmpty() || (host() == QLatin1String("localhost")))
663
 
     return true;
664
 
 
665
 
  char hostname[ 256 ];
666
 
  hostname[ 0 ] = '\0';
667
 
  if (!gethostname( hostname, 255 ))
668
 
     hostname[sizeof(hostname)-1] = '\0';
669
 
 
670
 
  for(char *p = hostname; *p; p++)
671
 
     *p = tolower(*p);
672
 
 
673
 
  return (host() == hostname);
674
 
}
675
 
 
676
 
void KUrl::setFileEncoding(const QString &encoding)
677
 
{
678
 
  if (!isLocalFile())
679
 
     return;
680
 
 
681
 
  QString q = query();
682
 
 
683
 
  if (!q.isEmpty() && (q[0] == '?'))
684
 
     q = q.mid(1);
685
 
 
686
 
  QStringList args = q.split('&', QString::SkipEmptyParts);
687
 
  for(QStringList::Iterator it = args.begin();
688
 
      it != args.end();)
689
 
  {
690
 
      QString s = QUrl::fromPercentEncoding( (*it).toLatin1() );
691
 
      if (s.startsWith("charset="))
692
 
         it = args.erase(it);
693
 
      else
694
 
         ++it;
695
 
  }
696
 
  if (!encoding.isEmpty())
697
 
      args.append("charset=" + QUrl::toPercentEncoding(encoding));
698
 
 
699
 
  if (args.isEmpty())
700
 
     _setQuery(QString());
701
 
  else
702
 
     _setQuery(args.join("&"));
703
 
}
704
 
 
705
 
QString KUrl::fileEncoding() const
706
 
{
707
 
  if (!isLocalFile())
708
 
     return QString();
709
 
 
710
 
  QString q = query();
711
 
 
712
 
  if (q.isEmpty())
713
 
     return QString();
714
 
 
715
 
  if (q[0] == '?')
716
 
     q = q.mid(1);
717
 
 
718
 
  QStringList args = q.split('&', QString::SkipEmptyParts);
719
 
  for(QStringList::ConstIterator it = args.begin();
720
 
      it != args.end();
721
 
      ++it)
722
 
  {
723
 
      QString s = QUrl::fromPercentEncoding((*it).toLatin1());
724
 
      if (s.startsWith("charset="))
725
 
         return s.mid(8);
726
 
  }
727
 
  return QString();
728
 
}
729
 
 
730
 
bool KUrl::hasSubUrl() const
731
 
{
732
 
  if ( scheme().isEmpty() || !isValid() )
733
 
    return false;
734
 
  const QString ref = fragment();
735
 
  if (ref.isEmpty())
736
 
     return false;
737
 
  if (ref.startsWith("gzip:"))
738
 
     return true;
739
 
  if (ref.startsWith("bzip:"))
740
 
     return true;
741
 
  if (ref.startsWith("bzip2:"))
742
 
     return true;
743
 
  if (ref.startsWith("tar:"))
744
 
     return true;
745
 
  if (ref.startsWith("ar:"))
746
 
     return true;
747
 
  if (ref.startsWith("zip:"))
748
 
     return true;
749
 
  if ( scheme() == "error" ) // anything that starts with error: has suburls
750
 
     return true;
751
 
  return false;
752
 
}
753
 
 
754
 
QString KUrl::url( AdjustPathOption trailing ) const
755
 
{
756
 
  if ( trailing == AddTrailingSlash && !path().endsWith( QLatin1Char('/') ) ) {
757
 
      // -1 and 0 are provided by QUrl, but not +1, so that one is a bit tricky.
758
 
      // To avoid reimplementing toString() all over again, I just use another QUrl
759
 
      // Let's hope this is fast, or not called often...
760
 
      QUrl newUrl( *this );
761
 
      newUrl.setPath( path() + QLatin1Char('/') );
762
 
      return QString::fromLatin1( newUrl.toEncoded() ); // ### check
763
 
  }
764
 
  return QString::fromLatin1( toEncoded( trailing == RemoveTrailingSlash ? StripTrailingSlash : None ) ); // ## check encoding
765
 
}
766
 
 
767
 
QString KUrl::prettyUrl( AdjustPathOption trailing ) const
768
 
{
769
 
  // Can't use toString(), it breaks urls with %23 in them (becomes '#', which is parsed back as a fragment)
770
 
  // So prettyUrl is just url, with the password removed.
771
 
  // We could replace some chars, like "%20" -> ' ', though?
772
 
  if ( password().isEmpty() )
773
 
    return url( trailing );
774
 
 
775
 
  QUrl newUrl( *this );
776
 
  newUrl.setPassword( QString() );
777
 
  if ( trailing == AddTrailingSlash && !path().endsWith( QLatin1Char('/') ) ) {
778
 
      // -1 and 0 are provided by QUrl, but not +1.
779
 
      newUrl.setPath( path() + QLatin1Char('/') );
780
 
      return QString::fromLatin1( newUrl.toEncoded() );
781
 
  }
782
 
  return QString::fromLatin1( newUrl.toEncoded(  trailing == RemoveTrailingSlash ? StripTrailingSlash : None ) ); // ## check encoding
783
 
}
784
 
 
785
 
#if 0
786
 
QString KUrl::prettyUrl( int _trailing, AdjustementFlags _flags) const
787
 
{
788
 
  QString u = prettyUrl(_trailing);
789
 
  if (_flags & StripFileProtocol && u.startsWith("file://")) {
790
 
    u.remove(0, 7);
791
 
#ifdef Q_WS_WIN
792
 
    return QDir::convertSeparators(u);
793
 
#endif
794
 
  }
795
 
  return u;
796
 
}
797
 
#endif
798
 
 
799
 
QString KUrl::pathOrUrl() const
800
 
{
801
 
  if ( isLocalFile() && fragment().isNull() && encodedQuery().isNull() ) {
802
 
    return path();
803
 
  } else {
804
 
    return prettyUrl();
805
 
  }
806
 
}
807
 
 
808
 
QString KUrl::toMimeDataString() const // don't fold this into populateMimeData, it's also needed by other code like konqdrag
809
 
{
810
 
  if ( isLocalFile() )
811
 
  {
812
 
#if 1
813
 
//    return url(0, KGlobal::locale()->fileEncodingMib());
814
 
// Can't do that anymore with QUrl....
815
 
//      return url( 0, QTextCodec::codecForLocale()->mibEnum() );
816
 
    return url();
817
 
#else
818
 
    // According to the XDND spec, file:/ URLs for DND must have
819
 
    // the hostname part. But in really it just breaks many apps,
820
 
    // so it's disabled for now.
821
 
    const QString s = url( 0, KGlobal::locale()->fileEncodingMib() );
822
 
    if( !s.startsWith( "file://" ))
823
 
    {
824
 
        char hostname[257];
825
 
        if ( gethostname( hostname, 255 ) == 0 )
826
 
        {
827
 
            hostname[256] = '\0';
828
 
            return QString( "file://" ) + hostname + s.mid( 5 );
829
 
        }
830
 
    }
831
 
#endif
832
 
  }
833
 
 
834
 
  if ( protocol() == "mailto" ) {
835
 
      return path();
836
 
  }
837
 
 
838
 
  return url(/*0 , 106*/); // 106 is mib enum for utf8 codec
839
 
}
840
 
 
841
 
KUrl KUrl::fromMimeDataByteArray( const QByteArray& str )
842
 
{
843
 
  if ( str.startsWith( "file:" ) )
844
 
    return KUrl( str /*, QTextCodec::codecForLocale()->mibEnum()*/ );
845
 
 
846
 
  return KUrl( str /*, 106*/ ); // 106 is mib enum for utf8 codec;
847
 
}
848
 
 
849
 
KUrl::List KUrl::split( const KUrl& _url )
850
 
{
851
 
  QString ref;
852
 
  bool hasRef;
853
 
  KUrl::List lst;
854
 
  KUrl url = _url;
855
 
 
856
 
  while(true)
857
 
  {
858
 
     KUrl u = url;
859
 
     u.setFragment( QString() );
860
 
     lst.append(u);
861
 
     if (url.hasSubUrl())
862
 
     {
863
 
        url = KUrl(url.fragment());
864
 
     }
865
 
     else
866
 
     {
867
 
        ref = url.fragment();
868
 
#if defined( QT_KDE_QT_COPY ) || QT_VERSION >= 0x040200
869
 
        hasRef = url.hasFragment();
870
 
#else
871
 
        hasRef = !ref.isEmpty();
872
 
#endif
873
 
        break;
874
 
     }
875
 
  }
876
 
 
877
 
  if ( hasRef )
878
 
  {
879
 
    // Set HTML ref in all URLs.
880
 
    KUrl::List::Iterator it;
881
 
    for( it = lst.begin() ; it != lst.end(); ++it )
882
 
    {
883
 
      (*it).setFragment( ref );
884
 
    }
885
 
  }
886
 
 
887
 
  return lst;
888
 
}
889
 
 
890
 
KUrl::List KUrl::split( const QString& _url )
891
 
{
892
 
  return split(KUrl(_url));
893
 
}
894
 
 
895
 
KUrl KUrl::join( const KUrl::List & lst )
896
 
{
897
 
  if (lst.isEmpty()) return KUrl();
898
 
  KUrl tmp;
899
 
 
900
 
 
901
 
  bool first = true;
902
 
  QListIterator<KUrl> it(lst);
903
 
  it.toBack();
904
 
  while (it.hasPrevious())
905
 
  {
906
 
     KUrl u(it.previous());
907
 
     if (!first)
908
 
     {
909
 
         // ##### problem: this encodes the '#' into %23 every time,
910
 
         // so at the 2nd level we get %2523, etc...
911
 
         u.setFragment( tmp.url() );
912
 
     }
913
 
     tmp = u;
914
 
 
915
 
     first = false;
916
 
  }
917
 
 
918
 
  return tmp;
919
 
}
920
 
 
921
 
QString KUrl::fileName( const DirectoryOptions& options ) const
922
 
{
923
 
  QString fname;
924
 
  if (hasSubUrl()) { // If we have a suburl, then return the filename from there
925
 
    KUrl::List list = KUrl::split(*this);
926
 
    return list.last().fileName(options);
927
 
  }
928
 
  const QString path = this->path();
929
 
 
930
 
  int len = path.length();
931
 
  if ( len == 0 )
932
 
    return fname;
933
 
 
934
 
  if (!(options & ObeyTrailingSlash) )
935
 
  {
936
 
    while ( len >= 1 && path[ len - 1 ] == QLatin1Char('/') )
937
 
      len--;
938
 
  }
939
 
  else if ( path[ len - 1 ] == QLatin1Char('/') )
940
 
    return fname;
941
 
 
942
 
  // Does the path only consist of '/' characters ?
943
 
  if ( len == 1 && path[ 0 ] == QLatin1Char('/') )
944
 
    return fname;
945
 
 
946
 
  // Skip last n slashes
947
 
  int n = 1;
948
 
#if 0
949
 
  if (!m_strPath_encoded.isEmpty())
950
 
  {
951
 
     // This is hairy, we need the last unencoded slash.
952
 
     // Count in the encoded string how many encoded slashes follow the last
953
 
     // unencoded one.
954
 
     int i = m_strPath_encoded.lastIndexOf( QLatin1Char('/'), len - 1 );
955
 
     QString fileName_encoded = m_strPath_encoded.mid(i+1);
956
 
     n += fileName_encoded.count("%2f", Qt::CaseInsensitive);
957
 
  }
958
 
#endif
959
 
  int i = len;
960
 
  do {
961
 
    i = path.lastIndexOf( QLatin1Char('/'), i - 1 );
962
 
  }
963
 
  while (--n && (i > 0));
964
 
 
965
 
  // If ( i == -1 ) => the first character is not a '/'
966
 
  // So it's some URL like file:blah.tgz, return the whole path
967
 
  if ( i == -1 ) {
968
 
    if ( len == (int)path.length() )
969
 
      fname = path;
970
 
    else
971
 
      // Might get here if _strip_trailing_slash is true
972
 
      fname = path.left( len );
973
 
  }
974
 
  else
975
 
  {
976
 
     fname = path.mid( i + 1, len - i - 1 ); // TO CHECK
977
 
  }
978
 
  return fname;
979
 
}
980
 
 
981
 
void KUrl::addPath( const QString& _txt )
982
 
{
983
 
  if (hasSubUrl())
984
 
  {
985
 
     KUrl::List lst = split( *this );
986
 
     KUrl &u = lst.last();
987
 
     u.addPath(_txt);
988
 
     *this = join( lst );
989
 
     return;
990
 
  }
991
 
 
992
 
  //m_strPath_encoded.clear();
993
 
 
994
 
  if ( _txt.isEmpty() )
995
 
    return;
996
 
 
997
 
  QString strPath = path();
998
 
  int i = 0;
999
 
  int len = strPath.length();
1000
 
  // Add the trailing '/' if it is missing
1001
 
  if ( _txt[0] != QLatin1Char('/') && ( len == 0 || strPath[ len - 1 ] != QLatin1Char('/') ) )
1002
 
    strPath += QLatin1Char('/');
1003
 
 
1004
 
  // No double '/' characters
1005
 
  i = 0;
1006
 
  const int _txtlen = _txt.length();
1007
 
  if ( strPath.endsWith( QLatin1Char('/') ) )
1008
 
  {
1009
 
    while ( ( i < _txtlen ) && ( _txt[i] == QLatin1Char('/') ) )
1010
 
      ++i;
1011
 
  }
1012
 
 
1013
 
  setPath( strPath + _txt.mid( i ) );
1014
 
  //kDebug(126)<<"addPath: resultpath="<<path()<<endl;
1015
 
}
1016
 
 
1017
 
QString KUrl::directory( const DirectoryOptions& options ) const
1018
 
{
1019
 
  QString result = path(); //m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded;
1020
 
  if ( !(options & ObeyTrailingSlash) )
1021
 
    result = trailingSlash( RemoveTrailingSlash, result );
1022
 
 
1023
 
  if ( result.isEmpty() || result == "/" )
1024
 
    return result;
1025
 
 
1026
 
  int i = result.lastIndexOf( "/" );
1027
 
  // If ( i == -1 ) => the first character is not a '/'
1028
 
  // So it's some URL like file:blah.tgz, with no path
1029
 
  if ( i == -1 )
1030
 
    return QString();
1031
 
 
1032
 
  if ( i == 0 )
1033
 
  {
1034
 
    result = "/";
1035
 
    return result;
1036
 
  }
1037
 
 
1038
 
  if ( options & AppendTrailingSlash )
1039
 
    result = result.left( i + 1 );
1040
 
  else
1041
 
    result = result.left( i );
1042
 
 
1043
 
  //if (!m_strPath_encoded.isEmpty())
1044
 
  //  result = decode(result);
1045
 
 
1046
 
  return result;
1047
 
}
1048
 
 
1049
 
 
1050
 
bool KUrl::cd( const QString& _dir )
1051
 
{
1052
 
  if ( _dir.isEmpty() || !isValid() )
1053
 
    return false;
1054
 
 
1055
 
  if (hasSubUrl())
1056
 
  {
1057
 
     KUrl::List lst = split( *this );
1058
 
     KUrl &u = lst.last();
1059
 
     u.cd(_dir);
1060
 
     *this = join( lst );
1061
 
     return true;
1062
 
  }
1063
 
 
1064
 
  // absolute path ?
1065
 
  if ( _dir[0] == QLatin1Char('/') )
1066
 
  {
1067
 
    //m_strPath_encoded.clear();
1068
 
    setPath( _dir );
1069
 
    setHTMLRef( QString() );
1070
 
    setEncodedQuery( QByteArray() );
1071
 
    return true;
1072
 
  }
1073
 
 
1074
 
  // Users home directory on the local disk ?
1075
 
  if ( ( _dir[0] == '~' ) && ( scheme() == "file" ))
1076
 
  {
1077
 
    //m_strPath_encoded.clear();
1078
 
    QString strPath = QDir::homePath();
1079
 
    strPath += QLatin1Char('/');
1080
 
    strPath += _dir.right( strPath.length() - 1 );
1081
 
    setPath( strPath );
1082
 
    setHTMLRef( QString() );
1083
 
    setEncodedQuery( QByteArray() );
1084
 
    return true;
1085
 
  }
1086
 
 
1087
 
  // relative path
1088
 
  // we always work on the past of the first url.
1089
 
  // Sub URLs are not touched.
1090
 
 
1091
 
  // append '/' if necessary
1092
 
  QString p = path(AddTrailingSlash);
1093
 
  p += _dir;
1094
 
  p = cleanpath( p, true, false );
1095
 
  setPath( p );
1096
 
 
1097
 
  setHTMLRef( QString() );
1098
 
  setEncodedQuery( QByteArray() );
1099
 
 
1100
 
  return true;
1101
 
}
1102
 
 
1103
 
KUrl KUrl::upUrl( ) const
1104
 
{
1105
 
  if (!encodedQuery().isEmpty())
1106
 
  {
1107
 
     KUrl u(*this);
1108
 
     u.setEncodedQuery(QByteArray());
1109
 
     return u;
1110
 
  };
1111
 
 
1112
 
  if (!hasSubUrl())
1113
 
  {
1114
 
     KUrl u(*this);
1115
 
 
1116
 
     u.cd("../");
1117
 
 
1118
 
     return u;
1119
 
  }
1120
 
 
1121
 
  // We have a subURL.
1122
 
  KUrl::List lst = split( *this );
1123
 
  if (lst.isEmpty())
1124
 
      return KUrl(); // Huh?
1125
 
  while (true)
1126
 
  {
1127
 
     KUrl &u = lst.last();
1128
 
     const QString old = u.path();
1129
 
     u.cd("../");
1130
 
     if (u.path() != old)
1131
 
         break; // Finshed.
1132
 
     if (lst.count() == 1)
1133
 
         break; // Finished.
1134
 
     lst.removeLast();
1135
 
  }
1136
 
  return join( lst );
1137
 
}
1138
 
 
1139
 
QString KUrl::htmlRef() const
1140
 
{
1141
 
  if ( !hasSubUrl() )
1142
 
  {
1143
 
      return QUrl::fromPercentEncoding( ref().toLatin1() );
1144
 
  }
1145
 
 
1146
 
  List lst = split( *this );
1147
 
  return QUrl::fromPercentEncoding( (*lst.begin()).ref().toLatin1() );
1148
 
}
1149
 
 
1150
 
QString KUrl::encodedHtmlRef() const
1151
 
{
1152
 
  if ( !hasSubUrl() )
1153
 
  {
1154
 
    return ref();
1155
 
  }
1156
 
 
1157
 
  List lst = split( *this );
1158
 
  return (*lst.begin()).ref();
1159
 
}
1160
 
 
1161
 
void KUrl::setHTMLRef( const QString& _ref )
1162
 
{
1163
 
  if ( !hasSubUrl() )
1164
 
  {
1165
 
    setFragment( _ref );
1166
 
    return;
1167
 
  }
1168
 
 
1169
 
  List lst = split( *this );
1170
 
 
1171
 
  (*lst.begin()).setFragment( _ref );
1172
 
 
1173
 
  *this = join( lst );
1174
 
}
1175
 
 
1176
 
bool KUrl::hasHTMLRef() const
1177
 
{
1178
 
  if ( !hasSubUrl() )
1179
 
  {
1180
 
    return hasRef();
1181
 
  }
1182
 
 
1183
 
  List lst = split( *this );
1184
 
  return (*lst.begin()).hasRef();
1185
 
}
1186
 
 
1187
 
void KUrl::setDirectory( const QString &dir)
1188
 
{
1189
 
  if ( dir.endsWith("/"))
1190
 
     setPath(dir);
1191
 
  else
1192
 
     setPath(dir+'/');
1193
 
}
1194
 
 
1195
 
void KUrl::setQuery( const QString &_txt )
1196
 
{
1197
 
  if (!_txt.isEmpty() && _txt[0] == '?')
1198
 
    _setQuery( _txt.length() > 1 ? _txt.mid(1) : "" /*empty, not null*/ );
1199
 
  else
1200
 
    _setQuery( _txt );
1201
 
}
1202
 
 
1203
 
void KUrl::_setQuery( const QString& query )
1204
 
{
1205
 
  setEncodedQuery( query.isNull() ? QByteArray() : query.toLatin1() ); // ### TODO encoding ok?
1206
 
}
1207
 
 
1208
 
QString KUrl::query() const
1209
 
{
1210
 
#if defined( QT_KDE_QT_COPY ) || QT_VERSION >= 0x040200
1211
 
  if (!hasQuery())
1212
 
#else
1213
 
  // For now we'll ignore the case of "a query but it's empty", waiting for Qt-4.2
1214
 
  if (query().isEmpty())
1215
 
#endif
1216
 
  {
1217
 
    return QString();
1218
 
  }
1219
 
  return QString( QChar( '?' ) ) + QString::fromAscii( encodedQuery() );
1220
 
}
1221
 
 
1222
 
bool urlcmp( const QString& _url1, const QString& _url2 )
1223
 
{
1224
 
  return QUrl( _url1, QUrl::TolerantMode ) == QUrl( _url2, QUrl::TolerantMode );
1225
 
#if 0
1226
 
  // Both empty ?
1227
 
  if ( _url1.isEmpty() && _url2.isEmpty() )
1228
 
    return true;
1229
 
  // Only one empty ?
1230
 
  if ( _url1.isEmpty() || _url2.isEmpty() )
1231
 
    return false;
1232
 
 
1233
 
  KUrl::List list1 = KUrl::split( _url1 );
1234
 
  KUrl::List list2 = KUrl::split( _url2 );
1235
 
 
1236
 
  // Malformed ?
1237
 
  if ( list1.isEmpty() || list2.isEmpty() )
1238
 
    return false;
1239
 
 
1240
 
  return ( list1 == list2 );
1241
 
#endif
1242
 
}
1243
 
 
1244
 
bool urlcmp( const QString& _url1, const QString& _url2, const KUrl::EqualsOptions& _options )
1245
 
{
1246
 
    QUrl u1( _url1 );
1247
 
    QUrl u2( _url2 );
1248
 
    QUrl::FormattingOptions options = QUrl::None;
1249
 
    if ( _options & KUrl::CompareWithoutTrailingSlash )
1250
 
        options |= QUrl::StripTrailingSlash;
1251
 
    if ( _options & KUrl::CompareWithoutFragment )
1252
 
        options |= QUrl::RemoveFragment;
1253
 
    return u1.toString( options ) == u2.toString( options );
1254
 
 
1255
 
#if 0
1256
 
  // Both empty ?
1257
 
  if ( _url1.isEmpty() && _url2.isEmpty() )
1258
 
    return true;
1259
 
  // Only one empty ?
1260
 
  if ( _url1.isEmpty() || _url2.isEmpty() )
1261
 
    return false;
1262
 
 
1263
 
  KUrl::List list1 = KUrl::split( _url1 );
1264
 
  KUrl::List list2 = KUrl::split( _url2 );
1265
 
 
1266
 
  // Malformed ?
1267
 
  if ( list1.isEmpty() || list2.isEmpty() )
1268
 
    return false;
1269
 
 
1270
 
  int size = list1.count();
1271
 
  if ( list2.count() != size )
1272
 
    return false;
1273
 
 
1274
 
  if ( _ignore_ref )
1275
 
  {
1276
 
    (*list1.begin()).setRef(QString());
1277
 
    (*list2.begin()).setRef(QString());
1278
 
  }
1279
 
 
1280
 
  KUrl::List::Iterator it1 = list1.begin();
1281
 
  KUrl::List::Iterator it2 = list2.begin();
1282
 
  for( ; it1 != list1.end() ; ++it1, ++it2 )
1283
 
    if ( !(*it1).equals( *it2, _ignore_trailing ) )
1284
 
      return false;
1285
 
  return true;
1286
 
#endif
1287
 
}
1288
 
 
1289
 
// static
1290
 
KUrl KUrl::fromPathOrUrl( const QString& text )
1291
 
{
1292
 
    KUrl url;
1293
 
    if ( !text.isEmpty() )
1294
 
    {
1295
 
        if (!QDir::isRelativePath(text) || text[0] == '~')
1296
 
            url.setPath( text );
1297
 
        else
1298
 
            url = KUrl( text );
1299
 
    }
1300
 
 
1301
 
    return url;
1302
 
}
1303
 
 
1304
 
static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent)
1305
 
{
1306
 
   QString _base_dir(QDir::cleanPath(base_dir));
1307
 
   QString _path(QDir::cleanPath(path.isEmpty() || (path[0] != QLatin1Char('/')) ? _base_dir+'/'+path : path));
1308
 
 
1309
 
   if (_base_dir.isEmpty())
1310
 
      return _path;
1311
 
 
1312
 
   if (_base_dir[_base_dir.length()-1] != QLatin1Char('/'))
1313
 
      _base_dir.append(QLatin1Char('/') );
1314
 
 
1315
 
   QStringList list1 = _base_dir.split(QLatin1Char('/'), QString::SkipEmptyParts);
1316
 
   QStringList list2 = _path.split(QLatin1Char('/'), QString::SkipEmptyParts);
1317
 
 
1318
 
   // Find where they meet
1319
 
   int level = 0;
1320
 
   int maxLevel = qMin(list1.count(), list2.count());
1321
 
   while((level < maxLevel) && (list1[level] == list2[level])) level++;
1322
 
 
1323
 
   QString result;
1324
 
   // Need to go down out of the first path to the common branch.
1325
 
   for(int i = level; i < list1.count(); i++)
1326
 
      result.append("../");
1327
 
 
1328
 
   // Now up up from the common branch to the second path.
1329
 
   for(int i = level; i < list2.count(); i++)
1330
 
      result.append(list2[i]).append("/");
1331
 
 
1332
 
   if ((level < list2.count()) && (path[path.length()-1] != QLatin1Char('/')))
1333
 
      result.truncate(result.length()-1);
1334
 
 
1335
 
   isParent = (level == list1.count());
1336
 
 
1337
 
   return result;
1338
 
}
1339
 
 
1340
 
QString KUrl::relativePath(const QString &base_dir, const QString &path, bool *isParent)
1341
 
{
1342
 
   bool parent = false;
1343
 
   QString result = _relativePath(base_dir, path, parent);
1344
 
   if (parent)
1345
 
      result.prepend("./");
1346
 
 
1347
 
   if (isParent)
1348
 
      *isParent = parent;
1349
 
 
1350
 
   return result;
1351
 
}
1352
 
 
1353
 
 
1354
 
QString KUrl::relativeUrl(const KUrl &base_url, const KUrl &url)
1355
 
{
1356
 
   if ((url.protocol() != base_url.protocol()) ||
1357
 
       (url.host() != base_url.host()) ||
1358
 
       (url.port() && url.port() != base_url.port()) ||
1359
 
       (url.hasUser() && url.user() != base_url.user()) ||
1360
 
       (url.hasPass() && url.pass() != base_url.pass()))
1361
 
   {
1362
 
      return url.url();
1363
 
   }
1364
 
 
1365
 
   QString relURL;
1366
 
 
1367
 
   if ((base_url.path() != url.path()) || (base_url.query() != url.query()))
1368
 
   {
1369
 
      bool dummy;
1370
 
      QString basePath = base_url.directory(KUrl::ObeyTrailingSlash);
1371
 
      relURL = _relativePath(basePath, url.path(), dummy); // was QUrl::toPercentEncoding() but why?
1372
 
      relURL += url.query();
1373
 
   }
1374
 
 
1375
 
   if ( url.hasRef() )
1376
 
   {
1377
 
      relURL += '#';
1378
 
      relURL += url.ref();
1379
 
   }
1380
 
 
1381
 
   if ( relURL.isEmpty() )
1382
 
      return "./";
1383
 
 
1384
 
   return relURL;
1385
 
}
1386
 
 
1387
 
void KUrl::setPath( const QString& _path )
1388
 
{
1389
 
    if ( scheme().isEmpty() )
1390
 
        setScheme( "file" );
1391
 
#ifndef KDE_QT_ONLY
1392
 
    QString path = KShell::tildeExpand( _path );
1393
 
#else
1394
 
    const QString& path = _path;
1395
 
#endif
1396
 
    QUrl::setPath( path );
1397
 
}
1398
 
 
1399
 
#if 0 // this would be if we didn't decode '+' into ' '
1400
 
QMap< QString, QString > KUrl::queryItems( int options ) const {
1401
 
  QMap< QString, QString > result;
1402
 
  const QList<QPair<QString, QString> > items = QUrl::queryItems();
1403
 
  QPair<QString, QString> item;
1404
 
  Q_FOREACH( item, items ) {
1405
 
      result.insert( options & CaseInsensitiveKeys ? item.first.toLower() : item.first, item.second );
1406
 
  }
1407
 
  return result;
1408
 
}
1409
 
#endif
1410
 
 
1411
 
QMap< QString, QString > KUrl::queryItems( const QueryItemsOptions &options ) const {
1412
 
  const QString strQueryEncoded = encodedQuery();
1413
 
  if ( strQueryEncoded.isEmpty() )
1414
 
    return QMap<QString,QString>();
1415
 
 
1416
 
  QMap< QString, QString > result;
1417
 
  const QStringList items = strQueryEncoded.split( '&', QString::SkipEmptyParts );
1418
 
  for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) {
1419
 
    const int equal_pos = (*it).indexOf( '=' );
1420
 
    if ( equal_pos > 0 ) { // = is not the first char...
1421
 
      QString name = (*it).left( equal_pos );
1422
 
      if ( options & CaseInsensitiveKeys )
1423
 
        name = name.toLower();
1424
 
      QString value = (*it).mid( equal_pos + 1 );
1425
 
      if ( value.isEmpty() )
1426
 
        result.insert( name, QString::fromLatin1("") );
1427
 
      else {
1428
 
        // ### why is decoding name not necessary?
1429
 
        value.replace( '+', ' ' ); // + in queries means space
1430
 
        result.insert( name, QUrl::fromPercentEncoding( value.toLatin1() ) );
1431
 
      }
1432
 
    } else if ( equal_pos < 0 ) { // no =
1433
 
      QString name = (*it);
1434
 
      if ( options & CaseInsensitiveKeys )
1435
 
        name = name.toLower();
1436
 
      result.insert( name, QString() );
1437
 
    }
1438
 
  }
1439
 
 
1440
 
  return result;
1441
 
}
1442
 
 
1443
 
QString KUrl::queryItem( const QString& _item ) const
1444
 
{
1445
 
  const QString strQueryEncoded = encodedQuery();
1446
 
  const QString item = _item + '=';
1447
 
  if ( strQueryEncoded.length() <= 1 )
1448
 
    return QString();
1449
 
 
1450
 
  const QStringList items = strQueryEncoded.split( '&', QString::SkipEmptyParts );
1451
 
  const int _len = item.length();
1452
 
  for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it )
1453
 
  {
1454
 
    if ( (*it).startsWith( item ) )
1455
 
    {
1456
 
      if ( (*it).length() > _len )
1457
 
      {
1458
 
        QString str = (*it).mid( _len );
1459
 
        str.replace( '+', ' ' ); // + in queries means space.
1460
 
        return QUrl::fromPercentEncoding( str.toLatin1() );
1461
 
      }
1462
 
      else // empty value
1463
 
        return QString::fromLatin1("");
1464
 
    }
1465
 
  }
1466
 
 
1467
 
  return QString();
1468
 
}
1469
 
 
1470
 
void KUrl::addQueryItem( const QString& _item, const QString& _value )
1471
 
{
1472
 
  QString item = _item + '=';
1473
 
  QString value = QUrl::toPercentEncoding( _value );
1474
 
 
1475
 
  QString strQueryEncoded = encodedQuery();
1476
 
  if (!strQueryEncoded.isEmpty())
1477
 
     strQueryEncoded += '&';
1478
 
  strQueryEncoded += item + value;
1479
 
  setEncodedQuery( strQueryEncoded.toLatin1() );
1480
 
}
1481
 
 
1482
 
void KUrl::populateMimeData( QMimeData* mimeData,
1483
 
                             const MetaDataMap& metaData,
1484
 
                             MimeDataFlags flags ) const
1485
 
{
1486
 
  KUrl::List lst( *this );
1487
 
  lst.populateMimeData( mimeData, metaData, flags );
1488
 
}
1489
 
 
1490
 
bool KUrl::hasRef() const
1491
 
{
1492
 
#if defined( QT_KDE_QT_COPY ) || QT_VERSION >= 0x040200
1493
 
  return hasFragment();
1494
 
#else
1495
 
  // For now we'll ignore the case of "a fragment but it's empty", waiting for Qt-4.2
1496
 
  return !fragment().isEmpty();
1497
 
#endif
1498
 
}
1499
 
 
1500
 
void KUrl::setRef( const QString& fragment )
1501
 
{
1502
 
  if ( fragment.isNull() )
1503
 
    setFragment( fragment ); // pass null, not empty
1504
 
  else
1505
 
    setFragment( QUrl::fromPercentEncoding( fragment.toLatin1() ) );
1506
 
}