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 isLocalContentAuthority(QStringView authority)
585{
586 return authority.isEmpty()
587 || authority == QLatin1String(authority_externalstorage)
588 || authority == QLatin1String(authority_downloads_documents)
589 || authority == QLatin1String(authority_media_documents);
590}
591
592static bool hasLocalContentAuthority(const QUrl &url)
593{
594 return isLocalContentAuthority(url.authority());
595}
596#endif
597
598/*!
599 Returns \c true if \a url is a local file that can be opened with \l{QFile}.
600 Otherwise returns \c false. Local file urls have either a \c{qrc:} or
601 \c{file:} scheme.
602
603 \note On Android, urls with \c{assets:} or \c{content:} scheme are also
604 considered local files.
605*/
606bool QQmlFile::isLocalFile(const QUrl &url)
607{
608 QString scheme = url.scheme();
609
610 // file: URLs with two slashes following the scheme can be interpreted as local files
611 // where the slashes are part of the path. Therefore, disregard the authority.
612 // See QUrl::toLocalFile().
613 if (scheme.size() == 4 && scheme.startsWith(QLatin1String(file_string), Qt::CaseInsensitive))
614 return true;
615
616 if (scheme.size() == 3 && scheme.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive))
617 return url.authority().isEmpty();
618
619#if defined(Q_OS_ANDROID)
620 if (scheme.length() == 6
621 && scheme.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive))
622 return url.authority().isEmpty();
623 if (scheme.length() == 7
624 && scheme.startsWith(QLatin1String(content_string), Qt::CaseInsensitive))
625 return hasLocalContentAuthority(url);
626#endif
627
628#if defined(Q_OS_WASM)
629 if (scheme.length() == 12
630 && scheme.startsWith(QLatin1String(weblocalfile_string), Qt::CaseInsensitive))
631 return true;
632#endif
633
634 return false;
635}
636
637static bool hasScheme(const QString &url, const char *scheme, qsizetype schemeLength)
638{
639 const qsizetype urlLength = url.size();
640
641 if (urlLength < schemeLength + 1)
642 return false;
643
644 if (!url.startsWith(QLatin1String(scheme, scheme + schemeLength), Qt::CaseInsensitive))
645 return false;
646
647 if (url[schemeLength] != QLatin1Char(':'))
648 return false;
649
650 return true;
651}
652
653static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
654{
655 const qsizetype urlLength = url.size();
656
657 if (urlLength < schemeLength + 3)
658 return -1;
659
660 const QLatin1Char slash('/');
661 if (url[schemeLength + 1] == slash && url[schemeLength + 2] == slash) {
662 // Exactly two slashes denote an authority.
663 if (urlLength < schemeLength + 4 || url[schemeLength + 3] != slash)
664 return schemeLength + 3;
665 }
666
667 return -1;
668}
669
670#if defined(Q_OS_ANDROID)
671static bool hasLocalContentAuthority(const QString &url, qsizetype schemeLength)
672{
673 const qsizetype offset = authorityOffset(url, schemeLength);
674 if (offset == -1)
675 return true; // no authority is a local authority.
676
677 const qsizetype slash = url.indexOf(QLatin1Char('/'), offset);
678 const qsizetype end = slash == -1 ? url.size() : slash;
679 const QStringView authority = QStringView(url).sliced(offset, end - offset);
680 return isLocalContentAuthority(authority);
681}
682
683#endif
684
685/*!
686 Returns \c true if \a url is a local file that can be opened with \l{QFile}.
687 Otherwise returns \c false. Local file urls have either a \c{qrc:} or
688 \c{file:} scheme.
689
690 \note On Android, urls with \c{assets:} or \c{content:} scheme are also considered
691 local files.
692*/
693bool QQmlFile::isLocalFile(const QString &url)
694{
695 if (url.size() < 4 /* qrc: */)
696 return false;
697
698 switch (url[0].toLatin1()) {
699 case 'f':
700 case 'F': {
701 // file: URLs with two slashes following the scheme can be interpreted as local files
702 // where the slashes are part of the path. Therefore, disregard the authority.
703 // See QUrl::toLocalFile().
704 const qsizetype fileLength = strlen(file_string);
705 return url.startsWith(QLatin1String(file_string, file_string + fileLength),
706 Qt::CaseInsensitive)
707 && url.size() > fileLength
708 && url[fileLength] == QLatin1Char(':');
709 }
710 case 'q':
711 case 'Q':
712 return hasScheme(url, qrc_string, strlen(qrc_string))
713 && authorityOffset(url, strlen(qrc_string)) == -1;
714#if defined(Q_OS_ANDROID)
715 case 'a':
716 case 'A':
717 return hasScheme(url, assets_string, strlen(assets_string))
718 && authorityOffset(url, strlen(assets_string)) == -1;
719 case 'c':
720 case 'C':
721 return hasScheme(url, content_string, strlen(content_string))
722 && hasLocalContentAuthority(url, strlen(content_string));
723#endif
724#if defined(Q_OS_WASM)
725 case 'w':
726 case 'W':
727 return hasScheme(url, weblocalfile_string, strlen(weblocalfile_string));
728#endif
729 default:
730 break;
731 }
732
733 return false;
734}
735
736/*!
737 If \a url is a local file returns a path suitable for passing to \l{QFile}.
738 Otherwise returns an empty string.
739
740 \sa isLocalFile
741*/
742QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
743{
744 if (url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive) == 0) {
745 if (url.authority().isEmpty())
746 return QLatin1Char(':') + url.path();
747 return QString();
748 }
749
750#if defined(Q_OS_ANDROID)
751 if (url.scheme().compare(QLatin1String(assets_string), Qt::CaseInsensitive) == 0)
752 return url.authority().isEmpty() ? url.toString() : QString();
753 if (url.scheme().compare(QLatin1String(content_string), Qt::CaseInsensitive) == 0) {
754 if (hasLocalContentAuthority(url))
755 return url.toString();
756 return QString();
757 }
758#endif
759
760#if defined(Q_OS_WASM)
761 if (url.scheme().compare(QLatin1String("weblocalfile"), Qt::CaseInsensitive) == 0)
762 return url.toString();
763#endif
764
765 return url.toLocalFile();
766}
767
768static QString toLocalFile(const QString &url)
769{
770 const QUrl file(url);
771 if (!file.isLocalFile())
772 return QString();
773
774 // QUrl::toLocalFile() interprets two slashes as part of the path.
775 // Therefore windows hostnames like "//servername/path/to/file.txt" are preserved.
776
777 return file.toLocalFile();
778}
779
780static bool isDoubleSlashed(const QString &url, qsizetype offset)
781{
782 const qsizetype urlLength = url.size();
783 if (urlLength < offset + 2)
784 return false;
785
786 const QLatin1Char slash('/');
787 if (url[offset] != slash || url[offset + 1] != slash)
788 return false;
789
790 if (urlLength < offset + 3)
791 return true;
792
793 return url[offset + 2] != slash;
794}
795
796/*!
797 If \a url is a local file returns a path suitable for passing to \l{QFile}.
798 Otherwise returns an empty string.
799
800 \sa isLocalFile
801*/
802QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
803{
804 if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) {
805 // Exactly two slashes are bad because that's a URL authority.
806 // One slash is fine and >= 3 slashes are file.
807 if (url.size() == 6 || url[6] != QLatin1Char('/')) {
808 Q_ASSERT(isDoubleSlashed(url, strlen("qrc:")));
809 return QString();
810 }
811 Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
812 return QLatin1Char(':') + QStringView{url}.mid(6);
813 }
814
815 if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
816 Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
817 if (url.size() > 4)
818 return QLatin1Char(':') + QStringView{url}.mid(4);
819 return QStringLiteral(":");
820 }
821
822#if defined(Q_OS_ANDROID)
823 if (hasScheme(url, assets_string, strlen(assets_string)))
824 return authorityOffset(url, strlen(assets_string)) == -1 ? url : QString();
825 if (hasScheme(url, content_string, strlen(content_string)))
826 return hasLocalContentAuthority(url, strlen(content_string)) ? url : QString();
827#endif
828
829#if defined(Q_OS_WASM)
830 if (hasScheme(url, weblocalfile_string, strlen(weblocalfile_string)))
831 return url;
832#endif
833
834 return toLocalFile(url);
835}
836
837QT_END_NAMESPACE
838
839#include "qqmlfile.moc"
Combined button and popup list for selecting options.
static QString toLocalFile(const QString &url)
Definition qqmlfile.cpp:768
static bool isDoubleSlashed(const QString &url, qsizetype offset)
Definition qqmlfile.cpp:780
static qsizetype authorityOffset(const QString &url, qsizetype schemeLength)
Definition qqmlfile.cpp:653
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:637