7#include <QtCore/qurl.h>
8#include <QtCore/qobject.h>
9#include <QtCore/qmetaobject.h>
10#include <QtCore/qfile.h>
11#include <private/qqmlengine_p.h>
12#include <private/qqmlglobal_p.h>
17
18
19
20
21
22
23
24
29#if defined(Q_OS_ANDROID)
30static char assets_string[] =
"assets";
31static char content_string[] =
"content";
32static char authority_externalstorage[] =
"com.android.externalstorage.documents";
33static char authority_downloads_documents[] =
"com.android.providers.downloads.documents";
34static char authority_media_documents[] =
"com.android.providers.media.documents";
38static char weblocalfile_string[] =
"weblocalfile";
41#if QT_DEPRECATED_SINCE(6
, 11
)
43QT_WARNING_DISABLE_DEPRECATED
46
47
48
49
50
51
52
53
54
58#if QT_CONFIG(qml_network)
59class QQmlFileNetworkReply :
public QObject
63 QQmlFileNetworkReply(QQmlEngine *, QQmlFilePrivate *,
const QUrl &);
64 ~QQmlFileNetworkReply();
68 void downloadProgress(qint64, qint64);
71 void networkFinished();
72 void networkDownloadProgress(qint64, qint64);
75 static int finishedIndex;
76 static int downloadProgressIndex;
77 static int networkFinishedIndex;
78 static int networkDownloadProgressIndex;
79 static int replyFinishedIndex;
80 static int replyDownloadProgressIndex;
86 QNetworkReply *m_reply;
96 mutable QString urlString;
101 None, NotFound, Network
106#if QT_CONFIG(qml_network)
107 QQmlFileNetworkReply *reply;
111#if QT_CONFIG(qml_network)
112int QQmlFileNetworkReply::finishedIndex = -1;
113int QQmlFileNetworkReply::downloadProgressIndex = -1;
114int QQmlFileNetworkReply::networkFinishedIndex = -1;
115int QQmlFileNetworkReply::networkDownloadProgressIndex = -1;
116int QQmlFileNetworkReply::replyFinishedIndex = -1;
117int QQmlFileNetworkReply::replyDownloadProgressIndex = -1;
119QQmlFileNetworkReply::QQmlFileNetworkReply(QQmlEngine *e, QQmlFilePrivate *p,
const QUrl &url)
120: m_engine(e), m_p(p), m_reply(
nullptr)
122 if (finishedIndex == -1) {
123 finishedIndex = QMetaMethod::fromSignal(&QQmlFileNetworkReply::finished).methodIndex();
124 downloadProgressIndex = QMetaMethod::fromSignal(&QQmlFileNetworkReply::downloadProgress).methodIndex();
125 const QMetaObject *smo = &staticMetaObject;
126 networkFinishedIndex = smo->indexOfMethod(
"networkFinished()");
127 networkDownloadProgressIndex = smo->indexOfMethod(
"networkDownloadProgress(qint64,qint64)");
129 replyFinishedIndex = QMetaMethod::fromSignal(&QNetworkReply::finished).methodIndex();
130 replyDownloadProgressIndex = QMetaMethod::fromSignal(&QNetworkReply::downloadProgress).methodIndex();
132 Q_ASSERT(finishedIndex != -1 && downloadProgressIndex != -1 &&
133 networkFinishedIndex != -1 && networkDownloadProgressIndex != -1 &&
134 replyFinishedIndex != -1 && replyDownloadProgressIndex != -1);
136 QNetworkRequest req(url);
137 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute,
true);
139 m_reply = m_engine->networkAccessManager()->get(req);
140 QMetaObject::connect(m_reply, replyFinishedIndex,
this, networkFinishedIndex);
141 QMetaObject::connect(m_reply, replyDownloadProgressIndex,
this, networkDownloadProgressIndex);
144QQmlFileNetworkReply::~QQmlFileNetworkReply()
147 m_reply->disconnect();
148 m_reply->deleteLater();
152void QQmlFileNetworkReply::networkFinished()
154 if (m_reply->error()) {
155 m_p->errorString = m_reply->errorString();
156 m_p->error = QQmlFilePrivate::Network;
158 m_p->data = m_reply->readAll();
161 m_reply->deleteLater();
164 m_p->reply =
nullptr;
169void QQmlFileNetworkReply::networkDownloadProgress(qint64 a, qint64 b)
171 emit downloadProgress(a, b);
175QQmlFilePrivate::QQmlFilePrivate()
177#if QT_CONFIG(qml_network)
184
185
187: d(
new QQmlFilePrivate)
192
193
194
195QQmlFile::QQmlFile(QQmlEngine *engine,
const QUrl &url)
196: d(
new QQmlFilePrivate)
202
203
204
205QQmlFile::QQmlFile(QQmlEngine *engine,
const QString &url)
206 : QQmlFile(engine, QUrl(url))
211
212
215#if QT_CONFIG(qml_network)
223
224
225bool QQmlFile::isNull()
const
227 return status() == Null;
231
232
233bool QQmlFile::isReady()
const
235 return status() == Ready;
239
240
241bool QQmlFile::isError()
const
243 return status() == Error;
247
248
249bool QQmlFile::isLoading()
const
251 return status() == Loading;
255
256
257QUrl QQmlFile::url()
const
259 if (!d->urlString.isEmpty()) {
260 d->url = QUrl(d->urlString);
261 d->urlString = QString();
267
268
269QQmlFile::Status QQmlFile::status()
const
271 if (d->url.isEmpty() && d->urlString.isEmpty())
273#if QT_CONFIG(qml_network)
277 else if (d->error != QQmlFilePrivate::None)
284
285
286
287QString QQmlFile::error()
const
291 case QQmlFilePrivate::None:
293 case QQmlFilePrivate::NotFound:
294 return QLatin1String(
"File not found");
299
300
301
302qint64 QQmlFile::size()
const
304 return d->data.size();
308
309
310
311const char *QQmlFile::data()
const
313 return d->data.constData();
317
318
319
320QByteArray QQmlFile::dataByteArray()
const
326
327
328
329
330
331void QQmlFile::load(QQmlEngine *engine,
const QUrl &url)
338 if (isLocalFile(url)) {
339 const QString lf = urlToLocalFileOrQrc(url);
340 if (!QQmlTypeLoader::get(engine)->fileExists(lf)) {
341 d->error = QQmlFilePrivate::NotFound;
346 if (file.open(QFile::ReadOnly)) {
347 d->data = file.readAll();
349 d->error = QQmlFilePrivate::NotFound;
352#if QT_CONFIG(qml_network)
353 d->reply =
new QQmlFileNetworkReply(engine, d, url);
355 d->error = QQmlFilePrivate::NotFound;
361
362
363
364
365
366void QQmlFile::load(QQmlEngine *engine,
const QString &url)
374 if (isLocalFile(url)) {
375 const QString lf = urlToLocalFileOrQrc(url);
376 if (!QQmlTypeLoader::get(engine)->fileExists(lf)) {
377 d->error = QQmlFilePrivate::NotFound;
382 if (file.open(QFile::ReadOnly)) {
383 d->data = file.readAll();
385 d->error = QQmlFilePrivate::NotFound;
388#if QT_CONFIG(qml_network)
391 d->urlString = QString();
392 d->reply =
new QQmlFileNetworkReply(engine, d, qurl);
394 d->error = QQmlFilePrivate::NotFound;
400
401
402
403void QQmlFile::clear()
406 d->urlString = QString();
407 d->data = QByteArray();
408 d->error = QQmlFilePrivate::None;
412
413
414
415
416
417void QQmlFile::clear(QObject *object)
423#if QT_CONFIG(qml_network)
426
427
428
429bool QQmlFile::connectFinished(QObject *object,
const char *method)
431 if (!d || !d->reply) {
432 qWarning(
"QQmlFile: connectFinished() called when not loading.");
436 return QObject::connect(d->reply, SIGNAL(finished()), object, method);
440
441
442
443
444
445bool QQmlFile::connectFinished(QObject *object,
int method)
447 if (!d || !d->reply) {
448 qWarning(
"QQmlFile: connectFinished() called when not loading.");
452 return QMetaObject::connect(d->reply, QQmlFileNetworkReply::finishedIndex,
457
458
459
460
461
462bool QQmlFile::connectDownloadProgress(QObject *object,
const char *method)
464 if (!d || !d->reply) {
465 qWarning(
"QQmlFile: connectDownloadProgress() called when not loading.");
469 return QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
474
475
476
477
478
479bool QQmlFile::connectDownloadProgress(QObject *object,
int method)
481 if (!d || !d->reply) {
482 qWarning(
"QQmlFile: connectDownloadProgress() called when not loading.");
486 return QMetaObject::connect(d->reply, QQmlFileNetworkReply::downloadProgressIndex,
495
496
497
498
499
500
501
502
503
504bool QQmlFile::isSynchronous(
const QUrl &url)
506 QString scheme = url.scheme();
508 if ((scheme.size() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
509 (scheme.size() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
512#if defined(Q_OS_ANDROID)
513 }
else if (scheme.length() == 6 && 0 == scheme.compare(QLatin1String(assets_string), Qt::CaseInsensitive)) {
515 }
else if (scheme.length() == 7 && 0 == scheme.compare(QLatin1String(content_string), Qt::CaseInsensitive)) {
519#if defined(Q_OS_WASM)
520 }
else if (scheme.length() == 12 && 0 == scheme.compare(QLatin1String(weblocalfile_string), Qt::CaseInsensitive)) {
530
531
532
533
534
535
536
537
538
539bool QQmlFile::isSynchronous(
const QString &url)
546 if (f == QLatin1Char(
'f') || f == QLatin1Char(
'F')) {
548 return url.size() >= 7 &&
549 url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
550 url[4] == QLatin1Char(
':') && url[5] == QLatin1Char(
'/') && url[6] == QLatin1Char(
'/');
552 }
else if (f == QLatin1Char(
'q') || f == QLatin1Char(
'Q')) {
554 return url.size() >= 5 &&
555 url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
556 url[3] == QLatin1Char(
':') && url[4] == QLatin1Char(
'/');
560#if defined(Q_OS_ANDROID)
561 else if (f == QLatin1Char(
'a') || f == QLatin1Char(
'A')) {
562 return url.length() >= 8 &&
563 url.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive) &&
564 url[6] == QLatin1Char(
':') && url[7] == QLatin1Char(
'/');
565 }
else if (f == QLatin1Char(
'c') || f == QLatin1Char(
'C')) {
566 return url.length() >= 9 &&
567 url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
568 url[7] == QLatin1Char(
':') && url[8] == QLatin1Char(
'/');
572#if defined(Q_OS_WASM)
573 else if (f == QLatin1Char(
'w') || f == QLatin1Char(
'W')) {
574 return url.length() >= 14 &&
575 url.startsWith(QLatin1String(weblocalfile_string), Qt::CaseInsensitive) &&
576 url[12] == QLatin1Char(
':') && url[13] == QLatin1Char(
'/');
583#if defined(Q_OS_ANDROID)
584static bool hasLocalContentAuthority(
const QUrl &url)
586 const QString authority = url.authority();
587 return authority.isEmpty()
588 || authority == QLatin1String(authority_externalstorage)
589 || authority == QLatin1String(authority_downloads_documents)
590 || authority == QLatin1String(authority_media_documents);
595
596
597
598
599
600
601
602bool QQmlFile::isLocalFile(
const QUrl &url)
604 QString scheme = url.scheme();
609 if (scheme.size() == 4 && scheme.startsWith(QLatin1String(file_string), Qt::CaseInsensitive))
612 if (scheme.size() == 3 && scheme.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive))
613 return url.authority().isEmpty();
615#if defined(Q_OS_ANDROID)
616 if (scheme.length() == 6
617 && scheme.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive))
618 return url.authority().isEmpty();
619 if (scheme.length() == 7
620 && scheme.startsWith(QLatin1String(content_string), Qt::CaseInsensitive))
621 return hasLocalContentAuthority(url);
624#if defined(Q_OS_WASM)
625 if (scheme.length() == 12
626 && scheme.startsWith(QLatin1String(weblocalfile_string), Qt::CaseInsensitive))
633static bool hasScheme(
const QString &url,
const char *scheme, qsizetype schemeLength)
635 const qsizetype urlLength = url.size();
637 if (urlLength < schemeLength + 1)
640 if (!url.startsWith(QLatin1String(scheme, scheme + schemeLength), Qt::CaseInsensitive))
643 if (url[schemeLength] != QLatin1Char(
':'))
651 const qsizetype urlLength = url.size();
653 if (urlLength < schemeLength + 3)
656 const QLatin1Char slash(
'/');
657 if (url[schemeLength + 1] == slash && url[schemeLength + 2] == slash) {
659 if (urlLength < schemeLength + 4 || url[schemeLength + 3] != slash)
660 return schemeLength + 3;
666#if defined(Q_OS_ANDROID)
667static bool hasLocalContentAuthority(
const QString &url, qsizetype schemeLength)
669 const qsizetype offset = authorityOffset(url, schemeLength);
673 const QString authorityAndPath = url.sliced(offset);
674 return authorityAndPath.startsWith(QLatin1String(authority_externalstorage))
675 || authorityAndPath.startsWith(QLatin1String(authority_downloads_documents))
676 || authorityAndPath.startsWith(QLatin1String(authority_media_documents));
682
683
684
685
686
687
688
689bool QQmlFile::isLocalFile(
const QString &url)
694 switch (url[0].toLatin1()) {
700 const qsizetype fileLength = strlen(file_string);
701 return url.startsWith(QLatin1String(file_string, file_string + fileLength),
703 && url.size() > fileLength
704 && url[fileLength] == QLatin1Char(
':');
708 return hasScheme(url, qrc_string, strlen(qrc_string))
709 && authorityOffset(url, strlen(qrc_string)) == -1;
710#if defined(Q_OS_ANDROID)
713 return hasScheme(url, assets_string, strlen(assets_string))
714 && authorityOffset(url, strlen(assets_string)) == -1;
717 return hasScheme(url, content_string, strlen(content_string))
718 && hasLocalContentAuthority(url, strlen(content_string));
720#if defined(Q_OS_WASM)
723 return hasScheme(url, weblocalfile_string, strlen(weblocalfile_string));
733
734
735
736
737
738QString QQmlFile::urlToLocalFileOrQrc(
const QUrl& url)
740 if (url.scheme().compare(QLatin1String(
"qrc"), Qt::CaseInsensitive) == 0) {
741 if (url.authority().isEmpty())
742 return QLatin1Char(
':') + url.path();
746#if defined(Q_OS_ANDROID)
747 if (url.scheme().compare(QLatin1String(
"assets"), Qt::CaseInsensitive) == 0)
748 return url.authority().isEmpty() ? url.toString() : QString();
749 if (url.scheme().compare(QLatin1String(
"content"), Qt::CaseInsensitive) == 0) {
750 if (hasLocalContentAuthority(url))
751 return url.toString();
756#if defined(Q_OS_WASM)
757 if (url.scheme().compare(QLatin1String(
"weblocalfile"), Qt::CaseInsensitive) == 0)
758 return url.toString();
761 return url.toLocalFile();
766 const QUrl file(url);
767 if (!file.isLocalFile())
773 return file.toLocalFile();
778 const qsizetype urlLength = url.size();
779 if (urlLength < offset + 2)
782 const QLatin1Char slash(
'/');
783 if (url[offset] != slash || url[offset + 1] != slash)
786 if (urlLength < offset + 3)
789 return url[offset + 2] != slash;
793
794
795
796
797
798QString QQmlFile::urlToLocalFileOrQrc(
const QString& url)
800 if (url.startsWith(QLatin1String(
"qrc://"), Qt::CaseInsensitive)) {
803 if (url.size() == 6 || url[6] != QLatin1Char(
'/')) {
804 Q_ASSERT(isDoubleSlashed(url, strlen(
"qrc:")));
807 Q_ASSERT(!isDoubleSlashed(url, strlen(
"qrc:")));
808 return QLatin1Char(
':') + QStringView{url}.mid(6);
811 if (url.startsWith(QLatin1String(
"qrc:"), Qt::CaseInsensitive)) {
812 Q_ASSERT(!isDoubleSlashed(url, strlen(
"qrc:")));
814 return QLatin1Char(
':') + QStringView{url}.mid(4);
815 return QStringLiteral(
":");
818#if defined(Q_OS_ANDROID)
819 if (url.startsWith(QLatin1String(
"assets:"), Qt::CaseInsensitive))
820 return isDoubleSlashed(url, strlen(
"assets:")) ? QString() : url;
821 if (hasScheme(url, content_string, strlen(content_string)))
822 return hasLocalContentAuthority(url, strlen(content_string)) ? url : QString();
825#if defined(Q_OS_WASM)
826 if (hasScheme(url, weblocalfile_string, strlen(weblocalfile_string)))
830 return toLocalFile(url);
835#include "qqmlfile.moc"
Combined button and popup list for selecting options.
static QString toLocalFile(const QString &url)
static bool isDoubleSlashed(const QString &url, qsizetype offset)
static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
static char file_string[]
static bool hasScheme(const QString &url, const char *scheme, qsizetype schemeLength)