summaryrefslogtreecommitdiffstats
path: root/src/tools/rcc
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rcc')
-rw-r--r--src/tools/rcc/main.cpp77
-rw-r--r--src/tools/rcc/rcc.cpp196
-rw-r--r--src/tools/rcc/rcc.h4
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;