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