diff options
Diffstat (limited to 'src/tools/rcc')
-rw-r--r-- | src/tools/rcc/CMakeLists.txt | 24 | ||||
-rw-r--r-- | src/tools/rcc/main.cpp | 116 | ||||
-rw-r--r-- | src/tools/rcc/rcc.cpp | 299 | ||||
-rw-r--r-- | src/tools/rcc/rcc.h | 34 |
4 files changed, 222 insertions, 251 deletions
diff --git a/src/tools/rcc/CMakeLists.txt b/src/tools/rcc/CMakeLists.txt index 8b0d9c8182..35a72c43fe 100644 --- a/src/tools/rcc/CMakeLists.txt +++ b/src/tools/rcc/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from rcc.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## rcc Tool: @@ -6,10 +7,10 @@ qt_get_tool_target_name(target_name rcc) qt_internal_add_tool(${target_name} - BOOTSTRAP + TRY_RUN TARGET_DESCRIPTION "Qt Resource Compiler" INSTALL_DIR "${INSTALL_LIBEXECDIR}" - TOOLS_TARGET Core # special case + TOOLS_TARGET Core SOURCES main.cpp rcc.cpp rcc.h @@ -17,25 +18,16 @@ qt_internal_add_tool(${target_name} QT_NO_CAST_FROM_ASCII QT_NO_FOREACH QT_RCC + QT_USE_NODISCARD_FILE_OPEN INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} ) - -#### Keys ignored in scope 1:.:.:rcc.pro:<TRUE>: -# QMAKE_TARGET_DESCRIPTION = "Qt Resource Compiler" -# _OPTION = "host_build" +qt_internal_return_unless_building_tools() ## Scopes: ##################################################################### -qt_internal_extend_target(${target_name} CONDITION QT_FEATURE_zstd AND NOT CMAKE_CROSSCOMPILING - DEFINES - QT_FEATURE_zstd=1 +qt_internal_extend_target(${target_name} CONDITION QT_FEATURE_zstd LIBRARIES - ZSTD::ZSTD -) - -qt_internal_extend_target(${target_name} CONDITION CMAKE_CROSSCOMPILING OR NOT QT_FEATURE_zstd - DEFINES - QT_FEATURE_zstd=-1 + WrapZSTD::WrapZSTD ) diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp index eca7991280..03709ccbd4 100644 --- a/src/tools/rcc/main.cpp +++ b/src/tools/rcc/main.cpp @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// Copyright (C) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <rcc.h> @@ -49,6 +24,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + void dumpRecursive(const QDir &dir, QTextStream &out) { const QFileInfoList entries = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot @@ -57,9 +34,9 @@ void dumpRecursive(const QDir &dir, QTextStream &out) if (entry.isDir()) { dumpRecursive(entry.filePath(), out); } else { - out << QLatin1String("<file>") + out << "<file>"_L1 << entry.filePath() - << QLatin1String("</file>\n"); + << "</file>\n"_L1; } } } @@ -69,7 +46,7 @@ int createProject(const QString &outFileName) QDir currentDir = QDir::current(); QString currentDirName = currentDir.dirName(); if (currentDirName.isEmpty()) - currentDirName = QLatin1String("root"); + currentDirName = "root"_L1; QFile file; bool isOk = false; @@ -87,14 +64,14 @@ int createProject(const QString &outFileName) } QTextStream out(&file); - out << QLatin1String("<!DOCTYPE RCC><RCC version=\"1.0\">\n" - "<qresource>\n"); + out << "<!DOCTYPE RCC><RCC version=\"1.0\">\n" + "<qresource>\n"_L1; - // use "." as dir to get relative file pathes - dumpRecursive(QDir(QLatin1String(".")), out); + // use "." as dir to get relative file paths + dumpRecursive(QDir("."_L1), out); - out << QLatin1String("</qresource>\n" - "</RCC>\n"); + out << "</qresource>\n" + "</RCC>\n"_L1; return 0; } @@ -105,11 +82,11 @@ QString makefileEscape(const QString &filepath) // Always use forward slashes QString result = QDir::cleanPath(filepath); // Spaces are escaped with a backslash - result.replace(QLatin1Char(' '), QLatin1String("\\ ")); + result.replace(u' ', "\\ "_L1); // Pipes are escaped with a backslash - result.replace(QLatin1Char('|'), QLatin1String("\\|")); + result.replace(u'|', "\\|"_L1); // Dollars are escaped with a dollar - result.replace(QLatin1Char('$'), QLatin1String("$$")); + result.replace(u'$', "$$"_L1); return result; } @@ -118,16 +95,16 @@ void writeDepFile(QIODevice &iodev, const QStringList &depsList, const QString & { QTextStream out(&iodev); out << qPrintable(makefileEscape(targetName)); - out << QLatin1Char(':'); + out << QChar(u':'); // Write depfile for (int i = 0; i < depsList.size(); ++i) { - out << QLatin1Char(' '); + out << QChar(u' '); out << qPrintable(makefileEscape(depsList.at(i))); } - out << QLatin1Char('\n'); + out << QChar(u'\n'); } int runRcc(int argc, char *argv[]) @@ -139,7 +116,7 @@ int runRcc(int argc, char *argv[]) // If you use this code as an example for a translated app, make sure to translate the strings. QCommandLineParser parser; parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - parser.setApplicationDescription(QLatin1String("Qt Resource Compiler version " QT_VERSION_STR)); + parser.setApplicationDescription("Qt Resource Compiler version " QT_VERSION_STR ""_L1); parser.addHelpOption(); parser.addVersionOption(); @@ -233,9 +210,9 @@ int runRcc(int argc, char *argv[]) bool ok = false; formatVersion = parser.value(formatVersionOption).toUInt(&ok); if (!ok) { - errorMsg = QLatin1String("Invalid format version specified"); + errorMsg = "Invalid format version specified"_L1; } else if (formatVersion < 1 || formatVersion > 3) { - errorMsg = QLatin1String("Unsupported format version specified"); + errorMsg = "Unsupported format version specified"_L1; } } @@ -244,19 +221,22 @@ int runRcc(int argc, char *argv[]) library.setInitName(parser.value(nameOption)); if (parser.isSet(rootOption)) { library.setResourceRoot(QDir::cleanPath(parser.value(rootOption))); - if (library.resourceRoot().isEmpty() - || library.resourceRoot().at(0) != QLatin1Char('/')) - errorMsg = QLatin1String("Root must start with a /"); + if (library.resourceRoot().isEmpty() || library.resourceRoot().at(0) != u'/') + errorMsg = "Root must start with a /"_L1; } if (parser.isSet(compressionAlgoOption)) library.setCompressionAlgorithm(RCCResourceLibrary::parseCompressionAlgorithm(parser.value(compressionAlgoOption), &errorMsg)); - if (formatVersion < 3 && library.compressionAlgorithm() == RCCResourceLibrary::CompressionAlgorithm::Zstd) - errorMsg = QLatin1String("Zstandard compression requires format version 3 or higher"); - if (parser.isSet(nocompressOption)) - library.setCompressionAlgorithm(RCCResourceLibrary::CompressionAlgorithm::None); if (parser.isSet(noZstdOption)) library.setNoZstd(true); + if (library.compressionAlgorithm() == RCCResourceLibrary::CompressionAlgorithm::Zstd) { + if (formatVersion < 3) + errorMsg = "Zstandard compression requires format version 3 or higher"_L1; + if (library.noZstd()) + errorMsg = "--compression-algo=zstd and --no-zstd both specified."_L1; + } + if (parser.isSet(nocompressOption)) + library.setCompressionAlgorithm(RCCResourceLibrary::CompressionAlgorithm::None); if (parser.isSet(compressOption) && errorMsg.isEmpty()) { int level = library.parseCompressionLevel(library.compressionAlgorithm(), parser.value(compressOption), &errorMsg); library.setCompressLevel(level); @@ -267,25 +247,25 @@ int runRcc(int argc, char *argv[]) library.setFormat(RCCResourceLibrary::Binary); if (parser.isSet(generatorOption)) { auto value = parser.value(generatorOption); - if (value == QLatin1String("cpp")) { + if (value == "cpp"_L1) { library.setFormat(RCCResourceLibrary::C_Code); - } else if (value == QLatin1String("python")) { + } else if (value == "python"_L1) { library.setFormat(RCCResourceLibrary::Python_Code); - } else if (value == QLatin1String("python2")) { // ### fixme Qt 7: remove + } else if (value == "python2"_L1) { // ### fixme Qt 7: remove qWarning("Format python2 is no longer supported, defaulting to python."); library.setFormat(RCCResourceLibrary::Python_Code); } else { - errorMsg = QLatin1String("Invalid generator: ") + value; + errorMsg = "Invalid generator: "_L1 + value; } } if (parser.isSet(passOption)) { - if (parser.value(passOption) == QLatin1String("1")) + if (parser.value(passOption) == "1"_L1) library.setFormat(RCCResourceLibrary::Pass1); - else if (parser.value(passOption) == QLatin1String("2")) + else if (parser.value(passOption) == "2"_L1) library.setFormat(RCCResourceLibrary::Pass2); else - errorMsg = QLatin1String("Pass number must be 1 or 2"); + errorMsg = "Pass number must be 1 or 2"_L1; } if (parser.isSet(namespaceOption)) library.setUseNameSpace(!library.useNameSpace()); @@ -298,7 +278,7 @@ int runRcc(int argc, char *argv[]) const QStringList filenamesIn = parser.positionalArguments(); for (const QString &file : filenamesIn) { - if (file == QLatin1String("-")) + if (file == "-"_L1) continue; else if (!QFile::exists(file)) { qWarning("%s: File does not exist '%s'", argv[0], qPrintable(file)); @@ -323,7 +303,8 @@ int runRcc(int argc, char *argv[]) return 1; } QFile errorDevice; - errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text); + if (!errorDevice.open(stderr, QIODevice::WriteOnly|QIODevice::Text)) + return 1; if (library.verbose()) errorDevice.write("Qt resource compiler\n"); @@ -350,7 +331,7 @@ int runRcc(int argc, char *argv[]) } - if (outFilename.isEmpty() || outFilename == QLatin1String("-")) { + if (outFilename.isEmpty() || outFilename == "-"_L1) { #ifdef Q_OS_WIN // Make sure fwrite to stdout doesn't do LF->CRLF if (library.format() == RCCResourceLibrary::Binary) @@ -361,7 +342,12 @@ int runRcc(int argc, char *argv[]) mode &= ~QIODevice::Text; #endif // Q_OS_WIN // using this overload close() only flushes. - out.open(stdout, mode); + if (!out.open(stdout, mode)) { + const QString msg = QString::fromLatin1("Unable to open standard output for writing: %1\n") + .arg(out.errorString()); + errorDevice.write(msg.toUtf8()); + return 1; + } } else { out.setFileName(outFilename); if (!out.open(mode)) { @@ -398,7 +384,7 @@ int runRcc(int argc, char *argv[]) QFile depout; depout.setFileName(depFilename); - if (outFilename.isEmpty() || outFilename == QLatin1String("-")) { + if (outFilename.isEmpty() || outFilename == "-"_L1) { const QString msg = QString::fromUtf8("Unable to write depfile when outputting to stdout!\n"); errorDevice.write(msg.toUtf8()); return 1; diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 1825c77b53..2bda7f2977 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// Copyright (C) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "rcc.h" @@ -33,7 +8,7 @@ #include <qdatetime.h> #include <qdebug.h> #include <qdir.h> -#include <qdiriterator.h> +#include <qdirlisting.h> #include <qfile.h> #include <qiodevice.h> #include <qlocale.h> @@ -50,6 +25,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + enum { CONSTANT_USENAMESPACE = 1, CONSTANT_COMPRESSLEVEL_DEFAULT = -1, @@ -58,14 +35,6 @@ enum { CONSTANT_COMPRESSTHRESHOLD_DEFAULT = 70 }; -#if QT_CONFIG(zstd) && QT_VERSION >= QT_VERSION_CHECK(6,0,0) -# define CONSTANT_COMPRESSALGO_DEFAULT RCCResourceLibrary::CompressionAlgorithm::Zstd -#elif !defined(QT_NO_COMPRESS) -# define CONSTANT_COMPRESSALGO_DEFAULT RCCResourceLibrary::CompressionAlgorithm::Zlib -#else -# define CONSTANT_COMPRESSALGO_DEFAULT RCCResourceLibrary::CompressionAlgorithm::None -#endif - void RCCResourceLibrary::write(const char *str, int len) { int n = m_out.size(); @@ -106,15 +75,18 @@ public: CompressedZstd = 0x04 }; - RCCFileInfo(const QString &name = QString(), const QFileInfo &fileInfo = QFileInfo(), - QLocale::Language language = QLocale::C, - QLocale::Territory territory = QLocale::AnyTerritory, - uint flags = NoFlags, - RCCResourceLibrary::CompressionAlgorithm compressAlgo = CONSTANT_COMPRESSALGO_DEFAULT, - int compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT, - int compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT, - bool noZstd = false); + + RCCFileInfo() = default; + RCCFileInfo(const QString &name, const QFileInfo &fileInfo, QLocale::Language language, + QLocale::Territory territory, uint flags, + RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel, + int compressThreshold, bool noZstd, bool isEmpty); + ~RCCFileInfo(); + RCCFileInfo(const RCCFileInfo &) = delete; + RCCFileInfo &operator=(const RCCFileInfo &) = delete; + RCCFileInfo(RCCFileInfo &&) = default; + RCCFileInfo &operator=(RCCFileInfo &&other) = delete; QString resourceName() const; @@ -123,41 +95,40 @@ public: qint64 writeDataName(RCCResourceLibrary &, qint64 offset); void writeDataInfo(RCCResourceLibrary &lib); - int m_flags; + int m_flags = NoFlags; + QLocale::Language m_language = QLocale::C; + QLocale::Territory m_territory = QLocale::AnyTerritory; QString m_name; - QLocale::Language m_language; - QLocale::Territory m_territory; QFileInfo m_fileInfo; - RCCFileInfo *m_parent; + RCCFileInfo *m_parent = nullptr; QMultiHash<QString, RCCFileInfo *> m_children; - RCCResourceLibrary::CompressionAlgorithm m_compressAlgo; - int m_compressLevel; - int m_compressThreshold; - - qint64 m_nameOffset; - qint64 m_dataOffset; - qint64 m_childOffset; - bool m_noZstd; + + RCCResourceLibrary::CompressionAlgorithm m_compressAlgo = RCCResourceLibrary::CompressionAlgorithm::Best; + int m_compressLevel = CONSTANT_COMPRESSLEVEL_DEFAULT; + int m_compressThreshold = CONSTANT_COMPRESSTHRESHOLD_DEFAULT; + bool m_noZstd = false; + bool m_isEmpty = false; + + qint64 m_nameOffset = 0; + qint64 m_dataOffset = 0; + qint64 m_childOffset = 0; }; -RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo, - QLocale::Language language, QLocale::Territory territory, uint flags, - RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel, int compressThreshold, - bool noZstd) +RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo, QLocale::Language language, + QLocale::Territory territory, uint flags, + RCCResourceLibrary::CompressionAlgorithm compressAlgo, int compressLevel, + int compressThreshold, bool noZstd, bool isEmpty) + : m_flags(flags), + m_language(language), + m_territory(territory), + m_name(name), + m_fileInfo(fileInfo), + m_compressAlgo(compressAlgo), + m_compressLevel(compressLevel), + m_compressThreshold(compressThreshold), + m_noZstd(noZstd), + m_isEmpty(isEmpty) { - m_name = name; - m_fileInfo = fileInfo; - m_language = language; - m_territory = territory; - m_flags = flags; - m_parent = nullptr; - m_nameOffset = 0; - m_dataOffset = 0; - m_childOffset = 0; - m_compressAlgo = compressAlgo; - m_compressLevel = compressLevel; - m_compressThreshold = compressThreshold; - m_noZstd = noZstd; } RCCFileInfo::~RCCFileInfo() @@ -169,8 +140,9 @@ 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; + resource = resource.prepend(p->m_name + u'/'); + resource.prepend(u':'); + return resource; } void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) @@ -229,7 +201,7 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) if (lib.formatVersion() >= 2) { // last modified time stamp - const QDateTime lastModified = m_fileInfo.lastModified(); + const QDateTime lastModified = m_fileInfo.lastModified(QTimeZone::UTC); quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0); static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong(); if (sourceDate != 0) @@ -256,14 +228,18 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, //capture the offset m_dataOffset = offset; + QByteArray data; - //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; + if (!m_isEmpty) { + //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; + } + + data = file.readAll(); } - QByteArray data = file.readAll(); // Check if compression is useful for this file if (data.size() != 0) { @@ -345,7 +321,7 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, // some info if (text || pass1) { lib.writeString(" // "); - lib.writeByteArray(m_fileInfo.absoluteFilePath().toLocal8Bit()); + lib.writeByteArray(m_fileInfo.fileName().toLocal8Bit()); lib.writeString("\n "); } @@ -402,7 +378,7 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) } // write the length - lib.writeNumber2(m_name.length()); + lib.writeNumber2(m_name.size()); if (text || pass1) lib.writeString("\n "); else if (python) @@ -419,14 +395,14 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) // write the m_name const QChar *unicode = m_name.unicode(); - for (int i = 0; i < m_name.length(); ++i) { + for (int i = 0; i < m_name.size(); ++i) { lib.writeNumber2(unicode[i].unicode()); if ((text || pass1) && i % 16 == 0) lib.writeString("\n "); else if (python && i % 16 == 0) lib.writeString("\\\n"); } - offset += m_name.length()*2; + offset += m_name.size()*2; // done if (text || pass1) @@ -445,14 +421,15 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) /////////////////////////////////////////////////////////// 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")), + TAG_RCC("RCC"_L1), + TAG_RESOURCE("qresource"_L1), + TAG_FILE("file"_L1), + ATTRIBUTE_LANG("lang"_L1), + ATTRIBUTE_PREFIX("prefix"_L1), + ATTRIBUTE_ALIAS("alias"_L1), + ATTRIBUTE_EMPTY("empty"_L1), + ATTRIBUTE_THRESHOLD("threshold"_L1), + ATTRIBUTE_COMPRESS("compress"_L1), ATTRIBUTE_COMPRESSALGO(QStringLiteral("compression-algorithm")) { } @@ -461,7 +438,7 @@ RCCResourceLibrary::RCCResourceLibrary(quint8 formatVersion) : m_root(nullptr), m_format(C_Code), m_verbose(false), - m_compressionAlgo(CONSTANT_COMPRESSALGO_DEFAULT), + m_compressionAlgo(CompressionAlgorithm::Best), m_compressLevel(CONSTANT_COMPRESSLEVEL_DEFAULT), m_compressThreshold(CONSTANT_COMPRESSTHRESHOLD_DEFAULT), m_treeOffset(0), @@ -495,11 +472,22 @@ enum RCCXmlTag { }; Q_DECLARE_TYPEINFO(RCCXmlTag, Q_PRIMITIVE_TYPE); +static bool parseBoolean(QStringView value, QString *errorMsg) +{ + if (value.compare("true"_L1, Qt::CaseInsensitive) == 0) + return true; + if (value.compare("false"_L1, Qt::CaseInsensitive) == 0) + return false; + + *errorMsg = QString::fromLatin1("Invalid value for boolean attribute: '%1'").arg(value); + return false; +} + bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, const QString &fname, QString currentPath, bool listMode) { Q_ASSERT(m_errorDevice); - const QChar slash = QLatin1Char('/'); + const QChar slash = u'/'; if (!currentPath.isEmpty() && !currentPath.endsWith(slash)) currentPath += slash; @@ -510,6 +498,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, QLocale::Language language = QLocale::c().language(); QLocale::Territory territory = QLocale::c().territory(); QString alias; + bool empty = false; auto compressAlgo = m_compressionAlgo; int compressLevel = m_compressLevel; int compressThreshold = m_compressThreshold; @@ -520,12 +509,12 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, case QXmlStreamReader::StartElement: if (reader.name() == m_strings.TAG_RCC) { if (!tokens.isEmpty()) - reader.raiseError(QLatin1String("expected <RCC> tag")); + reader.raiseError("expected <RCC> tag"_L1); else tokens.push(RccTag); } else if (reader.name() == m_strings.TAG_RESOURCE) { if (tokens.isEmpty() || tokens.top() != RccTag) { - reader.raiseError(QLatin1String("unexpected <RESOURCE> tag")); + reader.raiseError("unexpected <RESOURCE> tag"_L1); } else { tokens.push(ResourceTag); @@ -537,7 +526,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, QString attribute = attributes.value(m_strings.ATTRIBUTE_LANG).toString(); QLocale lang = QLocale(attribute); language = lang.language(); - if (2 == attribute.length()) { + if (2 == attribute.size()) { // Language only territory = QLocale::AnyTerritory; } else { @@ -555,7 +544,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, } } else if (reader.name() == m_strings.TAG_FILE) { if (tokens.isEmpty() || tokens.top() != ResourceTag) { - reader.raiseError(QLatin1String("unexpected <FILE> tag")); + reader.raiseError("unexpected <FILE> tag"_L1); } else { tokens.push(FileTag); @@ -569,6 +558,11 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, compressThreshold = m_compressThreshold; QString errorString; + if (attributes.hasAttribute(m_strings.ATTRIBUTE_EMPTY)) + empty = parseBoolean(attributes.value(m_strings.ATTRIBUTE_EMPTY), &errorString); + else + empty = false; + if (attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESSALGO)) compressAlgo = parseCompressionAlgorithm(attributes.value(m_strings.ATTRIBUTE_COMPRESSALGO), &errorString); if (errorString.isEmpty() && attributes.hasAttribute(m_strings.ATTRIBUTE_COMPRESS)) { @@ -587,7 +581,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, reader.raiseError(errorString); } } else { - reader.raiseError(QString(QLatin1String("unexpected tag: %1")).arg(reader.name().toString())); + reader.raiseError("unexpected tag: %1"_L1.arg(reader.name().toString())); } break; @@ -596,17 +590,17 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, if (!tokens.isEmpty() && tokens.top() == RccTag) tokens.pop(); else - reader.raiseError(QLatin1String("unexpected closing tag")); + reader.raiseError("unexpected closing tag"_L1); } else if (reader.name() == m_strings.TAG_RESOURCE) { if (!tokens.isEmpty() && tokens.top() == ResourceTag) tokens.pop(); else - reader.raiseError(QLatin1String("unexpected closing tag")); + reader.raiseError("unexpected closing tag"_L1); } else if (reader.name() == m_strings.TAG_FILE) { if (!tokens.isEmpty() && tokens.top() == FileTag) tokens.pop(); else - reader.raiseError(QLatin1String("unexpected closing tag")); + reader.raiseError("unexpected closing tag"_L1); } break; @@ -614,7 +608,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, if (reader.isWhitespace()) break; if (tokens.isEmpty() || tokens.top() != FileTag) { - reader.raiseError(QLatin1String("unexpected text")); + reader.raiseError("unexpected text"_L1); } else { QString fileName = reader.text().toString(); if (fileName.isEmpty()) { @@ -626,7 +620,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, alias = fileName; alias = QDir::cleanPath(alias); - while (alias.startsWith(QLatin1String("../"))) + while (alias.startsWith("../"_L1)) alias.remove(0, 3); alias = QDir::cleanPath(m_resourceRoot) + prefix + alias; @@ -640,13 +634,12 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, alias += slash; QStringList filePaths; - QDirIterator it(dir, QDirIterator::FollowSymlinks|QDirIterator::Subdirectories); - while (it.hasNext()) { - it.next(); - if (it.fileName() == QLatin1String(".") - || it.fileName() == QLatin1String("..")) + using F = QDirListing::IteratorFlag; + for (const auto &entry : QDirListing(dir, F::FollowSymlinks | F::Recursive)) { + const QString &fileName = entry.fileName(); + if (fileName == "."_L1 || fileName == ".."_L1) continue; - filePaths.append(it.filePath()); + filePaths.emplace_back(entry.filePath()); } // make rcc output deterministic @@ -660,7 +653,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, child.isDir() ? RCCFileInfo::Directory : RCCFileInfo::NoFlags, compressAlgo, compressLevel, compressThreshold, - m_noZstd)); + m_noZstd, empty)); if (!arc) m_failedResources.push_back(child.fileName()); } @@ -675,7 +668,7 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, compressAlgo, compressLevel, compressThreshold, - m_noZstd) + m_noZstd, empty) ); if (!arc) m_failedResources.push_back(absFileName); @@ -714,15 +707,15 @@ bool RCCResourceLibrary::interpretResourceFile(QIODevice *inputDevice, m_errorDevice->write(msg.toUtf8()); if (!listMode && m_format == Binary) { // create dummy entry, otherwise loading with QResource will crash - m_root = new RCCFileInfo(QString(), QFileInfo(), - QLocale::C, QLocale::AnyTerritory, RCCFileInfo::Directory); + m_root = new RCCFileInfo{}; + m_root->m_flags = RCCFileInfo::Directory; } } return true; } -bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) +bool RCCResourceLibrary::addFile(const QString &alias, RCCFileInfo file) { Q_ASSERT(m_errorDevice); if (file.m_fileInfo.size() > 0xffffffff) { @@ -730,17 +723,21 @@ bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) m_errorDevice->write(msg.toUtf8()); return false; } - if (!m_root) - m_root = new RCCFileInfo(QString(), QFileInfo(), QLocale::C, QLocale::AnyTerritory, RCCFileInfo::Directory); + if (!m_root) { + m_root = new RCCFileInfo{}; + m_root->m_flags = RCCFileInfo::Directory; + } RCCFileInfo *parent = m_root; - const QStringList nodes = alias.split(QLatin1Char('/')); + const QStringList nodes = alias.split(u'/'); 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::AnyTerritory, RCCFileInfo::Directory); + RCCFileInfo *s = new RCCFileInfo{}; + s->m_name = node; + s->m_flags = RCCFileInfo::Directory; s->m_parent = parent; parent->m_children.insert(node, s); parent = s; @@ -750,14 +747,14 @@ bool RCCResourceLibrary::addFile(const QString &alias, const RCCFileInfo &file) } const QString filename = nodes.at(nodes.size()-1); - RCCFileInfo *s = new RCCFileInfo(file); + RCCFileInfo *s = new RCCFileInfo(std::move(file)); s->m_parent = parent; auto cbegin = parent->m_children.constFind(filename); auto cend = parent->m_children.constEnd(); for (auto it = cbegin; it != cend; ++it) { if (it.key() == filename && it.value()->m_language == s->m_language && it.value()->m_territory == s->m_territory) { - for (const QString &name : qAsConst(m_fileNames)) { + for (const QString &name : std::as_const(m_fileNames)) { qWarning("%s: Warning: potential duplicate alias detected: '%s'", qPrintable(name), qPrintable(filename)); } @@ -793,8 +790,8 @@ bool RCCResourceLibrary::readFiles(bool listMode, QIODevice &errorDevice) QFile fileIn; QString fname = m_fileNames.at(i); QString pwd; - if (fname == QLatin1String("-")) { - fname = QLatin1String("(stdin)"); + if (fname == "-"_L1) { + fname = "(stdin)"_L1; pwd = QDir::currentPath(); fileIn.setFileName(fname); if (!fileIn.open(stdin, QIODevice::ReadOnly)) { @@ -845,7 +842,7 @@ QStringList RCCResourceLibrary::dataFiles() const // 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) { - const QChar slash = QLatin1Char('/'); + const QChar slash = u'/'; const auto cend = m_root->m_children.constEnd(); for (auto it = m_root->m_children.constBegin(); it != cend; ++it) { const RCCFileInfo *child = it.value(); @@ -862,27 +859,27 @@ RCCResourceLibrary::ResourceDataFileMap RCCResourceLibrary::resourceDataFileMap( { ResourceDataFileMap rc; if (m_root) - resourceDataFileMapRecursion(m_root, QString(QLatin1Char(':')), rc); + resourceDataFileMapRecursion(m_root, QString(u':'), rc); return rc; } RCCResourceLibrary::CompressionAlgorithm RCCResourceLibrary::parseCompressionAlgorithm(QStringView value, QString *errorMsg) { - if (value == QLatin1String("best")) + if (value == "best"_L1) return CompressionAlgorithm::Best; - if (value == QLatin1String("zlib")) { + if (value == "zlib"_L1) { #ifdef QT_NO_COMPRESS - *errorMsg = QLatin1String("zlib support not compiled in"); + *errorMsg = "zlib support not compiled in"_L1; #else return CompressionAlgorithm::Zlib; #endif - } else if (value == QLatin1String("zstd")) { + } else if (value == "zstd"_L1) { #if QT_CONFIG(zstd) return CompressionAlgorithm::Zstd; #else - *errorMsg = QLatin1String("Zstandard support not compiled in"); + *errorMsg = "Zstandard support not compiled in"_L1; #endif - } else if (value != QLatin1String("none")) { + } else if (value != "none"_L1) { *errorMsg = QString::fromLatin1("Unknown compression algorithm '%1'").arg(value); } @@ -932,13 +929,17 @@ bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIO m_errorDevice->write("No data signature found\n"); return false; } + + if (c != pattern[i]) { + for (int k = 0; k < i; ++k) + outDevice.putChar(pattern[k]); + i = 0; + } + if (c == pattern[i]) { ++i; } else { - for (int k = 0; k < i; ++k) - outDevice.putChar(pattern[k]); outDevice.putChar(c); - i = 0; } } @@ -1097,6 +1098,10 @@ bool RCCResourceLibrary::writeHeader() writeString("\n**\n"); writeString("** WARNING! All changes made in this file will be lost!\n"); writeString( "*****************************************************************************/\n\n"); + writeString("#ifdef _MSC_VER\n" + "// disable informational message \"function ... selected for automatic inline expansion\"\n" + "#pragma warning (disable: 4711)\n" + "#endif\n\n"); break; case Python_Code: writeString("# Resource object code (Python 3)\n"); @@ -1348,7 +1353,7 @@ bool RCCResourceLibrary::writeInitializer() //write("\nQT_BEGIN_NAMESPACE\n"); QString initNameStr = m_initName; if (!initNameStr.isEmpty()) { - initNameStr.prepend(QLatin1Char('_')); + initNameStr.prepend(u'_'); auto isAsciiLetterOrNumber = [] (QChar c) -> bool { ushort ch = c.unicode(); return (ch >= '0' && ch <= '9') || @@ -1358,7 +1363,7 @@ bool RCCResourceLibrary::writeInitializer() }; for (QChar &c : initNameStr) { if (!isAsciiLetterOrNumber(c)) - c = QLatin1Char('_'); + c = u'_'; } } QByteArray initName = initNameStr.toLatin1(); @@ -1377,7 +1382,9 @@ bool RCCResourceLibrary::writeInitializer() "# define QT_RCC_MANGLE_NAMESPACE(name) name\n" "#endif\n\n"); - writeString("#ifdef QT_NAMESPACE\n" + writeString("#if defined(QT_INLINE_NAMESPACE)\n" + "inline namespace QT_NAMESPACE {\n" + "#elif defined(QT_NAMESPACE)\n" "namespace QT_NAMESPACE {\n" "#endif\n\n"); } @@ -1478,6 +1485,11 @@ bool RCCResourceLibrary::writeInitializer() writeString(" return 1;\n"); writeString("}\n\n"); + // -Wexit-time-destructors was added to clang 3.0.0 in 2011. + writeString("#ifdef __clang__\n" + "# pragma clang diagnostic push\n" + "# pragma clang diagnostic ignored \"-Wexit-time-destructors\"\n" + "#endif\n\n"); writeString("namespace {\n" " struct initializer {\n"); @@ -1490,7 +1502,12 @@ bool RCCResourceLibrary::writeInitializer() " ~initializer() { " + cleanResources + "(); }\n"); } writeString(" } dummy;\n" - "}\n"); + "}\n\n"); + + writeString("#ifdef __clang__\n" + "# pragma clang diagnostic pop\n" + "#endif\n"); + } else if (m_format == Binary) { int i = 4; diff --git a/src/tools/rcc/rcc.h b/src/tools/rcc/rcc.h index b6fcb21f5f..60af1c67cf 100644 --- a/src/tools/rcc/rcc.h +++ b/src/tools/rcc/rcc.h @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// Copyright (C) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 // Note: A copy of this file is used in Qt Designer (qttools/src/designer/src/lib/shared/rcc_p.h) @@ -121,13 +96,14 @@ private: const QString ATTRIBUTE_LANG; const QString ATTRIBUTE_PREFIX; const QString ATTRIBUTE_ALIAS; + const QString ATTRIBUTE_EMPTY; const QString ATTRIBUTE_THRESHOLD; const QString ATTRIBUTE_COMPRESS; const QString ATTRIBUTE_COMPRESSALGO; }; friend class RCCFileInfo; void reset(); - bool addFile(const QString &alias, const RCCFileInfo &file); + bool addFile(const QString &alias, RCCFileInfo file); bool interpretResourceFile(QIODevice *inputDevice, const QString &file, QString currentPath = QString(), bool listMode = false); bool writeHeader(); |