Reviewed by Anders. Landed by rwlbuis.
authorrwlbuis <rwlbuis@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Aug 2006 16:18:18 +0000 (16:18 +0000)
committerrwlbuis <rwlbuis@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Aug 2006 16:18:18 +0000 (16:18 +0000)
        Fixes parts of: http://bugzilla.opendarwin.org/show_bug.cgi?id=10467
        WebKit should have Qt platform support

        Note: StringQt.cpp is not part of the original patch, but was
        mistakenly omitted from earlier 10467 patch.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15989 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/platform/qt/ResourceLoaderCurl.cpp [new file with mode: 0644]
WebCore/platform/qt/ResourceLoaderManager.cpp [new file with mode: 0644]
WebCore/platform/qt/ResourceLoaderManager.h [new file with mode: 0644]
WebCore/platform/qt/StringQt.cpp [new file with mode: 0644]

index 0b343e2866dddfbc84784c769646d234b8dc99da..0e2419dcf71cdb48ca8198fe242e0881d8704e93 100644 (file)
@@ -1,3 +1,34 @@
+2006-08-23  Nikolas Zimmermann  <zimmermann@kde.org>
+
+        Reviewed by Anders. Landed by rwlbuis.
+
+        Fixes parts of: http://bugzilla.opendarwin.org/show_bug.cgi?id=10467
+        WebKit should have Qt platform support
+
+        * platform/qt/ResourceLoaderCurl.cpp: Added.
+        (WebCore::ResourceLoaderInternal::~ResourceLoaderInternal):
+        (WebCore::ResourceLoader::~ResourceLoader):
+        (WebCore::ResourceLoader::start):
+        (WebCore::ResourceLoader::cancel):
+        (WebCore::ResourceLoader::assembleResponseHeaders):
+        (WebCore::ResourceLoader::retrieveCharset):
+        (WebCore::ResourceLoader::receivedResponse):
+        * platform/qt/ResourceLoaderManager.cpp: Added.
+        (WebCore::ResourceLoaderManager::ResourceLoaderManager):
+        (WebCore::ResourceLoaderManager::get):
+        (WebCore::ResourceLoaderManager::useSimpleTransfer):
+        (WebCore::writeCallback):
+        (WebCore::headerCallback):
+        (WebCore::ResourceLoaderManager::downloadTimerCallback):
+        (WebCore::ResourceLoaderManager::remove):
+        (WebCore::ResourceLoaderManager::add):
+        (WebCore::ResourceLoaderManager::cancel):
+        * platform/qt/ResourceLoaderManager.h: Added.
+        * platform/qt/StringQt.cpp: Added.
+        (WebCore::String::String):
+        (WebCore::String::operator QString):
+        (WebCore::DeprecatedString::operator QString):
+
 2006-08-23  Brady Eidson  <beidson@apple.com>
 
         Reviewed by Maciej
