summaryrefslogtreecommitdiffstats
path: root/src/tools/rcc
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/tools/rcc
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/tools/rcc')
-rw-r--r--src/tools/rcc/main.cpp262
-rw-r--r--src/tools/rcc/rcc.cpp987
-rw-r--r--src/tools/rcc/rcc.h153
-rw-r--r--src/tools/rcc/rcc.pri3
-rw-r--r--src/tools/rcc/rcc.pro16
5 files changed, 1421 insertions, 0 deletions
diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp
new file mode 100644
index 0000000000..d91391af26
--- /dev/null
+++ b/src/tools/rcc/main.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <rcc.h>
+#include "../../corelib/kernel/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());
+ } 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);
+}
diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp
new file mode 100644
index 0000000000..010a785df4
--- /dev/null
+++ b/src/tools/rcc/rcc.cpp
@@ -0,0 +1,987 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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;
+ if (parent->m_children.contains(filename)) {
+ foreach (const QString &fileName, m_fileNames)
+ qWarning("%s: Warning: potential duplicate alias detected: '%s'",
+ qPrintable(fileName), qPrintable(filename));
+ }
+ 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");
+ writeString("#include <QtCore/qglobal.h>\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 unsigned char 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 unsigned char 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 unsigned char 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) {
+ writeString("QT_MANGLE_NAMESPACE(");
+ writeByteArray(name);
+ 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 Q_CORE_EXPORT bool qRegisterResourceData\n "
+ "(int, const unsigned char *, "
+ "const unsigned char *, const unsigned char *);\n\n");
+ writeString("extern Q_CORE_EXPORT bool qUnregisterResourceData\n "
+ "(int, const unsigned char *, "
+ "const unsigned char *, const unsigned char *);\n\n");
+ }
+ if (m_useNameSpace)
+ writeString("QT_END_NAMESPACE\n\n\n");
+ QString initResources = QLatin1String("qInitResources");
+ initResources += initName;
+ writeString("int ");
+ writeMangleNamespaceFunction(initResources.toLatin1());
+ writeString("()\n{\n");
+
+ if (m_root) {
+ writeString(" ");
+ writeAddNamespaceFunction("qRegisterResourceData");
+ writeString("\n (0x01, qt_resource_struct, "
+ "qt_resource_name, qt_resource_data);\n");
+ }
+ writeString(" return 1;\n");
+ writeString("}\n\n");
+ writeString("Q_CONSTRUCTOR_FUNCTION(");
+ writeMangleNamespaceFunction(initResources.toLatin1());
+ writeString(")\n\n");
+
+ //cleanup
+ QString cleanResources = QLatin1String("qCleanupResources");
+ cleanResources += initName;
+ writeString("int ");
+ writeMangleNamespaceFunction(cleanResources.toLatin1());
+ writeString("()\n{\n");
+ if (m_root) {
+ writeString(" ");
+ writeAddNamespaceFunction("qUnregisterResourceData");
+ writeString("\n (0x01, qt_resource_struct, "
+ "qt_resource_name, qt_resource_data);\n");
+ }
+ writeString(" return 1;\n");
+ writeString("}\n\n");
+ writeString("Q_DESTRUCTOR_FUNCTION(");
+ writeMangleNamespaceFunction(cleanResources.toLatin1());
+ 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
diff --git a/src/tools/rcc/rcc.h b/src/tools/rcc/rcc.h
new file mode 100644
index 0000000000..666cc09625
--- /dev/null
+++ b/src/tools/rcc/rcc.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@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
diff --git a/src/tools/rcc/rcc.pri b/src/tools/rcc/rcc.pri
new file mode 100644
index 0000000000..534f2acbff
--- /dev/null
+++ b/src/tools/rcc/rcc.pri
@@ -0,0 +1,3 @@
+INCLUDEPATH += $$PWD
+HEADERS += $$PWD/rcc.h
+SOURCES += $$PWD/rcc.cpp
diff --git a/src/tools/rcc/rcc.pro b/src/tools/rcc/rcc.pro
new file mode 100644
index 0000000000..edc85a1d15
--- /dev/null
+++ b/src/tools/rcc/rcc.pro
@@ -0,0 +1,16 @@
+TEMPLATE = app
+TARGET = rcc
+
+DESTDIR = ../../../bin
+DEFINES += QT_RCC
+INCLUDEPATH += .
+DEPENDPATH += .
+
+include(rcc.pri)
+HEADERS += ../../corelib/kernel/qcorecmdlineargs_p.h
+SOURCES += main.cpp
+include(../bootstrap/bootstrap.pri)
+
+target.path=$$[QT_INSTALL_BINS]
+INSTALLS += target
+include(../../qt_targets.pri)