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
qv4dataview.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
7#include "qv4symbol_p.h"
8
9#include <QtCore/private/qnumeric_p.h>
10#include "qendian.h"
11
12using namespace QV4;
13
16
17void Heap::DataViewCtor::init(QV4::ExecutionEngine *engine)
18{
19 Heap::FunctionObject::init(engine, QStringLiteral("DataView"));
20}
21
22static uint toIndex(ExecutionEngine *e, const Value &v)
23{
24 if (v.isUndefined())
25 return 0;
26 double index = v.toInteger();
27 if (index < 0) {
28 e->throwRangeError(QStringLiteral("index out of range"));
29 return 0;
30 }
31 uint idx = static_cast<uint>(index);
32 if (idx != index) {
33 e->throwRangeError(QStringLiteral("index out of range"));
34 return 0;
35 }
36 return idx;
37}
38
39ReturnedValue DataViewCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
40{
41 Scope scope(f->engine());
42 Scoped<SharedArrayBuffer> buffer(scope, argc ? argv[0] : Value::undefinedValue());
43 if (!newTarget || !buffer)
44 return scope.engine->throwTypeError();
45
46 uint offset = ::toIndex(scope.engine, argc > 1 ? argv[1] : Value::undefinedValue());
47 if (scope.hasException())
48 return Encode::undefined();
49 if (buffer->hasDetachedArrayData())
50 return scope.engine->throwTypeError();
51
52 uint bufferLength = buffer->arrayDataLength();
53 if (offset > bufferLength)
54 return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
55
56 uint byteLength = (argc < 3 || argv[2].isUndefined()) ? (bufferLength - offset) : ::toIndex(scope.engine, argv[2]);
57 if (scope.hasException())
58 return Encode::undefined();
59 if (offset > bufferLength || byteLength > bufferLength - offset)
60 return scope.engine->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
61
62 Scoped<DataView> a(scope, scope.engine->memoryManager->allocate<DataView>());
63 a->d()->buffer.set(scope.engine, buffer->d());
64 a->d()->byteLength = byteLength;
65 a->d()->byteOffset = offset;
66 return a.asReturnedValue();
67}
68
69ReturnedValue DataViewCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
70{
71 return f->engine()->throwTypeError();
72}
73
74void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
75{
76 Scope scope(engine);
77 ScopedObject o(scope);
78 ctor->defineReadonlyConfigurableProperty(engine->id_length(), Value::fromInt32(1));
79 ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
80 defineDefaultProperty(engine->id_constructor(), (o = ctor));
81 defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, nullptr);
82 defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
83 defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, nullptr);
84
85 defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 1);
86 defineDefaultProperty(QStringLiteral("getUint8"), method_getChar<unsigned char>, 1);
87 defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 1);
88 defineDefaultProperty(QStringLiteral("getUint16"), method_get<unsigned short>, 1);
89 defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 1);
90 defineDefaultProperty(QStringLiteral("getUint32"), method_get<unsigned int>, 1);
91 defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 1);
92 defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 1);
93
94 defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 2);
95 defineDefaultProperty(QStringLiteral("setUint8"), method_setChar<unsigned char>, 2);
96 defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 2);
97 defineDefaultProperty(QStringLiteral("setUint16"), method_set<unsigned short>, 2);
98 defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 2);
99 defineDefaultProperty(QStringLiteral("setUint32"), method_set<unsigned int>, 2);
100 defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 2);
101 defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 2);
102
103 ScopedString name(scope, engine->newString(QStringLiteral("DataView")));
104 defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
105
106 // For backword compatibility
107 defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 1);
108 defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 1);
109 defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 1);
110 defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 1);
111 defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 1);
112 defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 1);
113}
114
115ReturnedValue DataViewPrototype::method_get_buffer(const FunctionObject *b, const Value *thisObject, const Value *, int)
116{
117 const DataView *v = thisObject->as<DataView>();
118 if (!v)
119 return b->engine()->throwTypeError();
120
121 return v->d()->buffer->asReturnedValue();
122}
123
124ReturnedValue DataViewPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
125{
126 const DataView *v = thisObject->as<DataView>();
127 if (!v)
128 return b->engine()->throwTypeError();
129
130 if (v->d()->buffer->hasDetachedArrayData())
131 return b->engine()->throwTypeError();
132
133 return Encode(v->d()->byteLength);
134}
135
136ReturnedValue DataViewPrototype::method_get_byteOffset(const FunctionObject *b, const Value *thisObject, const Value *, int)
137{
138 const DataView *v = thisObject->as<DataView>();
139 if (!v)
140 return b->engine()->throwTypeError();
141
142 if (v->d()->buffer->hasDetachedArrayData())
143 return b->engine()->throwTypeError();
144
145 return Encode(v->d()->byteOffset);
146}
147
148template <typename T>
149ReturnedValue DataViewPrototype::method_getChar(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
150{
151 ExecutionEngine *e = b->engine();
152 const DataView *v = thisObject->as<DataView>();
153 if (!v)
154 return e->throwTypeError();
155 uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
156 if (e->hasException)
157 return Encode::undefined();
158 if (v->d()->buffer->hasDetachedArrayData())
159 return e->throwTypeError();
160 if (idx + sizeof(T) > v->d()->byteLength)
161 return e->throwRangeError(QStringLiteral("index out of range"));
162 idx += v->d()->byteOffset;
163
164 T t = T(v->d()->buffer->constArrayData()[idx]);
165
166 return Encode((int)t);
167}
168
169template <typename T>
170ReturnedValue DataViewPrototype::method_get(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
171{
172 ExecutionEngine *e = b->engine();
173 const DataView *v = thisObject->as<DataView>();
174 if (!v)
175 return e->throwTypeError();
176 uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
177 if (e->hasException)
178 return Encode::undefined();
179 if (v->d()->buffer->hasDetachedArrayData())
180 return e->throwTypeError();
181 if (idx + sizeof(T) > v->d()->byteLength)
182 return e->throwRangeError(QStringLiteral("index out of range"));
183 idx += v->d()->byteOffset;
184
185 bool littleEndian = argc < 2 ? false : argv[1].toBoolean();
186
187 T t = littleEndian
188 ? qFromLittleEndian<T>((const uchar *)v->d()->buffer->constArrayData() + idx)
189 : qFromBigEndian<T>((const uchar *)v->d()->buffer->constArrayData() + idx);
190
191 return Encode(t);
192}
193
194template <typename T>
195ReturnedValue DataViewPrototype::method_getFloat(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
196{
197 ExecutionEngine *e = b->engine();
198 const DataView *v = thisObject->as<DataView>();
199 if (!v)
200 return e->throwTypeError();
201 uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
202 if (e->hasException)
203 return Encode::undefined();
204 if (v->d()->buffer->hasDetachedArrayData())
205 return e->throwTypeError();
206 if (idx + sizeof(T) > v->d()->byteLength)
207 return e->throwRangeError(QStringLiteral("index out of range"));
208 idx += v->d()->byteOffset;
209
210 bool littleEndian = argc < 2 ? false : argv[1].toBoolean();
211
212 if (sizeof(T) == 4) {
213 // float
214 union {
215 uint i;
216 float f;
217 } u;
218 u.i = littleEndian
219 ? qFromLittleEndian<uint>((const uchar *)v->d()->buffer->constArrayData() + idx)
220 : qFromBigEndian<uint>((const uchar *)v->d()->buffer->constArrayData() + idx);
221 return Encode(u.f);
222 } else {
223 Q_ASSERT(sizeof(T) == 8);
224 union {
225 quint64 i;
226 double d;
227 } u;
228 u.i = littleEndian
229 ? qFromLittleEndian<quint64>((const uchar *)v->d()->buffer->constArrayData() + idx)
230 : qFromBigEndian<quint64>((const uchar *)v->d()->buffer->constArrayData() + idx);
231 return Encode(u.d);
232 }
233}
234
235template <typename T>
236ReturnedValue DataViewPrototype::method_setChar(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
237{
238 ExecutionEngine *e = b->engine();
239 const DataView *v = thisObject->as<DataView>();
240 if (!v)
241 return e->throwTypeError();
242 uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
243 if (e->hasException)
244 return Encode::undefined();
245
246 int val = argc >= 2 ? argv[1].toInt32() : 0;
247
248 if (v->d()->buffer->hasDetachedArrayData())
249 return e->throwTypeError();
250
251 if (idx + sizeof(T) > v->d()->byteLength)
252 return e->throwRangeError(QStringLiteral("index out of range"));
253 idx += v->d()->byteOffset;
254
255 v->d()->buffer->arrayData()[idx] = (char)val;
256
258}
259
260template <typename T>
261ReturnedValue DataViewPrototype::method_set(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
262{
263 ExecutionEngine *e = b->engine();
264 const DataView *v = thisObject->as<DataView>();
265 if (!v)
266 return e->throwTypeError();
267 uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
268 if (e->hasException)
269 return Encode::undefined();
270
271 int val = argc >= 2 ? argv[1].toInt32() : 0;
272 bool littleEndian = argc < 3 ? false : argv[2].toBoolean();
273
274 if (v->d()->buffer->hasDetachedArrayData())
275 return e->throwTypeError();
276
277 if (idx + sizeof(T) > v->d()->byteLength)
278 return e->throwRangeError(QStringLiteral("index out of range"));
279 idx += v->d()->byteOffset;
280
281
282 if (littleEndian)
283 qToLittleEndian<T>(val, (uchar *)v->d()->buffer->arrayData() + idx);
284 else
285 qToBigEndian<T>(val, (uchar *)v->d()->buffer->arrayData() + idx);
286
288}
289
290template <typename T>
291ReturnedValue DataViewPrototype::method_setFloat(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
292{
293 ExecutionEngine *e = b->engine();
294 const DataView *v = thisObject->as<DataView>();
295 if (!v)
296 return e->throwTypeError();
297 uint idx = ::toIndex(e, argc ? argv[0] : Value::undefinedValue());
298 if (e->hasException)
299 return Encode::undefined();
300
301 double val = argc >= 2 ? argv[1].toNumber() : qt_qnan();
302 bool littleEndian = argc < 3 ? false : argv[2].toBoolean();
303
304 if (v->d()->buffer->hasDetachedArrayData())
305 return e->throwTypeError();
306
307 if (idx + sizeof(T) > v->d()->byteLength)
308 return e->throwRangeError(QStringLiteral("index out of range"));
309 idx += v->d()->byteOffset;
310
311 if (sizeof(T) == 4) {
312 // float
313 union {
314 uint i;
315 float f;
316 } u;
317 u.f = val;
318 if (littleEndian)
319 qToLittleEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
320 else
321 qToBigEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
322 } else {
323 Q_ASSERT(sizeof(T) == 8);
324 union {
325 quint64 i;
326 double d;
327 } u;
328 u.d = val;
329 if (littleEndian)
330 qToLittleEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
331 else
332 qToBigEndian(u.i, (uchar *)v->d()->buffer->arrayData() + idx);
333 }
335}
static uint toIndex(ExecutionEngine *e, const Value &v)
DEFINE_OBJECT_VTABLE(DataViewCtor)
DEFINE_OBJECT_VTABLE(DataView)
#define RETURN_UNDEFINED()