2014-11-13 01:04:59 +02:00
|
|
|
/*
|
|
|
|
Copyright (C) 1999 Torben Weis <weis@kde.org>
|
|
|
|
Copyright (C) 2005-2006 David Faure <faure@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/// KDE4 TODO: maybe we should use QUrl::resolved()
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The currently active RFC for URL/URIs is RFC3986
|
|
|
|
* Previous (and now deprecated) RFCs are RFC1738 and RFC2396
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kurl.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kglobal.h>
|
|
|
|
#include <kshell.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <QtCore/QDir>
|
2019-06-21 19:56:58 +00:00
|
|
|
#include <QtCore/QStringList>
|
2014-11-13 01:04:59 +02:00
|
|
|
#include <QtCore/QRegExp>
|
|
|
|
#include <QtCore/QMimeData>
|
|
|
|
#include <QtCore/QTextCodec>
|
2019-06-21 19:56:58 +00:00
|
|
|
#include <QtNetwork/QHostInfo>
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
#ifdef DEBUG_KURL
|
|
|
|
static int kurlDebugArea() { static int s_area = KDebug::registerArea("kdecore (KUrl)"); return s_area; }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static QString cleanpath( const QString &_path, bool cleanDirSeparator, bool decodeDots )
|
|
|
|
{
|
|
|
|
if (_path.isEmpty())
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
if (QFileInfo(_path).isRelative())
|
|
|
|
return _path; // Don't mangle mailto-style URLs
|
|
|
|
|
|
|
|
QString path = _path;
|
|
|
|
|
|
|
|
int len = path.length();
|
|
|
|
|
|
|
|
if (decodeDots)
|
|
|
|
{
|
2016-05-26 15:51:32 +00:00
|
|
|
static const QString &encodedDot = KGlobal::staticQString(QLatin1String("%2e"));
|
2014-11-13 01:04:59 +02:00
|
|
|
if (path.indexOf(encodedDot, 0, Qt::CaseInsensitive) != -1)
|
|
|
|
{
|
2016-05-26 15:51:32 +00:00
|
|
|
static const QString &encodedDOT = KGlobal::staticQString(QLatin1String("%2E")); // Uppercase!
|
2014-11-13 01:04:59 +02:00
|
|
|
path.replace(encodedDot, QString(QLatin1Char('.')));
|
|
|
|
path.replace(encodedDOT, QString(QLatin1Char('.')));
|
|
|
|
len = path.length();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const bool slash = (len && path[len-1] == QLatin1Char('/')) ||
|
|
|
|
(len > 1 && path[len-2] == QLatin1Char('/') && path[len-1] == QLatin1Char('.'));
|
|
|
|
|
|
|
|
// The following code cleans up directory path much like
|
|
|
|
// QDir::cleanPath() except it can be made to ignore multiple
|
|
|
|
// directory separators by setting the flag to false. That fixes
|
|
|
|
// bug# 15044, mail.altavista.com and other similar brain-dead server
|
|
|
|
// implementations that do not follow what has been specified in
|
|
|
|
// RFC 2396!! (dA)
|
|
|
|
QString result;
|
|
|
|
int cdUp, orig_pos, pos;
|
|
|
|
|
|
|
|
cdUp = 0;
|
|
|
|
pos = orig_pos = len;
|
|
|
|
while ( pos && (pos = path.lastIndexOf(QLatin1Char('/'),--pos)) != -1 )
|
|
|
|
{
|
|
|
|
len = orig_pos - pos - 1;
|
|
|
|
if ( len == 2 && path[pos+1] == QLatin1Char('.') && path[pos+2] == QLatin1Char('.') )
|
|
|
|
cdUp++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Ignore any occurrences of '.'
|
|
|
|
// This includes entries that simply do not make sense like /..../
|
|
|
|
if ( (len || !cleanDirSeparator) &&
|
|
|
|
(len != 1 || path[pos+1] != QLatin1Char('.') ) )
|
|
|
|
{
|
|
|
|
if ( !cdUp )
|
|
|
|
result.prepend(path.mid(pos, len+1));
|
|
|
|
else
|
|
|
|
cdUp--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
orig_pos = pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( result.isEmpty() )
|
|
|
|
result = QLatin1Char('/');
|
|
|
|
else if ( slash && result[result.length()-1] != QLatin1Char('/') )
|
|
|
|
result.append(QLatin1Char('/'));
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KUrl::isRelativeUrl(const QString &_url)
|
|
|
|
{
|
|
|
|
int len = _url.length();
|
|
|
|
if (!len) return true; // Very short relative URL.
|
|
|
|
const QChar *str = _url.unicode();
|
|
|
|
|
|
|
|
// Absolute URL must start with alpha-character
|
|
|
|
if (!isalpha(str[0].toLatin1()))
|
|
|
|
return true; // Relative URL
|
|
|
|
|
|
|
|
for(int i = 1; i < len; i++)
|
|
|
|
{
|
|
|
|
char c = str[i].toLatin1(); // Note: non-latin1 chars return 0!
|
|
|
|
if (c == ':')
|
|
|
|
return false; // Absolute URL
|
|
|
|
|
|
|
|
// Protocol part may only contain alpha, digit, + or -
|
|
|
|
if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-'))
|
|
|
|
return true; // Relative URL
|
|
|
|
}
|
|
|
|
// URL did not contain ':'
|
|
|
|
return true; // Relative URL
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List::List(const KUrl &url)
|
|
|
|
{
|
|
|
|
append( url );
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List::List(const QList<KUrl> &list)
|
|
|
|
: QList<KUrl>(list)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List::List(const QList<QUrl> &list)
|
|
|
|
{
|
|
|
|
foreach(const QUrl& url, list) {
|
|
|
|
append(KUrl(url));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List::List(const QStringList &list)
|
|
|
|
{
|
|
|
|
for (QStringList::ConstIterator it = list.begin();
|
|
|
|
it != list.end();
|
|
|
|
++it)
|
|
|
|
{
|
|
|
|
append( KUrl(*it) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList KUrl::List::toStringList() const
|
|
|
|
{
|
|
|
|
return toStringList(KUrl::LeaveTrailingSlash);
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList KUrl::List::toStringList(KUrl::AdjustPathOption trailing) const
|
|
|
|
{
|
|
|
|
QStringList lst;
|
|
|
|
for(KUrl::List::ConstIterator it = constBegin();
|
|
|
|
it != constEnd(); ++it) {
|
|
|
|
lst.append(it->url(trailing));
|
|
|
|
}
|
|
|
|
return lst;
|
|
|
|
}
|
|
|
|
|
|
|
|
static QByteArray uriListData(const KUrl::List& urls)
|
|
|
|
{
|
2015-09-28 15:50:22 +00:00
|
|
|
QByteArray uriListData;
|
|
|
|
foreach(const KUrl uit, urls) {
|
2014-11-13 01:04:59 +02:00
|
|
|
// Get each URL encoded in utf8 - and since we get it in escaped
|
|
|
|
// form on top of that, .toLatin1() is fine.
|
2015-09-28 15:50:22 +00:00
|
|
|
uriListData += uit.toMimeDataString().toLatin1();
|
2015-10-01 10:25:57 +03:00
|
|
|
uriListData += "\r\n";
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return uriListData;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char s_kdeUriListMime[] = "application/x-kde4-urilist";
|
|
|
|
|
|
|
|
void KUrl::List::populateMimeData( QMimeData* mimeData,
|
|
|
|
const KUrl::MetaDataMap& metaData,
|
|
|
|
MimeDataFlags flags ) const
|
|
|
|
{
|
|
|
|
mimeData->setData(QString::fromLatin1("text/uri-list"), uriListData(*this));
|
|
|
|
|
|
|
|
if ( ( flags & KUrl::NoTextExport ) == 0 )
|
|
|
|
{
|
|
|
|
QStringList prettyURLsList;
|
|
|
|
KUrl::List::ConstIterator uit = constBegin();
|
|
|
|
const KUrl::List::ConstIterator uEnd = constEnd();
|
|
|
|
for ( ; uit != uEnd ; ++uit ) {
|
|
|
|
QString prettyURL = (*uit).prettyUrl();
|
|
|
|
if ( (*uit).protocol() == QLatin1String("mailto") ) {
|
|
|
|
prettyURL = (*uit).path(); // remove mailto: when pasting into konsole
|
|
|
|
}
|
|
|
|
prettyURLsList.append( prettyURL );
|
|
|
|
}
|
|
|
|
|
|
|
|
QByteArray plainTextData = prettyURLsList.join(QString(QLatin1Char('\n'))).toLocal8Bit();
|
|
|
|
if( count() > 1 ) // terminate last line, unless it's the only line
|
|
|
|
plainTextData.append( "\n" );
|
|
|
|
mimeData->setData( QString::fromLatin1("text/plain"), plainTextData );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !metaData.isEmpty() )
|
|
|
|
{
|
|
|
|
QByteArray metaDataData; // :)
|
2015-09-28 16:08:18 +00:00
|
|
|
QMapIterator<QString, QString> it(metaData);
|
2015-09-28 15:50:22 +00:00
|
|
|
while(it.hasNext())
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
2015-09-28 15:50:22 +00:00
|
|
|
it.next();
|
2014-11-13 01:04:59 +02:00
|
|
|
metaDataData += it.key().toUtf8();
|
|
|
|
metaDataData += "$@@$";
|
|
|
|
metaDataData += it.value().toUtf8();
|
|
|
|
metaDataData += "$@@$";
|
|
|
|
}
|
|
|
|
mimeData->setData( QString::fromLatin1("application/x-kio-metadata"), metaDataData );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KUrl::List::populateMimeData(const KUrl::List& mostLocalUrls,
|
|
|
|
QMimeData* mimeData,
|
|
|
|
const KUrl::MetaDataMap& metaData,
|
|
|
|
MimeDataFlags flags) const
|
|
|
|
{
|
|
|
|
// Export the most local urls as text/uri-list and plain text.
|
|
|
|
mostLocalUrls.populateMimeData(mimeData, metaData, flags);
|
|
|
|
|
|
|
|
mimeData->setData(QString::fromLatin1(s_kdeUriListMime), uriListData(*this));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KUrl::List::canDecode( const QMimeData *mimeData )
|
|
|
|
{
|
|
|
|
return mimeData->hasFormat(QString::fromLatin1("text/uri-list")) ||
|
|
|
|
mimeData->hasFormat(QString::fromLatin1(s_kdeUriListMime));
|
|
|
|
}
|
|
|
|
|
|
|
|
QStringList KUrl::List::mimeDataTypes()
|
|
|
|
{
|
|
|
|
return QStringList() << QString::fromLatin1(s_kdeUriListMime) << QString::fromLatin1("text/uri-list");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KUrl::List KUrl::List::fromMimeData(const QMimeData *mimeData,
|
2016-03-29 23:43:20 +00:00
|
|
|
KUrl::MetaDataMap* metaData,
|
|
|
|
DecodeOptions decodeOptions)
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
|
|
|
|
KUrl::List uris;
|
|
|
|
const char* firstMimeType = s_kdeUriListMime;
|
|
|
|
const char* secondMimeType = "text/uri-list";
|
|
|
|
if (decodeOptions == PreferLocalUrls) {
|
|
|
|
qSwap(firstMimeType, secondMimeType);
|
|
|
|
}
|
|
|
|
QByteArray payload = mimeData->data(QString::fromLatin1(firstMimeType));
|
|
|
|
if (payload.isEmpty())
|
|
|
|
payload = mimeData->data(QString::fromLatin1(secondMimeType));
|
|
|
|
if ( !payload.isEmpty() ) {
|
|
|
|
int c = 0;
|
|
|
|
const char* d = payload.constData();
|
|
|
|
while ( c < payload.size() && d[c] ) {
|
|
|
|
int f = c;
|
|
|
|
// Find line end
|
|
|
|
while (c < payload.size() && d[c] && d[c]!='\r'
|
|
|
|
&& d[c] != '\n')
|
|
|
|
c++;
|
|
|
|
QByteArray s( d+f, c-f );
|
|
|
|
if ( s[0] != '#' ) // non-comment?
|
|
|
|
uris.append( KUrl::fromMimeDataByteArray( s ) );
|
|
|
|
// Skip junk
|
|
|
|
while ( c < payload.size() && d[c] &&
|
|
|
|
( d[c] == '\n' || d[c] == '\r' ) )
|
|
|
|
++c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( metaData )
|
|
|
|
{
|
|
|
|
const QByteArray metaDataPayload = mimeData->data(QLatin1String("application/x-kio-metadata"));
|
|
|
|
if ( !metaDataPayload.isEmpty() )
|
|
|
|
{
|
|
|
|
QString str = QString::fromUtf8( metaDataPayload );
|
|
|
|
Q_ASSERT(str.endsWith(QLatin1String("$@@$")));
|
|
|
|
str.truncate( str.length() - 4 );
|
|
|
|
const QStringList lst = str.split(QLatin1String("$@@$"));
|
|
|
|
bool readingKey = true; // true, then false, then true, etc.
|
|
|
|
QString key;
|
2015-09-28 15:50:22 +00:00
|
|
|
foreach(const QString it, lst) {
|
2014-11-13 01:04:59 +02:00
|
|
|
if ( readingKey )
|
2015-09-28 15:50:22 +00:00
|
|
|
key = it;
|
2014-11-13 01:04:59 +02:00
|
|
|
else
|
2015-09-28 15:50:22 +00:00
|
|
|
metaData->insert( key, it );
|
2014-11-13 01:04:59 +02:00
|
|
|
readingKey = !readingKey;
|
|
|
|
}
|
|
|
|
Q_ASSERT( readingKey ); // an odd number of items would be, well, odd ;-)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return uris;
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List::operator QVariant() const
|
|
|
|
{
|
|
|
|
return qVariantFromValue(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List::operator QList<QUrl>() const
|
|
|
|
{
|
|
|
|
QList<QUrl> list;
|
|
|
|
foreach(const KUrl& url, *this) {
|
|
|
|
list << url;
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
KUrl::KUrl()
|
2017-08-03 11:20:08 +00:00
|
|
|
: QUrl()
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::~KUrl()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KUrl::KUrl( const QString &str )
|
2017-08-03 11:20:08 +00:00
|
|
|
: QUrl()
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
if ( !str.isEmpty() ) {
|
|
|
|
if ( str[0] == QLatin1Char('/') || str[0] == QLatin1Char('~') )
|
|
|
|
setPath( str );
|
|
|
|
else {
|
|
|
|
_setEncodedUrl( str.toUtf8() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::KUrl( const char * str )
|
2017-08-03 11:20:08 +00:00
|
|
|
: QUrl()
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
if ( str && str[0] ) {
|
|
|
|
if ( str[0] == '/' || str[0] == '~' )
|
|
|
|
setPath( QString::fromUtf8( str ) );
|
|
|
|
else
|
|
|
|
_setEncodedUrl( str );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::KUrl( const QByteArray& str )
|
2017-08-03 11:20:08 +00:00
|
|
|
: QUrl()
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
if ( !str.isEmpty() ) {
|
|
|
|
if ( str[0] == '/' || str[0] == '~' )
|
|
|
|
setPath( QString::fromUtf8( str ) );
|
|
|
|
else
|
|
|
|
_setEncodedUrl( str );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::KUrl( const KUrl& _u )
|
2017-08-03 11:20:08 +00:00
|
|
|
: QUrl( _u )
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::KUrl( const QUrl &u )
|
2017-08-03 11:20:08 +00:00
|
|
|
: QUrl( u )
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::KUrl( const KUrl& _u, const QString& _rel_url )
|
2017-08-03 11:20:08 +00:00
|
|
|
: QUrl()
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (_u.hasSubUrl()) // Operate on the last suburl, not the first
|
|
|
|
{
|
|
|
|
KUrl::List lst = split( _u );
|
|
|
|
KUrl u(lst.last(), _rel_url);
|
|
|
|
lst.erase( --lst.end() );
|
|
|
|
lst.append( u );
|
|
|
|
*this = join( lst );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
QString rUrl = _rel_url;
|
|
|
|
|
|
|
|
// WORKAROUND THE RFC 1606 LOOPHOLE THAT ALLOWS
|
|
|
|
// http:/index.html AS A VALID SYNTAX FOR RELATIVE
|
|
|
|
// URLS. ( RFC 2396 section 5.2 item # 3 )
|
|
|
|
const int len = _u.scheme().length();
|
|
|
|
if ( !_u.host().isEmpty() && !rUrl.isEmpty() &&
|
|
|
|
rUrl.indexOf( _u.scheme(), 0, Qt::CaseInsensitive ) == 0 &&
|
|
|
|
rUrl[len] == QLatin1Char(':') && (rUrl[len+1] != QLatin1Char('/') ||
|
|
|
|
(rUrl[len+1] == QLatin1Char('/') && rUrl[len+2] != QLatin1Char('/'))) )
|
|
|
|
{
|
|
|
|
rUrl.remove( 0, rUrl.indexOf( QLatin1Char(':') ) + 1 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( rUrl.isEmpty() )
|
|
|
|
{
|
|
|
|
*this = _u;
|
|
|
|
}
|
|
|
|
else if ( rUrl[0] == QLatin1Char('#') )
|
|
|
|
{
|
|
|
|
*this = _u;
|
|
|
|
QByteArray strRef_encoded = rUrl.mid(1).toLatin1();
|
|
|
|
if ( strRef_encoded.isNull() )
|
|
|
|
setFragment(QString::fromLatin1("")); // we know there was an (empty) html ref, we saw the '#'
|
|
|
|
else
|
|
|
|
setFragment(QUrl::fromPercentEncoding(strRef_encoded));
|
|
|
|
}
|
|
|
|
else if ( isRelativeUrl( rUrl ) )
|
|
|
|
{
|
|
|
|
*this = _u;
|
|
|
|
setFragment( QString() );
|
|
|
|
setEncodedQuery( QByteArray() );
|
|
|
|
QString strPath = path();
|
|
|
|
if ( rUrl[0] == QLatin1Char('/') )
|
|
|
|
{
|
|
|
|
if ((rUrl.length() > 1) && (rUrl[1] == QLatin1Char('/')))
|
|
|
|
{
|
|
|
|
setHost( QString() );
|
|
|
|
setPort( -1 );
|
|
|
|
// File protocol returns file:/// without host, strip // from rUrl
|
|
|
|
if ( _u.isLocalFile() )
|
|
|
|
rUrl.remove(0, 2);
|
|
|
|
}
|
|
|
|
strPath.clear();
|
|
|
|
}
|
|
|
|
else if ( rUrl[0] != QLatin1Char('?') )
|
|
|
|
{
|
|
|
|
const int pos = strPath.lastIndexOf( QLatin1Char('/') );
|
|
|
|
if (pos >= 0)
|
|
|
|
strPath.truncate(pos);
|
|
|
|
strPath += QLatin1Char('/');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( strPath.isEmpty() )
|
|
|
|
strPath = QLatin1Char('/');
|
|
|
|
}
|
|
|
|
setPath( strPath );
|
|
|
|
//kDebug(kurlDebugArea()) << "url()=" << url() << " rUrl=" << rUrl;
|
|
|
|
const KUrl tmp( url() + rUrl);
|
|
|
|
//kDebug(kurlDebugArea()) << "assigning tmp=" << tmp.url();
|
|
|
|
*this = tmp;
|
|
|
|
cleanPath(KeepDirSeparators);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const KUrl tmp( rUrl );
|
|
|
|
//kDebug(kurlDebugArea()) << "not relative; assigning tmp=" << tmp.url();
|
|
|
|
*this = tmp;
|
|
|
|
// Preserve userinfo if applicable.
|
|
|
|
if (!_u.userInfo().isEmpty() && userInfo().isEmpty()
|
|
|
|
&& (_u.host() == host()) && (_u.scheme() == scheme()))
|
|
|
|
{
|
|
|
|
setUserInfo( _u.userInfo() );
|
|
|
|
}
|
|
|
|
cleanPath(KeepDirSeparators);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl& KUrl::operator=( const KUrl& _u )
|
|
|
|
{
|
|
|
|
QUrl::operator=( _u );
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KUrl::operator==( const KUrl& _u ) const
|
|
|
|
{
|
|
|
|
return QUrl::operator==( _u );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KUrl::operator==( const QString& _u ) const
|
|
|
|
{
|
|
|
|
KUrl u( _u );
|
|
|
|
return ( *this == u );
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::operator QVariant() const
|
|
|
|
{
|
|
|
|
return qVariantFromValue(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KUrl::equals( const KUrl &_u, const EqualsOptions& options ) const
|
|
|
|
{
|
|
|
|
if ( !isValid() || !_u.isValid() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( options & CompareWithoutTrailingSlash || options & CompareWithoutFragment )
|
|
|
|
{
|
|
|
|
QString path1 = path((options & CompareWithoutTrailingSlash) ? RemoveTrailingSlash : LeaveTrailingSlash);
|
|
|
|
QString path2 = _u.path((options & CompareWithoutTrailingSlash) ? RemoveTrailingSlash : LeaveTrailingSlash);
|
|
|
|
|
|
|
|
if (options & AllowEmptyPath) {
|
|
|
|
if (path1 == QLatin1String("/"))
|
|
|
|
path1.clear();
|
|
|
|
if (path2 == QLatin1String("/"))
|
|
|
|
path2.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( path1 != path2 )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( scheme() == _u.scheme() &&
|
|
|
|
authority() == _u.authority() && // user+pass+host+port
|
|
|
|
encodedQuery() == _u.encodedQuery() &&
|
|
|
|
(fragment() == _u.fragment() || options & CompareWithoutFragment ) )
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ( *this == _u );
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl KUrl::fromPath( const QString& text )
|
|
|
|
{
|
|
|
|
KUrl u;
|
|
|
|
u.setPath( text );
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::setFileName( const QString& _txt )
|
|
|
|
{
|
|
|
|
setFragment( QString() );
|
|
|
|
int i = 0;
|
|
|
|
while( i < _txt.length() && _txt[i] == QLatin1Char('/') )
|
|
|
|
++i;
|
|
|
|
QString tmp = i ? _txt.mid( i ) : _txt;
|
|
|
|
|
|
|
|
QString path = this->path();
|
|
|
|
if ( path.isEmpty() )
|
|
|
|
path = QDir::rootPath();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int lastSlash = path.lastIndexOf( QLatin1Char('/') );
|
|
|
|
if ( lastSlash == -1)
|
|
|
|
path.clear(); // there's only the file name, remove it
|
|
|
|
else if ( !path.endsWith( QLatin1Char('/') ) )
|
|
|
|
path.truncate( lastSlash+1 ); // keep the "/"
|
|
|
|
}
|
|
|
|
|
|
|
|
path += tmp;
|
|
|
|
setPath( path );
|
|
|
|
|
|
|
|
cleanPath();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::cleanPath( const CleanPathOption& options )
|
|
|
|
{
|
|
|
|
//if (m_iUriMode != URL) return;
|
|
|
|
const QString newPath = cleanpath(path(), !(options & KeepDirSeparators), false);
|
|
|
|
if ( path() != newPath )
|
|
|
|
setPath( newPath );
|
|
|
|
// WABA: Is this safe when "/../" is encoded with %?
|
|
|
|
//m_strPath_encoded = cleanpath(m_strPath_encoded, cleanDirSeparator, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString trailingSlash( KUrl::AdjustPathOption trailing, const QString &path )
|
|
|
|
{
|
|
|
|
if ( trailing == KUrl::LeaveTrailingSlash ) {
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString result = path;
|
|
|
|
|
|
|
|
if ( trailing == KUrl::AddTrailingSlash )
|
|
|
|
{
|
|
|
|
int len = result.length();
|
|
|
|
if ((len > 0) && (result[ len - 1 ] != QLatin1Char('/')))
|
|
|
|
result += QLatin1Char('/');
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else if ( trailing == KUrl::RemoveTrailingSlash )
|
|
|
|
{
|
|
|
|
if ( result == QLatin1String("/") )
|
|
|
|
return result;
|
|
|
|
int len = result.length();
|
|
|
|
while (len > 1 && result[ len - 1 ] == QLatin1Char('/'))
|
|
|
|
{
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
result.truncate( len );
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
assert( 0 );
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::adjustPath( AdjustPathOption trailing )
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (!m_strPath_encoded.isEmpty())
|
|
|
|
{
|
|
|
|
m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
const QString newPath = trailingSlash( trailing, path() );
|
|
|
|
if ( path() != newPath )
|
|
|
|
setPath( newPath );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString KUrl::encodedPathAndQuery( AdjustPathOption trailing , const EncodedPathAndQueryOptions &options) const
|
|
|
|
{
|
|
|
|
QString encodedPath;
|
|
|
|
encodedPath = trailingSlash(trailing, QString::fromLatin1(QUrl::encodedPath()));
|
|
|
|
|
|
|
|
if ((options & AvoidEmptyPath) && encodedPath.isEmpty()) {
|
|
|
|
encodedPath.append(QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasQuery()) {
|
|
|
|
return encodedPath + QLatin1Char('?') + QString::fromLatin1(encodedQuery());
|
|
|
|
} else {
|
|
|
|
return encodedPath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
void KUrl::setEncodedPath( const QString& _txt, int encoding_hint )
|
|
|
|
{
|
|
|
|
m_strPath_encoded = _txt;
|
|
|
|
|
|
|
|
decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint );
|
|
|
|
// Throw away encoding for local files, makes file-operations faster.
|
|
|
|
if (m_strProtocol == "file")
|
|
|
|
m_strPath_encoded.clear();
|
|
|
|
|
|
|
|
if ( m_iUriMode == Auto )
|
|
|
|
m_iUriMode = URL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void KUrl::setEncodedPathAndQuery( const QString& _txt )
|
|
|
|
{
|
|
|
|
const int pos = _txt.indexOf(QLatin1Char('?'));
|
|
|
|
if ( pos == -1 )
|
|
|
|
{
|
|
|
|
setPath( QUrl::fromPercentEncoding( _txt.toLatin1() ) );
|
|
|
|
setEncodedQuery( QByteArray() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setPath( QUrl::fromPercentEncoding(_txt.toLatin1().left(pos)) );
|
|
|
|
_setQuery( _txt.right( _txt.length() - pos - 1 ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::path( AdjustPathOption trailing ) const
|
|
|
|
{
|
|
|
|
return trailingSlash( trailing, QUrl::path() );
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::toLocalFile( AdjustPathOption trailing ) const
|
|
|
|
{
|
|
|
|
if (hasHost() && isLocalFile()) {
|
|
|
|
KUrl urlWithoutHost(*this);
|
|
|
|
urlWithoutHost.setHost(QString());
|
|
|
|
return trailingSlash(trailing, urlWithoutHost.toLocalFile());
|
|
|
|
}
|
2021-01-09 16:39:44 +02:00
|
|
|
#warning FIXME: Remove condition below once QTBUG-20322 is fixed, also see BR# 194746.
|
2014-11-13 01:04:59 +02:00
|
|
|
if (isLocalFile()) {
|
|
|
|
return trailingSlash(trailing, QUrl::path());
|
|
|
|
}
|
|
|
|
return trailingSlash(trailing, QUrl::toLocalFile());
|
|
|
|
}
|
|
|
|
|
2017-08-03 11:20:08 +00:00
|
|
|
bool KUrl::isLocalFile() const
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
2017-08-03 11:20:08 +00:00
|
|
|
if ( scheme().compare(QLatin1String("file"), Qt::CaseInsensitive) != 0 || hasSubUrl() )
|
2014-11-13 01:04:59 +02:00
|
|
|
return false;
|
|
|
|
|
2017-08-03 11:20:08 +00:00
|
|
|
if (host().isEmpty() || (host() == QLatin1String("localhost")))
|
2014-11-13 01:04:59 +02:00
|
|
|
return true;
|
|
|
|
|
2019-06-21 19:56:58 +00:00
|
|
|
return (host() == QHostInfo::localHostName().toLower());
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::setFileEncoding(const QString &encoding)
|
|
|
|
{
|
|
|
|
if (!isLocalFile())
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString q = query();
|
|
|
|
|
|
|
|
if (!q.isEmpty() && q[0] == QLatin1Char('?'))
|
|
|
|
q = q.mid(1);
|
|
|
|
|
|
|
|
QStringList args = q.split(QLatin1Char('&'), QString::SkipEmptyParts);
|
|
|
|
for(QStringList::Iterator it = args.begin();
|
|
|
|
it != args.end();)
|
|
|
|
{
|
|
|
|
QString s = QUrl::fromPercentEncoding( (*it).toLatin1() );
|
|
|
|
if (s.startsWith(QLatin1String("charset=")))
|
|
|
|
it = args.erase(it);
|
|
|
|
else
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
if (!encoding.isEmpty())
|
|
|
|
args.append(QLatin1String("charset=") + QString::fromLatin1(QUrl::toPercentEncoding(encoding)));
|
|
|
|
|
|
|
|
if (args.isEmpty())
|
|
|
|
_setQuery(QString());
|
|
|
|
else
|
|
|
|
_setQuery(args.join(QString(QLatin1Char('&'))));
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::fileEncoding() const
|
|
|
|
{
|
|
|
|
if (!isLocalFile())
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
QString q = query();
|
|
|
|
|
|
|
|
if (q.isEmpty())
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
if (q[0] == QLatin1Char('?'))
|
|
|
|
q = q.mid(1);
|
|
|
|
|
|
|
|
const QStringList args = q.split(QLatin1Char('&'), QString::SkipEmptyParts);
|
2015-09-28 15:50:22 +00:00
|
|
|
foreach(const QString it, args)
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
2015-09-28 15:50:22 +00:00
|
|
|
QString s = QUrl::fromPercentEncoding(it.toLatin1());
|
2014-11-13 01:04:59 +02:00
|
|
|
if (s.startsWith(QLatin1String("charset=")))
|
|
|
|
return s.mid(8);
|
|
|
|
}
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
2017-08-03 11:20:08 +00:00
|
|
|
bool KUrl::hasSubUrl() const
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
// The isValid call triggers QUrlPrivate::validate which needs the full encoded url,
|
|
|
|
// all this takes too much time for isLocalFile()
|
2017-08-03 11:20:08 +00:00
|
|
|
const QString uscheme = scheme();
|
|
|
|
if ( uscheme.isEmpty() /*|| !isValid()*/ )
|
2014-11-13 01:04:59 +02:00
|
|
|
return false;
|
2017-08-03 11:20:08 +00:00
|
|
|
const QString ref( fragment() );
|
2014-11-13 01:04:59 +02:00
|
|
|
if (ref.isEmpty())
|
|
|
|
return false;
|
|
|
|
switch ( ref.at(0).unicode() ) {
|
|
|
|
case 'g':
|
|
|
|
if ( ref.startsWith(QLatin1String("gzip:")) )
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
if ( ref.startsWith(QLatin1String("bzip:")) || ref.startsWith(QLatin1String("bzip2:")) )
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
if ( ref.startsWith(QLatin1String("lzma:")) )
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
if ( ref.startsWith(QLatin1String("xz:")) )
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
if ( ref.startsWith(QLatin1String("tar:")) )
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
if ( ref.startsWith(QLatin1String("ar:")) )
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
case 'z':
|
|
|
|
if ( ref.startsWith(QLatin1String("zip:")) )
|
|
|
|
return true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2017-08-03 11:20:08 +00:00
|
|
|
if ( uscheme == QLatin1String("error") ) // anything that starts with error: has suburls
|
2014-11-13 01:04:59 +02:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::url( AdjustPathOption trailing ) const
|
|
|
|
{
|
|
|
|
if (QString::compare(scheme(), QLatin1String("mailto"), Qt::CaseInsensitive) == 0) {
|
|
|
|
// mailto urls should be prettified, see the url183433 testcase.
|
|
|
|
return prettyUrl(trailing);
|
|
|
|
}
|
|
|
|
if ( trailing == AddTrailingSlash && !path().endsWith( QLatin1Char('/') ) ) {
|
|
|
|
// -1 and 0 are provided by QUrl, but not +1, so that one is a bit tricky.
|
|
|
|
// To avoid reimplementing toEncoded() all over again, I just use another QUrl
|
|
|
|
// Let's hope this is fast, or not called often...
|
|
|
|
QUrl newUrl( *this );
|
|
|
|
newUrl.setPath( path() + QLatin1Char('/') );
|
|
|
|
return QString::fromLatin1(newUrl.toEncoded());
|
|
|
|
}
|
|
|
|
else if ( trailing == RemoveTrailingSlash) {
|
|
|
|
const QString cleanedPath = trailingSlash(trailing, path());
|
|
|
|
if (cleanedPath == QLatin1String("/")) {
|
|
|
|
if (path() != QLatin1String("/")) {
|
|
|
|
QUrl fixedUrl = *this;
|
|
|
|
fixedUrl.setPath(cleanedPath);
|
|
|
|
return QLatin1String(fixedUrl.toEncoded(None));
|
|
|
|
}
|
|
|
|
return QLatin1String(toEncoded(None));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return QString::fromLatin1(toEncoded(trailing == RemoveTrailingSlash ? StripTrailingSlash : None));
|
|
|
|
}
|
|
|
|
|
|
|
|
static QString toPrettyPercentEncoding(const QString &input, bool forFragment)
|
|
|
|
{
|
|
|
|
QString result;
|
|
|
|
result.reserve(input.length());
|
|
|
|
for (int i = 0; i < input.length(); ++i) {
|
|
|
|
const QChar c = input.at(i);
|
2019-05-15 21:52:19 +00:00
|
|
|
ushort u = c.unicode();
|
2014-11-13 01:04:59 +02:00
|
|
|
if (u < 0x20
|
|
|
|
|| (!forFragment && u == '?') // don't escape '?' in fragments, not needed and wrong (#173101)
|
|
|
|
|| u == '#' || u == '%'
|
|
|
|
|| (u == ' ' && (i+1 == input.length() || input.at(i+1).unicode() == ' '))) {
|
|
|
|
static const char hexdigits[] = "0123456789ABCDEF";
|
|
|
|
result += QLatin1Char('%');
|
|
|
|
result += QLatin1Char(hexdigits[(u & 0xf0) >> 4]);
|
|
|
|
result += QLatin1Char(hexdigits[u & 0xf]);
|
|
|
|
} else {
|
|
|
|
result += c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::prettyUrl( AdjustPathOption trailing ) const
|
|
|
|
{
|
|
|
|
// reconstruct the URL in a "pretty" form
|
|
|
|
// a "pretty" URL is NOT suitable for data transfer. It's only for showing data to the user.
|
|
|
|
// however, it must be parseable back to its original state, since
|
|
|
|
// notably Konqueror displays it in the Location address.
|
|
|
|
|
|
|
|
// A pretty URL is the same as a normal URL, except that:
|
|
|
|
// - the password is removed
|
|
|
|
// - the hostname is shown in Unicode (as opposed to ACE/Punycode)
|
|
|
|
// - the pathname and fragment parts are shown in Unicode (as opposed to %-encoding)
|
|
|
|
QString result = scheme();
|
|
|
|
if (!result.isEmpty())
|
|
|
|
{
|
|
|
|
if (!authority().isEmpty() || result == QLatin1String("file") || (path().isEmpty()
|
|
|
|
&& scheme().compare(QLatin1String("mailto"), Qt::CaseInsensitive) != 0))
|
|
|
|
result += QLatin1String("://");
|
|
|
|
else
|
|
|
|
result += QLatin1Char(':');
|
|
|
|
}
|
|
|
|
|
|
|
|
QString tmp = userName();
|
|
|
|
if (!tmp.isEmpty()) {
|
|
|
|
result += QString::fromLatin1(QUrl::toPercentEncoding(tmp));
|
|
|
|
result += QLatin1Char('@');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if host is an ipv6 address
|
|
|
|
tmp = host();
|
|
|
|
if (tmp.contains(QLatin1Char(':')))
|
|
|
|
result += QLatin1Char('[') + tmp + QLatin1Char(']');
|
|
|
|
else
|
|
|
|
result += tmp;
|
|
|
|
|
|
|
|
if (port() != -1) {
|
|
|
|
result += QLatin1Char(':');
|
|
|
|
result += QString::number(port());
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = path();
|
|
|
|
result += toPrettyPercentEncoding(tmp, false);
|
|
|
|
|
|
|
|
// adjust the trailing slash, if necessary
|
|
|
|
if (trailing == AddTrailingSlash && !tmp.endsWith(QLatin1Char('/')))
|
|
|
|
result += QLatin1Char('/');
|
|
|
|
else if (trailing == RemoveTrailingSlash && tmp.length() > 1 && tmp.endsWith(QLatin1Char('/')))
|
|
|
|
result.chop(1);
|
|
|
|
|
|
|
|
if (hasQuery()) {
|
|
|
|
result += QLatin1Char('?');
|
|
|
|
result += QString::fromLatin1(encodedQuery());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasFragment()) {
|
|
|
|
result += QLatin1Char('#');
|
|
|
|
result += toPrettyPercentEncoding(fragment(), true);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
QString KUrl::prettyUrl( int _trailing, AdjustementFlags _flags) const
|
|
|
|
{
|
|
|
|
QString u = prettyUrl(_trailing);
|
|
|
|
if (_flags & StripFileProtocol && u.startsWith("file://")) {
|
|
|
|
u.remove(0, 7);
|
|
|
|
}
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
QString KUrl::pathOrUrl(AdjustPathOption trailing) const
|
|
|
|
{
|
|
|
|
if ( isLocalFile() && fragment().isNull() && encodedQuery().isNull() ) {
|
|
|
|
return toLocalFile(trailing);
|
|
|
|
} else {
|
|
|
|
return prettyUrl(trailing);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used for text/uri-list in the mime data
|
|
|
|
QString KUrl::toMimeDataString() const // don't fold this into populateMimeData, it's also needed by other code like konqdrag
|
|
|
|
{
|
|
|
|
if ( isLocalFile() )
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
return url();
|
|
|
|
#else
|
|
|
|
// According to the XDND spec, file:/ URLs for DND must have
|
|
|
|
// the hostname part. But in really it just breaks many apps,
|
|
|
|
// so it's disabled for now.
|
|
|
|
const QString s = url( 0, KGlobal::locale()->fileEncodingMib() );
|
|
|
|
if( !s.startsWith( QLatin1String ( "file://" ) ))
|
|
|
|
{
|
2019-06-21 19:56:58 +00:00
|
|
|
QString hostname = QHostInfo::localHostName();
|
|
|
|
if ( !hostname.isEmpty() )
|
2014-11-13 01:04:59 +02:00
|
|
|
{
|
|
|
|
return QString( "file://" ) + hostname + s.mid( 5 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hasPass()) {
|
|
|
|
KUrl safeUrl(*this);
|
|
|
|
safeUrl.setPassword(QString());
|
|
|
|
return safeUrl.url();
|
|
|
|
}
|
|
|
|
return url();
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl KUrl::fromMimeDataByteArray( const QByteArray& str )
|
|
|
|
{
|
|
|
|
if ( str.startsWith( "file:" ) ) // krazy:exclude=strings
|
|
|
|
return KUrl( str /*, QTextCodec::codecForLocale()->mibEnum()*/ );
|
|
|
|
|
|
|
|
return KUrl( str /*, 106*/ ); // 106 is mib enum for utf8 codec;
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List KUrl::split( const KUrl& _url )
|
|
|
|
{
|
|
|
|
QString ref;
|
|
|
|
bool hasRef;
|
|
|
|
KUrl::List lst;
|
|
|
|
KUrl url = _url;
|
|
|
|
|
|
|
|
while(true)
|
|
|
|
{
|
|
|
|
KUrl u = url;
|
|
|
|
u.setFragment( QString() );
|
|
|
|
lst.append(u);
|
|
|
|
if (url.hasSubUrl())
|
|
|
|
{
|
|
|
|
url = KUrl(url.fragment());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ref = url.fragment();
|
|
|
|
hasRef = url.hasFragment();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( hasRef )
|
|
|
|
{
|
|
|
|
// Set HTML ref in all URLs.
|
|
|
|
KUrl::List::Iterator it;
|
|
|
|
for( it = lst.begin() ; it != lst.end(); ++it )
|
|
|
|
{
|
|
|
|
(*it).setFragment( ref );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return lst;
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl::List KUrl::split( const QString& _url )
|
|
|
|
{
|
|
|
|
return split(KUrl(_url));
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl KUrl::join( const KUrl::List & lst )
|
|
|
|
{
|
|
|
|
if (lst.isEmpty()) return KUrl();
|
|
|
|
KUrl tmp;
|
|
|
|
|
|
|
|
bool first = true;
|
|
|
|
QListIterator<KUrl> it(lst);
|
|
|
|
it.toBack();
|
|
|
|
while (it.hasPrevious())
|
|
|
|
{
|
|
|
|
KUrl u(it.previous());
|
|
|
|
if (!first) {
|
|
|
|
u.setEncodedFragment(tmp.url().toLatin1() /* TODO double check encoding */);
|
|
|
|
}
|
|
|
|
tmp = u;
|
|
|
|
|
|
|
|
first = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::fileName( const DirectoryOptions& options ) const
|
|
|
|
{
|
|
|
|
Q_ASSERT( options != 0 ); //Disallow options == false
|
|
|
|
QString fname;
|
|
|
|
if (hasSubUrl()) { // If we have a suburl, then return the filename from there
|
|
|
|
const KUrl::List list = KUrl::split(*this);
|
|
|
|
return list.last().fileName(options);
|
|
|
|
}
|
|
|
|
const QString path = this->path();
|
|
|
|
|
|
|
|
int len = path.length();
|
|
|
|
if ( len == 0 )
|
|
|
|
return fname;
|
|
|
|
|
|
|
|
if (!(options & ObeyTrailingSlash) )
|
|
|
|
{
|
|
|
|
while ( len >= 1 && path[ len - 1 ] == QLatin1Char('/') )
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
else if ( path[ len - 1 ] == QLatin1Char('/') )
|
|
|
|
return fname;
|
|
|
|
|
|
|
|
// Does the path only consist of '/' characters ?
|
|
|
|
if ( len == 1 && path[ 0 ] == QLatin1Char('/') )
|
|
|
|
return fname;
|
|
|
|
|
|
|
|
// Skip last n slashes
|
|
|
|
int n = 1;
|
|
|
|
#if 0
|
|
|
|
if (!m_strPath_encoded.isEmpty())
|
|
|
|
{
|
|
|
|
// This is hairy, we need the last unencoded slash.
|
|
|
|
// Count in the encoded string how many encoded slashes follow the last
|
|
|
|
// unencoded one.
|
|
|
|
int i = m_strPath_encoded.lastIndexOf( QLatin1Char('/'), len - 1 );
|
|
|
|
QString fileName_encoded = m_strPath_encoded.mid(i+1);
|
|
|
|
n += fileName_encoded.count("%2f", Qt::CaseInsensitive);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
int i = len;
|
|
|
|
do {
|
|
|
|
i = path.lastIndexOf( QLatin1Char('/'), i - 1 );
|
|
|
|
}
|
|
|
|
while (--n && (i > 0));
|
|
|
|
|
|
|
|
// If ( i == -1 ) => the first character is not a '/'
|
|
|
|
// So it's some URL like file:blah.tgz, return the whole path
|
|
|
|
if ( i == -1 ) {
|
|
|
|
if ( len == (int)path.length() )
|
|
|
|
fname = path;
|
|
|
|
else
|
|
|
|
// Might get here if _strip_trailing_slash is true
|
|
|
|
fname = path.left( len );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fname = path.mid( i + 1, len - i - 1 ); // TO CHECK
|
|
|
|
}
|
|
|
|
return fname;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::addPath( const QString& _txt )
|
|
|
|
{
|
|
|
|
if (hasSubUrl())
|
|
|
|
{
|
|
|
|
KUrl::List lst = split( *this );
|
|
|
|
KUrl &u = lst.last();
|
|
|
|
u.addPath(_txt);
|
|
|
|
*this = join( lst );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//m_strPath_encoded.clear();
|
|
|
|
|
|
|
|
if ( _txt.isEmpty() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
QString strPath = path();
|
|
|
|
int i = 0;
|
|
|
|
int len = strPath.length();
|
|
|
|
// Add the trailing '/' if it is missing
|
|
|
|
if ( _txt[0] != QLatin1Char('/') && ( len == 0 || strPath[ len - 1 ] != QLatin1Char('/') ) )
|
|
|
|
strPath += QLatin1Char('/');
|
|
|
|
|
|
|
|
// No double '/' characters
|
|
|
|
i = 0;
|
|
|
|
const int _txtlen = _txt.length();
|
|
|
|
if ( strPath.endsWith( QLatin1Char('/') ) )
|
|
|
|
{
|
|
|
|
while ( ( i < _txtlen ) && ( _txt[i] == QLatin1Char('/') ) )
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
setPath( strPath + _txt.mid( i ) );
|
|
|
|
//kDebug(kurlDebugArea())<<"addPath: resultpath="<<path();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::directory( const DirectoryOptions& options ) const
|
|
|
|
{
|
|
|
|
Q_ASSERT( options != 0 ); //Disallow options == false
|
|
|
|
QString result = path(); //m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded;
|
|
|
|
if ( !(options & ObeyTrailingSlash) )
|
|
|
|
result = trailingSlash( RemoveTrailingSlash, result );
|
|
|
|
|
|
|
|
if ( result.isEmpty() || result == QLatin1String ( "/" ) )
|
|
|
|
return result;
|
|
|
|
|
|
|
|
int i = result.lastIndexOf( QLatin1Char('/') );
|
|
|
|
// If ( i == -1 ) => the first character is not a '/'
|
|
|
|
// So it's some URL like file:blah.tgz, with no path
|
|
|
|
if ( i == -1 )
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
if ( i == 0 )
|
|
|
|
{
|
|
|
|
return QString(QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ( options & AppendTrailingSlash )
|
|
|
|
result = result.left( i + 1 );
|
|
|
|
else
|
|
|
|
result = result.left( i );
|
|
|
|
|
|
|
|
//if (!m_strPath_encoded.isEmpty())
|
|
|
|
// result = decode(result);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KUrl::cd( const QString& _dir )
|
|
|
|
{
|
|
|
|
if ( _dir.isEmpty() || !isValid() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (hasSubUrl())
|
|
|
|
{
|
|
|
|
KUrl::List lst = split( *this );
|
|
|
|
KUrl &u = lst.last();
|
|
|
|
u.cd(_dir);
|
|
|
|
*this = join( lst );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// absolute path ?
|
|
|
|
if ( _dir[0] == QLatin1Char('/') )
|
|
|
|
{
|
|
|
|
//m_strPath_encoded.clear();
|
|
|
|
setPath( _dir );
|
|
|
|
setHTMLRef( QString() );
|
|
|
|
setEncodedQuery( QByteArray() );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Users home directory on the local disk ?
|
|
|
|
if (_dir[0] == QLatin1Char('~') && scheme() == QLatin1String ("file"))
|
|
|
|
{
|
|
|
|
//m_strPath_encoded.clear();
|
|
|
|
QString strPath = QDir::homePath();
|
|
|
|
strPath += QLatin1Char('/');
|
|
|
|
strPath += _dir.right( strPath.length() - 1 );
|
|
|
|
setPath( strPath );
|
|
|
|
setHTMLRef( QString() );
|
|
|
|
setEncodedQuery( QByteArray() );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// relative path
|
|
|
|
// we always work on the past of the first url.
|
|
|
|
// Sub URLs are not touched.
|
|
|
|
|
|
|
|
// append '/' if necessary
|
|
|
|
QString p = path(AddTrailingSlash);
|
|
|
|
p += _dir;
|
|
|
|
p = cleanpath( p, true, false );
|
|
|
|
setPath( p );
|
|
|
|
|
|
|
|
setHTMLRef( QString() );
|
|
|
|
setEncodedQuery( QByteArray() );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
KUrl KUrl::upUrl( ) const
|
|
|
|
{
|
|
|
|
if (!isValid() || isRelative())
|
|
|
|
return KUrl();
|
|
|
|
|
|
|
|
if (!encodedQuery().isEmpty())
|
|
|
|
{
|
|
|
|
KUrl u(*this);
|
|
|
|
u.setEncodedQuery(QByteArray());
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!hasSubUrl())
|
|
|
|
{
|
|
|
|
KUrl u(*this);
|
|
|
|
u.cd(QLatin1String("../"));
|
|
|
|
return u;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have a subURL.
|
|
|
|
KUrl::List lst = split( *this );
|
|
|
|
if (lst.isEmpty())
|
|
|
|
return KUrl(); // Huh?
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
KUrl &u = lst.last();
|
|
|
|
const QString old = u.path();
|
|
|
|
u.cd(QLatin1String("../"));
|
|
|
|
if (u.path() != old)
|
|
|
|
break; // Finished.
|
|
|
|
if (lst.count() == 1)
|
|
|
|
break; // Finished.
|
|
|
|
lst.removeLast();
|
|
|
|
}
|
|
|
|
return join( lst );
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::htmlRef() const
|
|
|
|
{
|
|
|
|
if ( !hasSubUrl() )
|
|
|
|
{
|
|
|
|
return fragment();
|
|
|
|
}
|
|
|
|
|
|
|
|
const List lst = split( *this );
|
|
|
|
return (*lst.begin()).fragment();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::encodedHtmlRef() const
|
|
|
|
{
|
|
|
|
if ( !hasSubUrl() )
|
|
|
|
{
|
|
|
|
return ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
const List lst = split( *this );
|
|
|
|
return (*lst.begin()).ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::setHTMLRef( const QString& _ref )
|
|
|
|
{
|
|
|
|
if ( !hasSubUrl() )
|
|
|
|
{
|
|
|
|
setFragment( _ref );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
List lst = split( *this );
|
|
|
|
|
|
|
|
(*lst.begin()).setFragment( _ref );
|
|
|
|
|
|
|
|
*this = join( lst );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KUrl::hasHTMLRef() const
|
|
|
|
{
|
|
|
|
if ( !hasSubUrl() )
|
|
|
|
{
|
|
|
|
return hasRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
const List lst = split( *this );
|
|
|
|
return (*lst.begin()).hasRef();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::setDirectory( const QString &dir)
|
|
|
|
{
|
|
|
|
if ( dir.endsWith(QLatin1Char('/')))
|
|
|
|
setPath(dir);
|
|
|
|
else
|
|
|
|
setPath(dir + QLatin1Char('/'));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::setQuery( const QString &_txt )
|
|
|
|
{
|
|
|
|
if (!_txt.isEmpty() && _txt[0] == QLatin1Char('?'))
|
|
|
|
_setQuery( _txt.length() > 1 ? _txt.mid(1) : QString::fromLatin1("") /*empty, not null*/ );
|
|
|
|
else
|
|
|
|
_setQuery( _txt );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::_setQuery( const QString& query )
|
|
|
|
{
|
|
|
|
if ( query.isNull() ) {
|
|
|
|
setEncodedQuery( QByteArray() );
|
|
|
|
} else if ( query.isEmpty() ) {
|
|
|
|
setEncodedQuery("");
|
|
|
|
} else {
|
|
|
|
setEncodedQuery( query.toLatin1() ); // already percent-escaped, so toLatin1 is ok
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::query() const
|
|
|
|
{
|
|
|
|
if (!hasQuery()) {
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
return QString(QLatin1Char('?')) + QString::fromLatin1(encodedQuery());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::_setEncodedUrl(const QByteArray& url)
|
|
|
|
{
|
|
|
|
setEncodedUrl(url, QUrl::TolerantMode);
|
|
|
|
if (!isValid()) // see unit tests referring to N183630/task 183874
|
|
|
|
setUrl(QString::fromUtf8(url), QUrl::TolerantMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent)
|
|
|
|
{
|
|
|
|
QString _base_dir(QDir::cleanPath(base_dir));
|
|
|
|
QString _path(QDir::cleanPath(path.isEmpty() || QDir::isRelativePath(path) ? _base_dir+QLatin1Char('/')+path : path));
|
|
|
|
|
|
|
|
if (_base_dir.isEmpty())
|
|
|
|
return _path;
|
|
|
|
|
|
|
|
if (_base_dir[_base_dir.length()-1] != QLatin1Char('/'))
|
|
|
|
_base_dir.append(QLatin1Char('/') );
|
|
|
|
|
|
|
|
const QStringList list1 = _base_dir.split(QLatin1Char('/'), QString::SkipEmptyParts);
|
|
|
|
const QStringList list2 = _path.split(QLatin1Char('/'), QString::SkipEmptyParts);
|
|
|
|
|
|
|
|
// Find where they meet
|
|
|
|
int level = 0;
|
|
|
|
int maxLevel = qMin(list1.count(), list2.count());
|
|
|
|
while((level < maxLevel) && (list1[level] == list2[level])) level++;
|
|
|
|
|
|
|
|
QString result;
|
|
|
|
// Need to go down out of the first path to the common branch.
|
|
|
|
for(int i = level; i < list1.count(); i++)
|
|
|
|
result.append(QLatin1String("../"));
|
|
|
|
|
|
|
|
// Now up up from the common branch to the second path.
|
|
|
|
for(int i = level; i < list2.count(); i++)
|
|
|
|
result.append(list2[i]).append(QLatin1Char('/'));
|
|
|
|
|
|
|
|
if ((level < list2.count()) && (path[path.length()-1] != QLatin1Char('/')))
|
|
|
|
result.truncate(result.length()-1);
|
|
|
|
|
|
|
|
isParent = (level == list1.count());
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::relativePath(const QString &base_dir, const QString &path, bool *isParent)
|
|
|
|
{
|
|
|
|
bool parent = false;
|
|
|
|
QString result = _relativePath(base_dir, path, parent);
|
|
|
|
if (parent)
|
|
|
|
result.prepend(QLatin1String("./"));
|
|
|
|
|
|
|
|
if (isParent)
|
|
|
|
*isParent = parent;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString KUrl::relativeUrl(const KUrl &base_url, const KUrl &url)
|
|
|
|
{
|
|
|
|
if ((url.protocol() != base_url.protocol()) ||
|
|
|
|
(url.host() != base_url.host()) ||
|
|
|
|
(url.port() && url.port() != base_url.port()) ||
|
|
|
|
(url.hasUser() && url.user() != base_url.user()) ||
|
|
|
|
(url.hasPass() && url.pass() != base_url.pass()))
|
|
|
|
{
|
|
|
|
return url.url();
|
|
|
|
}
|
|
|
|
|
|
|
|
QString relURL;
|
|
|
|
|
|
|
|
if ((base_url.path() != url.path()) || (base_url.query() != url.query()))
|
|
|
|
{
|
|
|
|
bool dummy;
|
|
|
|
QString basePath = base_url.directory(KUrl::ObeyTrailingSlash);
|
|
|
|
static const char s_pathExcludeChars[] = "!$&'()*+,;=:@/";
|
|
|
|
relURL = QString::fromLatin1(QUrl::toPercentEncoding(_relativePath(basePath, url.path(), dummy), s_pathExcludeChars));
|
|
|
|
relURL += url.query();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( url.hasRef() )
|
|
|
|
{
|
|
|
|
relURL += QLatin1Char('#');
|
|
|
|
relURL += url.ref();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( relURL.isEmpty() )
|
|
|
|
return QLatin1String("./");
|
|
|
|
|
|
|
|
return relURL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::setPath( const QString& _path )
|
|
|
|
{
|
2016-04-24 17:50:43 +00:00
|
|
|
if ( scheme().isEmpty() && !_path.startsWith( QLatin1String("file:/") ) )
|
2014-11-13 01:04:59 +02:00
|
|
|
setScheme( QLatin1String( "file" ) );
|
|
|
|
QString path = KShell::tildeExpand( _path );
|
|
|
|
if (path.isEmpty())
|
|
|
|
path = _path;
|
|
|
|
QUrl::setPath( path );
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0 // this would be if we didn't decode '+' into ' '
|
|
|
|
QMap< QString, QString > KUrl::queryItems( int options ) const {
|
|
|
|
QMap< QString, QString > result;
|
|
|
|
const QList<QPair<QString, QString> > items = QUrl::queryItems();
|
|
|
|
QPair<QString, QString> item;
|
|
|
|
Q_FOREACH( item, items ) {
|
|
|
|
result.insert( options & CaseInsensitiveKeys ? item.first.toLower() : item.first, item.second );
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
QMap< QString, QString > KUrl::queryItems( const QueryItemsOptions &options ) const
|
|
|
|
{
|
|
|
|
const QString strQueryEncoded = QString::fromLatin1(encodedQuery());
|
|
|
|
if ( strQueryEncoded.isEmpty() )
|
|
|
|
return QMap<QString,QString>();
|
|
|
|
|
|
|
|
QMap< QString, QString > result;
|
|
|
|
const QStringList items = strQueryEncoded.split( QLatin1Char('&'), QString::SkipEmptyParts );
|
2015-09-28 15:50:22 +00:00
|
|
|
foreach(const QString it, items) {
|
|
|
|
const int equal_pos = it.indexOf(QLatin1Char('='));
|
2014-11-13 01:04:59 +02:00
|
|
|
if ( equal_pos > 0 ) { // = is not the first char...
|
2015-09-28 15:50:22 +00:00
|
|
|
QString name = it.left( equal_pos );
|
2014-11-13 01:04:59 +02:00
|
|
|
if ( options & CaseInsensitiveKeys )
|
|
|
|
name = name.toLower();
|
2015-09-28 15:50:22 +00:00
|
|
|
QString value = it.mid( equal_pos + 1 );
|
2014-11-13 01:04:59 +02:00
|
|
|
if ( value.isEmpty() )
|
|
|
|
result.insert( name, QString::fromLatin1("") );
|
|
|
|
else {
|
|
|
|
// ### why is decoding name not necessary?
|
|
|
|
value.replace( QLatin1Char('+'), QLatin1Char(' ') ); // + in queries means space
|
|
|
|
result.insert( name, QUrl::fromPercentEncoding( value.toLatin1() ) );
|
|
|
|
}
|
|
|
|
} else if ( equal_pos < 0 ) { // no =
|
2015-09-28 15:50:22 +00:00
|
|
|
QString name = it;
|
2014-11-13 01:04:59 +02:00
|
|
|
if ( options & CaseInsensitiveKeys )
|
|
|
|
name = name.toLower();
|
|
|
|
result.insert( name, QString() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::queryItem( const QString& _item ) const
|
|
|
|
{
|
|
|
|
const QString strQueryEncoded = QString::fromLatin1(encodedQuery());
|
|
|
|
const QString item = _item + QLatin1Char('=');
|
|
|
|
if ( strQueryEncoded.length() <= 1 )
|
|
|
|
return QString();
|
|
|
|
|
|
|
|
const QStringList items = strQueryEncoded.split( QString(QLatin1Char('&')), QString::SkipEmptyParts );
|
|
|
|
const int _len = item.length();
|
|
|
|
for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it )
|
|
|
|
{
|
|
|
|
if ( (*it).startsWith( item ) )
|
|
|
|
{
|
|
|
|
if ( (*it).length() > _len )
|
|
|
|
{
|
|
|
|
QString str = (*it).mid( _len );
|
|
|
|
str.replace( QLatin1Char('+'), QLatin1Char(' ') ); // + in queries means space.
|
|
|
|
return QUrl::fromPercentEncoding( str.toLatin1() );
|
|
|
|
}
|
|
|
|
else // empty value
|
|
|
|
return QString::fromLatin1("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QString();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::addQueryItem( const QString& _item, const QString& _value )
|
|
|
|
{
|
|
|
|
QString item = _item + QLatin1Char('=');
|
|
|
|
QString value = QString::fromLatin1(QUrl::toPercentEncoding(_value));
|
|
|
|
|
|
|
|
QString strQueryEncoded = QString::fromLatin1(encodedQuery());
|
|
|
|
if (!strQueryEncoded.isEmpty())
|
|
|
|
strQueryEncoded += QLatin1Char('&');
|
|
|
|
strQueryEncoded += item + value;
|
|
|
|
setEncodedQuery( strQueryEncoded.toLatin1() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::populateMimeData( QMimeData* mimeData,
|
|
|
|
const MetaDataMap& metaData,
|
|
|
|
MimeDataFlags flags ) const
|
|
|
|
{
|
|
|
|
KUrl::List lst( *this );
|
|
|
|
lst.populateMimeData( mimeData, metaData, flags );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KUrl::hasRef() const
|
|
|
|
{
|
|
|
|
return hasFragment();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KUrl::setRef( const QString& fragment )
|
|
|
|
{
|
|
|
|
if ( fragment.isEmpty() ) // empty or null
|
|
|
|
setFragment( fragment );
|
|
|
|
else
|
|
|
|
setFragment( QUrl::fromPercentEncoding( fragment.toLatin1() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KUrl::ref() const
|
|
|
|
{
|
|
|
|
if ( !hasFragment() )
|
|
|
|
return QString();
|
|
|
|
else
|
|
|
|
return QString::fromLatin1( encodedFragment() );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KUrl::isParentOf( const KUrl& u ) const
|
|
|
|
{
|
|
|
|
return QUrl::isParentOf( u ) || equals( u, CompareWithoutTrailingSlash );
|
|
|
|
}
|
|
|
|
|
|
|
|
uint qHash(const KUrl& kurl)
|
|
|
|
{
|
|
|
|
// qHash(kurl.url()) was the worse implementation possible, since QUrl::toEncoded()
|
|
|
|
// had to concatenate the bits of the url into the full url every time.
|
|
|
|
|
|
|
|
return qHash(kurl.protocol()) ^ qHash(kurl.path()) ^ qHash(kurl.fragment()) ^ qHash(kurl.query());
|
|
|
|
}
|