src/corelib/io/qurl.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 5 d3bac044e0f0
--- a/src/corelib/io/qurl.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/corelib/io/qurl.cpp	Fri Feb 19 23:40:16 2010 +0200
@@ -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();
@@ -3850,6 +3850,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 +3867,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 +3923,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 +4078,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 +4091,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 +4113,8 @@
 */
 QUrl::QUrl(const QUrl &other) : d(other.d)
 {
-    d->ref.ref();
+    if (d)
+        d->ref.ref();
 }
 
 /*!
@@ -4111,7 +4122,7 @@
 */
 QUrl::~QUrl()
 {
-    if (!d->ref.deref())
+    if (d && !d->ref.deref())
         delete d;
 }
 
@@ -4126,6 +4137,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 +4150,8 @@
 */
 bool QUrl::isEmpty() const
 {
+    if (!d) return true;
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed))
         return d->encodedOriginal.isEmpty();
     else
@@ -4157,8 +4172,9 @@
 */
 void QUrl::clear()
 {
-    detach();
-    d->clear();
+    if (d && !d->ref.deref())
+        delete d;
+    d = 0;
 }
 
 /*!
@@ -4257,8 +4273,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 +4349,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 +4365,7 @@
 */
 QString QUrl::scheme() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->scheme;
@@ -4370,6 +4389,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 +4406,8 @@
 */
 QString QUrl::authority() const
 {
+    if (!d) return QString();
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->authority();
@@ -4405,6 +4428,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 +4443,8 @@
 */
 QString QUrl::userInfo() const
 {
+    if (!d) return QString();
+
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->userInfo();
@@ -4432,6 +4459,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 +4477,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 +4500,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 +4521,7 @@
 */
 QByteArray QUrl::encodedUserName() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -4504,6 +4537,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 +4554,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 +4576,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 +4597,7 @@
 */
 QByteArray QUrl::encodedPassword() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -4575,6 +4612,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 +4626,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 +4680,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 +4698,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 +4717,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 +4737,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 +4753,7 @@
 */
 QString QUrl::path() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     if (d->path.isNull()) {
@@ -4741,6 +4785,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 +4806,7 @@
 */
 QByteArray QUrl::encodedPath() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -4776,6 +4822,7 @@
 */
 bool QUrl::hasQuery() const
 {
+    if (!d) return false;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->hasQuery;
@@ -4805,6 +4852,7 @@
 */
 void QUrl::setQueryDelimiters(char valueDelimiter, char pairDelimiter)
 {
+    if (!d) d = new QUrlPrivate;
     detach();
 
     d->valueDelimiter = valueDelimiter;
@@ -4817,6 +4865,7 @@
 */
 char QUrl::queryPairDelimiter() const
 {
+    if (!d) return '&';
     return d->pairDelimiter;
 }
 
@@ -4826,6 +4875,7 @@
 */
 char QUrl::queryValueDelimiter() const
 {
+    if (!d) return '=';
     return d->valueDelimiter;
 }
 
@@ -4848,6 +4898,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 +4918,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 +4958,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 +4988,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 +5023,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 +5044,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 +5077,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 +5106,7 @@
 */
 bool QUrl::hasQueryItem(const QString &key) const
 {
+    if (!d) return false;
     return hasEncodedQueryItem(toPercentEncoding(key, queryExcludeChars));
 }
 
@@ -5067,6 +5125,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 +5148,7 @@
 */
 QString QUrl::queryItemValue(const QString &key) const
 {
+    if (!d) return QString();
     QByteArray tmp = encodedQueryItemValue(toPercentEncoding(key, queryExcludeChars));
     return fromPercentEncodingMutable(&tmp);
 }
@@ -5108,6 +5168,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 +5192,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 +5230,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 +5258,7 @@
 */
 void QUrl::removeQueryItem(const QString &key)
 {
+    if (!d) return;
     removeEncodedQueryItem(toPercentEncoding(key, queryExcludeChars));
 }
 
@@ -5213,6 +5277,7 @@
 */
 void QUrl::removeEncodedQueryItem(const QByteArray &key)
 {
+    if (!d) return;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -5239,6 +5304,7 @@
 */
 void QUrl::removeAllQueryItems(const QString &key)
 {
+    if (!d) return;
     removeAllEncodedQueryItems(toPercentEncoding(key, queryExcludeChars));
 }
 
@@ -5257,6 +5323,7 @@
 */
 void QUrl::removeAllEncodedQueryItems(const QByteArray &key)
 {
+    if (!d) return;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
     detach();
 
@@ -5280,6 +5347,7 @@
 */
 QByteArray QUrl::encodedQuery() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->query;
@@ -5304,6 +5372,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 +5389,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 +5420,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 +5442,7 @@
 */
 QByteArray QUrl::encodedFragment() const
 {
+    if (!d) return QByteArray();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     d->ensureEncodedParts();
@@ -5386,6 +5458,7 @@
 */
 bool QUrl::hasFragment() const
 {
+    if (!d) return false;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->hasFragment;
@@ -5412,6 +5485,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 +5503,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 +5534,7 @@
 */
 bool QUrl::isRelative() const
 {
+    if (!d) return true;
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     return d->scheme.isEmpty();
@@ -5472,6 +5549,7 @@
 */
 QString QUrl::toString(FormattingOptions options) const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QString url;
@@ -5523,6 +5601,7 @@
 */
 QByteArray QUrl::toEncoded(FormattingOptions options) const
 {
+    if (!d) return QByteArray();
     return d->toEncoded(options);
 }
 
@@ -5773,7 +5852,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 +5865,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 +5886,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 +5905,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 +5920,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 +5974,7 @@
 */
 QString QUrl::toLocalFile() const
 {
+    if (!d) return QString();
     if (!QURL_HASFLAG(d->stateFlags, QUrlPrivate::Parsed)) d->parse();
 
     QString tmp;
@@ -5899,9 +6003,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 +6251,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();
 }