Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlfile.cpp
Go to the documentation of this file.
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// Qt-Security score:significant
4
5#include "qqmlfile.h"
6
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>
13
15
16/*!
17 \class QQmlFile
18 \inmodule QtQml
19 \since 5.0
20 \brief The QQmlFile class provides static utility methods to categorize URLs.
21
22 QQmlFile provides some static utility methods to categorize URLs
23 and file names the way \l{QQmlEngine} does when loading content from them.
24*/
25
26static char qrc_string[] = "qrc";
27static char file_string[] = "file";
28
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";
35#endif
36
37#if defined(Q_OS_WASM)
38static char weblocalfile_string[] = "weblocalfile";
39#endif
40
41#if QT_DEPRECATED_SINCE(6, 11)
42QT_WARNING_PUSH
43QT_WARNING_DISABLE_DEPRECATED
44
45/*!
46 \internal
47 \deprecated [6.11]
48
49 \enum QQmlFile::Status
50 \value Null
51 \value Ready
52 \value Error
53 \value Loading
54 */
55
56class QQmlFilePrivate;
57
58#if QT_CONFIG(qml_network)
59class QQmlFileNetworkReply : public QObject
60{
61Q_OBJECT
62public:
63 QQmlFileNetworkReply(QQmlEngine *, QQmlFilePrivate *, const QUrl &);
64 ~QQmlFileNetworkReply();
65
66signals:
67 void finished();
68 void downloadProgress(qint64, qint64);
69
70public slots:
71 void networkFinished();
72 void networkDownloadProgress(qint64, qint64);
73
74public:
75 static int finishedIndex;
76 static int downloadProgressIndex;
77 static int networkFinishedIndex;
78 static int networkDownloadProgressIndex;
79 static int replyFinishedIndex;
80 static int replyDownloadProgressIndex;
81
82private:
83 QQmlEngine *m_engine;
84 QQmlFilePrivate *m_p;
85
86 QNetworkReply *m_reply;
87};
88#endif
89
90class QQmlFilePrivate
91{
92public:
93 QQmlFilePrivate();
94
95 mutable QUrl url;
96 mutable QString urlString;
97
98 QByteArray data;
99
100 enum Error {
101 None, NotFound, Network
102 };
103
104 Error error;
105 QString errorString;
106#if QT_CONFIG(qml_network)
107 QQmlFileNetworkReply *reply;
108#endif
109};
110
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;
118
119QQmlFileNetworkReply::QQmlFileNetworkReply(QQmlEngine *e, QQmlFilePrivate *p, const QUrl &url)
120: m_engine(e), m_p(p), m_reply(nullptr)
121{
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)");
128
129 replyFinishedIndex = QMetaMethod::fromSignal(&QNetworkReply::finished).methodIndex();
130 replyDownloadProgressIndex = QMetaMethod::fromSignal(&QNetworkReply::downloadProgress).methodIndex();
131 }
132 Q_ASSERT(finishedIndex != -1 && downloadProgressIndex != -1 &&
133 networkFinishedIndex != -1 && networkDownloadProgressIndex != -1 &&
134 replyFinishedIndex != -1 && replyDownloadProgressIndex != -1);
135
136 QNetworkRequest req(url);
137 req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true);
138
139 m_reply = m_engine->networkAccessManager()->get(req);
140 QMetaObject::connect(m_reply, replyFinishedIndex, this, networkFinishedIndex);
141 QMetaObject::connect(m_reply, replyDownloadProgressIndex, this, networkDownloadProgressIndex);
142}
143
144QQmlFileNetworkReply::~QQmlFileNetworkReply()
145{
146 if (m_reply) {
147 m_reply->disconnect();
148 m_reply->deleteLater();
149 }
150}
151
152void QQmlFileNetworkReply::networkFinished()
153{
154 if (m_reply->error()) {
155 m_p->errorString = m_reply->errorString();
156 m_p->error = QQmlFilePrivate::Network;
157 } else {
158 m_p->data = m_reply->readAll();
159 }
160
161 m_reply->deleteLater();
162 m_reply = nullptr;
163
164 m_p->reply = nullptr;
165 emit finished();
166 delete this;
167}
168
169void QQmlFileNetworkReply::networkDownloadProgress(qint64 a, qint64 b)
170{
171 emit downloadProgress(a, b);
172}
173#endif // qml_network
174
175QQmlFilePrivate::QQmlFilePrivate()
176: error(None)
177#if QT_CONFIG(qml_network)
178, reply(nullptr)
179#endif
180{
181}
182
183/*!
184 \internal
185 */
186QQmlFile::QQmlFile()
187: d(new QQmlFilePrivate)
188{
189}
190
191/*!
192 \internal
193 Constructs a QQmlFile for content at \a url, using \a engine to retrieve it.
194 */
195QQmlFile::QQmlFile(QQmlEngine *engine, const QUrl &url)
196: d(new QQmlFilePrivate)
197{
198 load(engine, url);
199}
200
201/*!
202 \internal
203 Constructs a QQmlFile for content at \a url, using \a engine to retrieve it.
204 */
205QQmlFile::QQmlFile(QQmlEngine *engine, const QString &url)
206 : QQmlFile(engine, QUrl(url))
207{
208}
209
210/*!
211 \internal
212 */
213QQmlFile::~QQmlFile()
214{
215#if QT_CONFIG(qml_network)
216 delete d->reply;
217#endif
218 delete d;
219 d = nullptr;
220}
221
222/*!
223 \internal
224 */
225bool QQmlFile::isNull() const
226{
227 return status() == Null;
228}
229
230/*!
231 \internal
232 */
233bool QQmlFile::isReady() const
234{
235 return status() == Ready;
236}
237
238/*!
239 \internal
240 */
241bool QQmlFile::isError() const
242{
243 return status() == Error;
244}
245
246/*!
247 \internal
248 */
249bool QQmlFile::isLoading() const
250{
251 return status() == Loading;
252}
253
254/*!
255 \internal
256 */
257QUrl QQmlFile::url() const
258{
259 if (!d->urlString.isEmpty()) {
260 d->url = QUrl(d->urlString);
261 d->urlString = QString();
262 }
263 return d->url;
264}
265
266/*!
267 \internal
268 */
269QQmlFile::Status QQmlFile::status() const
270{
271 if (d->url.isEmpty() && d->urlString.isEmpty())
272 return Null;
273#if QT_CONFIG(qml_network)
274 else if (d->reply)
275 return Loading;
276#endif
277 else if (d->error != QQmlFilePrivate::None)
278 return Error;
279 else
280 return Ready;
281}
282
283/*!
284 \internal
285 \deprecated [6.11]
286 */
287QString QQmlFile::error() const
288{
289 switch (d->error) {
290 default:
291 case QQmlFilePrivate::None:
292 return QString();
293 case QQmlFilePrivate::NotFound:
294 return QLatin1String("File not found");
295 }
296}
297
298/*!
299 \internal
300 \deprecated [6.11]
301 */
302qint64 QQmlFile::size() const
303{
304 return d->data.size();
305}
306
307/*!
308 \internal
309 \deprecated [6.11]
310 */
311const char *QQmlFile::data() const
312{
313 return d->data.constData();
314}
315
316/*!
317 \internal
318 \deprecated [6.11]
319 */
320QByteArray QQmlFile::dataByteArray() const
321{
322 return d->data;
323}
324
325/*!
326 \internal
327 \deprecated [6.11]
328
329 Loads content at \a url using \a engine.
330 */
331void QQmlFile::load(QQmlEngine *engine, const QUrl &url)
332{
333 Q_ASSERT(engine);
334
335 clear();
336 d->url = url;
337
338 if (isLocalFile(url)) {
339 const QString lf = urlToLocalFileOrQrc(url);
340 if (!QQmlTypeLoader::get(engine)->fileExists(lf)) {
341 d->error = QQmlFilePrivate::NotFound;
342 return;
343 }
344
345 QFile file(lf);
346 if (file.open(QFile::ReadOnly)) {
347 d->data = file.readAll();
348 } else {
349 d->error = QQmlFilePrivate::NotFound;
350 }
351 } else {
352#if QT_CONFIG(qml_network)
353 d->reply = new QQmlFileNetworkReply(engine, d, url);
354#else
355 d->error = QQmlFilePrivate::NotFound;
356#endif
357 }
358}
359
360/*!
361 \internal
362 \deprecated [6.11]
363
364 Loads content at \a url using \a engine.
365 */
366void QQmlFile::load(QQmlEngine *engine, const QString &url)
367{
368 Q_ASSERT(engine);
369
370 clear();
371
372 d->urlString = url;
373
374 if (isLocalFile(url)) {
375 const QString lf = urlToLocalFileOrQrc(url);
376 if (!QQmlTypeLoader::get(engine)->fileExists(lf)) {
377 d->error = QQmlFilePrivate::NotFound;
378 return;
379 }
380
381 QFile file(lf);
382 if (file.open(QFile::ReadOnly)) {
383 d->data = file.readAll();
384 } else {
385 d->error = QQmlFilePrivate::NotFound;
386 }
387 } else {
388#if QT_CONFIG(qml_network)
389 QUrl qurl(url);
390 d->url = qurl;
391 d->urlString = QString();
392 d->reply = new QQmlFileNetworkReply(engine, d, qurl);
393#else
394 d->error = QQmlFilePrivate::NotFound;
395#endif
396 }
397}
398
399/*!
400 \internal
401 \deprecated [6.11]
402 */
403void QQmlFile::clear()
404{
405 d->url = QUrl();
406 d->urlString = QString();
407 d->data = QByteArray();
408 d->error = QQmlFilePrivate::None;
409}
410
411/*!
412 \internal
413 \deprecated [6.11]
414
415 Redirects to the other clear() overload, ignoring \a object.
416 */
417void QQmlFile::clear(QObject *object)
418{
419 Q_UNUSED(object);
420 clear();
421}
422
423#if QT_CONFIG(qml_network)
424
425/*!
426 \internal
427 Connects \a method of \a object to the internal \c{finished} signal.
428 */
429bool QQmlFile::connectFinished(QObject *object, const char *method)
430{
431 if (!d || !d->reply) {
432 qWarning("QQmlFile: connectFinished() called when not loading.");
433 return false;
434 }
435
436 return QObject::connect(d->reply, SIGNAL(finished()), object, method);
437}
438
439/*!
440 \internal
441 \deprecated [6.11]
442
443 Connects \a method of \a object to the internal \c{finished} signal.
444 */
445bool QQmlFile::connectFinished(QObject *object, int method)
446{
447 if (!d || !d->reply) {
448 qWarning("QQmlFile: connectFinished() called when not loading.");
449 return false;
450 }
451
452 return QMetaObject::connect(d->reply, QQmlFileNetworkReply::finishedIndex,
453 object, method);
454}
455
456/*!
457 \internal
458 \deprecated [6.11]
459
460 Connects \a method of \a object to the internal \c{downloadProgress} signal.
461 */
462bool QQmlFile::connectDownloadProgress(QObject *object, const char *method)
463{
464 if (!d || !d->reply) {
465 qWarning("QQmlFile: connectDownloadProgress() called when not loading.");
466 return false;
467 }
468
469 return QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)),
470 object, method);
471}
472
473/*!
474 \internal
475 \deprecated [6.11]
476
477 Connects \a method of \a object to the internal \c{downloadProgress} signal.
478 */
479bool QQmlFile::connectDownloadProgress(QObject *object, int method)
480{
481 if (!d || !d->reply) {
482 qWarning("QQmlFile: connectDownloadProgress() called when not loading.");
483 return false;
484 }
485
486 return QMetaObject::connect(d->reply, QQmlFileNetworkReply::downloadProgressIndex,
487 object, method);
488}
489#endif
490
491QT_WARNING_POP
492#endif // QT_DEPRECATED_SINCE(6, 11)
493
494/*!
495 \internal
496
497 Returns \c true if QQmlFile will open \a url synchronously.
498 Otherwise returns \c false. Synchronous urls have a \c{qrc:} or \c{file:}
499 scheme.
500
501 \note On Android, urls with \c{assets:} or \c{content:} scheme are also
502 considered synchronous.
503*/
504bool QQmlFile::isSynchronous(const QUrl &url)
505{
506 QString scheme = url.scheme();
507
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))) {
510 return true;
511
512#if defined(Q_OS_ANDROID)
513 } else if (scheme.length() == 6 && 0 == scheme.compare(QLatin1String(assets_string), Qt::CaseInsensitive)) {
514 return true;
515 } else if (scheme.length() == 7 && 0 == scheme.compare(QLatin1String(content_string), Qt::CaseInsensitive)) {
516 return true;
517#endif
518
519#if defined(Q_OS_WASM)
520 } else if (scheme.length() == 12 && 0 == scheme.compare(QLatin1String(weblocalfile_string), Qt::CaseInsensitive)) {
521 return true;
522#endif
523
524 } else {
525 return false;
526 }
527}
528
529/*!
530 \internal
531
532 Returns \c true if QQmlFile will open \a url synchronously.
533 Otherwise returns \c false. Synchronous urls have a \c{qrc:} or \c{file:}
534 scheme.
535
536 \note On Android, urls with \c{assets:} or \c{content:} scheme are also
537 considered synchronous.
538*/
539bool QQmlFile::isSynchronous(const QString &url)
540{
541 if (url.size() < 5 /* qrc:/ */)
542 return false;
543
544 QChar f = url[0];
545
546 if (f == QLatin1Char('f') || f == QLatin1Char('F')) {
547
548 return url.size() >= 7 /* file:// */ &&
549 url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
550 url[4] == QLatin1Char(':') && url[5] == QLatin1Char('/') && url[6] == QLatin1Char('/');
551
552 } else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
553
554 return url.size() >= 5 /* qrc:/ */ &&
555 url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
556 url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
557
558 }
559
560#if defined(Q_OS_ANDROID)
561 else if (f == QLatin1Char('a') || f == QLatin1Char('A')) {
562 return url.length() >= 8 /* assets:/ */ &&
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 /* content:/ */ &&
567 url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
568 url[7] == QLatin1Char(':') && url[8] == QLatin1Char('/');
569 }
570#endif
571
572#if defined(Q_OS_WASM)
573 else if (f == QLatin1Char('w') || f == QLatin1Char('W')) {
574 return url.length() >= 14 /* weblocalfile:/ */ &&
575 url.startsWith(QLatin1String(weblocalfile_string), Qt::CaseInsensitive) &&
576 url[12] == QLatin1Char(':') && url[13] == QLatin1Char('/');
577 }
578#endif
579
580 return false;
581}
582
583#if defined(Q_OS_ANDROID)
584static bool hasLocalContentAuthority(const QUrl &url)
585{
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);
591}
592#endif
593
594/*!
595 Returns \c true if \a url is a local file that can be opened with \l{QFile}.
596 Otherwise returns \c false. Local file urls have either a \c{qrc:} or
597 \c{file:} scheme.
598
599 \note On Android, urls with \c{assets:} or \c{content:} scheme are also
600 considered local files.
601*/
602bool QQmlFile::isLocalFile(const QUrl &url)
603{
604 QString scheme = url.scheme();
605
606 // file: URLs with two slashes following the scheme can be interpreted as local files
607 // where the slashes are part of the path. Therefore, disregard the authority.
608 // See QUrl::toLocalFile().
609 if (scheme.size() == 4 && scheme.startsWith(QLatin1String(file_string), Qt::CaseInsensitive))
610 return true;
611
612 if (scheme.size() == 3 && scheme.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive))
613 return url.authority().isEmpty();
614
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);
622#endif
623
624#if defined(Q_OS_WASM)
625 if (scheme.length() == 12
626 && scheme.startsWith(QLatin1String(weblocalfile_string), Qt::CaseInsensitive))
627 return true;
628#endif
629
630 return false;
631}
632
633static bool hasScheme(const QString &url, const char *scheme, qsizetype schemeLength)
634{
635 const qsizetype urlLength = url.size();
636
637 if (urlLength < schemeLength + 1)
638 return false;
639
640 if (!url.startsWith(QLatin1String(scheme, scheme + schemeLength), Qt::CaseInsensitive))
641 return false;
642
643 if (url[schemeLength] != QLatin1Char(':'))
644 return false;
645
646 return true;
647}
648
649static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
650{
651 const qsizetype urlLength = url.size();
652
653 if (urlLength < schemeLength + 3)
654 return -1;
655
656 const QLatin1Char slash('/');
657 if (url[schemeLength + 1] == slash && url[schemeLength + 2] == slash) {
658 // Exactly two slashes denote an authority.
659 if (urlLength < schemeLength + 4 || url[schemeLength + 3] != slash)
660 return schemeLength + 3;
661 }
662
663 return -1;
664}
665
666#if defined(Q_OS_ANDROID)
667static bool hasLocalContentAuthority(const QString &url, qsizetype schemeLength)
668{
669 const qsizetype offset = authorityOffset(url, schemeLength);
670 if (offset == -1)
671 return true; // no authority is a local authority.
672
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));
677}
678
679#endif
680
681/*!
682 Returns \c true if \a url is a local file that can be opened with \l{QFile}.
683 Otherwise returns \c false. Local file urls have either a \c{qrc:} or
684 \c{file:} scheme.
685
686 \note On Android, urls with \c{assets:} or \c{content:} scheme are also considered
687 local files.
688*/
689bool QQmlFile::isLocalFile(const QString &url)
690{
691 if (url.size() < 4 /* qrc: */)
692 return false;
693
694 switch (url[0].toLatin1()) {
695 case 'f':
696 case 'F': {
697 // file: URLs with two slashes following the scheme can be interpreted as local files
698 // where the slashes are part of the path. Therefore, disregard the authority.
699 // See QUrl::toLocalFile().
700 const qsizetype fileLength = strlen(file_string);
701 return url.startsWith(QLatin1String(file_string, file_string + fileLength),
702 Qt::CaseInsensitive)
703 && url.size() > fileLength
704 && url[fileLength] == QLatin1Char(':');
705 }
706 case 'q':
707 case 'Q':
708 return hasScheme(url, qrc_string, strlen(qrc_string))
709 && authorityOffset(url, strlen(qrc_string)) == -1;
710#if defined(Q_OS_ANDROID)
711 case 'a':
712 case 'A':
713 return hasScheme(url, assets_string, strlen(assets_string))
714 && authorityOffset(url, strlen(assets_string)) == -1;
715 case 'c':
716 case 'C':
717 return hasScheme(url, content_string, strlen(content_string))
718 && hasLocalContentAuthority(url, strlen(content_string));
719#endif
720#if defined(Q_OS_WASM)
721 case 'w':
722 case 'W':
723 return hasScheme(url, weblocalfile_string, strlen(weblocalfile_string));
724#endif
725 default:
726 break;
727 }
728
729 return false;
730}
731
732/*!
733 If \a url is a local file returns a path suitable for passing to \l{QFile}.
734 Otherwise returns an empty string.
735
736 \sa isLocalFile
737*/
738QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
739{
740 if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) {
741 if (url.authority().isEmpty())
742 return QLatin1Char(':') + url.path();
743 return QString();
744 }
745
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();
752 return QString();
753 }
754#endif
755
756#if defined(Q_OS_WASM)
757 if (url.scheme().compare(QLatin1String("weblocalfile"), Qt::CaseInsensitive) == 0)
758 return url.toString();
759#endif
760
761 return url.toLocalFile();
762}
763
764static QString toLocalFile(const QString &url)
765{
766 const QUrl file(url);
767 if (!file.isLocalFile())
768 return QString();
769
770 // QUrl::toLocalFile() interprets two slashes as part of the path.
771 // Therefore windows hostnames like "//servername/path/to/file.txt" are preserved.
772
773 return file.toLocalFile();
774}
775
776static bool isDoubleSlashed(const QString &url, qsizetype offset)
777{
778 const qsizetype urlLength = url.size();
779 if (urlLength < offset + 2)
780 return false;
781
782 const QLatin1Char slash('/');
783 if (url[offset] != slash || url[offset + 1] != slash)
784 return false;
785
786 if (urlLength < offset + 3)
787 return true;
788
789 return url[offset + 2] != slash;
790}
791
792/*!
793 If \a url is a local file returns a path suitable for passing to \l{QFile}.
794 Otherwise returns an empty string.
795
796 \sa isLocalFile
797*/
798QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
799{
800 if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) {
801 // Exactly two slashes are bad because that's a URL authority.
802 // One slash is fine and >= 3 slashes are file.
803 if (url.size() == 6 || url[6] != QLatin1Char('/')) {
804 Q_ASSERT(isDoubleSlashed(url, strlen("qrc:")));
805 return QString();
806 }
807 Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
808 return QLatin1Char(':') + QStringView{url}.mid(6);
809 }
810
811 if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
812 Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
813 if (url.size() > 4)
814 return QLatin1Char(':') + QStringView{url}.mid(4);
815 return QStringLiteral(":");
816 }
817
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();
823#endif
824
825#if defined(Q_OS_WASM)
826 if (hasScheme(url, weblocalfile_string, strlen(weblocalfile_string)))
827 return url;
828#endif
829
830 return toLocalFile(url);
831}
832
833QT_END_NAMESPACE
834
835#include "qqmlfile.moc"
Combined button and popup list for selecting options.
static QString toLocalFile(const QString &url)
Definition qqmlfile.cpp:764
static bool isDoubleSlashed(const QString &url, qsizetype offset)
Definition qqmlfile.cpp:776
static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
Definition qqmlfile.cpp:649
static char qrc_string[]
Definition qqmlfile.cpp:26
static char file_string[]
Definition qqmlfile.cpp:27
static bool hasScheme(const QString &url, const char *scheme, qsizetype schemeLength)
Definition qqmlfile.cpp:633