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
qv4include.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 "qv4include_p.h"
7#include "qv4jscall_p.h"
8
9#include <QtQml/qjsengine.h>
10#if QT_CONFIG(qml_network)
11#include <QtNetwork/qnetworkrequest.h>
12#include <QtNetwork/qnetworkreply.h>
13#endif
14#include <QtCore/qfile.h>
15#include <QtQml/qqmlfile.h>
16
17#include <private/qqmlengine_p.h>
18#include <private/qqmlscriptblob_p.h>
19#include <private/qqmlscriptdata_p.h>
20#include <private/qv4context_p.h>
21#include <private/qv4engine_p.h>
22#include <private/qv4functionobject_p.h>
23#include <private/qv4script_p.h>
24
26
27QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4)
28{
29 QV4::Scope scope(v4);
30
31 // XXX It seems inefficient to create this object from scratch each time.
32 QV4::ScopedObject o(scope, v4->newObject());
33 QV4::ScopedString s(scope);
34 QV4::ScopedValue v(scope);
35 o->put((s = v4->newString(QStringLiteral("OK"))), (v = QV4::Value::fromInt32(Ok)));
36 o->put((s = v4->newString(QStringLiteral("LOADING"))), (v = QV4::Value::fromInt32(Loading)));
37 o->put((s = v4->newString(QStringLiteral("NETWORK_ERROR"))), (v = QV4::Value::fromInt32(NetworkError)));
38 o->put((s = v4->newString(QStringLiteral("EXCEPTION"))), (v = QV4::Value::fromInt32(Exception)));
39 return o.asReturnedValue();
40}
41
42void QV4Include::populateResultValue(QV4::Object *o, Status status, const QString &statusText)
43{
44 QV4::Scope scope(o->engine());
45 QV4::ScopedString statusKey(scope, scope.engine->newString(QStringLiteral("status")));
46 QV4::ScopedValue statusValue(scope, QV4::Value::fromInt32(status));
47 o->put(statusKey, statusValue);
48 if (statusText.isEmpty())
49 return;
50
51 QV4::ScopedString textKey(scope, scope.engine->newString(QStringLiteral("statusText")));
52 QV4::ScopedValue textValue(scope, scope.engine->newString(statusText));
53 o->put(textKey, textValue);
54}
55
56QV4Include::QV4Include(
57 QV4::Object *result, QV4::FunctionObject *callbackFunction, QV4::QmlContext *qmlContext)
58{
59 Q_ASSERT(result);
60 QV4::ExecutionEngine *engine = result->engine();
61 m_resultObject.set(engine, result->asReturnedValue());
62 if (callbackFunction)
63 m_callbackFunction.set(engine, callbackFunction->asReturnedValue());
64 if (qmlContext)
65 m_qmlContext.set(engine, qmlContext->asReturnedValue());
66}
67
68void QV4Include::callback(QV4::FunctionObject *callback, QV4::Object *result)
69{
70 if (!callback)
71 return;
72
73 QV4::Scope scope(callback->engine());
74 QV4::JSCallArguments jsCallData(scope, 1);
75 *jsCallData.thisObject = scope.engine->globalObject->asReturnedValue();
76 jsCallData.args[0] = result;
77 callback->call(jsCallData);
78 if (scope.hasException())
79 scope.engine->catchException();
80}
81
82/*
83 Documented in qv4engine.cpp
84*/
85QJSValue QV4Include::method_include(QV4::ExecutionEngine *engine, const QUrl &url,
86 const QJSValue &callbackFunction)
87{
88 QQmlRefPointer<QQmlContextData> context = engine->callingQmlContext();
89
90 if ((!context || !context->isJSContext()) && engine->qmlEngine()) {
91 return QJSValuePrivate::fromReturnedValue(
92 engine->throwError(
93 QString::fromUtf8(
94 "Qt.include(): Can only be called from JavaScript files")));
95 }
96
97 // The JavaScript compilation unit inherits its context when doing Qt.include().
98 // This means we need to turn fast lookups off at compile time.
99 // Signal this through the URL fragment.
100 QUrl includeUrl = url;
101 includeUrl.setFragment(QLatin1String("include"));
102 QQmlRefPointer<QQmlScriptBlob> scriptBlob = engine->typeLoader()->getScript(includeUrl);
103
104 QV4::Scope scope(engine);
105 QV4::ScopedObject result(scope, resultValue(engine));
106 QV4::ScopedFunctionObject callback(
107 scope, QJSValuePrivate::asReturnedValue(&callbackFunction));
108 QV4::Scoped<QV4::QmlContext> qmlContext(scope, scope.engine->qmlContext());
109
110 if (scriptBlob->isCompleteOrError()) {
111 processScriptBlob(scriptBlob.data(), result, callback, qmlContext);
112 return QJSValuePrivate::fromReturnedValue(result.asReturnedValue());
113 }
114
115 scriptBlob->registerCallback(new QV4Include(result, callback, qmlContext));
116 populateResultValue(result, Loading);
117 return QJSValuePrivate::fromReturnedValue(result.asReturnedValue());
118}
119
120void QV4Include::ready(QQmlNotifyingBlob *notifyingBlob)
121{
122 Q_ASSERT(notifyingBlob);
123 Q_ASSERT(notifyingBlob->type() == QQmlDataBlob::JavaScriptFile);
124
125 processScriptBlob(
126 static_cast<QQmlScriptBlob *>(notifyingBlob), m_resultObject.as<QV4::Object>(),
127 m_callbackFunction.as<QV4::FunctionObject>(), m_qmlContext.as<QV4::QmlContext>());
128
129 delete this;
130}
131
132void QV4Include::processScriptBlob(
133 QQmlScriptBlob *scriptBlob, QV4::Object *result, QV4::FunctionObject *callbackFunction,
134 QV4::QmlContext *qmlContext)
135{
136 Q_ASSERT(scriptBlob);
137 Q_ASSERT(result);
138
139 QV4::Scope scope(result->engine());
140
141 if (scriptBlob->isError()) {
142 const QList<QQmlError> errors = scriptBlob->errors();
143 Q_ASSERT(!errors.isEmpty());
144 const QString errorString = QLatin1String("Error opening source file %1: %2")
145 .arg(scriptBlob->finalUrlString(), errors[0].toString());
146 populateResultValue(result, NetworkError, errorString);
147 callback(callbackFunction, result);
148 return;
149 }
150
151 Q_ASSERT(scriptBlob->isComplete());
152 const auto cu = scope.engine->executableCompilationUnit(
153 scriptBlob->scriptData()->compilationUnit());
154 if (QV4::Function *vmFunction = cu->rootFunction()) {
155 QScopedValueRollback<QV4::Function *> savedGlobal(scope.engine->globalCode, vmFunction);
156 vmFunction->call(nullptr, nullptr, 0, qmlContext ? qmlContext : scope.engine->rootContext());
157 }
158
159 if (scope.hasException()) {
160 QV4::ScopedValue ex(scope, scope.engine->catchException());
161 populateResultValue(result, Exception);
162 QV4::ScopedString exception(scope, scope.engine->newString(QStringLiteral("exception")));
163 result->put(exception, ex);
164 } else {
165 populateResultValue(result, Ok);
166 }
167
168 callback(callbackFunction, result);
169}
170
171QT_END_NAMESPACE
Definition qjsvalue.h:23
Scoped< FunctionObject > ScopedFunctionObject
Scoped< Object > ScopedObject
Scoped< String > ScopedString
JSCallArguments(const Scope &scope, int argc=0)
Definition qv4jscall_p.h:60
Scope(ExecutionEngine *e)