34QString mangledIdentifier(
const QString &str)
36 Q_ASSERT(!str.isEmpty());
39 mangled.reserve(str.size());
42 if (str.startsWith(QLatin1Char(
'_')) && str.size() > 1) {
44 if (ch == QLatin1Char(
'_')
45 || (ch >= QLatin1Char(
'A') && ch <= QLatin1Char(
'Z'))) {
46 mangled += QLatin1String(
"_0x5f_");
51 for (
int ei = str.size(); i != ei; ++i) {
52 auto c = str.at(i).unicode();
53 if ((c >= QLatin1Char(
'0') && c <= QLatin1Char(
'9'))
54 || (c >= QLatin1Char(
'a') && c <= QLatin1Char(
'z'))
55 || (c >= QLatin1Char(
'A') && c <= QLatin1Char(
'Z'))
56 || c == QLatin1Char(
'_')) {
59 mangled += QLatin1String(
"_0x") + QString::number(c, 16) + QLatin1Char(
'_');
68 QFileInfo fi(relativePath);
69 QString symbol = fi.path();
70 if (symbol.size() == 1 && symbol.startsWith(QLatin1Char(
'.'))) {
73 symbol.replace(QLatin1Char(
'/'), QLatin1Char(
'_'));
74 symbol += QLatin1Char(
'_');
76 symbol += fi.baseName();
77 symbol += QLatin1Char(
'_');
78 symbol += fi.completeSuffix();
79 return mangledIdentifier(symbol);
93 const QStringList &resourceFileMappings, QString *errorString)
95 QByteArray generatedLoaderCode;
98 QTextStream stream(&generatedLoaderCode);
99 stream <<
"#include <QtQml/qqmlprivate.h>\n";
100 stream <<
"#include <QtCore/qdir.h>\n";
101 stream <<
"#include <QtCore/qurl.h>\n";
102 stream <<
"#include <QtCore/qhash.h>\n";
103 stream <<
"#include <QtCore/qstring.h>\n";
106 stream <<
"namespace QmlCacheGeneratedCode {\n";
107 for (
int i = 0; i < compiledFiles.size(); ++i) {
108 const QString compiledFile = compiledFiles.at(i);
109 const QString ns = qQmlJSSymbolNamespaceForPath(compiledFile);
110 stream <<
"namespace " << ns <<
" { \n";
111 stream <<
" extern const unsigned char qmlData[];\n";
112 stream <<
" extern const QQmlPrivate::AOTCompiledFunction aotBuiltFunctions[];\n";
113 stream <<
" const QQmlPrivate::CachedQmlUnit unit = {\n";
114 stream <<
" reinterpret_cast<const QV4::CompiledData::Unit*>(&qmlData), &aotBuiltFunctions[0], nullptr\n";
120 stream <<
"namespace {\n";
122 stream <<
"struct Registry {\n";
123 stream <<
" Registry();\n";
124 stream <<
" ~Registry();\n";
125 stream <<
" QHash<QString, const QQmlPrivate::CachedQmlUnit*> resourcePathToCachedUnit;\n";
126 stream <<
" static const QQmlPrivate::CachedQmlUnit *lookupCachedUnit(const QUrl &url);\n";
128 stream <<
"Q_GLOBAL_STATIC(Registry, unitRegistry)\n";
131 stream <<
"Registry::Registry() {\n";
133 for (
int i = 0; i < compiledFiles.size(); ++i) {
134 const QString qrcFile = compiledFiles.at(i);
135 const QString ns = qQmlJSSymbolNamespaceForPath(qrcFile);
136 stream <<
" resourcePathToCachedUnit.insert(QStringLiteral(\"" << qrcFile <<
"\"), &QmlCacheGeneratedCode::" << ns <<
"::unit);\n";
139 stream <<
" QQmlPrivate::RegisterQmlUnitCacheHook registration;\n";
140 stream <<
" registration.structVersion = 0;\n";
141 stream <<
" registration.lookupCachedQmlUnit = &lookupCachedUnit;\n";
142 stream <<
" QQmlPrivate::qmlregister(QQmlPrivate::QmlUnitCacheHookRegistration, ®istration);\n";
145 stream <<
"Registry::~Registry() {\n";
146 stream <<
" QQmlPrivate::qmlunregister(QQmlPrivate::QmlUnitCacheHookRegistration, quintptr(&lookupCachedUnit));\n";
149 stream <<
"const QQmlPrivate::CachedQmlUnit *Registry::lookupCachedUnit(const QUrl &url) {\n";
150 stream <<
" if (url.scheme() != QLatin1String(\"qrc\"))\n";
151 stream <<
" return nullptr;\n";
152 stream <<
" QString resourcePath = QDir::cleanPath(url.path());\n";
153 stream <<
" if (resourcePath.isEmpty())\n";
154 stream <<
" return nullptr;\n";
155 stream <<
" if (!resourcePath.startsWith(QLatin1Char('/')))\n";
156 stream <<
" resourcePath.prepend(QLatin1Char('/'));\n";
157 stream <<
" return unitRegistry()->resourcePathToCachedUnit.value(resourcePath, nullptr);\n";
161 for (
const QString &mapping: resourceFileMappings) {
162 QString originalResourceFile = mapping;
163 QString newResourceFile;
164 const int mappingSplit = originalResourceFile.indexOf(QLatin1Char(
'='));
165 if (mappingSplit != -1) {
166 newResourceFile = originalResourceFile.mid(mappingSplit + 1);
167 originalResourceFile.truncate(mappingSplit);
170 const QString suffix = qtResourceNameForFile(originalResourceFile);
171 const QString initFunction = QLatin1String(
"qInitResources_") + suffix;
173 stream << QStringLiteral(
"int QT_MANGLE_NAMESPACE(%1)() {\n").arg(initFunction);
174 stream <<
" ::unitRegistry();\n";
175 if (!newResourceFile.isEmpty())
176 stream <<
" Q_INIT_RESOURCE(" << qtResourceNameForFile(newResourceFile) <<
");\n";
177 stream <<
" return 1;\n";
179 stream <<
"Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(" << initFunction <<
"))\n";
181 const QString cleanupFunction = QLatin1String(
"qCleanupResources_") + suffix;
182 stream << QStringLiteral(
"int QT_MANGLE_NAMESPACE(%1)() {\n").arg(cleanupFunction);
183 if (!newResourceFile.isEmpty())
184 stream <<
" Q_CLEANUP_RESOURCE(" << qtResourceNameForFile(newResourceFile) <<
");\n";
185 stream <<
" return 1;\n";
190#if QT_CONFIG(temporaryfile)
191 QSaveFile f(outputFileName);
193 QFile f(outputFileName);
195 if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
196 *errorString = f.errorString();
200 if (f.write(generatedLoaderCode) != generatedLoaderCode.size()) {
201 *errorString = f.errorString();
205#if QT_CONFIG(temporaryfile)
207 *errorString = f.errorString();