1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#ifndef QQMLDATABLOB_P_H
41#define QQMLDATABLOB_P_H
42
43//
44// W A R N I N G
45// -------------
46//
47// This file is not part of the Qt API. It exists purely as an
48// implementation detail. This header file may change from version to
49// version without notice, or even be removed.
50//
51// We mean it.
52//
53
54#include <private/qqmlrefcount_p.h>
55#include <private/qqmljsdiagnosticmessage_p.h>
56#include <private/qv4compileddata_p.h>
57
58#if QT_CONFIG(qml_network)
59#include <QtNetwork/qnetworkreply.h>
60#endif
61
62#include <QtQml/qqmlerror.h>
63#include <QtQml/qqmlabstracturlinterceptor.h>
64
65#include <QtCore/qdatetime.h>
66#include <QtCore/qfileinfo.h>
67#include <QtCore/qurl.h>
68
69QT_BEGIN_NAMESPACE
70
71class QQmlTypeLoader;
72class Q_QML_PRIVATE_EXPORT QQmlDataBlob : public QQmlRefCount
73{
74public:
75 enum Status {
76 Null, // Prior to QQmlTypeLoader::load()
77 Loading, // Prior to data being received and dataReceived() being called
78 WaitingForDependencies, // While there are outstanding addDependency()s
79 ResolvingDependencies, // While resolving outstanding dependencies, to detect cycles
80 Complete, // Finished
81 Error // Error
82 };
83
84 enum Type { //Matched in QQmlAbstractUrlInterceptor
85 QmlFile = QQmlAbstractUrlInterceptor::QmlFile,
86 JavaScriptFile = QQmlAbstractUrlInterceptor::JavaScriptFile,
87 QmldirFile = QQmlAbstractUrlInterceptor::QmldirFile
88 };
89
90 QQmlDataBlob(const QUrl &, Type, QQmlTypeLoader* manager);
91 ~QQmlDataBlob() override;
92
93 void startLoading();
94
95 QQmlTypeLoader *typeLoader() const { return m_typeLoader; }
96
97 Type type() const;
98
99 Status status() const;
100 bool isNull() const;
101 bool isLoading() const;
102 bool isWaiting() const;
103 bool isComplete() const;
104 bool isError() const;
105 bool isCompleteOrError() const;
106
107 qreal progress() const;
108
109 QUrl url() const;
110 QString urlString() const;
111 QUrl finalUrl() const;
112 QString finalUrlString() const;
113
114 QList<QQmlError> errors() const;
115
116 class SourceCodeData {
117 public:
118 QString readAll(QString *error) const;
119 QDateTime sourceTimeStamp() const;
120 bool exists() const;
121 bool isEmpty() const;
122 private:
123 friend class QQmlDataBlob;
124 friend class QQmlTypeLoader;
125 QString inlineSourceCode;
126 QFileInfo fileInfo;
127 bool hasInlineSourceCode = false;
128 };
129
130protected:
131 // Can be called from within callbacks
132 void setError(const QQmlError &);
133 void setError(const QList<QQmlError> &errors);
134 void setError(const QQmlJS::DiagnosticMessage &error);
135 void setError(const QVector<QQmlJS::DiagnosticMessage> &errors);
136 void setError(const QString &description);
137 void addDependency(QQmlDataBlob *);
138
139 // Callbacks made in load thread
140 virtual void dataReceived(const SourceCodeData &) = 0;
141 virtual void initializeFromCachedUnit(const QV4::CompiledData::Unit*) = 0;
142 virtual void done();
143#if QT_CONFIG(qml_network)
144 virtual void networkError(QNetworkReply::NetworkError);
145#endif
146 virtual void dependencyError(QQmlDataBlob *);
147 virtual void dependencyComplete(QQmlDataBlob *);
148 virtual void allDependenciesDone();
149
150 // Callbacks made in main thread
151 virtual void downloadProgressChanged(qreal);
152 virtual void completed();
153
154protected:
155 // Manager that is currently fetching data for me
156 QQmlTypeLoader *m_typeLoader;
157
158private:
159 friend class QQmlTypeLoader;
160 friend class QQmlTypeLoaderThread;
161
162 void tryDone();
163 void cancelAllWaitingFor();
164 void notifyAllWaitingOnMe();
165 void notifyComplete(QQmlDataBlob *);
166
167 struct ThreadData {
168 private:
169 enum {
170 StatusMask = 0x0000FFFF,
171 StatusShift = 0,
172 ProgressMask = 0x00FF0000,
173 ProgressShift = 16,
174 AsyncMask = 0x80000000,
175 NoMask = 0
176 };
177
178 public:
179 inline ThreadData()
180 : _p(0)
181 {
182 }
183
184 inline QQmlDataBlob::Status status() const
185 {
186 return QQmlDataBlob::Status((_p.loadRelaxed() & StatusMask) >> StatusShift);
187 }
188
189 inline void setStatus(QQmlDataBlob::Status status)
190 {
191 while (true) {
192 int d = _p.loadRelaxed();
193 int nd = (d & ~StatusMask) | ((status << StatusShift) & StatusMask);
194 if (d == nd || _p.testAndSetOrdered(d, nd)) return;
195 }
196 }
197
198 inline bool isAsync() const
199 {
200 return _p.loadRelaxed() & AsyncMask;
201 }
202
203 inline void setIsAsync(bool v)
204 {
205 while (true) {
206 int d = _p.loadRelaxed();
207 int nd = (d & ~AsyncMask) | (v ? AsyncMask : NoMask);
208 if (d == nd || _p.testAndSetOrdered(d, nd)) return;
209 }
210 }
211
212 inline quint8 progress() const
213 {
214 return quint8((_p.loadRelaxed() & ProgressMask) >> ProgressShift);
215 }
216
217 inline void setProgress(quint8 v)
218 {
219 while (true) {
220 int d = _p.loadRelaxed();
221 int nd = (d & ~ProgressMask) | ((v << ProgressShift) & ProgressMask);
222 if (d == nd || _p.testAndSetOrdered(d, nd)) return;
223 }
224 }
225
226 private:
227 QAtomicInt _p;
228 };
229 ThreadData m_data;
230
231 // m_errors should *always* be written before the status is set to Error.
232 // We use the status change as a memory fence around m_errors so that locking
233 // isn't required. Once the status is set to Error (or Complete), m_errors
234 // cannot be changed.
235 QList<QQmlError> m_errors;
236
237 Type m_type;
238
239 QUrl m_url;
240 QUrl m_finalUrl;
241 mutable QString m_urlString;
242 mutable QString m_finalUrlString;
243
244 // List of QQmlDataBlob's that are waiting for me to complete.
245 QList<QQmlDataBlob *> m_waitingOnMe;
246
247 // List of QQmlDataBlob's that I am waiting for to complete.
248 QVector<QQmlRefPointer<QQmlDataBlob>> m_waitingFor;
249
250 int m_redirectCount:30;
251 bool m_inCallback:1;
252 bool m_isDone:1;
253};
254
255QT_END_NAMESPACE
256
257#endif // QQMLDATABLOB_P_H
258