summaryrefslogtreecommitdiffstats
path: root/src/tools/rcc
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2018-11-08 14:16:33 -0800
committerThiago Macieira <thiago.macieira@intel.com>2018-12-12 16:36:09 +0000
commitd20c9805763ab3dc504ebf2cefd33499d89ef22c (patch)
treed6c9b9f2694461ff0cfe41ce4801ad34cdc05a37 /src/tools/rcc
parentc820e0b11745750a18460f85b697230881438006 (diff)
Resources: reject compressed content we can't decompress
This solution is composed of two features: 1) C++ code generated by RCC uses two symbols exported from QtCore that are only present if the feature was compiled in. If the feature was not compiled in, this will cause a linker error either at build time or at load time (if they were functions, the error could be at runtime). 2) Binary files generated by RCC have a new header field containing flags. We're currently using two flags, one for Zlib and one for Zstandard. This means we now have binary RCC format version 3. Change-Id: I42a48bd64ccc41aebf84fffd156545fb6a4f72d9 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/tools/rcc')
-rw-r--r--src/tools/rcc/main.cpp6
-rw-r--r--src/tools/rcc/rcc.cpp78
-rw-r--r--src/tools/rcc/rcc.h2
3 files changed, 74 insertions, 12 deletions
diff --git a/src/tools/rcc/main.cpp b/src/tools/rcc/main.cpp
index 71836b81bd..6e8c13be15 100644
--- a/src/tools/rcc/main.cpp
+++ b/src/tools/rcc/main.cpp
@@ -185,13 +185,13 @@ int runRcc(int argc, char *argv[])
QString errorMsg;
- quint8 formatVersion = 2;
+ quint8 formatVersion = 3;
if (parser.isSet(formatVersionOption)) {
bool ok = false;
formatVersion = parser.value(formatVersionOption).toUInt(&ok);
if (!ok) {
errorMsg = QLatin1String("Invalid format version specified");
- } else if (formatVersion != 1 && formatVersion != 2) {
+ } else if (formatVersion < 1 || formatVersion > 3) {
errorMsg = QLatin1String("Unsupported format version specified");
}
}
@@ -208,6 +208,8 @@ int runRcc(int argc, char *argv[])
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(compressOption) && errorMsg.isEmpty()) {
diff --git a/src/tools/rcc/rcc.cpp b/src/tools/rcc/rcc.cpp
index 5cbc771994..f284749781 100644
--- a/src/tools/rcc/rcc.cpp
+++ b/src/tools/rcc/rcc.cpp
@@ -295,6 +295,7 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
lib.m_errorDevice->write(msg.toUtf8());
}
+ lib.m_overallFlags |= CompressedZstd;
m_flags |= CompressedZstd;
data = std::move(compressed);
data.truncate(n);
@@ -321,6 +322,7 @@ qint64 RCCFileInfo::writeDataBlob(RCCResourceLibrary &lib, qint64 offset,
lib.m_errorDevice->write(msg.toUtf8());
}
data = compressed;
+ lib.m_overallFlags |= Compressed;
m_flags |= Compressed;
} else if (lib.verbose()) {
QString msg = QString::fromLatin1("%1: note: not compressed\n").arg(m_name);
@@ -438,6 +440,7 @@ RCCResourceLibrary::RCCResourceLibrary(quint8 formatVersion)
m_treeOffset(0),
m_namesOffset(0),
m_dataOffset(0),
+ m_overallFlags(0),
m_useNameSpace(CONSTANT_USENAMESPACE),
m_errorDevice(0),
m_outDevice(0),
@@ -945,6 +948,14 @@ bool RCCResourceLibrary::output(QIODevice &outDevice, QIODevice &tempDevice, QIO
return true;
}
+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
+}
+
void RCCResourceLibrary::writeHex(quint8 tmp)
{
const char digits[] = "0123456789abcdef";
@@ -1039,6 +1050,8 @@ bool RCCResourceLibrary::writeHeader()
writeNumber4(0);
writeNumber4(0);
writeNumber4(0);
+ if (m_formatVersion >= 3)
+ writeNumber4(m_overallFlags);
}
return true;
}
@@ -1241,10 +1254,35 @@ bool RCCResourceLibrary::writeInitializer()
if (m_root) {
writeString("bool qRegisterResourceData"
"(int, const unsigned char *, "
- "const unsigned char *, const unsigned char *);\n\n");
+ "const unsigned char *, const unsigned char *);\n");
writeString("bool qUnregisterResourceData"
"(int, const unsigned char *, "
"const unsigned char *, const unsigned char *);\n\n");
+
+ if (m_overallFlags & (RCCFileInfo::Compressed | RCCFileInfo::CompressedZstd)) {
+ // use variable relocations with ELF and Mach-O
+ writeString("#if defined(__ELF__) || defined(__APPLE__)\n");
+ if (m_overallFlags & RCCFileInfo::Compressed) {
+ writeString("static inline unsigned char qResourceFeatureZlib()\n"
+ "{\n"
+ " extern const unsigned char qt_resourceFeatureZlib;\n"
+ " return qt_resourceFeatureZlib;\n"
+ "}\n");
+ }
+ if (m_overallFlags & RCCFileInfo::CompressedZstd) {
+ writeString("static inline unsigned char qResourceFeatureZstd()\n"
+ "{\n"
+ " extern const unsigned char qt_resourceFeatureZstd;\n"
+ " return qt_resourceFeatureZstd;\n"
+ "}\n");
+ }
+ writeString("#else\n");
+ if (m_overallFlags & RCCFileInfo::Compressed)
+ writeString("unsigned char qResourceFeatureZlib();\n");
+ if (m_overallFlags & RCCFileInfo::CompressedZstd)
+ writeString("unsigned char qResourceFeatureZstd();\n");
+ writeString("#endif\n\n");
+ }
}
if (m_useNameSpace)
@@ -1263,12 +1301,12 @@ bool RCCResourceLibrary::writeInitializer()
writeString("()\n{\n");
if (m_root) {
- writeString(" ");
+ writeString(" int version = ");
+ writeDecimal(m_formatVersion);
+ writeString(";\n ");
writeAddNamespaceFunction("qRegisterResourceData");
- writeString("\n (");
- writeHex(m_formatVersion);
- writeString(" qt_resource_struct, "
- "qt_resource_name, qt_resource_data);\n");
+ writeString("\n (version, qt_resource_struct, "
+ "qt_resource_name, qt_resource_data);\n");
}
writeString(" return 1;\n");
writeString("}\n\n");
@@ -1286,11 +1324,24 @@ bool RCCResourceLibrary::writeInitializer()
writeMangleNamespaceFunction(cleanResources);
writeString("()\n{\n");
if (m_root) {
- writeString(" ");
+ writeString(" int version = ");
+ writeDecimal(m_formatVersion);
+ writeString(";\n ");
+
+ // ODR-use certain symbols from QtCore if we require optional features
+ if (m_overallFlags & RCCFileInfo::Compressed) {
+ writeString("version += ");
+ writeAddNamespaceFunction("qResourceFeatureZlib()");
+ writeString(";\n ");
+ }
+ if (m_overallFlags & RCCFileInfo::CompressedZstd) {
+ writeString("version += ");
+ writeAddNamespaceFunction("qResourceFeatureZstd()");
+ writeString(";\n ");
+ }
+
writeAddNamespaceFunction("qUnregisterResourceData");
- writeString("\n (");
- writeHex(m_formatVersion);
- writeString(" qt_resource_struct, "
+ writeString("\n (version, qt_resource_struct, "
"qt_resource_name, qt_resource_data);\n");
}
writeString(" return 1;\n");
@@ -1326,6 +1377,13 @@ bool RCCResourceLibrary::writeInitializer()
p[i++] = (m_namesOffset >> 16) & 0xff;
p[i++] = (m_namesOffset >> 8) & 0xff;
p[i++] = (m_namesOffset >> 0) & 0xff;
+
+ if (m_formatVersion >= 3) {
+ p[i++] = (m_overallFlags >> 24) & 0xff;
+ p[i++] = (m_overallFlags >> 16) & 0xff;
+ p[i++] = (m_overallFlags >> 8) & 0xff;
+ p[i++] = (m_overallFlags >> 0) & 0xff;
+ }
}
return true;
}
diff --git a/src/tools/rcc/rcc.h b/src/tools/rcc/rcc.h
index 7603a41cde..ad1c5cd166 100644
--- a/src/tools/rcc/rcc.h
+++ b/src/tools/rcc/rcc.h
@@ -134,6 +134,7 @@ private:
bool writeInitializer();
void writeMangleNamespaceFunction(const QByteArray &name);
void writeAddNamespaceFunction(const QByteArray &name);
+ void writeDecimal(int value);
void writeHex(quint8 number);
void writeNumber2(quint16 number);
void writeNumber4(quint32 number);
@@ -160,6 +161,7 @@ private:
int m_treeOffset;
int m_namesOffset;
int m_dataOffset;
+ quint32 m_overallFlags;
bool m_useNameSpace;
QStringList m_failedResources;
QIODevice *m_errorDevice;