src/corelib/io/qurl.cpp
changeset 18 2f34d5167611
parent 3 41300fa6a67c
child 19 fcece45ef507
--- a/src/corelib/io/qurl.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/corelib/io/qurl.cpp	Fri Apr 16 15:50:13 2010 +0300
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -350,8 +350,8 @@
     };
     int stateFlags;
 
-    QByteArray encodedNormalized;
-    const QByteArray & normalized();
+    mutable QByteArray encodedNormalized;
+    const QByteArray & normalized() const;
 
     mutable QUrlErrorInfo errorInfo;
     QString createErrorString();
@@ -3241,8 +3241,11 @@
     while (1) {
         int idx = nextDotDelimiter(domain, lastIdx);
         int labelLength = idx - lastIdx;
-        if (labelLength == 0)
+        if (labelLength == 0) {
+            if (idx == domain.length())
+                break;
             return QString(); // two delimiters in a row -- empty label not allowed
+        }
 
         // RFC 3490 says, about the ToASCII operation:
         //   3. If the UseSTD3ASCIIRules flag is set, then perform these checks:
@@ -3850,6 +3853,9 @@
     if (!QURL_HASFLAG(stateFlags, Parsed)) parse();
     else ensureEncodedParts();
 
+    if (options==0x100) // private - see qHash(QUrl)
+        return normalized();
+
     QByteArray url;
 
     if (!(options & QUrl::RemoveScheme) && !scheme.isEmpty()) {
@@ -3864,14 +3870,18 @@
         url += "//";
 
         if ((options & QUrl::RemoveUserInfo) != QUrl::RemoveUserInfo) {
+            bool hasUserOrPass = false;
             if (!userName.isEmpty()) {
                 url += encodedUserName;
-                if (!(options & QUrl::RemovePassword) && !password.isEmpty()) {
-                    url += ':';
-                    url += encodedPassword;
-                }
+                hasUserOrPass = true;
+            }
+            if (!(options & QUrl::RemovePassword) && !password.isEmpty()) {
+                url += ':';
+                url += encodedPassword;
+                hasUserOrPass = true;
+            }
+            if (hasUserOrPass)
                 url += '@';
-            }
         }
 
         if (host.startsWith(QLatin1Char('['))) {
@@ -3916,12 +3926,13 @@
 
 #define qToLower(ch) (((ch|32) >= 'a' && (ch|32) <= 'z') ? (ch|32) : ch)
 
-const QByteArray &QUrlPrivate::normalized()
+const QByteArray &QUrlPrivate::normalized() const
 {
     if (QURL_HASFLAG(stateFlags, QUrlPrivate::Normalized))
         return encodedNormalized;
 
-    QURL_SETFLAG(stateFlags, QUrlPrivate::Normalized);
+    QUrlPrivate *that = const_cast<QUrlPrivate *>(this);
+    QURL_SETFLAG(that->stateFlags, QUrlPrivate::Normalized);
 
     QUrlPrivate tmp = *this;
     tmp.scheme = tmp.scheme.toLower();
@@ -4070,7 +4081,7 @@
 
     \sa setUrl(), setEncodedUrl(), fromEncoded(), TolerantMode
 */
-QUrl::QUrl(const QString &url) : d(new QUrlPrivate)
+QUrl::QUrl(const QString &url) : d(0)
 {
     if (!url.isEmpty())
         setUrl(url);
@@ -4083,18 +4094,20 @@
 
     \sa setUrl()
 */
-QUrl::QUrl(const QString &url, ParsingMode parsingMode) : d(new QUrlPrivate)
+QUrl::QUrl(const QString &url, ParsingMode parsingMode) : d(0)
 {
     if (!url.isEmpty())
         setUrl(url, parsingMode);
-    else
+    else {
+        d = new QUrlPrivate;
         d->parsingMode = parsingMode;
+    }
 }
 
 /*!
     Constructs an empty QUrl object.
 */
-QUrl::QUrl() : d(new QUrlPrivate)
+QUrl::QUrl() : d(0)
 {
 }
 
@@ -4103,7 +4116,8 @@
 */
 QUrl::QUrl(const QUrl &other) : d(other.d)
 {
-    d->ref.ref();
+    if (d)
+        d->ref.ref();
 }
 
 /*!
@@ -4111,7 +4125,7 @@
 */
 QUrl::~QUrl()
 {
-    if (!d->ref.deref())
+    if (d && !d->ref.deref())
         delete d;
 }
 
@@ -4126,6 +4140,8 @@
 */
 bool QUrl::isValid() const
 {
+    if (!d) return false;
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Validated)) d->validate();
 
@@ -4137,6 +4153,8 @@
 */
 bool QUrl::isEmpty() const
 {
+    if (!d) return true;
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed))
         return d->encodedOriginal.isEmpty();
     else
@@ -4157,8 +4175,9 @@
 */
 void QUrl::clear()
 {
-    detach();
-    d->clear();
+    if (d && !d->ref.deref())
+        delete d;
+    d = 0;
 }
 
 /*!
@@ -4257,8 +4276,9 @@
 */
 void QUrl::setEncodedUrl(const QByteArray &encodedUrl, ParsingMode parsingMode)
 {
-    clear();
     QByteArray tmp = encodedUrl;
+    if (!d) d = new QUrlPrivate;
+    else d->clear();
     if ((d->parsingMode = parsingMode) == TolerantMode) {
         // Replace stray % with %25
         QByteArray copy = tmp;
@@ -4332,6 +4352,7 @@
 */
 void QUrl::setScheme(const QString &scheme)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4347,6 +4368,7 @@
 */
 QString QUrl::scheme() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->scheme;
@@ -4370,6 +4392,8 @@
 */
 void QUrl::setAuthority(const QString &authority)
 {
+    if (!d) d = new QUrlPrivate;
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4385,6 +4409,8 @@
 */
 QString QUrl::authority() const
 {
+    if (!d) return QString();
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->authority();
@@ -4405,6 +4431,8 @@
 */
 void QUrl::setUserInfo(const QString &userInfo)
 {
+    if (!d) d = new QUrlPrivate;
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4418,6 +4446,8 @@
 */
 QString QUrl::userInfo() const
 {
+    if (!d) return QString();
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->userInfo();
@@ -4432,6 +4462,8 @@
 */
 void QUrl::setUserName(const QString &userName)
 {
+    if (!d) d = new QUrlPrivate;
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4448,6 +4480,8 @@
 */
 QString QUrl::userName() const
 {
+    if (!d) return QString();
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->userInfo();              // causes the unencoded form to be set
@@ -4469,6 +4503,7 @@
 */
 void QUrl::setEncodedUserName(const QByteArray &userName)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4489,6 +4524,7 @@
 */
 QByteArray QUrl::encodedUserName() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -4504,6 +4540,7 @@
 */
 void QUrl::setPassword(const QString &password)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4520,6 +4557,7 @@
 */
 QString QUrl::password() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->userInfo();              // causes the unencoded form to be set
@@ -4541,6 +4579,7 @@
 */
 void QUrl::setEncodedPassword(const QByteArray &password)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4561,6 +4600,7 @@
 */
 QByteArray QUrl::encodedPassword() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -4575,6 +4615,7 @@
 */
 void QUrl::setHost(const QString &host)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized | QUrlPrivate::HostCanonicalized);
@@ -4588,6 +4629,7 @@
 */
 QString QUrl::host() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     if (d->host.isEmpty() || d->host.at(0) != QLatin1Char('['))
@@ -4641,6 +4683,7 @@
 */
 void QUrl::setPort(int port)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4658,6 +4701,7 @@
 */
 int QUrl::port() const
 {
+    if (!d) return -1;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Validated)) d->validate();
     return d->port;
@@ -4676,6 +4720,7 @@
 */
 int QUrl::port(int defaultPort) const
 {
+    if (!d) return defaultPort;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     return d->port == -1 ? defaultPort : d->port;
 }
@@ -4695,6 +4740,7 @@
 */
 void QUrl::setPath(const QString &path)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4710,6 +4756,7 @@
 */
 QString QUrl::path() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     if (d->path.isNull()) {
@@ -4741,6 +4788,7 @@
 */
 void QUrl::setEncodedPath(const QByteArray &path)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4761,6 +4809,7 @@
 */
 QByteArray QUrl::encodedPath() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -4776,6 +4825,7 @@
 */
 bool QUrl::hasQuery() const
 {
+    if (!d) return false;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->hasQuery;
@@ -4805,6 +4855,7 @@
 */
 void QUrl::setQueryDelimiters(char valueDelimiter, char pairDelimiter)
 {
+    if (!d) d = new QUrlPrivate;
     detach();
 
     d->valueDelimiter = valueDelimiter;
@@ -4817,6 +4868,7 @@
 */
 char QUrl::queryPairDelimiter() const
 {
+    if (!d) return '&';
     return d->pairDelimiter;
 }
 
@@ -4826,6 +4878,7 @@
 */
 char QUrl::queryValueDelimiter() const
 {
+    if (!d) return '=';
     return d->valueDelimiter;
 }
 
@@ -4848,6 +4901,7 @@
 */
 void QUrl::setEncodedQuery(const QByteArray &query)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -4867,6 +4921,7 @@
 */
 void QUrl::setQueryItems(const QList<QPair<QString, QString> > &query)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -4906,6 +4961,7 @@
 */
 void QUrl::setEncodedQueryItems(const QList<QPair<QByteArray, QByteArray> > &query)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -4935,6 +4991,7 @@
 */
 void QUrl::addQueryItem(const QString &key, const QString &value)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -4969,6 +5026,7 @@
 */
 void QUrl::addEncodedQueryItem(const QByteArray &key, const QByteArray &value)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -4989,6 +5047,7 @@
 */
 QList<QPair<QString, QString> > QUrl::queryItems() const
 {
+    if (!d) return QList<QPair<QString, QString> >();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QList<QPair<QString, QString> > itemMap;
@@ -5021,6 +5080,7 @@
 */
 QList<QPair<QByteArray, QByteArray> > QUrl::encodedQueryItems() const
 {
+    if (!d) return QList<QPair<QByteArray, QByteArray> >();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QList<QPair<QByteArray, QByteArray> > itemMap;
@@ -5049,6 +5109,7 @@
 */
 bool QUrl::hasQueryItem(const QString &key) const
 {
+    if (!d) return false;
     return hasEncodedQueryItem(toPercentEncoding(key, queryExcludeChars));
 }
 
@@ -5067,6 +5128,7 @@
 */
 bool QUrl::hasEncodedQueryItem(const QByteArray &key) const
 {
+    if (!d) return false;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     int pos = 0;
@@ -5089,6 +5151,7 @@
 */
 QString QUrl::queryItemValue(const QString &key) const
 {
+    if (!d) return QString();
     QByteArray tmp = encodedQueryItemValue(toPercentEncoding(key, queryExcludeChars));
     return fromPercentEncodingMutable(&tmp);
 }
@@ -5108,6 +5171,7 @@
 */
 QByteArray QUrl::encodedQueryItemValue(const QByteArray &key) const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     int pos = 0;
@@ -5131,6 +5195,7 @@
 */
 QStringList QUrl::allQueryItemValues(const QString &key) const
 {
+    if (!d) return QStringList();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QByteArray encodedKey = toPercentEncoding(key, queryExcludeChars);
@@ -5168,6 +5233,7 @@
 */
 QList<QByteArray> QUrl::allEncodedQueryItemValues(const QByteArray &key) const
 {
+    if (!d) return QList<QByteArray>();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QList<QByteArray> values;
@@ -5195,6 +5261,7 @@
 */
 void QUrl::removeQueryItem(const QString &key)
 {
+    if (!d) return;
     removeEncodedQueryItem(toPercentEncoding(key, queryExcludeChars));
 }
 
@@ -5213,6 +5280,7 @@
 */
 void QUrl::removeEncodedQueryItem(const QByteArray &key)
 {
+    if (!d) return;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -5239,6 +5307,7 @@
 */
 void QUrl::removeAllQueryItems(const QString &key)
 {
+    if (!d) return;
     removeAllEncodedQueryItems(toPercentEncoding(key, queryExcludeChars));
 }
 
@@ -5257,6 +5326,7 @@
 */
 void QUrl::removeAllEncodedQueryItems(const QByteArray &key)
 {
+    if (!d) return;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -5280,6 +5350,7 @@
 */
 QByteArray QUrl::encodedQuery() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->query;
@@ -5304,6 +5375,7 @@
 */
 void QUrl::setFragment(const QString &fragment)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -5320,6 +5392,7 @@
 */
 QString QUrl::fragment() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     if (d->fragment.isNull() && !d->encodedFragment.isNull()) {
@@ -5350,6 +5423,7 @@
 */
 void QUrl::setEncodedFragment(const QByteArray &fragment)
 {
+    if (!d) d = new QUrlPrivate;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
     QURL_UNSETFLAG(d->stateFlags, QUrlPrivate::Validated | QUrlPrivate::Normalized);
@@ -5371,6 +5445,7 @@
 */
 QByteArray QUrl::encodedFragment() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -5386,6 +5461,7 @@
 */
 bool QUrl::hasFragment() const
 {
+    if (!d) return false;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->hasFragment;
@@ -5412,6 +5488,8 @@
 */
 QUrl QUrl::resolved(const QUrl &relative) const
 {
+    if (!d) return relative;
+    if (!relative.d) return *this;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     if (!QURL_HASFLAG(relative.d->stateFlags, QUrlPrivate::Parsed))
@@ -5428,6 +5506,7 @@
         if (!relative.authority().isEmpty()) {
             t = relative;
         } else {
+            t.d = new QUrlPrivate;
             if (relative.d->encodedPath.isEmpty()) {
                 t.d->encodedPath = d->encodedPath;
                 t.setEncodedQuery(relative.d->hasQuery ? relative.d->query : d->query);
@@ -5458,6 +5537,7 @@
 */
 bool QUrl::isRelative() const
 {
+    if (!d) return true;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->scheme.isEmpty();
@@ -5472,6 +5552,7 @@
 */
 QString QUrl::toString(FormattingOptions options) const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QString url;
@@ -5523,6 +5604,7 @@
 */
 QByteArray QUrl::toEncoded(FormattingOptions options) const
 {
+    if (!d) return QByteArray();
     return d->toEncoded(options);
 }
 
@@ -5773,7 +5855,9 @@
 */
 bool QUrl::operator <(const QUrl &url) const
 {
+    if (!d) return url.d ? QByteArray() < url.d->normalized() : false;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
+    if (!url.d) return d->normalized() < QByteArray();
     if (!QURL_HASFLAG(url.d->stateFlags, QUrlPrivate::Parsed)) url.d->parse();
     return d->normalized() < url.d->normalized();
 }
@@ -5784,6 +5868,8 @@
 */
 bool QUrl::operator ==(const QUrl &url) const
 {
+    if (!d) return url.isEmpty();
+    if (!url.d) return isEmpty();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     if (!QURL_HASFLAG(url.d->stateFlags, QUrlPrivate::Parsed)) url.d->parse();
     return d->normalized() == url.d->normalized();
@@ -5803,7 +5889,17 @@
 */
 QUrl &QUrl::operator =(const QUrl &url)
 {
-    qAtomicAssign(d, url.d);
+    if (!d) {
+        if (url.d) {
+            url.d->ref.ref();
+            d = url.d;
+        }
+    } else {
+        if (url.d)
+            qAtomicAssign(d, url.d);
+        else
+            clear();
+    }
     return *this;
 }
 
@@ -5812,8 +5908,13 @@
 */
 QUrl &QUrl::operator =(const QString &url)
 {
-    QUrl tmp(url);
-    qAtomicAssign(d, tmp.d);
+    if (url.isEmpty()) {
+        clear();
+    } else {
+        QUrl tmp(url);
+        if (!d) d = new QUrlPrivate;
+        qAtomicAssign(d, tmp.d);
+    }
     return *this;
 }
 
@@ -5822,14 +5923,19 @@
     Forces a detach.
 */
 void QUrl::detach()
-{ qAtomicDetach(d); }
+{
+    if (!d)
+        d = new QUrlPrivate;
+    else
+        qAtomicDetach(d);
+}
 
 /*!
     \internal
 */
 bool QUrl::isDetached() const
 {
-    return d->ref == 1;
+    return !d || d->ref == 1;
 }
 
 
@@ -5871,6 +5977,7 @@
 */
 QString QUrl::toLocalFile() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QString tmp;
@@ -5899,9 +6006,15 @@
 */
 bool QUrl::isParentOf(const QUrl &childUrl) const
 {
+    QString childPath = childUrl.path();
+
+    if (!d)
+        return ((childUrl.scheme().isEmpty())
+            && (childUrl.authority().isEmpty())
+            && childPath.length() > 0 && childPath.at(0) == QLatin1Char('/'));
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
-    QString childPath = childUrl.path();
     QString ourPath = path();
 
     return ((childUrl.scheme().isEmpty() || d->scheme == childUrl.scheme())
@@ -6141,6 +6254,8 @@
 */
 QString QUrl::errorString() const
 {
+    if (!d)
+        return QLatin1String(QT_TRANSLATE_NOOP(QUrl, "Invalid URL \"\": ")); // XXX not a good message, but the one an empty URL produces
     return d->createErrorString();
 }