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