1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLTYPELOADER_P_H
5#define QQMLTYPELOADER_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qqmldatablob_p.h>
19#include <private/qqmlimport_p.h>
20#include <private/qqmlmetatype_p.h>
21#include <private/qqmltypeloaderdata_p.h>
22#include <private/qqmltypeloaderthread_p.h>
23#include <private/qv4compileddata_p.h>
24#include <private/qv4engine_p.h>
25
26#include <QtQml/qtqmlglobal.h>
27#include <QtQml/qqmlerror.h>
28
29#include <memory>
30
31QT_BEGIN_NAMESPACE
32
33class QQmlEngine;
34class QQmlEngineExtensionInterface;
35class QQmlExtensionInterface;
36class QQmlNetworkAccessManagerFactory;
37class QQmlProfiler;
38class QQmlQmldirData;
39class QQmlScriptBlob;
40class QQmlTypeData;
41class QQmlTypeLoaderThread;
42
43class Q_QML_EXPORT QQmlTypeLoader
44{
45 Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
46public:
47 using ChecksumCache = QQmlTypeLoaderThreadData::ChecksumCache;
48 enum Mode { PreferSynchronous, Asynchronous, Synchronous };
49
50 class Q_QML_EXPORT Blob : public QQmlDataBlob
51 {
52 public:
53 Blob(const QUrl &url, QQmlDataBlob::Type type, QQmlTypeLoader *loader);
54 ~Blob() override;
55
56 const QQmlImports *imports() const { return m_importCache.data(); }
57
58 void setCachedUnitStatus(QQmlMetaType::CachedUnitLookupError status) { m_cachedUnitStatus = status; }
59
60 struct PendingImport
61 {
62 QString uri;
63 QString qualifier;
64
65 QV4::CompiledData::Import::ImportType type
66 = QV4::CompiledData::Import::ImportType::ImportLibrary;
67 QV4::CompiledData::Location location;
68
69 QQmlImports::ImportFlags flags;
70 quint8 precedence = 0;
71 int priority = 0;
72
73 QTypeRevision version;
74
75 PendingImport() = default;
76 PendingImport(const QQmlRefPointer<Blob> &blob, const QV4::CompiledData::Import *import,
77 QQmlImports::ImportFlags flags);
78 };
79 using PendingImportPtr = std::shared_ptr<PendingImport>;
80
81 void importQmldirScripts(const PendingImportPtr &import, const QQmlTypeLoaderQmldirContent &qmldir, const QUrl &qmldirUrl);
82 bool handleLocalQmldirForImport(
83 const PendingImportPtr &import, const QString &qmldirFilePath,
84 const QString &qmldirUrl, QList<QQmlError> *errors);
85
86 protected:
87 bool addImport(const QV4::CompiledData::Import *import, QQmlImports::ImportFlags,
88 QList<QQmlError> *errors);
89 bool addImport(const PendingImportPtr &import, QList<QQmlError> *errors);
90
91 bool fetchQmldir(
92 const QUrl &url, const PendingImportPtr &import, int priority,
93 QList<QQmlError> *errors);
94 bool updateQmldir(const QQmlRefPointer<QQmlQmldirData> &data, const PendingImportPtr &import, QList<QQmlError> *errors);
95
96 private:
97 bool addScriptImport(const PendingImportPtr &import);
98 bool addFileImport(const PendingImportPtr &import, QList<QQmlError> *errors);
99 bool addLibraryImport(const PendingImportPtr &import, QList<QQmlError> *errors);
100
101 virtual bool qmldirDataAvailable(const QQmlRefPointer<QQmlQmldirData> &, QList<QQmlError> *);
102
103 virtual void scriptImported(
104 const QQmlRefPointer<QQmlScriptBlob> &, const QV4::CompiledData::Location &,
105 const QString &, const QString &)
106 {
107 assertTypeLoaderThread();
108 }
109
110 void dependencyComplete(const QQmlDataBlob::Ptr &) override;
111
112 bool loadImportDependencies(
113 const PendingImportPtr &currentImport, const QString &qmldirUri,
114 QQmlImports::ImportFlags flags, QList<QQmlError> *errors);
115
116 protected:
117
118 bool registerPendingTypes(const PendingImportPtr &import);
119
120 bool loadDependentImports(
121 const QList<QQmlDirParser::Import> &imports, const QString &qualifier,
122 QTypeRevision version, quint16 precedence, QQmlImports::ImportFlags flags,
123 QList<QQmlError> *errors);
124 virtual QString stringAt(int) const { return QString(); }
125
126 QQmlRefPointer<QQmlImports> m_importCache;
127 QVector<PendingImportPtr> m_unresolvedImports;
128 QVector<QQmlRefPointer<QQmlQmldirData>> m_qmldirs;
129 QQmlMetaType::CachedUnitLookupError m_cachedUnitStatus = QQmlMetaType::CachedUnitLookupError::NoError;
130 };
131
132 QQmlTypeLoader(QQmlEngine *);
133 ~QQmlTypeLoader();
134
135 template<
136 typename Engine,
137 typename EnginePrivate = QQmlEnginePrivate,
138 typename = std::enable_if_t<std::is_same_v<Engine, QQmlEngine>>>
139 static QQmlTypeLoader *get(Engine *engine)
140 {
141 return get(EnginePrivate::get(engine));
142 }
143
144 template<
145 typename Engine,
146 typename = std::enable_if_t<std::is_same_v<Engine, QQmlEnginePrivate>>>
147 static QQmlTypeLoader *get(Engine *engine)
148 {
149 return &engine->typeLoader;
150 }
151
152 static void sanitizeUNCPath(QString *path)
153 {
154 // This handles the UNC path case as when the path is retrieved from the QUrl it
155 // will convert the host name from upper case to lower case. So the absoluteFilePath
156 // is changed at this point to make sure it will match later on in that case.
157 if (path->startsWith(QStringLiteral("//"))) {
158 // toLocalFile() since that faithfully restores all the things you can do to a
159 // path but not a URL, in particular weird characters like '%'.
160 *path = QUrl::fromLocalFile(localfile: *path).toLocalFile();
161 }
162 }
163
164 // We can't include QQmlTypeData here.
165 // Use a template specialized only for QQmlTypeData::TypeReference instead.
166 template<typename TypeReference>
167 QByteArray hashDependencies(
168 QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache,
169 const QList<TypeReference> &compositeSingletons)
170 {
171 QQmlTypeLoaderThreadDataPtr data(&m_data);
172
173 QCryptographicHash hash(QCryptographicHash::Md5);
174 return (resolvedTypeCache->addToHash(hash: &hash, checksums: &data->checksumCache)
175 && addTypeReferenceChecksumsToHash(
176 compositeSingletons, &data->checksumCache, &hash))
177 ? hash.result()
178 : QByteArray();
179 }
180
181 static QUrl normalize(const QUrl &unNormalizedUrl);
182
183 QQmlRefPointer<QQmlTypeData> getType(
184 const QUrl &unNormalizedUrl, Mode mode = PreferSynchronous);
185 QQmlRefPointer<QQmlTypeData> getType(
186 const QByteArray &data, const QUrl &url, Mode mode = PreferSynchronous);
187
188 QQmlRefPointer<QV4::CompiledData::CompilationUnit> injectModule(
189 const QUrl &relativeUrl, const QV4::CompiledData::Unit *unit);
190
191 QQmlRefPointer<QQmlScriptBlob> getScript(const QUrl &unNormalizedUrl, const QUrl &relativeUrl);
192 QQmlRefPointer<QQmlQmldirData> getQmldir(const QUrl &);
193
194 QString absoluteFilePath(const QString &path);
195 bool fileExists(const QString &path, const QString &file);
196 bool directoryExists(const QString &path);
197
198 const QQmlTypeLoaderQmldirContent qmldirContent(const QString &filePath);
199 void setQmldirContent(const QString &filePath, const QString &content);
200
201 void clearCache();
202 void trimCache();
203
204 bool isTypeLoaded(const QUrl &url) const;
205 bool isScriptLoaded(const QUrl &url) const;
206
207 void loadWithStaticData(
208 const QQmlDataBlob::Ptr &blob, const QByteArray &data, Mode mode = PreferSynchronous);
209
210 void drop(const QQmlDataBlob::Ptr &blob);
211
212 void initializeEngine(QQmlEngineExtensionInterface *, const char *);
213 void initializeEngine(QQmlExtensionInterface *, const char *);
214 void invalidate();
215
216 void addUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
217 void removeUrlInterceptor(QQmlAbstractUrlInterceptor *urlInterceptor);
218 QList<QQmlAbstractUrlInterceptor *> urlInterceptors() const;
219 QUrl interceptUrl(const QUrl &url, QQmlAbstractUrlInterceptor::DataType type) const;
220 bool hasUrlInterceptors() const;
221
222#if !QT_CONFIG(qml_debug)
223 quintptr profiler() const { return 0; }
224 void setProfiler(quintptr) {}
225#else
226 QQmlProfiler *profiler() const
227 {
228 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
229 return data->profiler.data();
230 }
231 void setProfiler(QQmlProfiler *profiler);
232#endif // QT_CONFIG(qml_debug)
233
234 QStringList importPathList() const
235 {
236 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
237 return data->importPaths;
238 }
239 void setImportPathList(const QStringList &paths);
240 void addImportPath(const QString& dir);
241
242 QStringList pluginPathList() const
243 {
244 QQmlTypeLoaderConfiguredDataConstPtr data(&m_data);
245 return data->pluginPaths;
246 }
247 void setPluginPathList(const QStringList &paths);
248 void addPluginPath(const QString& path);
249
250 void setPluginInitialized(const QString &plugin)
251 {
252 QQmlTypeLoaderThreadDataPtr data(&m_data);
253 data->initializedPlugins.insert(value: plugin);
254 }
255 bool isPluginInitialized(const QString &plugin) const
256 {
257 QQmlTypeLoaderThreadDataConstPtr data(&m_data);
258 return data->initializedPlugins.contains(value: plugin);
259 }
260
261 void setModulePluginProcessingDone(const QString &module)
262 {
263 QQmlTypeLoaderThreadDataPtr data(&m_data);
264 data->modulesForWhichPluginsHaveBeenProcessed.insert(value: module);
265 }
266 bool isModulePluginProcessingDone(const QString &module)
267 {
268 QQmlTypeLoaderThreadDataConstPtr data(&m_data);
269 return data->modulesForWhichPluginsHaveBeenProcessed.contains(value: module);
270 }
271
272#if QT_CONFIG(qml_network)
273 QQmlNetworkAccessManagerFactoryPtrConst networkAccessManagerFactory() const;
274 void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *factory);
275 QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const;
276#endif
277
278 bool writeCacheFile();
279 bool readCacheFile();
280 bool isDebugging();
281
282private:
283 friend struct PlainLoader;
284 friend struct CachedLoader;
285 friend struct StaticLoader;
286
287 friend class QQmlDataBlob;
288 friend class QQmlTypeLoaderThread;
289#if QT_CONFIG(qml_network)
290 friend class QQmlTypeLoaderNetworkReplyProxy;
291#endif // qml_network
292
293 enum PathType { Local, Remote, LocalOrRemote };
294
295 enum LocalQmldirResult {
296 QmldirFound,
297 QmldirNotFound,
298 QmldirInterceptedToRemote,
299 QmldirRejected
300 };
301
302 QQmlTypeLoaderThread *thread() const { return m_data.thread(); }
303 QQmlEngine *engine() const { return m_data.engine(); }
304
305 void startThread();
306 void shutdownThread();
307 QQmlTypeLoaderThread *ensureThread()
308 {
309 if (!thread())
310 startThread();
311 return thread();
312 }
313
314 void trimCache(const QQmlTypeLoaderSharedDataPtr &data);
315
316 void loadThread(const QQmlDataBlob::Ptr &);
317 void loadWithStaticDataThread(const QQmlDataBlob::Ptr &, const QByteArray &);
318 void loadWithCachedUnitThread(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit);
319#if QT_CONFIG(qml_network)
320 void networkReplyFinished(QNetworkReply *);
321 void networkReplyProgress(QNetworkReply *, qint64, qint64);
322#endif
323
324 void setData(const QQmlDataBlob::Ptr &, const QByteArray &);
325 void setData(const QQmlDataBlob::Ptr &, const QString &fileName);
326 void setData(const QQmlDataBlob::Ptr &, const QQmlDataBlob::SourceCodeData &);
327 void setCachedUnit(const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit);
328
329 QStringList importPathList(PathType type) const;
330 void clearQmldirInfo();
331
332 LocalQmldirResult locateLocalQmldir(
333 QQmlTypeLoader::Blob *blob, const QQmlTypeLoader::Blob::PendingImportPtr &import,
334 QList<QQmlError> *errors);
335
336 void load(const QQmlDataBlob::Ptr &blob, Mode mode = PreferSynchronous);
337 void loadWithCachedUnit(
338 const QQmlDataBlob::Ptr &blob, const QQmlPrivate::CachedQmlUnit *unit,
339 Mode mode = PreferSynchronous);
340
341 template<typename Loader>
342 void doLoad(const Loader &loader, const QQmlDataBlob::Ptr &blob, Mode mode);
343 void updateTypeCacheTrimThreshold(const QQmlTypeLoaderSharedDataPtr &data);
344
345 template<typename TypeReference>
346 static bool addTypeReferenceChecksumsToHash(
347 const QList<TypeReference> &typeRefs,
348 QHash<quintptr, QByteArray> *checksums, QCryptographicHash *hash)
349 {
350 for (const auto &typeRef: typeRefs) {
351 if (typeRef.typeData) {
352 const auto unit = typeRef.typeData->compilationUnit()->unitData();
353 hash->addData({unit->md5Checksum, sizeof(unit->md5Checksum)});
354 } else if (const QMetaObject *mo = typeRef.type.metaObject()) {
355 const auto propertyCache = QQmlMetaType::propertyCache(metaObject: mo);
356 bool ok = false;
357 hash->addData(data: propertyCache->checksum(checksums, ok: &ok));
358 if (!ok)
359 return false;
360 }
361 }
362 return true;
363 }
364
365 QQmlMetaType::CacheMode aotCacheMode();
366
367 QQmlTypeLoaderLockedData m_data;
368};
369
370QT_END_NAMESPACE
371
372#endif // QQMLTYPELOADER_P_H
373

source code of qtdeclarative/src/qml/qml/qqmltypeloader_p.h