diff --git a/WebCore/platform/qt/ResourceLoaderCurl.cpp b/WebCore/platform/qt/ResourceLoaderCurl.cpp
new file mode 100644 (file)
index 0000000..82eda3a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2005, 2006 Michael Emmel mike.emmel@gmail.com 
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include <QDebug>
+#include "config.h"
+#include "ResourceLoader.h"
+
+#include "DocLoader.h"
+#include "ResourceLoaderInternal.h"
+#include "ResourceLoaderManager.h"
+
+#define notImplemented() do { fprintf(stderr, "FIXME: UNIMPLEMENTED: %s:%d\n", __FILE__, __LINE__); } while(0)
+
+namespace WebCore {
+
+ResourceLoaderInternal::~ResourceLoaderInternal()
+{
+}
+
+ResourceLoader::~ResourceLoader()
+{
+    cancel();
+}
+
+bool ResourceLoader::start(DocLoader* docLoader)
+{
+    ResourceLoaderManager::get()->add(this);
+    return true;
+}
+
+void ResourceLoader::cancel()
+{
+    ResourceLoaderManager::get()->cancel(this);
+}
+
+void ResourceLoader::assembleResponseHeaders() const
+{
+    if (!d->assembledResponseHeaders) {
+        d->responseHeaders = DeprecatedString::fromUtf8(d->response.toUtf8(), d->response.length());
+        d->assembledResponseHeaders = true;
+        // TODO: Move the client activation to receivedResponse(), once
+        // we use KIO, and receivedResponse() is called only once.
+        if (d->client) {
+            d->client->receivedResponse(const_cast<ResourceLoader *>(this), (char *) d->response.data());
+        }
+
+        d->response = QString(); // Reset
+    }
+}
+
+void ResourceLoader::retrieveCharset() const
+{
+    if (!d->retrievedCharset) {
+        d->retrievedCharset = true;
+    }
+
+    // TODO: We can just parse the headers here, but once we use KIO
+    // we can set the response parameter to sth. else than a "char*".
+    // I save my time but not implementing it for now :-)
+    notImplemented();
+}
+
+void ResourceLoader::receivedResponse(char* response)
+{
+    Q_ASSERT(method() == "POST");
+
+    d->assembledResponseHeaders = false;
+    d->retrievedCharset = false;
+
+    // TODO: This is flawed:
+    // - usually receivedResponse() should be called _once_, when the
+    //   response is available - seems very unflexible to do that with libcurl
+    //   (so let's wait until it dies and do it properly with KIO then.)
+    // - QString::fromLatin1() is also wrong, of course.
+    //
+    // Anyway, let's collect the response data here, as the ResourceLoaderManager
+    // calls us for every line of the header it receives.
+    d->response += QString::fromLatin1(response);
+}
+
+} // namespace WebCore
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/qt/ResourceLoaderManager.cpp b/WebCore/platform/qt/ResourceLoaderManager.cpp
new file mode 100644 (file)
index 0000000..aeec1f2
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "ResourceLoaderManager.h"
+
+#include "ResourceLoader.h"
+#include "ResourceLoaderInternal.h"
+
+namespace WebCore {
+
+const int selectTimeoutMS = 5;
+const double pollTimeSeconds = 0.05;
+
+ResourceLoaderManager::ResourceLoaderManager()
+    : m_useSimple(false)
+    , jobs(new HashSet<ResourceLoader*>)
+    , m_downloadTimer(this, &ResourceLoaderManager::downloadTimerCallback)
+{
+    curl_global_init(CURL_GLOBAL_ALL);
+    curlMultiHandle = curl_multi_init();
+}
+
+ResourceLoaderManager* ResourceLoaderManager::get()
+{
+    static ResourceLoaderManager* s_singleton;
+
+    if (!s_singleton)
+        s_singleton = new ResourceLoaderManager;
+
+    return s_singleton;
+}
+
+void ResourceLoaderManager::useSimpleTransfer(bool useSimple)
+{
+    m_useSimple = useSimple;
+}
+
+static size_t writeCallback(void* ptr, size_t size, size_t nmemb, void* obj)
+{
+    ResourceLoader* job = static_cast<ResourceLoader*>(obj);
+    ResourceLoaderInternal* d = job->getInternal();
+    int totalSize = size * nmemb;
+    d->client->receivedData(job, static_cast<char*>(ptr), totalSize);
+    return totalSize;
+}
+
+static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* obj)
+{
+    ResourceLoader* job = static_cast<ResourceLoader*>(obj);
+    ResourceLoaderInternal* d = job->getInternal();
+    if (job->method() == "POST") {
+        job->receivedResponse(ptr);
+    }
+    
+    int totalSize = size * nmemb;
+    return totalSize;
+}
+
+void ResourceLoaderManager::downloadTimerCallback(Timer<ResourceLoaderManager>* timer)
+{
+    if (jobs->isEmpty()) {
+        m_downloadTimer.stop();
+        return;
+    }
+
+    if (m_useSimple) {
+        for (HashSet<ResourceLoader*>::iterator it = jobs->begin(); it != jobs->end(); ++it) {
+            ResourceLoader* job = *it;
+            ResourceLoaderInternal* d = job->getInternal();
+            CURLcode res = curl_easy_perform(d->m_handle);
+            if (res != CURLE_OK)
+                printf("Error WITH JOB %d\n", res);
+            d->client->receivedAllData(job, 0);
+            d->client->receivedAllData(job);
+            curl_easy_cleanup(d->m_handle);
+            d->m_handle = 0;
+        }
+
+        jobs->clear();
+        m_downloadTimer.stop();
+    } else {
+        FD_ZERO(&fdread);
+        FD_ZERO(&fdwrite);
+        FD_ZERO(&fdexcep);
+        curl_multi_fdset(curlMultiHandle, &fdread, &fdwrite, &fdexcep, &maxfd);
+        int nrunning;
+        struct timeval timeout;
+        int retval;
+        timeout.tv_sec = 0;
+        timeout.tv_usec = selectTimeoutMS * 1000;       // select waits microseconds
+        retval = ::select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
+        switch (retval) {
+            case -1:                        // select error
+#ifndef NDEBUG
+                printf("%s, select error(%d)\n", __PRETTY_FUNCTION__,retval);
+#endif
+                /* fallthrough*/
+            case 0:                 // select timeout
+#ifndef NDEBUG
+                printf("%s, select timeout %d\n", __PRETTY_FUNCTION__,retval);
+#endif
+                /* fallthrough. this can be the first perform to be made */
+            default:                        // 1+ descriptors have data
+                while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curlMultiHandle, &nrunning))
+                    { }
+        }
+
+        // check the curl messages indicating completed transfers
+        // and free their resources
+        ResourceLoader* job;
+        int nmsgs;
+        while (CURLMsg* msg = curl_multi_info_read(curlMultiHandle, &nmsgs)) {
+            if (msg->msg == CURLMSG_DONE) {
+                // find the node which has same d->m_handle as completed transfer
+                CURL* chandle = msg->easy_handle;
+                assert(chandle);
+                ResourceLoader *job;
+                curl_easy_getinfo(chandle, CURLINFO_PRIVATE, &job);
+                assert(job); //fixme: assert->if ?
+                // if found, delete it
+                if (job) {
+                    ResourceLoaderInternal *d = job->getInternal();
+                    switch (msg->data.result) {
+                        case CURLE_OK: {
+                            // use this to authenticate
+                            long respCode = -1;
+                            curl_easy_getinfo(d->m_handle, CURLINFO_RESPONSE_CODE, &respCode);
+                            remove(job);
+                            break;
+                        }
+                        default:
+                            printf("Curl ERROR %s\n", curl_easy_strerror(msg->data.result));
+                            job->setError(msg->data.result);
+                            remove(job);
+                            break;
+                    }
+                } else {
+                    printf("CurlRequest not found, eventhough curl d->m_handle finished\n");
+                    assert(0);
+                }
+            }
+
+        }
+    }
+    if (!jobs->isEmpty())
+        m_downloadTimer.startOneShot(pollTimeSeconds);
+}
+
+void ResourceLoaderManager::remove(ResourceLoader* job)
+{
+    ResourceLoaderInternal* d = job->getInternal();
+    if (!d->m_handle)
+        return;
+    if (jobs->contains(job))
+        jobs->remove(job);
+    if (jobs->isEmpty())
+        m_downloadTimer.stop();
+    d->client->receivedAllData(job, 0);
+    d->client->receivedAllData(job);
+    if (d->m_handle) {
+        curl_multi_remove_handle(curlMultiHandle, d->m_handle);
+        curl_easy_cleanup(d->m_handle);
+        d->m_handle = NULL;
+    }
+}
+
+void ResourceLoaderManager::add(ResourceLoader* job)
+{
+    bool startTimer = jobs->isEmpty();
+    ResourceLoaderInternal* d = job->getInternal();
+    DeprecatedString url = d->URL.url();
+    d->m_handle = curl_easy_init();
+    curl_easy_setopt(d->m_handle, CURLOPT_PRIVATE, job);
+    curl_easy_setopt(d->m_handle, CURLOPT_ERRORBUFFER, error_buffer);
+    curl_easy_setopt(d->m_handle, CURLOPT_WRITEFUNCTION, writeCallback);
+    curl_easy_setopt(d->m_handle, CURLOPT_WRITEDATA, job);
+    curl_easy_setopt(d->m_handle, CURLOPT_HEADERFUNCTION, headerCallback);
+    curl_easy_setopt(d->m_handle, CURLOPT_WRITEHEADER, job);
+    curl_easy_setopt(d->m_handle, CURLOPT_FOLLOWLOCATION, 1);
+    curl_easy_setopt(d->m_handle, CURLOPT_MAXREDIRS, 10);
+    curl_easy_setopt(d->m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+    // url ptr must remain valid through the request
+    curl_easy_setopt(d->m_handle, CURLOPT_URL, url.ascii());
+
+    if (job->method() == "POST") {
+        DeprecatedString postData = job->postData().flattenToString();
+
+        char *postDataString = (char *) malloc(postData.length() + 1);
+        strncpy(postDataString, postData.ascii(), postData.length());
+        postDataString[postData.length()] = '\0';
+
+        // TODO: Do it properly after we got rid of libcurl! (also leaks the headerlist. hmpf.)
+        curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDS, postDataString);
+    }
+
+    if (m_useSimple)
+        jobs->add(job);
+    else {
+        CURLMcode ret = curl_multi_add_handle(curlMultiHandle, d->m_handle);
+        // don't call perform, because events must be async
+        // timeout will occur and do curl_multi_perform
+        if (ret && ret != CURLM_CALL_MULTI_PERFORM) {
+            printf("Error %d starting job %s\n", ret, d->URL.url().ascii());
+            job->setError(1);
+            startTimer =false;
+        } else
+            jobs->add(job);
+    }
+    if (startTimer)
+        m_downloadTimer.startOneShot(pollTimeSeconds);
+}
+
+void ResourceLoaderManager::cancel(ResourceLoader* job)
+{
+    remove(job);
+    job->setError(1);
+}
+
+} // namespace WebCore
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/qt/ResourceLoaderManager.h b/WebCore/platform/qt/ResourceLoaderManager.h
new file mode 100644 (file)
index 0000000..9d8cb57
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com 
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef ResourceLoaderManager_H_
+#define ResourceLoaderManager_H_
+
+#include "Frame.h"
+#include "Timer.h"
+#include "ResourceLoaderClient.h"
+#include <curl/curl.h>
+
+namespace WebCore {
+
+class ResourceLoaderManager {
+public:
+    static ResourceLoaderManager* get();
+    void add(ResourceLoader*);
+    void cancel(ResourceLoader*);
+
+    // If true, don't multiplex downloads: download completely one at a time.
+    void useSimpleTransfer(bool useSimple);
+
+private:
+    ResourceLoaderManager();
+    void downloadTimerCallback(Timer<ResourceLoaderManager>*);
+    void remove(ResourceLoader*);
+
+    bool m_useSimple;
+    HashSet<ResourceLoader*>* jobs;
+    Timer<ResourceLoaderManager> m_downloadTimer;
+    CURLM* curlMultiHandle; // not freed
+
+    // curl filehandles to poll with select
+    fd_set fdread;
+    fd_set fdwrite;
+    fd_set fdexcep;
+
+    int maxfd;
+    char error_buffer[CURL_ERROR_SIZE];
+
+    // NULL-terminated list of supported protocols
+    const char* const* curl_protocols; // not freed
+};
+
+}
+
+#endif
+
+// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/qt/StringQt.cpp b/WebCore/platform/qt/StringQt.cpp
new file mode 100644 (file)
index 0000000..830b7c6
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "PlatformString.h"
+#include "DeprecatedString.h"
+
+#include <QString>
+
+namespace WebCore {
+
+String::String(const QString& qstr)
+{
+    unsigned int len = qstr.length();
+    const UChar* str = reinterpret_cast<const UChar*>(qstr.constData());
+
+    if (!str)
+        return;
+    
+    if (len == 0)
+        m_impl = StringImpl::empty();
+    else
+        m_impl = new StringImpl(str, len);
+}
+
+String::operator QString() const
+{
+    return QString(reinterpret_cast<const QChar*>(characters()), length());
+}
+
+DeprecatedString::operator QString() const
+{
+    return QString(reinterpret_cast<const QChar*>(unicode()), length());
+}
+
+}
+
+// vim: ts=4 sw=4 et