1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the tools applications of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 #include <QtCore/QByteArray>
45 #include <QtCore/QDateTime>
46 #include <QtCore/QDebug>
47 #include <QtCore/QDir>
48 #include <QtCore/QDirIterator>
49 #include <QtCore/QFile>
50 #include <QtCore/QIODevice>
51 #include <QtCore/QLocale>
52 #include <QtCore/QStack>
53 #include <QtCore/QXmlStreamReader>
55 // Note: A copy of this file is used in Qt Designer (qttools/src/designer/src/lib/shared/rcc.cpp)
60 CONSTANT_USENAMESPACE = 1,
61 CONSTANT_COMPRESSLEVEL_DEFAULT = -1,
62 CONSTANT_COMPRESSTHRESHOLD_DEFAULT = 70
66 #define writeString(s) write(s, sizeof(s))
68 void RCCResourceLibrary::write(const char *str, int len)
70 --len; // trailing \0 on string literals...
72 m_out.resize(n + len);
73 memcpy(m_out.data() + n, str, len);
76 void RCCResourceLibrary::writeByteArray(const QByteArray &other)
81 static inline QString msgOpenReadFailed(const QString &fname, const QString &why)
83 return QString::fromUtf8("Unable to open %1 for reading: %2\n").arg(fname).arg(why);
87 ///////////////////////////////////////////////////////////
91 ///////////////////////////////////////////////////////////
103 RCCFileInfo(const QString &name = QString(), const QFileInfo &fileInfo = QFileInfo(),
104 QLocale::Language language = QLocale::C,
105 QLocale::Country country = QLocale::AnyCountry,
106 uint flags = NoFlags,
107 int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT,
108 int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT);
111 QString resourceName() const;
114 qint64 writeDataBlob(RCCResourceLibrary &lib, qint64 offset, QString *errorMessage);
115 qint64 writeDataName(RCCResourceLibrary &, qint64 offset);
116 void writeDataInfo(RCCResourceLibrary &lib);
120 QLocale::Language m_language;
121 QLocale::Country m_country;
122 QFileInfo m_fileInfo;
123 RCCFileInfo *m_parent;
124 QHash<QString, RCCFileInfo*> m_children;
126 int m_compressThreshold;
130 qint64 m_childOffset;
133 RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo,
134 QLocale::Language language, QLocale::Country country, uint flags,
135 int compressLevel, int compressThreshold)
138 m_fileInfo = fileInfo;
139 m_language = language;
146 m_compressLevel = compressLevel;
147 m_compressThreshold = compressThreshold;
150 RCCFileInfo::~RCCFileInfo()
152 qDeleteAll(m_children);
155 QString RCCFileInfo::resourceName() const
157 QString resource = m_name;
158 for (RCCFileInfo *p = m_parent; p; p = p->m_parent)
159 resource = resource.prepend(p->m_name + QLatin1Char('/'));
160 return QLatin1Char(':') + resource;
163 void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib)
165 const bool text = (lib.m_format == RCCResourceLibrary::C_Code);
168 if (m_language != QLocale::C) {
169 lib.writeString(" // ");
170 lib.writeByteArray(resourceName().toLocal8Bit());
171 lib.writeString(" [");
172 lib.writeByteArray(QByteArray::number(m_country));
173 lib.writeString("::");
174 lib.writeByteArray(QByteArray::number(m_language));
175 lib.writeString("[\n ");
177 lib.writeString(" // ");
178 lib.writeByteArray(resourceName().toLocal8Bit());
179 lib.writeString("\n ");
184 if (m_flags & RCCFileInfo::Directory) {
186 lib.writeNumber4(m_nameOffset);
189 lib.writeNumber2(m_flags);
192 lib.writeNumber4(m_children.size());
194 // first child offset
195 lib.writeNumber4(m_childOffset);
198 lib.writeNumber4(m_nameOffset);
201 lib.writeNumber2(m_flags);
204 lib.writeNumber2(m_country);
205 lib.writeNumber2(m_language);
208 lib.writeNumber4(m_dataOffset);
214 qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
215 QString *errorMessage)
217 const bool text = (lib.m_format == RCCResourceLibrary::C_Code);
220 m_dataOffset = offset;
222 //find the data to be written
223 QFile file(m_fileInfo.absoluteFilePath());
224 if (!file.open(QFile::ReadOnly)) {
225 *errorMessage = msgOpenReadFailed(m_fileInfo.absoluteFilePath(), file.errorString());
228 QByteArray data = file.readAll();
230 #ifndef QT_NO_COMPRESS
231 // Check if compression is useful for this file
232 if (m_compressLevel != 0 && data.size() != 0) {
233 QByteArray compressed =
234 qCompress(reinterpret_cast<uchar *>(data.data()), data.size(), m_compressLevel);
236 int compressRatio = int(100.0 * (data.size() - compressed.size()) / data.size());
237 if (compressRatio >= m_compressThreshold) {
239 m_flags |= Compressed;
242 #endif // QT_NO_COMPRESS
246 lib.writeString(" // ");
247 lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit());
248 lib.writeString("\n ");
253 lib.writeNumber4(data.size());
255 lib.writeString("\n ");
259 const char *p = data.constData();
261 for (int i = data.size(), j = 0; --i >= 0; --j) {
264 lib.writeString("\n ");
269 for (int i = data.size(); --i >= 0; )
272 offset += data.size();
276 lib.writeString("\n ");
280 qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset)
282 const bool text = (lib.m_format == RCCResourceLibrary::C_Code);
284 // capture the offset
285 m_nameOffset = offset;
289 lib.writeString(" // ");
290 lib.writeByteArray(m_name.toLocal8Bit());
291 lib.writeString("\n ");
295 lib.writeNumber2(m_name.length());
297 lib.writeString("\n ");
301 lib.writeNumber4(qt_hash(m_name));
303 lib.writeString("\n ");
307 const QChar *unicode = m_name.unicode();
308 for (int i = 0; i < m_name.length(); ++i) {
309 lib.writeNumber2(unicode[i].unicode());
310 if (text && i % 16 == 0)
311 lib.writeString("\n ");
313 offset += m_name.length()*2;
317 lib.writeString("\n ");
322 ///////////////////////////////////////////////////////////
324 // RCCResourceLibrary
326 ///////////////////////////////////////////////////////////
328 RCCResourceLibrary::Strings::Strings() :
329 TAG_RCC(QLatin1String("RCC")),
330 TAG_RESOURCE(QLatin1String("qresource")),
331 TAG_FILE(QLatin1String("file")),
332 ATTRIBUTE_LANG(QLatin1String("lang")),
333 ATTRIBUTE_PREFIX(QLatin1String("prefix")),
334 ATTRIBUTE_ALIAS(QLatin1String("alias")),
335 ATTRIBUTE_THRESHOLD(QLatin1String("threshold")),
336 ATTRIBUTE_COMPRESS(QLatin1String("compress"))
340 RCCResourceLibrary::RCCResourceLibrary()
344 m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT),
345 m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT),
349 m_useNameSpace(CONSTANT_USENAMESPACE),
352 m_out.reserve(30 * 1000 * 1000);
355 RCCResourceLibrary::~RCCResourceLibrary()
366 bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice,
367 const QString &fname, QString currentPath, bool ignoreErrors)
369 Q_ASSERT(m_errorDevice);
370 const QChar slash = QLatin1Char('/');
371 if (!currentPath.isEmpty() && !currentPath.endsWith(slash))
372 currentPath += slash;
374 QXmlStreamReader reader(inputDevice);
375 QStack<RCCXmlTag> tokens;
378 QLocale::Language language = QLocale::c().language();
379 QLocale::Country country = QLocale::c().country();
381 int compressLevel = m_compressLevel;
382 int compressThreshold = m_compressThreshold;
384 while (!reader.atEnd()) {
385 QXmlStreamReader::TokenType t = reader.readNext();
387 case QXmlStreamReader::StartElement:
388 if (reader.name() == m_strings.TAG_RCC) {
389 if (!tokens.isEmpty())
390 reader.raiseError(QLatin1String("expected <RCC> tag"));
393 } else if (reader.name() == m_strings.TAG_RESOURCE) {
394 if (tokens.isEmpty() || tokens.top() != RccTag) {
395 reader.raiseError(QLatin1String("unexpected <RESOURCE> tag"));
397 tokens.push(ResourceTag);
399 QXmlStreamAttributes attributes = reader.attributes();
400 language = QLocale::c().language();
401 country = QLocale::c().country();
403 if (attributes.hasAttribute(m_strings.ATTRIBUTE_LANG)) {
404 QString attribute = attributes.value(m_strings.ATTRIBUTE_LANG).toString();
405 QLocale lang = QLocale(attribute);
406 language = lang.language();
407 if (2 == attribute.length()) {
409 country = QLocale::AnyCountry;
411 country = lang.country();
416 if (attributes.hasAttribute(m_strings.ATTRIBUTE_PREFIX))
417 prefix = attributes.value(m_strings.ATTRIBUTE_PREFIX).toString();
418 if (!prefix.startsWith(slash))
419 prefix.prepend(slash);
420 if (!prefix.endsWith(slash))
423 } else if (reader.name() == m_strings.TAG_FILE) {
424 if (tokens.isEmpty() || tokens.top() != ResourceTag) {
425 reader.raiseError(QLatin1String("unexpected <FILE> tag"));
427 tokens.push(FileTag);
429 QXmlStreamAttributes attributes = reader.attributes();
431 if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS))
432 alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString();
434 compressLevel = m_compressLevel;
435 if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS))
436 compressLevel = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString().toInt();
438 compressThreshold = m_compressThreshold;
439 if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD))
440 compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt();
442 // Special case for -no-compress. Overrides all other settings.
443 if (m_compressLevel == -2)
447 reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString()));
451 case QXmlStreamReader::EndElement:
452 if (reader.name() == m_strings.TAG_RCC) {
453 if (!tokens.isEmpty() && tokens.top() == RccTag)
456 reader.raiseError(QLatin1String("unexpected closing tag"));
457 } else if (reader.name() == m_strings.TAG_RESOURCE) {
458 if (!tokens.isEmpty() && tokens.top() == ResourceTag)
461 reader.raiseError(QLatin1String("unexpected closing tag"));
462 } else if (reader.name() == m_strings.TAG_FILE) {
463 if (!tokens.isEmpty() && tokens.top() == FileTag)
466 reader.raiseError(QLatin1String("unexpected closing tag"));
470 case QXmlStreamReader::Characters:
471 if (reader.isWhitespace())
473 if (tokens.isEmpty() || tokens.top() != FileTag) {
474 reader.raiseError(QLatin1String("unexpected text"));
476 QString fileName = reader.text().toString();
477 if (fileName.isEmpty()) {
478 const QString msg = QString::fromLatin1("RCC: Warning: Null node in XML of '%1'\n").arg(fname);
479 m_errorDevice->write(msg.toUtf8());
485 alias = QDir::cleanPath(alias);
486 while (alias.startsWith(QLatin1String("../")))
488 alias = QDir::cleanPath(m_resourceRoot) + prefix + alias;
490 QString absFileName = fileName;
491 if (QDir::isRelativePath(absFileName))
492 absFileName.prepend(currentPath);
493 QFileInfo file(absFileName);
494 if (!file.exists()) {
495 m_failedResources.push_back(absFileName);
496 const QString msg = QString::fromLatin1("RCC: Error in '%1': Cannot find file '%2'\n").arg(fname).arg(fileName);
497 m_errorDevice->write(msg.toUtf8());
502 } else if (file.isFile()) {
505 RCCFileInfo(alias.section(slash, -1),
509 RCCFileInfo::NoFlags,
514 m_failedResources.push_back(absFileName);
518 dir.setPath(file.filePath());
520 dir.setPath(file.path());
521 dir.setNameFilters(QStringList(file.fileName()));
522 if (alias.endsWith(file.fileName()))
523 alias = alias.left(alias.length()-file.fileName().length());
525 if (!alias.endsWith(slash))
527 QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories);
528 while (it.hasNext()) {
530 QFileInfo child(it.fileInfo());
531 if (child.fileName() != QLatin1String(".") && child.fileName() != QLatin1String("..")) {
533 addFile(alias + child.fileName(),
534 RCCFileInfo(child.fileName(),
538 RCCFileInfo::NoFlags,
543 m_failedResources.push_back(child.fileName());
555 if (reader.hasError()) {
558 int errorLine = reader.lineNumber();
559 int errorColumn = reader.columnNumber();
560 QString errorMessage = reader.errorString();
561 QString msg = QString::fromLatin1("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMessage);
562 m_errorDevice->write(msg.toUtf8());
567 const QString msg = QString::fromUtf8("RCC: Warning: No resources in '%1'.\n").arg(fname);
568 m_errorDevice->write(msg.toUtf8());
569 if (!ignoreErrors && m_format == Binary) {
570 // create dummy entry, otherwise loading with QResource will crash
571 m_root = new RCCFileInfo(QString(), QFileInfo(),
572 QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory);
579 bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file)
581 Q_ASSERT(m_errorDevice);
582 if (file.m_fileInfo.size() > 0xffffffff) {
583 const QString msg = QString::fromUtf8("File too big: %1\n").arg(file.m_fileInfo.absoluteFilePath());
584 m_errorDevice->write(msg.toUtf8());
588 m_root = new RCCFileInfo(QString(), QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory);
590 RCCFileInfo *parent = m_root;
591 const QStringList nodes = alias.split(QLatin1Char('/'));
592 for (int i = 1; i < nodes.size()-1; ++i) {
593 const QString node = nodes.at(i);
596 if (!parent->m_children.contains(node)) {
597 RCCFileInfo *s = new RCCFileInfo(node, QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory);
598 s->m_parent = parent;
599 parent->m_children.insert(node, s);
602 parent = parent->m_children[node];
606 const QString filename = nodes.at(nodes.size()-1);
607 RCCFileInfo *s = new RCCFileInfo(file);
608 s->m_parent = parent;
609 if (parent->m_children.contains(filename)) {
610 foreach (const QString &fileName, m_fileNames)
611 qWarning("%s: Warning: potential duplicate alias detected: '%s'",
612 qPrintable(fileName), qPrintable(filename));
614 parent->m_children.insertMulti(filename, s);
618 void RCCResourceLibrary::reset()
625 m_failedResources.clear();
629 bool RCCResourceLibrary::readFiles(bool ignoreErrors, QIODevice &errorDevice)
632 m_errorDevice = &errorDevice;
635 const QString msg = QString::fromUtf8("Processing %1 files [%2]\n")
636 .arg(m_fileNames.size()).arg(static_cast<int>(ignoreErrors));
637 m_errorDevice->write(msg.toUtf8());
639 for (int i = 0; i < m_fileNames.size(); ++i) {
641 QString fname = m_fileNames.at(i);
643 if (fname == QLatin1String("-")) {
644 fname = QLatin1String("(stdin)");
645 pwd = QDir::currentPath();
646 fileIn.setFileName(fname);
647 if (!fileIn.open(stdin, QIODevice::ReadOnly)) {
648 m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8());
652 pwd = QFileInfo(fname).path();
653 fileIn.setFileName(fname);
654 if (!fileIn.open(QIODevice::ReadOnly)) {
655 m_errorDevice->write(msgOpenReadFailed(fname, fileIn.errorString()).toUtf8());
660 const QString msg = QString::fromUtf8("Interpreting %1\n").arg(fname);
661 m_errorDevice->write(msg.toUtf8());
664 if (!interpretResourceFile(&fileIn, fname, pwd, ignoreErrors))
670 QStringList RCCResourceLibrary::dataFiles() const
673 QStack<RCCFileInfo*> pending;
677 pending.push(m_root);
678 while (!pending.isEmpty()) {
679 RCCFileInfo *file = pending.pop();
680 for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
681 it != file->m_children.end(); ++it) {
682 RCCFileInfo *child = it.value();
683 if (child->m_flags & RCCFileInfo::Directory)
685 ret.append(child->m_fileInfo.filePath());
691 // Determine map of resource identifier (':/newPrefix/images/p1.png') to file via recursion
692 static void resourceDataFileMapRecursion(const RCCFileInfo *m_root, const QString &path, RCCResourceLibrary::ResourceDataFileMap &m)
694 typedef QHash<QString, RCCFileInfo*>::const_iterator ChildConstIterator;
695 const QChar slash = QLatin1Char('/');
696 const ChildConstIterator cend = m_root->m_children.constEnd();
697 for (ChildConstIterator it = m_root->m_children.constBegin(); it != cend; ++it) {
698 const RCCFileInfo *child = it.value();
699 QString childName = path;
701 childName += child->m_name;
702 if (child->m_flags & RCCFileInfo::Directory) {
703 resourceDataFileMapRecursion(child, childName, m);
705 m.insert(childName, child->m_fileInfo.filePath());
710 RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap() const
712 ResourceDataFileMap rc;
714 resourceDataFileMapRecursion(m_root, QString(QLatin1Char(':')), rc);
718 bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &errorDevice)
720 m_errorDevice = &errorDevice;
723 m_errorDevice->write("Outputting code\n");
724 if (!writeHeader()) {
725 m_errorDevice->write("Could not write header\n");
729 if (!writeDataBlobs()) {
730 m_errorDevice->write("Could not write data blobs.\n");
733 if (!writeDataNames()) {
734 m_errorDevice->write("Could not write file names\n");
737 if (!writeDataStructure()) {
738 m_errorDevice->write("Could not write data tree\n");
742 if (!writeInitializer()) {
743 m_errorDevice->write("Could not write footer\n");
746 outDevice.write(m_out.constData(), m_out.size());
750 void RCCResourceLibrary::writeHex(quint8 tmp)
752 const char digits[] = "0123456789abcdef";
756 writeChar(digits[tmp]);
758 writeChar(digits[tmp >> 4]);
759 writeChar(digits[tmp & 0xf]);
764 void RCCResourceLibrary::writeNumber2(quint16 number)
766 if (m_format == RCCResourceLibrary::Binary) {
767 writeChar(number >> 8);
770 writeHex(number >> 8);
775 void RCCResourceLibrary::writeNumber4(quint32 number)
777 if (m_format == RCCResourceLibrary::Binary) {
778 writeChar(number >> 24);
779 writeChar(number >> 16);
780 writeChar(number >> 8);
783 writeHex(number >> 24);
784 writeHex(number >> 16);
785 writeHex(number >> 8);
790 bool RCCResourceLibrary::writeHeader()
792 if (m_format == C_Code) {
793 writeString("/****************************************************************************\n");
794 writeString("** Resource object code\n");
796 writeString("** Created: ");
797 writeByteArray(QDateTime::currentDateTime().toString().toLatin1());
798 writeString("\n** by: The Resource Compiler for Qt version ");
799 writeByteArray(QT_VERSION_STR);
800 writeString("\n**\n");
801 writeString("** WARNING! All changes made in this file will be lost!\n");
802 writeString( "*****************************************************************************/\n\n");
803 writeString("#include <QtCore/qglobal.h>\n\n");
804 } else if (m_format == Binary) {
814 bool RCCResourceLibrary::writeDataBlobs()
816 Q_ASSERT(m_errorDevice);
817 if (m_format == C_Code)
818 writeString("static const unsigned char qt_resource_data[] = {\n");
819 else if (m_format == Binary)
820 m_dataOffset = m_out.size();
821 QStack<RCCFileInfo*> pending;
826 pending.push(m_root);
828 QString errorMessage;
829 while (!pending.isEmpty()) {
830 RCCFileInfo *file = pending.pop();
831 for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
832 it != file->m_children.end(); ++it) {
833 RCCFileInfo *child = it.value();
834 if (child->m_flags & RCCFileInfo::Directory)
837 offset = child->writeDataBlob(*this, offset, &errorMessage);
839 m_errorDevice->write(errorMessage.toUtf8());
845 if (m_format == C_Code)
846 writeString("\n};\n\n");
850 bool RCCResourceLibrary::writeDataNames()
852 if (m_format == C_Code)
853 writeString("static const unsigned char qt_resource_name[] = {\n");
854 else if (m_format == Binary)
855 m_namesOffset = m_out.size();
857 QHash<QString, int> names;
858 QStack<RCCFileInfo*> pending;
863 pending.push(m_root);
865 while (!pending.isEmpty()) {
866 RCCFileInfo *file = pending.pop();
867 for (QHash<QString, RCCFileInfo*>::iterator it = file->m_children.begin();
868 it != file->m_children.end(); ++it) {
869 RCCFileInfo *child = it.value();
870 if (child->m_flags & RCCFileInfo::Directory)
872 if (names.contains(child->m_name)) {
873 child->m_nameOffset = names.value(child->m_name);
875 names.insert(child->m_name, offset);
876 offset = child->writeDataName(*this, offset);
880 if (m_format == C_Code)
881 writeString("\n};\n\n");
885 static bool qt_rcc_compare_hash(const RCCFileInfo *left, const RCCFileInfo *right)
887 return qt_hash(left->m_name) < qt_hash(right->m_name);
890 bool RCCResourceLibrary::writeDataStructure()
892 if (m_format == C_Code)
893 writeString("static const unsigned char qt_resource_struct[] = {\n");
894 else if (m_format == Binary)
895 m_treeOffset = m_out.size();
896 QStack<RCCFileInfo*> pending;
901 //calculate the child offsets (flat)
902 pending.push(m_root);
904 while (!pending.isEmpty()) {
905 RCCFileInfo *file = pending.pop();
906 file->m_childOffset = offset;
908 //sort by hash value for binary lookup
909 QList<RCCFileInfo*> m_children = file->m_children.values();
910 qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash);
912 //write out the actual data now
913 for (int i = 0; i < m_children.size(); ++i) {
914 RCCFileInfo *child = m_children.at(i);
916 if (child->m_flags & RCCFileInfo::Directory)
921 //write out the structure (ie iterate again!)
922 pending.push(m_root);
923 m_root->writeDataInfo(*this);
924 while (!pending.isEmpty()) {
925 RCCFileInfo *file = pending.pop();
927 //sort by hash value for binary lookup
928 QList<RCCFileInfo*> m_children = file->m_children.values();
929 qSort(m_children.begin(), m_children.end(), qt_rcc_compare_hash);
931 //write out the actual data now
932 for (int i = 0; i < m_children.size(); ++i) {
933 RCCFileInfo *child = m_children.at(i);
934 child->writeDataInfo(*this);
935 if (child->m_flags & RCCFileInfo::Directory)
939 if (m_format == C_Code)
940 writeString("\n};\n\n");
945 void RCCResourceLibrary::writeMangleNamespaceFunction(const QByteArray &name)
947 if (m_useNameSpace) {
948 writeString("QT_MANGLE_NAMESPACE(");
949 writeByteArray(name);
952 writeByteArray(name);
956 void RCCResourceLibrary::writeAddNamespaceFunction(const QByteArray &name)
958 if (m_useNameSpace) {
959 writeString("QT_PREPEND_NAMESPACE(");
960 writeByteArray(name);
963 writeByteArray(name);
967 bool RCCResourceLibrary::writeInitializer()
969 if (m_format == C_Code) {
970 //write("\nQT_BEGIN_NAMESPACE\n");
971 QString initName = m_initName;
972 if (!initName.isEmpty()) {
973 initName.prepend(QLatin1Char('_'));
974 initName.replace(QRegExp(QLatin1String("[^a-zA-Z0-9_]")), QLatin1String("_"));
979 writeString("QT_BEGIN_NAMESPACE\n\n");
981 writeString("extern Q_CORE_EXPORT bool qRegisterResourceData\n "
982 "(int, const unsigned char *, "
983 "const unsigned char *, const unsigned char *);\n\n");
984 writeString("extern Q_CORE_EXPORT bool qUnregisterResourceData\n "
985 "(int, const unsigned char *, "
986 "const unsigned char *, const unsigned char *);\n\n");
989 writeString("QT_END_NAMESPACE\n\n\n");
990 QString initResources = QLatin1String("qInitResources");
991 initResources += initName;
993 writeMangleNamespaceFunction(initResources.toLatin1());
994 writeString("()\n{\n");
998 writeAddNamespaceFunction("qRegisterResourceData");
999 writeString("\n (0x01, qt_resource_struct, "
1000 "qt_resource_name, qt_resource_data);\n");
1002 writeString(" return 1;\n");
1003 writeString("}\n\n");
1004 writeString("Q_CONSTRUCTOR_FUNCTION(");
1005 writeMangleNamespaceFunction(initResources.toLatin1());
1006 writeString(")\n\n");
1009 QString cleanResources = QLatin1String("qCleanupResources");
1010 cleanResources += initName;
1011 writeString("int ");
1012 writeMangleNamespaceFunction(cleanResources.toLatin1());
1013 writeString("()\n{\n");
1016 writeAddNamespaceFunction("qUnregisterResourceData");
1017 writeString("\n (0x01, qt_resource_struct, "
1018 "qt_resource_name, qt_resource_data);\n");
1020 writeString(" return 1;\n");
1021 writeString("}\n\n");
1022 writeString("Q_DESTRUCTOR_FUNCTION(");
1023 writeMangleNamespaceFunction(cleanResources.toLatin1());
1024 writeString(")\n\n");
1025 } else if (m_format == Binary) {
1027 char *p = m_out.data();
1033 p[i++] = (m_treeOffset >> 24) & 0xff;
1034 p[i++] = (m_treeOffset >> 16) & 0xff;
1035 p[i++] = (m_treeOffset >> 8) & 0xff;
1036 p[i++] = (m_treeOffset >> 0) & 0xff;
1038 p[i++] = (m_dataOffset >> 24) & 0xff;
1039 p[i++] = (m_dataOffset >> 16) & 0xff;
1040 p[i++] = (m_dataOffset >> 8) & 0xff;
1041 p[i++] = (m_dataOffset >> 0) & 0xff;
1043 p[i++] = (m_namesOffset >> 24) & 0xff;
1044 p[i++] = (m_namesOffset >> 16) & 0xff;
1045 p[i++] = (m_namesOffset >> 8) & 0xff;
1046 p[i++] = (m_namesOffset >> 0) & 0xff;