changeset 57:7be693ea7070

drcc, resource compiler, see interview demo
author eldar
date Tue, 19 May 2009 02:49:08 +0000
parents d5a6b6269f44
children 423e4afb245c
files changelog.txt cpp/qt_qtd/qtd_core.cpp demos/interview/build demos/interview/main.d demos/interview/model.d tools/drcc/main.cpp tools/drcc/qcorecmdlineargs_p.h tools/drcc/rcc.cpp tools/drcc/rcc.h tools/drcc/rcc.pro tools/duic/tests/ui_mainwindow.d
diffstat 11 files changed, 1586 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/changelog.txt	Mon May 18 22:15:59 2009 +0000
+++ b/changelog.txt	Tue May 19 02:49:08 2009 +0000
@@ -7,4 +7,5 @@
  * all imports inside Qt are public to avoid import hell
  * API dealing with containers is now wrapped
  * building system is now based on CMake to be crossplatform and more flexible
- * all classes from Gui, OpenGL, Xml, Svg, Network and Webkit packages are wrapped
\ No newline at end of file
+ * all classes from Gui, OpenGL, Xml, Svg, Network and Webkit packages are wrapped
+ * ported duic, a tool for generating code out from xml representation
\ No newline at end of file
--- a/cpp/qt_qtd/qtd_core.cpp	Mon May 18 22:15:59 2009 +0000
+++ b/cpp/qt_qtd/qtd_core.cpp	Tue May 19 02:49:08 2009 +0000
@@ -39,3 +39,21 @@
 //    std::cout << _d_toUtf8 << "\n";
 }
 #endif
+
+extern bool qRegisterResourceData
+    (int, const unsigned char *, const unsigned char *, const unsigned char *);
+
+extern bool qUnregisterResourceData
+    (int, const unsigned char *, const unsigned char *, const unsigned char *);
+
+extern "C" DLL_PUBLIC bool qtd_register_resource_data(int version, const unsigned char *tree,
+                                         const unsigned char *name, const unsigned char *data)
+{
+    return qRegisterResourceData(version, tree, name, data);
+}
+
+extern "C" DLL_PUBLIC bool qtd_unregister_resource_data(int version, const unsigned char *tree,
+                                           const unsigned char *name, const unsigned char *data)
+{
+    return qUnregisterResourceData(version, tree, name, data);
+}
--- a/demos/interview/build	Mon May 18 22:15:59 2009 +0000
+++ b/demos/interview/build	Tue May 19 02:49:08 2009 +0000
@@ -1,3 +1,4 @@
 #! /bin/bash
 
-dmd main.d model.d -L-L../../lib -L-lqtdgui -L-lqtdcore -I../../ -L-lQtGui -L-lQtCore
+./drcc -name interview interview.qrc -o qrc_interview.d
+dmd main.d model.d qrc_interview.d -L-L../../lib -L-lqtdgui -L-lqtdcore -I../../ -I../../qt/d1 -L-lQtGui -L-lQtCore
--- a/demos/interview/main.d	Mon May 18 22:15:59 2009 +0000
+++ b/demos/interview/main.d	Tue May 19 02:49:08 2009 +0000
@@ -48,11 +48,13 @@
 import qt.gui.QIcon;
 import qt.gui.QPixmap;
 
