5#include <private/qqmldatablob_p.h>
6#include <private/qqmlglobal_p.h>
7#include <private/qqmlprofiler_p.h>
8#include <private/qqmlsourcecoordinate_p.h>
9#include <private/qqmltypedata_p.h>
10#include <private/qqmltypeloader_p.h>
11#include <private/qqmltypeloaderthread_p.h>
13#include <QtQml/qqmlengine.h>
15#include <QtCore/qcryptographichash.h>
17#include <qtqml_tracepoints_p.h>
24
25
26
27
28
29
30
31
34
35
36
37
38
39
40
41
42
43
44
45
46
49
50
51
52
53
54
55
56
59
60
61QQmlDataBlob::QQmlDataBlob(
const QUrl &url, Type type, QQmlTypeLoader *manager)
62 : m_typeLoader(manager)
64 , m_url(manager->interceptUrl(url, (QQmlAbstractUrlInterceptor::DataType)type))
73QQmlDataBlob::~QQmlDataBlob()
75 Q_ASSERT(m_waitingOnMe.isEmpty());
92 cancelAllWaitingFor();
96
97
98void QQmlDataBlob::startLoading()
102 Q_ASSERT(status() == QQmlDataBlob::Null);
103 setStatus(QQmlDataBlob::Loading);
107
108
109QQmlDataBlob::Type QQmlDataBlob::type()
const
115
116
117QQmlDataBlob::Status QQmlDataBlob::status()
const
119 return m_data.status();
123
124
125bool QQmlDataBlob::isNull()
const
127 return status() == Null;
131
132
133bool QQmlDataBlob::isLoading()
const
135 return status() == Loading;
139
140
141bool QQmlDataBlob::isWaiting()
const
143 return status() == WaitingForDependencies ||
144 status() == ResolvingDependencies;
148
149
150bool QQmlDataBlob::isComplete()
const
152 return status() == Complete;
156
157
158bool QQmlDataBlob::isError()
const
160 return status() == Error;
164
165
166bool QQmlDataBlob::isCompleteOrError()
const
169 return s == Error || s == Complete;
172bool QQmlDataBlob::isAsync()
const
174 return m_data.isAsync();
178
179
180qreal QQmlDataBlob::progress()
const
182 return m_data.progress();
186
187
188
189
190
191
192QUrl QQmlDataBlob::url()
const
197QString QQmlDataBlob::urlString()
const
200 if (m_urlString.isEmpty())
201 m_urlString = m_url.toString();
207
208
209
210
211
212
213
214
215
216
217
218
219QUrl QQmlDataBlob::finalUrl()
const
225
226
227QString QQmlDataBlob::finalUrlString()
const
231 if (m_finalUrlString.isEmpty())
232 m_finalUrlString = m_finalUrl.toString();
234 return m_finalUrlString;
238
239
240
241
242QList<QQmlError> QQmlDataBlob::errors()
const
244 Q_ASSERT(isCompleteOrError()
246 || !m_typeLoader->thread()
247 || m_typeLoader->thread()->isThisThread());
252
253
254
255
256
257
258
259void QQmlDataBlob::setError(
const QQmlError &errors)
261 assertTypeLoaderThread();
269
270
271void QQmlDataBlob::setError(
const QList<QQmlError> &errors)
273 assertTypeLoaderThread();
275 Q_ASSERT(status() != Error);
276 Q_ASSERT(m_errors.isEmpty());
279 m_errors.reserve(errors.size());
280 for (
const QQmlError &error : errors) {
281 if (error.url().isEmpty()) {
282 QQmlError mutableError = error;
283 mutableError.setUrl(url());
284 m_errors.append(mutableError);
286 m_errors.append(error);
290 cancelAllWaitingFor();
294 qWarning().nospace() <<
"Errors for " << urlString();
295 for (
int ii = 0; ii < errors.size(); ++ii)
296 qWarning().nospace() <<
" " << qPrintable(errors.at(ii).toString());
303void QQmlDataBlob::setError(
const QQmlJS::DiagnosticMessage &error)
305 assertTypeLoaderThread();
307 e.setColumn(qmlConvertSourceCoordinate<quint32,
int>(error.loc.startColumn));
308 e.setLine(qmlConvertSourceCoordinate<quint32,
int>(error.loc.startLine));
309 e.setDescription(error.message);
314void QQmlDataBlob::setError(
const QString &description)
316 assertTypeLoaderThread();
318 e.setDescription(description);
324
325
326
327
328
329void QQmlDataBlob::addDependency(
const QQmlDataBlob::Ptr &blob)
331 assertTypeLoaderThread();
333 Q_ASSERT(status() != Null);
336 blob->status() == Error || blob->status() == Complete ||
337 status() == Error || status() == Complete || m_isDone)
340 for (
const auto &existingDep: std::as_const(m_waitingFor)) {
341 if (existingDep.data() == blob)
345 m_waitingFor.append(blob);
346 blob->m_waitingOnMe.append(
this);
348 setStatus(WaitingForDependencies);
351 if (m_waitingOnMe.indexOf(blob.data()) >= 0) {
352 qCWarning(lcCycle) <<
"Cyclic dependency detected between" <<
this->url().toString()
353 <<
"and" << blob->url().toString();
356 error.setDescription(QString::fromLatin1(
"Cyclic dependency detected between \"%1\" and \"%2\"")
357 .arg(url().toString(), blob->url().toString()));
363
364
365
366
367
368
371
372
373
374
375
376
377
378
379
380
381
382void QQmlDataBlob::done()
384 assertTypeLoaderThread();
387#if QT_CONFIG(qml_network)
389
390
391
392
393void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError)
395 assertTypeLoaderThread();
397 Q_UNUSED(networkError);
402 const char *errorString =
nullptr;
403 switch (networkError) {
405 errorString =
"Network error";
407 case QNetworkReply::ConnectionRefusedError:
408 errorString =
"Connection refused";
410 case QNetworkReply::RemoteHostClosedError:
411 errorString =
"Remote host closed the connection";
413 case QNetworkReply::HostNotFoundError:
414 errorString =
"Host not found";
416 case QNetworkReply::TimeoutError:
417 errorString =
"Timeout";
419 case QNetworkReply::ProxyConnectionRefusedError:
420 case QNetworkReply::ProxyConnectionClosedError:
421 case QNetworkReply::ProxyNotFoundError:
422 case QNetworkReply::ProxyTimeoutError:
423 case QNetworkReply::ProxyAuthenticationRequiredError:
424 case QNetworkReply::UnknownProxyError:
425 errorString =
"Proxy error";
427 case QNetworkReply::ContentAccessDenied:
428 errorString =
"Access denied";
430 case QNetworkReply::ContentNotFoundError:
431 errorString =
"File not found";
433 case QNetworkReply::AuthenticationRequiredError:
434 errorString =
"Authentication required";
438 error.setDescription(QLatin1String(errorString));
445
446
447
448
449void QQmlDataBlob::dependencyError(
const QQmlDataBlob::Ptr &blob)
451 assertTypeLoaderThread();
456
457
458
459
460void QQmlDataBlob::dependencyComplete(
const QQmlDataBlob::Ptr &blob)
462 assertTypeLoaderThread();
467
468
469
470
471
472void QQmlDataBlob::allDependenciesDone()
474 assertTypeLoaderThread();
475 setStatus(QQmlDataBlob::ResolvingDependencies);
479
480
481
482
483
484
485
486
487
488
489void QQmlDataBlob::downloadProgressChanged(qreal progress)
492 assertEngineThread();
496
497
498
499
500
501
502
503
504
505
506
507
508
509void QQmlDataBlob::completed()
511 assertEngineThread();
514void QQmlDataBlob::tryDone()
516 assertTypeLoaderThread();
518 if (status() != Loading && m_waitingFor.isEmpty() && !m_isDone) {
523 qWarning(
"QQmlDataBlob::done() %s", qPrintable(urlString()));
527 if (status() != Error)
530 notifyAllWaitingOnMe();
535 qWarning(
"QQmlDataBlob: Dispatching completed");
537 m_typeLoader->thread()->callCompleted(
this);
543void QQmlDataBlob::cancelAllWaitingFor()
545 while (m_waitingFor.size()) {
550 assertTypeLoaderThreadIfRunning();
552 QQmlRefPointer<QQmlDataBlob> blob = m_waitingFor.takeLast();
554 Q_ASSERT(blob->m_waitingOnMe.contains(
this));
556 blob->m_waitingOnMe.removeOne(
this);
560void QQmlDataBlob::notifyAllWaitingOnMe()
562 assertTypeLoaderThread();
564 while (m_waitingOnMe.size()) {
565 QQmlDataBlob::Ptr blob = m_waitingOnMe.takeLast();
567 Q_ASSERT(std::any_of(blob->m_waitingFor.constBegin(), blob->m_waitingFor.constEnd(),
568 [
this](
const QQmlRefPointer<QQmlDataBlob> &waiting) {
return waiting.data() ==
this; }));
570 blob->notifyComplete(
this);
574void QQmlDataBlob::notifyComplete(
const QQmlDataBlob::Ptr &blob)
576 assertTypeLoaderThread();
578 Q_ASSERT(blob->status() == Error || blob->status() == Complete);
579 Q_TRACE_SCOPE(QQmlCompiling, blob->url());
580 QQmlCompilingProfiler prof(typeLoader()->profiler(), blob.data());
584 QQmlRefPointer<QQmlDataBlob> blobRef;
585 for (
int i = 0; i < m_waitingFor.size(); ++i) {
586 if (m_waitingFor.at(i).data() == blob) {
587 blobRef = m_waitingFor.takeAt(i);
593 if (blob->status() == Error) {
594 dependencyError(blob);
595 }
else if (blob->status() == Complete) {
596 dependencyComplete(blob);
599 if (!isError() && m_waitingFor.isEmpty())
600 allDependenciesDone();
602 m_inCallback =
false;
607QString QQmlDataBlob::SourceCodeData::readAll(QString *error)
const
610 if (hasInlineSourceCode)
611 return inlineSourceCode;
613 QFile f(fileInfo.absoluteFilePath());
614 if (!f.open(QIODevice::ReadOnly)) {
615 *error = f.errorString();
619 const qint64 fileSize = fileInfo.size();
621 if (uchar *mappedData = f.map(0, fileSize)) {
622 QString source = QString::fromUtf8(
reinterpret_cast<
const char *>(mappedData), fileSize);
627 QByteArray data(fileSize, Qt::Uninitialized);
628 if (f.read(data.data(), data.size()) != data.size()) {
629 *error = f.errorString();
632 return QString::fromUtf8(data);
635QDateTime QQmlDataBlob::SourceCodeData::sourceTimeStamp()
const
637 if (hasInlineSourceCode)
640 return fileInfo.lastModified();
643QByteArray QQmlDataBlob::SourceCodeData::checksum()
const
645 QCryptographicHash hash(QCryptographicHash::Md5);
646 if (hasInlineSourceCode) {
647 hash.addData(inlineSourceCode.toUtf8());
648 return hash.result();
651 QFile f(fileInfo.absoluteFilePath());
652 if (!f.open(QIODevice::ReadOnly))
654 if (!hash.addData(&f))
656 return hash.result();
659bool QQmlDataBlob::SourceCodeData::exists()
const
661 if (hasInlineSourceCode)
663 return fileInfo.exists();
666bool QQmlDataBlob::SourceCodeData::isEmpty()
const
668 if (hasInlineSourceCode)
669 return inlineSourceCode.isEmpty();
670 return fileInfo.size() == 0;
673bool QQmlDataBlob::setStatus(Status status)
678 case WaitingForDependencies:
679 Q_ASSERT(!m_waitingFor.isEmpty());
682 case ResolvingDependencies:
685 Q_ASSERT(m_waitingFor.isEmpty());
689 return m_data.setStatus(status);
DEFINE_BOOL_CONFIG_OPTION(forceDiskCache, QML_FORCE_DISK_CACHE)