diff options
Diffstat (limited to 'src/tools/rcc')
-rw-r--r-- | src/tools/rcc/main.cpp | 77 | ||||
-rw-r--r-- | src/tools/rcc/rcc.cpp | 196 | ||||
-rw-r--r-- | src/tools/rcc/rcc.h | 4 |
3 files changed, 247 insertions, 30 deletions
diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp index 6e8c13be15..ac87e48e39 100644 --- a/src/tools/rcc/main.cpp +++ b/src/tools/rcc/main.cpp @@ -99,6 +99,37 @@ int createProject(const QString &outFileName) return 0; } +// Escapes a path for use in a Depfile (Makefile syntax) +QString makefileEscape(const QString &filepath) +{ + // Always use forward slashes + QString result = QDir::cleanPath(filepath); + // Spaces are escaped with a backslash + result.replace(QLatin1Char(' '), QLatin1String("\\ ")); + // Pipes are escaped with a backslash + result.replace(QLatin1Char('|'), QLatin1String("\\|")); + // Dollars are escaped with a dollar + result.replace(QLatin1Char('$'), QLatin1String("$$")); + + return result; +} + +void writeDepFile(QIODevice &iodev, const QStringList &depsList, const QString &targetName) +{ + QTextStream out(&iodev); + out << qPrintable(makefileEscape(targetName)); + out << QLatin1Char(':'); + + // Write depfile + for (int i = 0; i < depsList.size(); ++i) { + out << QLatin1Char(' '); + + out << qPrintable(makefileEscape(depsList.at(i))); + } + + out << QLatin1Char('\n'); +} + int runRcc(int argc, char *argv[]) { QCoreApplication app(argc, argv); @@ -155,6 +186,11 @@ int runRcc(int argc, char *argv[]) QCommandLineOption binaryOption(QStringLiteral("binary"), QStringLiteral("Output a binary file for use as a dynamic resource.")); parser.addOption(binaryOption); + QCommandLineOption generatorOption(QStringList{QStringLiteral("g"), QStringLiteral("generator")}); + generatorOption.setDescription(QStringLiteral("Select generator.")); + generatorOption.setValueName(QStringLiteral("cpp|python|python2")); + parser.addOption(generatorOption); + QCommandLineOption passOption(QStringLiteral("pass"), QStringLiteral("Pass number for big resources"), QStringLiteral("number")); parser.addOption(passOption); @@ -171,6 +207,10 @@ int runRcc(int argc, char *argv[]) QStringLiteral("Only output a mapping of resource paths to file system paths defined in the .qrc file, do not generate code.")); parser.addOption(mapOption); + QCommandLineOption depFileOption(QStringList{QStringLiteral("d"), QStringLiteral("depfile")}, + QStringLiteral("Write a depfile with the .qrc dependencies to <file>."), QStringLiteral("file")); + parser.addOption(depFileOption); + QCommandLineOption projectOption(QStringLiteral("project"), QStringLiteral("Output a resource file containing all files from the current directory.")); parser.addOption(projectOption); @@ -220,6 +260,18 @@ int runRcc(int argc, char *argv[]) library.setCompressThreshold(parser.value(thresholdOption).toInt()); if (parser.isSet(binaryOption)) library.setFormat(RCCResourceLibrary::Binary); + if (parser.isSet(generatorOption)) { + auto value = parser.value(generatorOption); + if (value == QLatin1String("cpp")) + library.setFormat(RCCResourceLibrary::C_Code); + else if (value == QLatin1String("python")) + library.setFormat(RCCResourceLibrary::Python3_Code); + else if (value == QLatin1String("python2")) + library.setFormat(RCCResourceLibrary::Python2_Code); + else + errorMsg = QLatin1String("Invalid generator: ") + value; + } + if (parser.isSet(passOption)) { if (parser.value(passOption) == QLatin1String("1")) library.setFormat(RCCResourceLibrary::Pass1); @@ -249,6 +301,7 @@ int runRcc(int argc, char *argv[]) QString outFilename = parser.value(outputOption); QString tempFilename = parser.value(tempOption); + QString depFilename = parser.value(depFileOption); if (projectRequested) { return createProject(outFilename); @@ -280,6 +333,8 @@ int runRcc(int argc, char *argv[]) switch (library.format()) { case RCCResourceLibrary::C_Code: case RCCResourceLibrary::Pass1: + case RCCResourceLibrary::Python3_Code: + case RCCResourceLibrary::Python2_Code: mode = QIODevice::WriteOnly | QIODevice::Text; break; case RCCResourceLibrary::Pass2: @@ -333,6 +388,28 @@ int runRcc(int argc, char *argv[]) return 0; } + // Write depfile + if (!depFilename.isEmpty()) { + QFile depout; + depout.setFileName(depFilename); + + if (outFilename.isEmpty() || outFilename == QLatin1String("-")) { + const QString msg = QString::fromUtf8("Unable to write depfile when outputting to stdout!\n"); + errorDevice.write(msg.toUtf8()); + return 1; + } + + if (!depout.open(QIODevice::WriteOnly | QIODevice::Text)) { + const QString msg = QString::fromUtf8("Unable to open depfile %1 for writing: %2\n") + .arg(depout.fileName(), depout.errorString()); + errorDevice.write(msg.toUtf8()); + return 1; + } + + writeDepFile(depout, library.dataFiles(), outFilename); + depout.close(); + } + QFile temp; if (!tempFilename.isEmpty()) { temp.setFileName(tempFilename); diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp index 011a7db810..9acbce25ff 100644 --- a/src/tools/rcc/rcc.cpp +++ b/src/tools/rcc/rcc.cpp @@ -37,6 +37,7 @@ #include <qfile.h> #include <qiodevice.h> #include <qlocale.h> +#include <qregexp.h> #include <qstack.h> #include <qxmlstream.h> @@ -66,11 +67,8 @@ enum { # define CONSTANT_COMPRESSALGO_DEFAULT RCCResourceLibrary::CompressionAlgorithm::None #endif -#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); @@ -176,6 +174,8 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) { const bool text = lib.m_format == RCCResourceLibrary::C_Code; const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; + const bool python = lib.m_format == RCCResourceLibrary::Python3_Code + || lib.m_format == RCCResourceLibrary::Python2_Code; //some info if (text || pass1) { if (m_language != QLocale::C) { @@ -222,6 +222,8 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) } if (text || pass1) lib.writeChar('\n'); + else if (python) + lib.writeString("\\\n"); if (lib.formatVersion() >= 2) { // last modified time stamp @@ -236,6 +238,8 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib) lib.writeNumber8(lastmod); if (text || pass1) lib.writeChar('\n'); + else if (python) + lib.writeString("\\\n"); } } @@ -246,6 +250,8 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; const bool pass2 = lib.m_format == RCCResourceLibrary::Pass2; const bool binary = lib.m_format == RCCResourceLibrary::Binary; + const bool python = lib.m_format == RCCResourceLibrary::Python3_Code + || lib.m_format == RCCResourceLibrary::Python2_Code; //capture the offset m_dataOffset = offset; @@ -343,20 +349,24 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, } // write the length - - if (text || binary || pass2) + if (text || binary || pass2 || python) lib.writeNumber4(data.size()); if (text || pass1) lib.writeString("\n "); + else if (python) + lib.writeString("\\\n"); offset += 4; // write the payload const char *p = data.constData(); - if (text) { + if (text || python) { for (int i = data.size(), j = 0; --i >= 0; --j) { lib.writeHex(*p++); if (j == 0) { - lib.writeString("\n "); + if (text) + lib.writeString("\n "); + else + lib.writeString("\\\n"); j = 16; } } @@ -368,6 +378,9 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset, // done if (text || pass1) lib.writeString("\n "); + else if (python) + lib.writeString("\\\n"); + return offset; } @@ -375,6 +388,8 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) { const bool text = lib.m_format == RCCResourceLibrary::C_Code; const bool pass1 = lib.m_format == RCCResourceLibrary::Pass1; + const bool python = lib.m_format == RCCResourceLibrary::Python3_Code + || lib.m_format == RCCResourceLibrary::Python2_Code; // capture the offset m_nameOffset = offset; @@ -390,12 +405,16 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) lib.writeNumber2(m_name.length()); if (text || pass1) lib.writeString("\n "); + else if (python) + lib.writeString("\\\n"); offset += 2; // write the hash lib.writeNumber4(qt_hash(m_name)); if (text || pass1) lib.writeString("\n "); + else if (python) + lib.writeString("\\\n"); offset += 4; // write the m_name @@ -404,12 +423,17 @@ qint64 RCCFileInfo::writeDataName(RCCResourceLibrary &lib, qint64 offset) 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; // done if (text || pass1) lib.writeString("\n "); + else if (python) + lib.writeString("\\\n"); + return offset; } @@ -956,21 +980,40 @@ void RCCResourceLibrary::writeDecimal(int value) Q_ASSERT(m_format != RCCResourceLibrary::Binary); char buf[std::numeric_limits<int>::digits10 + 2]; int n = snprintf(buf, sizeof(buf), "%d", value); - write(buf, n + 1); // write() takes a size including terminating NUL + write(buf, n); +} + +static const char hexDigits[] = "0123456789abcdef"; + +inline void RCCResourceLibrary::write2HexDigits(quint8 number) +{ + writeChar(hexDigits[number >> 4]); + writeChar(hexDigits[number & 0xf]); } void RCCResourceLibrary::writeHex(quint8 tmp) { - const char digits[] = "0123456789abcdef"; - writeChar('0'); - writeChar('x'); - if (tmp < 16) { - writeChar(digits[tmp]); - } else { - writeChar(digits[tmp >> 4]); - writeChar(digits[tmp & 0xf]); + switch (m_format) { + case RCCResourceLibrary::Python3_Code: + case RCCResourceLibrary::Python2_Code: + if (tmp >= 32 && tmp < 127 && tmp != '"' && tmp != '\\') { + writeChar(char(tmp)); + } else { + writeChar('\\'); + writeChar('x'); + write2HexDigits(tmp); + } + break; + default: + writeChar('0'); + writeChar('x'); + if (tmp < 16) + writeChar(hexDigits[tmp]); + else + write2HexDigits(tmp); + writeChar(','); + break; } - writeChar(','); } void RCCResourceLibrary::writeNumber2(quint16 number) @@ -1038,7 +1081,9 @@ void RCCResourceLibrary::writeNumber8(quint64 number) bool RCCResourceLibrary::writeHeader() { - if (m_format == C_Code || m_format == Pass1) { + switch (m_format) { + case C_Code: + case Pass1: writeString("/****************************************************************************\n"); writeString("** Resource object code\n"); writeString("**\n"); @@ -1047,7 +1092,20 @@ bool RCCResourceLibrary::writeHeader() writeString("\n**\n"); writeString("** WARNING! All changes made in this file will be lost!\n"); writeString( "*****************************************************************************/\n\n"); - } else if (m_format == Binary) { + break; + case Python3_Code: + case Python2_Code: + writeString("# Resource object code (Python "); + writeChar(m_format == Python3_Code ? '3' : '2'); + writeString(")\n"); + writeString("# Created by: object code\n"); + writeString("# Created by: The Resource Compiler for Qt version "); + writeByteArray(QT_VERSION_STR); + writeString("\n"); + writeString("# WARNING! All changes made in this file will be lost!\n\n"); + writeString("from PySide2 import QtCore\n\n"); + break; + case Binary: writeString("qres"); writeNumber4(0); writeNumber4(0); @@ -1055,6 +1113,9 @@ bool RCCResourceLibrary::writeHeader() writeNumber4(0); if (m_formatVersion >= 3) writeNumber4(m_overallFlags); + break; + default: + break; } return true; } @@ -1062,10 +1123,21 @@ bool RCCResourceLibrary::writeHeader() bool RCCResourceLibrary::writeDataBlobs() { Q_ASSERT(m_errorDevice); - if (m_format == C_Code) { + switch (m_format) { + case C_Code: writeString("static const unsigned char qt_resource_data[] = {\n"); - } else if (m_format == Binary) { + break; + case Python3_Code: + writeString("qt_resource_data = b\"\\\n"); + break; + case Python2_Code: + writeString("qt_resource_data = \"\\\n"); + break; + case Binary: m_dataOffset = m_out.size(); + break; + default: + break; } if (!m_root) @@ -1091,24 +1163,46 @@ bool RCCResourceLibrary::writeDataBlobs() } } } - if (m_format == C_Code) + switch (m_format) { + case C_Code: writeString("\n};\n\n"); - else if (m_format == Pass1) { + break; + case Python3_Code: + case Python2_Code: + writeString("\"\n\n"); + break; + case Pass1: if (offset < 8) offset = 8; writeString("\nstatic const unsigned char qt_resource_data["); writeByteArray(QByteArray::number(offset)); writeString("] = { 'Q', 'R', 'C', '_', 'D', 'A', 'T', 'A' };\n\n"); + break; + default: + break; } return true; } bool RCCResourceLibrary::writeDataNames() { - if (m_format == C_Code || m_format == Pass1) + switch (m_format) { + case C_Code: + case Pass1: writeString("static const unsigned char qt_resource_name[] = {\n"); - else if (m_format == Binary) + break; + case Python3_Code: + writeString("qt_resource_name = b\"\\\n"); + break; + case Python2_Code: + writeString("qt_resource_name = \"\\\n"); + break; + case Binary: m_namesOffset = m_out.size(); + break; + default: + break; + } QHash<QString, int> names; QStack<RCCFileInfo*> pending; @@ -1133,8 +1227,18 @@ bool RCCResourceLibrary::writeDataNames() } } } - if (m_format == C_Code || m_format == Pass1) + switch (m_format) { + case C_Code: + case Pass1: writeString("\n};\n\n"); + break; + case Python3_Code: + case Python2_Code: + writeString("\"\n\n"); + break; + default: + break; + } return true; } @@ -1149,10 +1253,24 @@ struct qt_rcc_compare_hash bool RCCResourceLibrary::writeDataStructure() { - if (m_format == C_Code || m_format == Pass1) + switch (m_format) { + case C_Code: + case Pass1: writeString("static const unsigned char qt_resource_struct[] = {\n"); - else if (m_format == Binary) + break; + case Python3_Code: + writeString("qt_resource_struct = b\"\\\n"); + break; + case Python2_Code: + writeString("qt_resource_struct = \"\\\n"); + break; + case Binary: m_treeOffset = m_out.size(); + break; + default: + break; + } + QStack<RCCFileInfo*> pending; if (!m_root) @@ -1196,8 +1314,18 @@ bool RCCResourceLibrary::writeDataStructure() pending.push(child); } } - if (m_format == C_Code || m_format == Pass1) + switch (m_format) { + case C_Code: + case Pass1: writeString("\n};\n\n"); + break; + case Python3_Code: + case Python2_Code: + writeString("\"\n\n"); + break; + default: + break; + } return true; } @@ -1387,6 +1515,16 @@ bool RCCResourceLibrary::writeInitializer() p[i++] = (m_overallFlags >> 8) & 0xff; p[i++] = (m_overallFlags >> 0) & 0xff; } + } else if (m_format == Python3_Code || m_format == Python2_Code) { + writeString("def qInitResources():\n"); + writeString(" QtCore.qRegisterResourceData(0x"); + write2HexDigits(m_formatVersion); + writeString(", qt_resource_struct, qt_resource_name, qt_resource_data)\n\n"); + writeString("def qCleanupResources():\n"); + writeString(" QtCore.qUnregisterResourceData(0x"); + write2HexDigits(m_formatVersion); + writeString(", qt_resource_struct, qt_resource_name, qt_resource_data)\n\n"); + writeString("qInitResources()\n"); } return true; } diff --git a/src/tools/rcc/rcc.h b/src/tools/rcc/rcc.h index ad1c5cd166..190c37a1f6 100644 --- a/src/tools/rcc/rcc.h +++ b/src/tools/rcc/rcc.h @@ -58,7 +58,7 @@ public: bool readFiles(bool listMode, QIODevice &errorDevice); - enum Format { Binary, C_Code, Pass1, Pass2 }; + enum Format { Binary, C_Code, Pass1, Pass2, Python3_Code, Python2_Code }; void setFormat(Format f) { m_format = f; } Format format() const { return m_format; } @@ -136,12 +136,14 @@ private: void writeAddNamespaceFunction(const QByteArray &name); void writeDecimal(int value); void writeHex(quint8 number); + void write2HexDigits(quint8 number); void writeNumber2(quint16 number); void writeNumber4(quint32 number); void writeNumber8(quint64 number); void writeChar(char c) { m_out.append(c); } void writeByteArray(const QByteArray &); void write(const char *, int len); + void writeString(const char *s) { write(s, static_cast<int>(strlen(s))); } #if QT_CONFIG(zstd) ZSTD_CCtx *m_zstdCCtx; |