+extern(C) int qtd_init_resources_interview();
+static this() {
+    qtd_init_resources_interview();
+}
 
 int main(char[][] args)
 {
-//    Q_INIT_RESOURCE(interview);
-
     scope app = new QApplication(args);
     scope page = new QSplitter;
 
@@ -88,7 +90,7 @@
     list.setAttribute(Qt.WA_MacShowFocusRect, false);
     page.addWidget(list);
 
-    page.setWindowIcon(new QIcon(new QPixmap("images/interview.png")));
+    page.setWindowIcon(new QIcon(new QPixmap(":/images/interview.png")));
     page.setWindowTitle("Interview");
     page.show();
 
--- a/demos/interview/model.d	Mon May 18 22:15:59 2009 +0000
+++ b/demos/interview/model.d	Tue May 19 02:49:08 2009 +0000
@@ -78,7 +78,7 @@
         
         folder = iconProvider.icon(QFileIconProvider.Folder);
         file = iconProvider.icon(QFileIconProvider.File);
-        services = new QIcon("images/services.png");
+        services = new QIcon(":/images/services.png");
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/drcc/main.cpp	Tue May 19 02:49:08 2009 +0000
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rcc.h"
+#include "qcorecmdlineargs_p.h"
+
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+void showHelp(const QString &argv0, const QString &error)
+{
+    fprintf(stderr, "Qt resource compiler\n");
+    if (!error.isEmpty())
+        fprintf(stderr, "%s: %s\n", qPrintable(argv0), qPrintable(error));
+    fprintf(stderr, "Usage: %s  [options] <inputs>\n\n"
+        "Options:\n"
+        "  -o file              write output to file rather than stdout\n"
+        "  -name name           create an external initialization function with name\n"
+        "  -threshold level     threshold to consider compressing files\n"
+        "  -compress level      compress input files by level\n"
+        "  -root path           prefix resource access path with root path\n"
+        "  -no-compress         disable all compression\n"
+        "  -binary              output a binary file for use as a dynamic resource\n"
+        "  -namespace           turn off namespace macros\n"
+        "  -project             Output a resource file containing all\n"
+        "                       files from the current directory\n"
+        "  -version             display version\n"
+        "  -help                display this information\n",
+        qPrintable(argv0));
+}
+
+void dumpRecursive(const QDir &dir, QTextStream &out)
+{
+    QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot
+                                              | QDir::NoSymLinks);
+    foreach (QFileInfo entry, entries) {
+        if (entry.isDir()) {
+            dumpRecursive(entry.filePath(), out);
+        } else {
+            out << QLatin1String("<file>")
+                << entry.filePath()
+                << QLatin1String("</file>\n");
+        }
+    }
+}
+
+int createProject(const QString &outFileName)
+{
+    QDir currentDir = QDir::current();
+    QString currentDirName = currentDir.dirName();
+    if (currentDirName.isEmpty())
+        currentDirName = QLatin1String("root");
+
+    QFile file;
+    bool isOk = false;
+    if (outFileName.isEmpty()) {
+        isOk = file.open(stdout, QFile::WriteOnly | QFile::Text);
+    } else {
+        file.setFileName(outFileName);
+        isOk = file.open(QFile::WriteOnly | QFile::Text);
+    }
+    if (!isOk) {
+        fprintf(stderr, "Unable to open %s: %s\n",
+                outFileName.isEmpty() ? qPrintable(outFileName) : "standard output",
+                qPrintable(file.errorString()));
+        return 1;
+    }
+
+    QTextStream out(&file);
+    out << QLatin1String("<!DOCTYPE RCC><RCC version=\"1.0\">\n"
+                         "<qresource>\n");
+
+    // use "." as dir to get relative file pathes
+    dumpRecursive(QDir(QLatin1String(".")), out);
+
+    out << QLatin1String("</qresource>\n"
+                         "</RCC>\n");
+
+    return 0;
+}
+
+int runRcc(int argc, char *argv[])
+{
+    QString outFilename;
+    bool helpRequested = false;
+    bool list = false;
+    bool projectRequested = false;
+    QStringList filenamesIn;
+
+    QStringList args = qCmdLineArgs(argc, argv);
+
+    RCCResourceLibrary library;
+
+    //parse options
+    QString errorMsg;
+    for (int i = 1; i < args.count() && errorMsg.isEmpty(); i++) {
+        if (args[i].isEmpty())
+            continue;
+        if (args[i][0] == QLatin1Char('-')) {   // option
+            QString opt = args[i];
+            if (opt == QLatin1String("-o")) {
+                if (!(i < argc-1)) {
+                    errorMsg = QLatin1String("Missing output name");
+                    break;
+                }
+                outFilename = args[++i];
+            } else if (opt == QLatin1String("-name")) {
+                if (!(i < argc-1)) {
+                    errorMsg = QLatin1String("Missing target name");
+                    break;
+                }
+                library.setInitName(args[++i]);
+            } else if (opt == QLatin1String("-root")) {
+                if (!(i < argc-1)) {
+                    errorMsg = QLatin1String("Missing root path");
+                    break;
+                }
+                library.setResourceRoot(QDir::cleanPath(args[++i]));
+                if (library.resourceRoot().isEmpty()
+                        || library.resourceRoot().at(0) != QLatin1Char('/'))
+                    errorMsg = QLatin1String("Root must start with a /");
+            } else if (opt == QLatin1String("-compress")) {
+                if (!(i < argc-1)) {
+                    errorMsg = QLatin1String("Missing compression level");
+                    break;
+                }
+                library.setCompressLevel(args[++i].toInt());
+            } else if (opt == QLatin1String("-threshold")) {
+                if (!(i < argc-1)) {
+                    errorMsg = QLatin1String("Missing compression threshold");
+                    break;
+                }
+                library.setCompressThreshold(args[++i].toInt());
+            } else if (opt == QLatin1String("-binary")) {
+                library.setFormat(RCCResourceLibrary::Binary);
+            } else if (opt == QLatin1String("-namespace")) {
+//                library.setUseNameSpace(!library.useNameSpace());
+                library.setUseNameSpace(false);
+            } else if (opt == QLatin1String("-verbose")) {
+                library.setVerbose(true);
+            } else if (opt == QLatin1String("-list")) {
+                list = true;
+            } else if (opt == QLatin1String("-version") || opt == QLatin1String("-v")) {
+                fprintf(stderr, "Qt Resource Compiler version %s\n", QT_VERSION_STR);
+                return 1;
+            } else if (opt == QLatin1String("-help") || opt == QLatin1String("-h")) {
+                helpRequested = true;
+            } else if (opt == QLatin1String("-no-compress")) {
+                library.setCompressLevel(-2);
+            } else if (opt == QLatin1String("-project")) {
+                projectRequested = true;
+            } else {
+                errorMsg = QString::fromLatin1("Unknown option: '%1'").arg(args[i]);
+            }
+        } else {
+            if (!QFile::exists(args[i])) {
+                qWarning("%s: File does not exist '%s'",
+                    qPrintable(args[0]), qPrintable(args[i]));
+                return 1;
+            }
+            filenamesIn.append(args[i]);
+        }
+    }
+
+    if (projectRequested && !helpRequested) {
+        return createProject(outFilename);
+    }
+
+    if (!filenamesIn.size() || !errorMsg.isEmpty() || helpRequested) {
+        showHelp(args[0], errorMsg);
+        return 1;
+    }
+    QFile errorDevice;
+    errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text);
+    
+    if (library.verbose())
+        errorDevice.write("Qt resource compiler\n");
+
+    library.setInputFiles(filenamesIn);
+
+    if (!library.readFiles(list, errorDevice))
+        return 1;
+
+    // open output
+    QFile out;
+    QIODevice::OpenMode mode = QIODevice::WriteOnly;
+    if (library.format() == RCCResourceLibrary::C_Code)
+        mode |= QIODevice::Text;
+
+    if (outFilename.isEmpty() || outFilename == QLatin1String("-")) {
+        // using this overload close() only flushes.
+        out.open(stdout, mode);
+    } else {
+        out.setFileName(outFilename);
+        if (!out.open(mode)) {
+            const QString msg = QString::fromUtf8("Unable to open %1 for writing: %2\n").arg(outFilename).arg(out.errorString());
+            errorDevice.write(msg.toUtf8());
+            return 1;
+        }
+    }
+
+    // do the task
+    if (list) {
+        const QStringList data = library.dataFiles();
+        for (int i = 0; i < data.size(); ++i) {
+            out.write(qPrintable(QDir::cleanPath(data.at(i))));
+            out.write("\n");
+        }
+        return 0;
+    } 
+
+    return library.output(out, errorDevice) ? 0 : 1;
+}
+
+QT_END_NAMESPACE
+
+int main(int argc, char *argv[])
+{
+    return QT_PREPEND_NAMESPACE(runRcc)(argc, argv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/drcc/qcorecmdlineargs_p.h	Tue May 19 02:49:08 2009 +0000
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCORECMDLINEARGS_P_H
+#define QCORECMDLINEARGS_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists purely as an
+// implementation detail.  This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qstring.h"
+#include "QtCore/qstringlist.h"
+
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "QtCore/qvector.h"
+#include "qt_windows.h"
+QT_END_INCLUDE_NAMESPACE
+
+// template implementation of the parsing algorithm
+// this is used from qcoreapplication_win.cpp and the tools (rcc, uic...)
+
+template<typename Char>
+static QVector<Char*> qWinCmdLine(Char *cmdParam, int length, int &argc)
+{
+    QVector<Char*> argv(8);
+    Char *p = cmdParam;
+    Char *p_end = p + length;
+
+    argc = 0;
+
+    while (*p && p < p_end) {                                // parse cmd line arguments
+        while (QChar((short)(*p)).isSpace())                          // skip white space
+            p++;
+        if (*p && p < p_end) {                                // arg starts
+            int quote;
+            Char *start, *r;
+            if (*p == Char('\"') || *p == Char('\'')) {        // " or ' quote
+                quote = *p;
+                start = ++p;
+            } else {
+                quote = 0;
+                start = p;
+            }
+            r = start;
+            while (*p && p < p_end) {
+                if (quote) {
+                    if (*p == quote) {
+                        p++;
+                        if (QChar((short)(*p)).isSpace())
+                            break;
+                        quote = 0;
+                    }
+                }
+                if (*p == '\\') {                // escape char?
+                    p++;
+                    if (*p == Char('\"') || *p == Char('\''))
+                        ;                        // yes
+                    else
+                        p--;                        // treat \ literally
+                } else {
+                    if (!quote && (*p == Char('\"') || *p == Char('\''))) {        // " or ' quote
+                        quote = *p++;
+                        continue;
+                    } else if (QChar((short)(*p)).isSpace() && !quote)
+                        break;
+                }
+                if (*p)
+                    *r++ = *p++;
+            }
+            if (*p && p < p_end)
+                p++;
+            *r = Char('\0');
+
+            if (argc >= (int)argv.size()-1)        // expand array
+                argv.resize(argv.size()*2);
+            argv[argc++] = start;
+        }
+    }
+    argv[argc] = 0;
+
+    return argv;
+}
+
+static inline QStringList qWinCmdArgs(QString cmdLine) // not const-ref: this might be modified
+{
+    QStringList args;
+
+    int argc = 0;
+    QVector<ushort*> argv = qWinCmdLine<ushort>((ushort*)cmdLine.utf16(), cmdLine.length(), argc);
+    for (int a = 0; a < argc; ++a) {
+        args << QString::fromUtf16(argv[a]);
+    }
+
+    return args;
+}
+
+static inline QStringList qCmdLineArgs(int argc, char *argv[])
+{
+    Q_UNUSED(argc)
+    Q_UNUSED(argv)
+    QString cmdLine = QT_WA_INLINE(
+        QString::fromUtf16((unsigned short*)GetCommandLineW()),
+        QString::fromLocal8Bit(GetCommandLineA())
+    );
+    return qWinCmdArgs(cmdLine);
+}
+
+#else  // !Q_OS_WIN
+
+static inline QStringList qCmdLineArgs(int argc, char *argv[])
+{
+    QStringList args;
+	for (int i = 0; i != argc; ++i)
+        args += QString::fromLocal8Bit(argv[i]);
+    return args;
+}
+
+#endif // Q_OS_WIN
+
+QT_END_NAMESPACE
+
+#endif // QCORECMDLINEARGS_WIN_P_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/drcc/rcc.cpp	Tue May 19 02:49:08 2009 +0000
@@ -0,0 +1,954 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "rcc.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QDateTime>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QDirIterator>
+#include <QtCore/QFile>
+#include <QtCore/QIODevice>
+#include <QtCore/QLocale>
+#include <QtCore/QStack>
+
+#include <QtXml/QDomDocument>
+
+QT_BEGIN_NAMESPACE
+
+enum {
+    CONSTANT_USENAMESPACE = 1,
+    CONSTANT_COMPRESSLEVEL_DEFAULT = -1,
+    CONSTANT_COMPRESSTHRESHOLD_DEFAULT = 70
+};
+
+
+#define writeString(s) write(s, sizeof(s))
+
+void RCCResourceLibrary::write(const char *str, int len)
+{
+    --len; // trailing \0 on string literals...
+    int n = m_out.size();
+    m_out.resize(n + len);
+    memcpy(m_out.data() + n, str, len);
+}
+
+void RCCResourceLibrary::writeByteArray(const QByteArray &other)
+{
+    m_out.append(other);
+}
+
+static inline QString msgOpenReadFailed(const QString &fname, const QString &why)
+{
+    return QString::fromUtf8("Unable to open %1 for reading: %2\n").arg(fname).arg(why);
+}
+
+
+///////////////////////////////////////////////////////////
+//
+// RCCFileInfo
+//
+///////////////////////////////////////////////////////////
+
+class RCCFileInfo
+{
+public:
+    enum Flags
+    {
+        NoFlags = 0x00,
+        Compressed = 0x01,
+        Directory = 0x02
+    };
+
+    RCCFileInfo(const QString &name = QString(), const QFileInfo &fileInfo = QFileInfo(),
+                QLocale::Language language = QLocale::C,
+                QLocale::Country country = QLocale::AnyCountry,
+                uint flags = NoFlags,
+                int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT,
+                int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT);
+    ~RCCFileInfo();
+
+    QString resourceName() const;
+
+public:
+    qint64 writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage);
+    qint64 writeDataName(RCCResourceLibrary &, qint64 offset);
+    void writeDataInfo(RCCResourceLibrary &lib);
+
+    int m_flags;
+    QString m_name;
+    QLocale::Language m_language;
+    QLocale::Country m_country;
+    QFileInfo m_fileInfo;
+    RCCFileInfo *m_parent;
+    QHash<QString, RCCFileInfo*> m_children;
+    int m_compressLevel;
+    int m_compressThreshold;
+
+    qint64 m_nameOffset;
+    qint64 m_dataOffset;
+    qint64 m_childOffset;
+};
+
+RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo,
+    QLocale::Language language, QLocale::Country country, uint flags,
+    int compressLevel, int compressThreshold)
+{
+    m_name = name;
+    m_fileInfo = fileInfo;
+    m_language = language;
+    m_country = country;
+    m_flags = flags;
+    m_parent = 0;
+    m_nameOffset = 0;
+    m_dataOffset = 0;
+    m_childOffset = 0;
+    m_compressLevel = compressLevel;
+    m_compressThreshold = compressThreshold;
+}
+
+RCCFileInfo::~RCCFileInfo()
+{
+    qDeleteAll(m_children);
+}
+
+QString RCCFileInfo::resourceName() const
+{
+    QString resource = m_name;
+    for (RCCFileInfo *p = m_parent; p; p = p->m_parent)
+        resource = resource.prepend(p->m_name + QLatin1Char('/'));
+    return QLatin1Char(':') + resource;
+}
+
+void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib)
+{
+    const bool text = (lib.m_format == RCCResourceLibrary::C_Code);
+    //some info
+    if (text) {
+        if (m_language != QLocale::C) {
+            lib.writeString("  // ");
+            lib.writeByteArray(resourceName().toLocal8Bit());
+            lib.writeString(" [");
+            lib.writeByteArray(QByteArray::number(m_country));
+            lib.writeString("::");
+            lib.writeByteArray(QByteArray::number(m_language));
+            lib.writeString("[\n  ");
+        } else {
+            lib.writeString("  // ");
+            lib.writeByteArray(resourceName().toLocal8Bit());
+            lib.writeString("\n  ");
+        }
+    }
+
+    //pointer data
+    if (m_flags & RCCFileInfo::Directory) {
+        // name offset
+        lib.writeNumber4(m_nameOffset);
+
+        // flags
+        lib.writeNumber2(m_flags);
+
+        // child count
+        lib.writeNumber4(m_children.size());
+
+        // first child offset
+        lib.writeNumber4(m_childOffset);
+    } else {
+        // name offset
+        lib.writeNumber4(m_nameOffset);
+
+        // flags
+        lib.writeNumber2(m_flags);
+
+        // locale
+        lib.writeNumber2(m_country);
+        lib.writeNumber2(m_language);
+
+        //data offset
+        lib.writeNumber4(m_dataOffset);
+    }
+    if (text)
+        lib.writeChar('\n');
+}
+
+qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
+    QString *errorMessage)
+{
+    const bool text = (lib.m_format == RCCResourceLibrary::C_Code);
+
+    //capture the offset
+    m_dataOffset = offset;
+
+    //find the data to be written
+    QFile file(m_fileInfo.absoluteFilePath());
+    if (!file.open(QFile::ReadOnly)) {
+        *errorMessage = msgOpenReadFailed(m_fileInfo.absoluteFilePath(), file.errorString());
+        return 0;
+    }
+    QByteArray data = file.readAll();
+
+#ifndef QT_NO_COMPRESS
+    // Check if compression is useful for this file
+    if (m_compressLevel != 0 && data.size() != 0) {
+        QByteArray compressed =
+            qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel);
+
+        int compressRatio = int(100.0 * (data.size() - compressed.size()) / data.size());
+        if (compressRatio >= m_compressThreshold) {
+            data = compressed;
+            m_flags |= Compressed;
+        }
+    }
+#endif // QT_NO_COMPRESS
+
+    // some info
+    if (text) {
+        lib.writeString("  // ");
+        lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit());
+        lib.writeString("\n  ");
+    }
+
+    // write the length
+
+    lib.writeNumber4(data.size());
+    if (text)
+        lib.writeString("\n  ");
+    offset += 4;
+
+    // write the payload
+    const char *p = data.constData();
+    if (text) {
+        for (int i = data.size(), j = 0; --i >= 0; --j) {
+            lib.writeHex(*p++);
+            if (j == 0) {
+                lib.writeString("\n  ");
+                j = 16;
+            }
+        }
+    } else {
+        for (int i = data.size(); --i >= 0; )
+           lib.writeChar(*p++);
+    }
+    offset += data.size();
+
+    // done
+    if (text)
+        lib.writeString("\n  ");
+    return offset;
+}
+
+qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset)
+{
+    const bool text = (lib.m_format == RCCResourceLibrary::C_Code);
+
+    // capture the offset
+    m_nameOffset = offset;
+
+    // some info
+    if (text) {
+        lib.writeString("  // ");
+        lib.writeByteArray(m_name.toLocal8Bit());
+        lib.writeString("\n  ");
+    }
+
+    // write the length
+    lib.writeNumber2(m_name.length());
+    if (text)
+        lib.writeString("\n  ");
+    offset += 2;
+
+    // write the hash
+    lib.writeNumber4(qHash(m_name));
+    if (text)
+        lib.writeString("\n  ");
+    offset += 4;
+
+    // write the m_name
+    const QChar *unicode = m_name.unicode();
+    for (int i = 0; i < m_name.length(); ++i) {
+        lib.writeNumber2(unicode[i].unicode());
+        if (text && i % 16 == 0)
+            lib.writeString("\n  ");
+    }
+    offset += m_name.length()*2;
+
+    // done
+    if (text)
+        lib.writeString("\n  ");
+    return offset;
+}
+
+
+///////////////////////////////////////////////////////////
+//
+// RCCResourceLibrary
+//
+///////////////////////////////////////////////////////////
+
+RCCResourceLibrary::Strings::Strings() :
+   TAG_RCC(QLatin1String("RCC")),
+   TAG_RESOURCE(QLatin1String("qresource")),
+   TAG_FILE(QLatin1String("file")),
+   ATTRIBUTE_LANG(QLatin1String("lang")),
+   ATTRIBUTE_PREFIX(QLatin1String("prefix")),
+   ATTRIBUTE_ALIAS(QLatin1String("alias")),
+   ATTRIBUTE_THRESHOLD(QLatin1String("threshold")),
+   ATTRIBUTE_COMPRESS(QLatin1String("compress"))
+{
+}
+
+RCCResourceLibrary::RCCResourceLibrary()
+  : m_root(0),
+    m_format(C_Code),
+    m_verbose(false),
+    m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT),
+    m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT),
+    m_treeOffset(0),
+    m_namesOffset(0),
+    m_dataOffset(0),
+    m_useNameSpace(CONSTANT_USENAMESPACE),
+    m_errorDevice(0)
+{
+    m_out.reserve(30 * 1000 * 1000);
+}
+
+RCCResourceLibrary::~RCCResourceLibrary()
+{
+    delete m_root;
+}
+
+bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
+    const QString &fname, QString currentPath, bool ignoreErrors)
+{
+    Q_ASSERT(m_errorDevice);
+    const QChar slash = QLatin1Char('/');
+    if (!currentPath.isEmpty() && !currentPath.endsWith(slash))
+        currentPath += slash;
+
+    QDomDocument document;
+    {
+        QString errorMsg;
+        int errorLine = 0;
+        int errorColumn = 0;
+        if (!document.setContent(inputDevice, &errorMsg, &errorLine, &errorColumn)) {
+            if (ignoreErrors)
+                return true;
+            const QString msg = QString::fromUtf8("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMsg);
+            m_errorDevice->write(msg.toUtf8());
+            return false;
+        }
+    }
+
+    QDomElement domRoot = document.firstChildElement(m_strings.TAG_RCC).toElement();
+    if (!domRoot.isNull() && domRoot.tagName() == m_strings.TAG_RCC) {
+        for (QDomNode node = domRoot.firstChild(); !node.isNull(); node = node.nextSibling()) {
+            if (!node.isElement())
+                continue;
+
+            QDomElement child = node.toElement();
+            if (!child.isNull() && child.tagName() == m_strings.TAG_RESOURCE) {
+                QLocale::Language language = QLocale::c().language();
+                QLocale::Country country = QLocale::c().country();
+
+                if (child.hasAttribute(m_strings.ATTRIBUTE_LANG)) {
+                    QString attribute = child.attribute(m_strings.ATTRIBUTE_LANG);
+                    QLocale lang = QLocale(attribute);
+                    language = lang.language();
+                    if (2 == attribute.length()) {
+                        // Language only
+                        country = QLocale::AnyCountry;
+                    } else {
+                        country = lang.country();
+                    }
+                }
+
+                QString prefix;
+                if (child.hasAttribute(m_strings.ATTRIBUTE_PREFIX))
+                    prefix = child.attribute(m_strings.ATTRIBUTE_PREFIX);
+                if (!prefix.startsWith(slash))
+                    prefix.prepend(slash);
+                if (!prefix.endsWith(slash))
+                    prefix += slash;
+
+                for (QDomNode res = child.firstChild(); !res.isNull(); res = res.nextSibling()) {
+                    if (res.isElement() && res.toElement().tagName() == m_strings.TAG_FILE) {
+
+                        QString fileName(res.firstChild().toText().data());
+                        if (fileName.isEmpty()) {
+                            const QString msg = QString::fromUtf8("RCC: Warning: Null node in XML of '%1'\n").arg(fname);
+                            m_errorDevice->write(msg.toUtf8());
+                        }
+                        QString alias;
+                        if (res.toElement().hasAttribute(m_strings.ATTRIBUTE_ALIAS))
+                            alias = res.toElement().attribute(m_strings.ATTRIBUTE_ALIAS);
+                        else
+                            alias = fileName;
+
+                        int compressLevel = m_compressLevel;
+                        if (res.toElement().hasAttribute(m_strings.ATTRIBUTE_COMPRESS))
+                            compressLevel = res.toElement().attribute(m_strings.ATTRIBUTE_COMPRESS).toInt();
+                        int compressThreshold = m_compressThreshold;
+                        if (res.toElement().hasAttribute(m_strings.ATTRIBUTE_THRESHOLD))
+                            compressThreshold = res.toElement().attribute(m_strings.ATTRIBUTE_THRESHOLD).toInt();
+
+                        // Special case for -no-compress. Overrides all other settings.
+                        if (m_compressLevel == -2)
+                            compressLevel = 0;
+
+                        alias = QDir::cleanPath(alias);
+                        while (alias.startsWith(QLatin1String("../")))
+                            alias.remove(0, 3);
+                        alias = QDir::cleanPath(m_resourceRoot) + prefix + alias;
+
+                        QString absFileName = fileName;
+                        if (QDir::isRelativePath(absFileName))
+                            absFileName.prepend(currentPath);
+                        QFileInfo file(absFileName);
+                        if (!file.exists()) {
+                            m_failedResources.push_back(absFileName);
+                            const QString msg = QString::fromUtf8("RCC: Error in '%1': Cannot find file '%2'\n").arg(fname).arg(fileName);
+                            m_errorDevice->write(msg.toUtf8());
+                            if (ignoreErrors)
+                                continue;
+                            else
+                                return false;
+                        } else if (file.isFile()) {
+                            const bool arc = addFile(alias, RCCFileInfo(alias.section(slash, -1), file, language, country,
+                                                                        RCCFileInfo::NoFlags, compressLevel, compressThreshold));
+                            if (!arc)
+                                m_failedResources.push_back(absFileName);
+                        } else {
+                            QDir dir;
+                            if (file.isDir()) {
+                                dir.setPath(file.filePath());
+                            } else {
+                                dir.setPath(file.path());
+                                dir.setNameFilters(QStringList(file.fileName()));
+                                if (alias.endsWith(file.fileName()))
+                                    alias = alias.left(alias.length()-file.fileName().length());
+                            }
+                            if (!alias.endsWith(slash))
+                                alias += slash;
+                            QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories);
+                            while (it.hasNext()) {
+                                it.next();
+                                QFileInfo child(it.fileInfo());
+                                if (child.fileName() != QLatin1String(".") && child.fileName() != QLatin1String("..")) {
+                                    const bool arc = addFile(alias + child.fileName(),
+                                                             RCCFileInfo(child.fileName(), child, language, country,
+                                                             RCCFileInfo::NoFlags, compressLevel, compressThreshold));
+                                    if (!arc)
+                                        m_failedResources.push_back(child.fileName());
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    if (m_root == 0) {
+        const QString msg = QString::fromUtf8("RCC: Warning: No resources in '%1'.\n").arg(fname);
+        m_errorDevice->write(msg.toUtf8());
+        if (!ignoreErrors && m_format == Binary) {
+            // create dummy entry, otherwise loading qith QResource will crash
+            m_root = new RCCFileInfo(QString(), QFileInfo(),
+                    QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory);
+        }
+    }
+
+    return true;
+}
+
+bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file)
+{
+    Q_ASSERT(m_errorDevice);
+    if (file.m_fileInfo.size() > 0xffffffff) {
+        const QString msg = QString::fromUtf8("File too big: %1\n").arg(file.m_fileInfo.absoluteFilePath());
+        m_errorDevice->write(msg.toUtf8());
+        return false;
+    }
+    if (!m_root)
+        m_root = new RCCFileInfo(QString(), QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory);
+
+    RCCFileInfo *parent = m_root;
+    const QStringList nodes = alias.split(QLatin1Char('/'));
+    for (int i = 1; i < nodes.size()-1; ++i) {
+        const QString node = nodes.at(i);
+        if (node.isEmpty())
+            continue;
+        if (!parent->m_children.contains(node)) {
+            RCCFileInfo *s = new RCCFileInfo(node, QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory);
+            s->m_parent = parent;
+            parent->m_children.insert(node, s);
+            parent = s;
+        } else {
+            parent = parent->m_children[node];
+        }
+    }
+
+    const QString filename = nodes.at(nodes.size()-1);
+    RCCFileInfo *s = new RCCFileInfo(file);
+    s->m_parent = parent;
+    parent->m_children.insertMulti(filename, s);
+    return true;
+}
+
+void RCCResourceLibrary::reset()
+{
+     if (m_root) {
+        delete m_root;
+        m_root = 0;
+    }
+    m_errorDevice = 0;
+    m_failedResources.clear();
+}
+
+
+bool RCCResourceLibrary::readFiles(bool ignoreErrors, QIODevice &errorDevice)
+{
+    reset();
+    m_errorDevice = &errorDevice;
+    //read in data
+    if (m_verbose) {
+        const QString msg = QString::fromUtf8("Processing %1 files [%2]\n")
+            .arg(m_fileNames.size()).arg(static_cast<int>(ignoreErrors));
+        m_errorDevice->write(msg.toUtf8());
+    }
+    for (int i = 0; i < m_fileNames.size(); ++i) {
+        QFile fileIn;
+        QString fname = m_fileNames.at(i);
+        QString pwd;
+        if (fname == QLatin1String("-")) {
+            fname = QLatin1String("(stdin)");
+            pwd = QDir::currentPath();
+            fileIn.setFileName(fname);
+            if (!fileIn.open(stdin, QIODevice::ReadOnly)) {
+                m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8());
+                return false;
+            }
+        } else {
+            pwd = QFileInfo(fname).path();
+            fileIn.setFileName(fname);
+            if (!fileIn.open(QIODevice::ReadOnly)) {
+                m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8());
+                return false;
+            }
+        }
+        if (m_verbose) {
+            const QString msg = QString::fromUtf8("Interpreting %1\n").arg(fname);
+            m_errorDevice->write(msg.toUtf8());
+        }
+
+        if (!interpretResourceFile(&fileIn, fname, pwd, ignoreErrors))
+            return false;
+    }
+    return true;
+}
+
+QStringList RCCResourceLibrary::dataFiles() const
+{
+    QStringList ret;
+    QStack<RCCFileInfo*> pending;
+
+    if (!m_root)
+        return ret;
+    pending.push(m_root);
+    while (!pending.isEmpty()) {
+        RCCFileInfo *file = pending.pop();
+        for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
+            it != file->m_children.end(); ++it) {
+            RCCFileInfo *child = it.value();
+            if (child->m_flags & RCCFileInfo::Directory)
+                pending.push(child);
+            ret.append(child->m_fileInfo.filePath());
+        }
+    }
+    return ret;
+}
+
+// Determine map of resource identifier (':/newPrefix/images/p1.png') to file via recursion
+static void resourceDataFileMapRecursion(const RCCFileInfo *m_root, const QString &path, RCCResourceLibrary::ResourceDataFileMap &m)
+{
+    typedef QHash<QString, RCCFileInfo*>::const_iterator ChildConstIterator;
+    const QChar slash = QLatin1Char('/');
+    const ChildConstIterator cend = m_root->m_children.constEnd();
+    for (ChildConstIterator it = m_root->m_children.constBegin(); it != cend; ++it) {
+        const RCCFileInfo *child = it.value();
+        QString childName = path;
+        childName += slash;
+        childName += child->m_name;
+        if (child->m_flags & RCCFileInfo::Directory) {
+            resourceDataFileMapRecursion(child, childName, m);
+        } else {
+            m.insert(childName, child->m_fileInfo.filePath());
+        }
+    }
+}
+
+RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap() const
+{
+    ResourceDataFileMap rc;
+    if (m_root)
+        resourceDataFileMapRecursion(m_root, QString(QLatin1Char(':')),  rc);
+    return rc;
+}
+
+bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &errorDevice)
+{
+    m_errorDevice = &errorDevice;
+    //write out
+    if (m_verbose)
+        m_errorDevice->write("Outputting code\n");
+    if (!writeHeader()) {
+        m_errorDevice->write("Could not write header\n");
+        return false;
+    }
+    if (m_root) {
+        if (!writeDataBlobs()) {
+            m_errorDevice->write("Could not write data blobs.\n");
+            return false;
+        }
+        if (!writeDataNames()) {
+            m_errorDevice->write("Could not write file names\n");
+            return false;
+        }
+        if (!writeDataStructure()) {
+            m_errorDevice->write("Could not write data tree\n");
+            return false;
+        }
+    }
+    if (!writeInitializer()) {
+        m_errorDevice->write("Could not write footer\n");
+        return false;
+    }
+    outDevice.write(m_out, m_out.size());
+    return true;
+}
+
+void RCCResourceLibrary::writeHex(quint8 tmp)
+{
+    const char * const digits = "0123456789abcdef";
+    writeChar('0');
+    writeChar('x');
+    if (tmp < 16) {
+        writeChar(digits[tmp]);
+    } else {
+        writeChar(digits[tmp >> 4]);
+        writeChar(digits[tmp & 0xf]);
+    }
+    writeChar(',');
+}
+
+void RCCResourceLibrary::writeNumber2(quint16 number)
+{
+    if (m_format == RCCResourceLibrary::Binary) {
+        writeChar(number >> 8);
+        writeChar(number);
+    } else {
+        writeHex(number >> 8);
+        writeHex(number);
+    }
+}
+
+void RCCResourceLibrary::writeNumber4(quint32 number)
+{
+    if (m_format == RCCResourceLibrary::Binary) {
+        writeChar(number >> 24);
+        writeChar(number >> 16);
+        writeChar(number >> 8);
+        writeChar(number);
+    } else {
+        writeHex(number >> 24);
+        writeHex(number >> 16);
+        writeHex(number >> 8);
+        writeHex(number);
+    }
+}
+
+bool RCCResourceLibrary::writeHeader()
+{
+    if (m_format == C_Code) {
+        writeString("/****************************************************************************\n");
+        writeString("** Resource object code\n");
+        writeString("**\n");
+        writeString("** Created: ");
+        writeByteArray(QDateTime::currentDateTime().toString().toLatin1());
+        writeString("\n**      by: The Resource Compiler for Qt version ");
+        writeByteArray(QT_VERSION_STR);
+        writeString("\n**\n");
+        writeString("** WARNING! All changes made in this file will be lost!\n");
+        writeString( "*****************************************************************************/\n\n");
+    } else if (m_format == Binary) {
+        writeString("qres");
+        writeNumber4(0);
+        writeNumber4(0);
+        writeNumber4(0);
+        writeNumber4(0);
+    }
+    return true;
+}
+
+bool RCCResourceLibrary::writeDataBlobs()
+{
+    Q_ASSERT(m_errorDevice);
+    if (m_format == C_Code)
+        writeString("static const ubyte[] qt_resource_data = [\n");
+    else if (m_format == Binary)
+        m_dataOffset = m_out.size();
+    QStack<RCCFileInfo*> pending;
+
+    if (!m_root)
+        return false;
+
+    pending.push(m_root);
+    qint64 offset = 0;
+    QString errorMessage;
+    while (!pending.isEmpty()) {
+        RCCFileInfo *file = pending.pop();
+        for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
+            it != file->m_children.end(); ++it) {
+            RCCFileInfo *child = it.value();
+            if (child->m_flags & RCCFileInfo::Directory)
+                pending.push(child);
+            else {
+                offset = child->writeDataBlob(*this, offset, &errorMessage);
+                if (offset == 0)
+                    m_errorDevice->write(errorMessage.toUtf8());
+            }
+        }
+    }
+    if (m_format == C_Code)
+        writeString("\n];\n\n");
+    return true;
+}
+
+bool RCCResourceLibrary::writeDataNames()
+{
+    if (m_format == C_Code)
+        writeString("static const ubyte[] qt_resource_name = [\n");
+    else if (m_format == Binary)
+        m_namesOffset = m_out.size();
+
+    QHash<QString, int> names;
+    QStack<RCCFileInfo*> pending;
+
+    if (!m_root)
+        return false;
+
+    pending.push(m_root);
+    qint64 offset = 0;
+    while (!pending.isEmpty()) {
+        RCCFileInfo *file = pending.pop();
+        for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
+            it != file->m_children.end(); ++it) {
+            RCCFileInfo *child = it.value();
+            if (child->m_flags & RCCFileInfo::Directory)
+                pending.push(child);
+            if (names.contains(child->m_name)) {
+                child->m_nameOffset = names.value(child->m_name);
+            } else {
+                names.insert(child->m_name, offset);
+                offset = child->writeDataName(*this, offset);
+            }
+        }
+    }
+    if (m_format == C_Code)
+        writeString("\n];\n\n");
+    return true;
+}
+
+static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *right)
+{
+    return qHash(left->m_name) < qHash(right->m_name);
+}
+
+bool RCCResourceLibrary::writeDataStructure()
+{
+    if (m_format == C_Code)
+        writeString("static const ubyte[] qt_resource_struct = [\n");
+    else if (m_format == Binary)
+        m_treeOffset = m_out.size();
+    QStack<RCCFileInfo*> pending;
+
+    if (!m_root)
+        return false;
+
+    //calculate the child offsets (flat)
+    pending.push(m_root);
+    int offset = 1;
+    while (!pending.isEmpty()) {
+        RCCFileInfo *file = pending.pop();
+        file->m_childOffset = offset;
+
+        //sort by hash value for binary lookup
+        QList<RCCFileInfo*> m_children = file->m_children.values();
+        qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash);
+
+        //write out the actual data now
+        for (int i = 0; i < m_children.size(); ++i) {
+            RCCFileInfo *child = m_children.at(i);
+            ++offset;
+            if (child->m_flags & RCCFileInfo::Directory)
+                pending.push(child);
+        }
+    }
+
+    //write out the structure (ie iterate again!)
+    pending.push(m_root);
+    m_root->writeDataInfo(*this);
+    while (!pending.isEmpty()) {
+        RCCFileInfo *file = pending.pop();
+
+        //sort by hash value for binary lookup
+        QList<RCCFileInfo*> m_children = file->m_children.values();
+        qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash);
+
+        //write out the actual data now
+        for (int i = 0; i < m_children.size(); ++i) {
+            RCCFileInfo *child = m_children.at(i);
+            child->writeDataInfo(*this);
+            if (child->m_flags & RCCFileInfo::Directory)
+                pending.push(child);
+        }
+    }
+    if (m_format == C_Code)
+        writeString("\n];\n\n");
+
+    return true;
+}
+
+void RCCResourceLibrary::writeMangleNamespaceFunction(const QByteArray &name)
+{
+    if (m_useNameSpace) {
+// qtd       writeString("QT_MANGLE_NAMESPACE(");
+        writeByteArray(name);
+// qtd       writeChar(')');
+    } else {
+        writeByteArray(name);
+    }
+}
+
+void RCCResourceLibrary::writeAddNamespaceFunction(const QByteArray &name)
+{
+    if (m_useNameSpace) {
+        writeString("QT_PREPEND_NAMESPACE(");
+        writeByteArray(name);
+        writeChar(')');
+    } else {
+        writeByteArray(name);
+    }
+}
+
+bool RCCResourceLibrary::writeInitializer()
+{
+    if (m_format == C_Code) {
+        //write("\nQT_BEGIN_NAMESPACE\n");
+        QString initName = m_initName;
+        if (!initName.isEmpty()) {
+            initName.prepend(QLatin1Char('_'));
+            initName.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_"));
+        }
+
+        //init
+        if (m_useNameSpace)
+            writeString("// QT_BEGIN_NAMESPACE\n\n");
+        if (m_root) {
+            writeString("extern(C) bool qtd_register_resource_data(int version_, ubyte *tree, ubyte *name, ubyte *data);\n\n");
+            writeString("extern(C) bool qtd_unregister_resource_data(int version_, ubyte *tree, ubyte *name, ubyte *data);\n\n");
+        }
+        if (m_useNameSpace)
+            writeString("// QT_END_NAMESPACE\n\n\n");
+        QString initResources = QLatin1String("qtd_init_resources");
+        initResources += initName;
+        writeString("extern(C) int ");
+        writeMangleNamespaceFunction(initResources.toLatin1());
+        writeString("()\n{\n");
+
+        if (m_root) {
+            writeString("    ");
+            writeString("qtd_register_resource_data(0x01, qt_resource_struct.ptr, "
+                       "qt_resource_name.ptr, qt_resource_data.ptr);\n");
+        }
+        writeString("    return 1;\n");
+        writeString("}\n\n");
+
+        //cleanup
+        QString cleanResources = QLatin1String("qtd_cleanup_resources");
+        cleanResources += initName;
+        writeString("extern(C) int ");
+        writeMangleNamespaceFunction(cleanResources.toLatin1());
+        writeString("()\n{\n");
+        if (m_root) {
+            writeString("    ");
+            writeString("qtd_unregister_resource_data(0x01, qt_resource_struct.ptr, "
+                      "qt_resource_name.ptr, qt_resource_data.ptr);\n");
+        }
+        writeString("    return 1;\n");
+        writeString("}\n\n");
+    } else if (m_format == Binary) {
+        int i = 4;
+        char *p = m_out.data();
+        p[i++] = 0; // 0x01
+        p[i++] = 0;
+        p[i++] = 0;
+        p[i++] = 1;
+
+        p[i++] = (m_treeOffset >> 24) & 0xff;
+        p[i++] = (m_treeOffset >> 16) & 0xff;
+        p[i++] = (m_treeOffset >>  8) & 0xff;
+        p[i++] = (m_treeOffset >>  0) & 0xff;
+
+        p[i++] = (m_dataOffset >> 24) & 0xff;
+        p[i++] = (m_dataOffset >> 16) & 0xff;
+        p[i++] = (m_dataOffset >>  8) & 0xff;
+        p[i++] = (m_dataOffset >>  0) & 0xff;
+
+        p[i++] = (m_namesOffset >> 24) & 0xff;
+        p[i++] = (m_namesOffset >> 16) & 0xff;
+        p[i++] = (m_namesOffset >>  8) & 0xff;
+        p[i++] = (m_namesOffset >>  0) & 0xff;
+    }
+    return true;
+}
+
+QT_END_NAMESPACE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/drcc/rcc.h	Tue May 19 02:49:08 2009 +0000
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RCC_H
+#define RCC_H
+
+#include <QtCore/QStringList>
+#include <QtCore/QHash>
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+
+class RCCFileInfo;
+class QIODevice;
+class QTextStream;
+
+
+class RCCResourceLibrary
+{
+    RCCResourceLibrary(const RCCResourceLibrary &);
+    RCCResourceLibrary &operator=(const RCCResourceLibrary &);
+
+public:
+    RCCResourceLibrary();
+    ~RCCResourceLibrary();
+
+    bool output(QIODevice &out, QIODevice &errorDevice);
+
+    bool readFiles(bool ignoreErrors, QIODevice &errorDevice);
+
+    enum Format { Binary, C_Code };
+    void setFormat(Format f) { m_format = f; }
+    Format format() const { return m_format; }
+
+    void setInputFiles(const QStringList &files) { m_fileNames = files; }
+    QStringList inputFiles() const { return m_fileNames; }
+
+    QStringList dataFiles() const;
+
+    // Return a map of resource identifier (':/newPrefix/images/p1.png') to file.
+    typedef QHash<QString, QString> ResourceDataFileMap;
+    ResourceDataFileMap resourceDataFileMap() const;
+
+    void setVerbose(bool b) { m_verbose = b; }
+    bool verbose() const { return m_verbose; }
+
+    void setInitName(const QString &name) { m_initName = name; }
+    QString initName() const { return m_initName; }
+
+    void setCompressLevel(int c) { m_compressLevel = c; }
+    int compressLevel() const { return m_compressLevel; }
+
+    void setCompressThreshold(int t) { m_compressThreshold = t; }
+    int compressThreshold() const { return m_compressThreshold; }
+
+    void setResourceRoot(const QString &root) { m_resourceRoot = root; }
+    QString resourceRoot() const { return m_resourceRoot; }
+    
+    void setUseNameSpace(bool v) { m_useNameSpace = v; }
+    bool useNameSpace() const { return m_useNameSpace; }
+    
+    QStringList failedResources() const { return m_failedResources; }
+
+private:
+    struct Strings {
+        Strings();
+        const QString TAG_RCC;
+        const QString TAG_RESOURCE;
+        const QString TAG_FILE;
+        const QString ATTRIBUTE_LANG;
+        const QString ATTRIBUTE_PREFIX;
+        const QString ATTRIBUTE_ALIAS;
+        const QString ATTRIBUTE_THRESHOLD;
+        const QString ATTRIBUTE_COMPRESS;
+    };
+    friend class RCCFileInfo;
+    void reset();
+    bool addFile(const QString &alias, const RCCFileInfo &file);
+    bool interpretResourceFile(QIODevice *inputDevice, const QString &file,
+        QString currentPath = QString(), bool ignoreErrors = false);
+    bool writeHeader();
+    bool writeDataBlobs();
+    bool writeDataNames();
+    bool writeDataStructure();
+    bool writeInitializer();
+    void writeMangleNamespaceFunction(const QByteArray &name);
+    void writeAddNamespaceFunction(const QByteArray &name);
+    void writeHex(quint8 number);
+    void writeNumber2(quint16 number);
+    void writeNumber4(quint32 number);
+    void writeChar(char c) { m_out.append(c); }
+    void writeByteArray(const QByteArray &);
+    void write(const char *, int len);
+
+    const Strings m_strings;
+    RCCFileInfo *m_root;
+    QStringList m_fileNames;
+    QString m_resourceRoot;
+    QString m_initName;
+    Format m_format;
+    bool m_verbose;
+    int m_compressLevel;
+    int m_compressThreshold;
+    int m_treeOffset;
+    int m_namesOffset;
+    int m_dataOffset;
+    bool m_useNameSpace;
+    QStringList m_failedResources;
+    QIODevice *m_errorDevice;
+    QByteArray m_out;
+};
+
+QT_END_NAMESPACE
+
+#endif // RCC_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/drcc/rcc.pro	Tue May 19 02:49:08 2009 +0000
@@ -0,0 +1,16 @@
+TEMPLATE = app
+TARGET = drcc
+
+DEFINES += QT_RCC
+INCLUDEPATH += .
+DEPENDPATH += .
+
+CONFIG += qt
+QT -= gui
+QT += xml
+
+HEADERS += qcorecmdlineargs_p.h rcc.h
+SOURCES += main.cpp rcc.cpp
+
+target.path=$$[QT_INSTALL_BINS]
+INSTALLS += target
--- a/tools/duic/tests/ui_mainwindow.d	Mon May 18 22:15:59 2009 +0000
+++ b/tools/duic/tests/ui_mainwindow.d	Tue May 19 02:49:08 2009 +0000
@@ -7,7 +7,7 @@
 ** WARNING! All changes made in this file will be lost when recompiling ui file!
 ********************************************************************************/
 
-module ui_mainwindow;
+//module ui_mainwindow;
 
 public import qt.core.QString;
 public import qt.core.QVariant;