diff options
-rw-r--r-- | tools/binarycreator/rcc/rcc.cpp | 321 | ||||
-rw-r--r-- | tools/binarycreator/rcc/rccmain.cpp | 2 |
2 files changed, 203 insertions, 120 deletions
diff --git a/tools/binarycreator/rcc/rcc.cpp b/tools/binarycreator/rcc/rcc.cpp index 2311fb66c..12c4fd17e 100644 --- a/tools/binarycreator/rcc/rcc.cpp +++ b/tools/binarycreator/rcc/rcc.cpp @@ -42,7 +42,7 @@ #include <QtCore/QLocale> #include <QtCore/QStack> -#include <QtXml/QDomDocument> +#include <QXmlStreamReader> QT_BEGIN_NAMESPACE @@ -351,6 +351,12 @@ RCCResourceLibrary::~RCCResourceLibrary() delete m_root; } +enum RCCXmlTag { + RccTag, + ResourceTag, + FileTag +}; + bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, const QString &fname, QString currentPath, bool ignoreErrors) { @@ -359,133 +365,203 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, 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(); + QXmlStreamReader reader(inputDevice); + QStack<RCCXmlTag> tokens; + + QString prefix; + QLocale::Language language = QLocale::c().language(); + QLocale::Country country = QLocale::c().country(); + QString alias; + int compressLevel = m_compressLevel; + int compressThreshold = m_compressThreshold; + + while (!reader.atEnd()) { + QXmlStreamReader::TokenType t = reader.readNext(); + switch (t) { + case QXmlStreamReader::StartElement: + if (reader.name() == m_strings.TAG_RCC) { + if (!tokens.isEmpty()) + reader.raiseError(QLatin1String("expected <RCC> tag")); + else + tokens.push(RccTag); + } else if (reader.name() == m_strings.TAG_RESOURCE) { + if (tokens.isEmpty() || tokens.top() != RccTag) { + reader.raiseError(QLatin1String("unexpected <RESOURCE> tag")); + } else { + tokens.push(ResourceTag); + + QXmlStreamAttributes attributes = reader.attributes(); + language = QLocale::c().language(); + country = QLocale::c().country(); + + if (attributes.hasAttribute(m_strings.ATTRIBUTE_LANG)) { + QString attribute = attributes.value(m_strings.ATTRIBUTE_LANG).toString(); + QLocale lang = QLocale(attribute); + language = lang.language(); + if (2 == attribute.length()) { + // Language only + country = QLocale::AnyCountry; + } else { + country = lang.country(); + } } + + prefix.clear(); + if (attributes.hasAttribute(m_strings.ATTRIBUTE_PREFIX)) + prefix = attributes.value(m_strings.ATTRIBUTE_PREFIX).toString(); + if (!prefix.startsWith(slash)) + prefix.prepend(slash); + if (!prefix.endsWith(slash)) + prefix += slash; } + } else if (reader.name() == m_strings.TAG_FILE) { + if (tokens.isEmpty() || tokens.top() != ResourceTag) { + reader.raiseError(QLatin1String("unexpected <FILE> tag")); + } else { + tokens.push(FileTag); + + QXmlStreamAttributes attributes = reader.attributes(); + alias.clear(); + if (attributes.hasAttribute(m_strings.ATTRIBUTE_ALIAS)) + alias = attributes.value(m_strings.ATTRIBUTE_ALIAS).toString(); + + compressLevel = m_compressLevel; + if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) + compressLevel = attributes.value(m_strings.ATTRIBUTE_COMPRESS).toString().toInt(); + + compressThreshold = m_compressThreshold; + if (attributes.hasAttribute(m_strings.ATTRIBUTE_THRESHOLD)) + compressThreshold = attributes.value(m_strings.ATTRIBUTE_THRESHOLD).toString().toInt(); + + // Special case for -no-compress. Overrides all other settings. + if (m_compressLevel == -2) + compressLevel = 0; + } + } else { + reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString())); + } + break; + + case QXmlStreamReader::EndElement: + if (reader.name() == m_strings.TAG_RCC) { + if (!tokens.isEmpty() && tokens.top() == RccTag) + tokens.pop(); + else + reader.raiseError(QLatin1String("unexpected closing tag")); + } else if (reader.name() == m_strings.TAG_RESOURCE) { + if (!tokens.isEmpty() && tokens.top() == ResourceTag) + tokens.pop(); + else + reader.raiseError(QLatin1String("unexpected closing tag")); + } else if (reader.name() == m_strings.TAG_FILE) { + if (!tokens.isEmpty() && tokens.top() == FileTag) + tokens.pop(); + else + reader.raiseError(QLatin1String("unexpected closing tag")); + } + break; - 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)); + case QXmlStreamReader::Characters: + if (reader.isWhitespace()) + break; + if (tokens.isEmpty() || tokens.top() != FileTag) { + reader.raiseError(QLatin1String("unexpected text")); + } else { + QString fileName = reader.text().toString(); + if (fileName.isEmpty()) { + const QString msg = QString::fromLatin1("RCC: Warning: Null node in XML of '%1'\n").arg(fname); + m_errorDevice->write(msg.toUtf8()); + } + + if (alias.isNull()) + alias = fileName; + + 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::fromLatin1("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, + child.isDir() ? RCCFileInfo::Directory : 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()); - } - } + m_failedResources.push_back(child.fileName()); } } } } + break; + + default: + break; } } + + if (reader.hasError()) { + if (ignoreErrors) + return true; + int errorLine = reader.lineNumber(); + int errorColumn = reader.columnNumber(); + QString errorMessage = reader.errorString(); + QString msg = QString::fromLatin1("RCC Parse Error: '%1' Line: %2 Column: %3 [%4]\n").arg(fname).arg(errorLine).arg(errorColumn).arg(errorMessage); + m_errorDevice->write(msg.toUtf8()); + return false; + } + 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 + // create dummy entry, otherwise loading with QResource will crash m_root = new RCCFileInfo(QString(), QFileInfo(), QLocale::C, QLocale::AnyCountry, RCCFileInfo::Directory); } @@ -524,6 +600,11 @@ bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) 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; } @@ -656,13 +737,13 @@ bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &errorDevice) m_errorDevice->write("Could not write footer\n"); return false; } - outDevice.write(m_out, m_out.size()); + outDevice.write(m_out.constData(), m_out.size()); return true; } void RCCResourceLibrary::writeHex(quint8 tmp) { - const char * const digits = "0123456789abcdef"; + const char digits[] = "0123456789abcdef"; writeChar('0'); writeChar('x'); if (tmp < 16) { @@ -748,8 +829,10 @@ bool RCCResourceLibrary::writeDataBlobs() pending.push(child); else { offset = child->writeDataBlob(*this, offset, &errorMessage); - if (offset == 0) + if (offset == 0) { m_errorDevice->write(errorMessage.toUtf8()); + return false; + } } } } @@ -893,10 +976,10 @@ bool RCCResourceLibrary::writeInitializer() if (m_useNameSpace) writeString("QT_BEGIN_NAMESPACE\n\n"); if (m_root) { - writeString("extern bool qRegisterResourceData\n " + writeString("extern Q_CORE_EXPORT bool qRegisterResourceData\n " "(int, const unsigned char *, " "const unsigned char *, const unsigned char *);\n\n"); - writeString("extern bool qUnregisterResourceData\n " + writeString("extern Q_CORE_EXPORT bool qUnregisterResourceData\n " "(int, const unsigned char *, " "const unsigned char *, const unsigned char *);\n\n"); } diff --git a/tools/binarycreator/rcc/rccmain.cpp b/tools/binarycreator/rcc/rccmain.cpp index 4256d5db4..535f1efef 100644 --- a/tools/binarycreator/rcc/rccmain.cpp +++ b/tools/binarycreator/rcc/rccmain.cpp @@ -67,7 +67,7 @@ void dumpRecursive(const QDir &dir, QTextStream &out) { QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); - foreach (QFileInfo entry, entries) { + foreach (const QFileInfo &entry, entries) { if (entry.isDir()) { dumpRecursive(entry.filePath(), out); } else { |