Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qv4globalobject.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 "qv4globalobject_p.h"
5
6#include <private/qv4alloca_p.h>
7#include <private/qv4codegen_p.h>
8#include <private/qv4context_p.h>
9#include <private/qv4function_p.h>
10#include <private/qv4mm_p.h>
11#include <private/qv4scopedvalue_p.h>
12#include <private/qv4script_p.h>
13#include <private/qv4stackframe_p.h>
14#include <private/qv4string_p.h>
15#include <private/qv4value_p.h>
16
17#include <wtf/MathExtras.h>
18
19#include <QtCore/private/qlocale_tools_p.h>
20#include <QtCore/private/qtools_p.h>
21
22#include <QtCore/qdebug.h>
23#include <QtCore/qstring.h>
24
25#include <iostream>
26
27using namespace QV4;
30
32{
34 output.reserve(input.size() * 3);
35 const int length = input.size();
36 for (int i = 0; i < length; ++i) {
37 ushort uc = input.at(i).unicode();
38 if (uc < 0x100) {
39 if ( (uc > 0x60 && uc < 0x7B)
40 || (uc > 0x3F && uc < 0x5B)
41 || (uc > 0x2C && uc < 0x3A)
42 || (uc == 0x2A)
43 || (uc == 0x2B)
44 || (uc == 0x5F)) {
45 output.append(QChar(uc));
46 } else {
47 output.append(u'%');
48 output.append(QLatin1Char(toHexUpper(uc >> 4)));
49 output.append(QLatin1Char(toHexUpper(uc)));
50 }
51 } else {
52 output.append(u'%');
53 output.append(u'u');
54 output.append(QLatin1Char(toHexUpper(uc >> 12)));
55 output.append(QLatin1Char(toHexUpper(uc >> 8)));
56 output.append(QLatin1Char(toHexUpper(uc >> 4)));
57 output.append(QLatin1Char(toHexUpper(uc)));
58 }
59 }
60 return output;
61}
62
64{
66 result.reserve(input.size());
67 int i = 0;
68 const int length = input.size();
69 while (i < length) {
70 QChar c = input.at(i++);
71 if ((c == u'%') && (i + 1 < length)) {
72 QChar a = input.at(i);
73 if ((a == u'u') && (i + 4 < length)) {
74 int d3 = fromHex(input.at(i+1).unicode());
75 int d2 = fromHex(input.at(i+2).unicode());
76 int d1 = fromHex(input.at(i+3).unicode());
77 int d0 = fromHex(input.at(i+4).unicode());
78 if ((d3 != -1) && (d2 != -1) && (d1 != -1) && (d0 != -1)) {
79 ushort uc = ushort((d3 << 12) | (d2 << 8) | (d1 << 4) | d0);
80 result.append(QChar(uc));
81 i += 5;
82 } else {
83 result.append(c);
84 }
85 } else {
86 int d1 = fromHex(a.unicode());
87 int d0 = fromHex(input.at(i+1).unicode());
88 if ((d1 != -1) && (d0 != -1)) {
89 c = QChar((d1 << 4) | d0);
90 i += 2;
91 }
92 result.append(c);
93 }
94 } else {
95 result.append(c);
96 }
97 }
98 return result;
99}
100
101static const char uriReserved[] = ";/?:@&=+$,#";
102static const char uriUnescaped[] = "-_.!~*'()";
103static const char uriUnescapedReserved[] = "-_.!~*'();/?:@&=+$,#";
104
106{
107 output.append(QLatin1Char('%'));
108 output.append(QLatin1Char(toHexUpper(ch >> 4)));
109 output.append(QLatin1Char(toHexUpper(ch & 0xf)));
110}
111
112static QString encode(const QString &input, const char *unescapedSet, bool *ok)
113{
114 *ok = true;
116 const int length = input.size();
117 int i = 0;
118 while (i < length) {
119 const QChar c = input.at(i);
120 bool escape = true;
121 if ((c.unicode() >= 'a' && c.unicode() <= 'z') ||
122 (c.unicode() >= 'A' && c.unicode() <= 'Z') ||
123 (c.unicode() >= '0' && c.unicode() <= '9')) {
124 escape = false;
125 } else {
126 const char *r = unescapedSet;
127 while (*r) {
128 if (*r == c.unicode()) {
129 escape = false;
130 break;
131 }
132 ++r;
133 }
134 }
135 if (escape) {
136 uint uc = c.unicode();
137 if ((uc >= 0xDC00) && (uc <= 0xDFFF)) {
138 *ok = false;
139 break;
140 }
141 if (!((uc < 0xD800) || (uc > 0xDBFF))) {
142 ++i;
143 if (i == length) {
144 *ok = false;
145 break;
146 }
147 const uint uc2 = input.at(i).unicode();
148 if ((uc2 < 0xDC00) || (uc2 > 0xDFFF)) {
149 *ok = false;
150 break;
151 }
152 uc = ((uc - 0xD800) * 0x400) + (uc2 - 0xDC00) + 0x10000;
153 }
154 if (uc < 0x80) {
156 } else {
157 if (uc < 0x0800) {
158 addEscapeSequence(output, 0xc0 | ((uchar) (uc >> 6)));
159 } else {
160
161 if (QChar::requiresSurrogates(uc)) {
162 addEscapeSequence(output, 0xf0 | ((uchar) (uc >> 18)));
163 addEscapeSequence(output, 0x80 | (((uchar) (uc >> 12)) & 0x3f));
164 } else {
165 addEscapeSequence(output, 0xe0 | (((uchar) (uc >> 12)) & 0x3f));
166 }
167 addEscapeSequence(output, 0x80 | (((uchar) (uc >> 6)) & 0x3f));
168 }
169 addEscapeSequence(output, 0x80 | ((uchar) (uc&0x3f)));
170 }
171 } else {
172 output.append(c);
173 }
174 ++i;
175 }
176 if (i != length)
177 *ok = false;
178 return output;
179}
180
185
186static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
187{
188 *ok = true;
190 output.reserve(input.size());
191 const int length = input.size();
192 int i = 0;
193 const QChar percent = QLatin1Char('%');
194 while (i < length) {
195 const QChar ch = input.at(i);
196 if (ch == percent) {
197 int start = i;
198 if (i + 2 >= length)
199 goto error;
200
201 int d1 = fromHex(input.at(i+1).unicode());
202 int d0 = fromHex(input.at(i+2).unicode());
203 if ((d1 == -1) || (d0 == -1))
204 goto error;
205
206 int b = (d1 << 4) | d0;
207 i += 2;
208 if (b & 0x80) {
209 int uc;
210 int min_uc;
211 int need;
212 if ((b & 0xe0) == 0xc0) {
213 uc = b & 0x1f;
214 need = 1;
215 min_uc = 0x80;
216 } else if ((b & 0xf0) == 0xe0) {
217 uc = b & 0x0f;
218 need = 2;
219 min_uc = 0x800;
220 } else if ((b & 0xf8) == 0xf0) {
221 uc = b & 0x07;
222 need = 3;
223 min_uc = 0x10000;
224 } else {
225 goto error;
226 }
227
228 if (i + (3 * need) >= length)
229 goto error;
230
231 for (int j = 0; j < need; ++j) {
232 ++i;
233 if (input.at(i) != percent)
234 goto error;
235
236 d1 = fromHex(input.at(i+1).unicode());
237 d0 = fromHex(input.at(i+2).unicode());
238 if ((d1 == -1) || (d0 == -1))
239 goto error;
240
241 b = (d1 << 4) | d0;
242 if ((b & 0xC0) != 0x80)
243 goto error;
244
245 i += 2;
246 uc = (uc << 6) + (b & 0x3f);
247 }
248 if (uc < min_uc)
249 goto error;
250
251 if (uc < 0x10000) {
252 output.append(QChar(uc));
253 } else {
254 if (uc > 0x10FFFF)
255 goto error;
256
257 ushort l = ushort(((uc - 0x10000) & 0x3FF) + 0xDC00);
258 ushort h = ushort((((uc - 0x10000) >> 10) & 0x3FF) + 0xD800);
259 output.append(QChar(h));
260 output.append(QChar(l));
261 }
262 } else {
263 if (decodeMode == DecodeNonReserved && b <= 0x40) {
264 const char *r = uriReserved;
265 while (*r) {
266 if (*r == b)
267 break;
268 ++r;
269 }
270 if (*r)
271 output.append(QStringView{input}.mid(start, i - start + 1));
272 else
273 output.append(QChar(b));
274 } else {
275 output.append(QChar(b));
276 }
277 }
278 } else {
279 output.append(ch);
280 }
281 ++i;
282 }
283 if (i != length)
284 *ok = false;
285 return output;
286 error:
287 *ok = false;
288 return QString();
289}
290
292
294{
295 Scope s(engine);
296 Heap::FunctionObject::init(engine, s.engine->id_eval());
297 ScopedFunctionObject f(s, this);
298 f->defineReadonlyConfigurableProperty(s.engine->id_length(), Value::fromInt32(1));
299}
300
301ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc, bool directCall) const
302{
303 if (argc < 1)
304 return Encode::undefined();
305
306 ExecutionEngine *v4 = engine();
308
309 Scope scope(v4);
310 ScopedContext ctx(scope, v4->currentContext());
311
312 if (!directCall) {
313 // the context for eval should be the global scope
314 ctx = v4->scriptContext();
315 }
316
317 String *scode = argv[0].stringValue();
318 if (!scode)
319 return argv[0].asReturnedValue();
320
321 const QString code = scode->toQString();
322 bool inheritContext = !isStrict;
323
324 Script script(ctx, QV4::Compiler::ContextType::Eval, code, QStringLiteral("eval code"));
325 script.strictMode = (directCall && isStrict);
326 script.inheritContext = inheritContext;
327 script.parse();
328 if (v4->hasException)
329 return Encode::undefined();
330
331 Function *function = script.function();
332 if (!function)
333 return Encode::undefined();
334 function->kind = Function::Eval;
335
336 if (function->isStrict() || isStrict) {
338 ScopedValue thisObject(scope, directCall ? scope.engine->currentStackFrame->thisObject() : scope.engine->globalObject->asReturnedValue());
339 return checkedResult(v4, e->call(thisObject, nullptr, 0));
340 }
341
342 ScopedValue thisObject(scope, scope.engine->currentStackFrame->thisObject());
343
344 return checkedResult(v4, function->call(thisObject, nullptr, 0, ctx));
345}
346
347
348ReturnedValue EvalFunction::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
349{
350 // indirect call
351 return static_cast<const EvalFunction *>(f)->evalCall(thisObject, argv, argc, false);
352}
353
354
355static inline int toInt(const QChar &qc, int R)
356{
357 ushort c = qc.unicode();
358 int v = -1;
359 if (c >= '0' && c <= '9')
360 v = c - '0';
361 else if (c >= 'A' && c <= 'Z')
362 v = c - 'A' + 10;
363 else if (c >= 'a' && c <= 'z')
364 v = c - 'a' + 10;
365 if (v >= 0 && v < R)
366 return v;
367 else
368 return -1;
369}
370
371// parseInt [15.1.2.2]
373{
374 Scope scope(b);
375 ScopedValue inputString(scope, argc ? argv[0] : Value::undefinedValue());
376 ScopedValue radix(scope, argc > 1 ? argv[1] : Value::undefinedValue());
377 int R = radix->isUndefined() ? 0 : radix->toInt32();
378
379 // [15.1.2.2] step by step:
380 QString trimmed = inputString->toQString().trimmed(); // 1 + 2
382
383 const QChar *pos = trimmed.constData();
384 const QChar *end = pos + trimmed.size();
385
386 int sign = 1; // 3
387 if (pos != end) {
388 if (*pos == QLatin1Char('-'))
389 sign = -1; // 4
390 if (*pos == QLatin1Char('-') || *pos == QLatin1Char('+'))
391 ++pos; // 5
392 }
393 bool stripPrefix = true; // 7
394 if (R) { // 8
395 if (R < 2 || R > 36)
396 RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 8a
397 if (R != 16)
398 stripPrefix = false; // 8b
399 } else { // 9
400 R = 10; // 9a
401 }
402 if (stripPrefix) { // 10
403 if ((end - pos >= 2)
404 && (pos[0] == QLatin1Char('0'))
405 && (pos[1] == QLatin1Char('x') || pos[1] == QLatin1Char('X'))) { // 10a
406 pos += 2;
407 R = 16;
408 }
409 }
410 // 11: Z is progressively built below
411 // 13: this is handled by the toInt function
412 if (pos == end) // 12
413 RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN()));
414 bool overflow = false;
415 qint64 v_overflow = 0;
416 unsigned overflow_digit_count = 0;
417 int d = toInt(*pos++, R);
418 if (d == -1)
419 RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN()));
420 qint64 v = d;
421 while (pos != end) {
422 d = toInt(*pos++, R);
423 if (d == -1)
424 break;
425 if (overflow) {
426 if (overflow_digit_count == 0) {
427 v_overflow = v;
428 v = 0;
429 }
430 ++overflow_digit_count;
431 v = v * R + d;
432 } else {
433 qint64 vNew = v * R + d;
434 if (vNew < v) {
435 overflow = true;
436 --pos;
437 } else {
438 v = vNew;
439 }
440 }
441 }
442
443 if (overflow) {
444 double result = (double) v_overflow * pow(static_cast<double>(R), static_cast<double>(overflow_digit_count));
445 result += v;
447 } else {
448 RETURN_RESULT(Encode(sign * (double) v)); // 15
449 }
450}
451
452// parseFloat [15.1.2.3]
454{
455 Scope scope(b);
456 // [15.1.2.3] step by step:
457 ScopedString inputString(scope, argc ? argv[0] : Value::undefinedValue(), ScopedString::Convert);
459
460 QString trimmed = inputString->toQString().trimmed(); // 2
461
462 // 4:
463 if (trimmed.startsWith(QLatin1String("Infinity"))
464 || trimmed.startsWith(QLatin1String("+Infinity")))
466 if (trimmed.startsWith(QLatin1String("-Infinity")))
468 QByteArray ba = trimmed.toLatin1();
469 bool ok;
470 const char *begin = ba.constData();
471 const char *end = nullptr;
472 double d = qstrtod(begin, &end, &ok);
473 if (end - begin == 0)
474 RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 3
475 else
477}
478
481{
482 if (!argc)
483 // undefined gets converted to NaN
484 RETURN_RESULT(Encode(true));
485
486 if (argv[0].integerCompatible())
487 RETURN_RESULT(Encode(false));
488
489 double d = argv[0].toNumber();
490 RETURN_RESULT(Encode((bool)std::isnan(d)));
491}
492
495{
496 if (!argc)
497 // undefined gets converted to NaN
498 RETURN_RESULT(Encode(false));
499
500 if (argv[0].integerCompatible())
501 RETURN_RESULT(Encode(true));
502
503 double d = argv[0].toNumber();
504 RETURN_RESULT(Encode((bool)std::isfinite(d)));
505}
506
509{
510 if (argc == 0)
512
513 ExecutionEngine *v4 = b->engine();
514 QString uriString = argv[0].toQString();
515 bool ok;
516 QString out = decode(uriString, DecodeNonReserved, &ok);
517 if (!ok) {
518 Scope scope(v4);
519 ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
521 }
522
524}
525
528{
529 if (argc == 0)
531
532 ExecutionEngine *v4 = b->engine();
533 QString uriString = argv[0].toQString();
534 bool ok;
535 QString out = decode(uriString, DecodeAll, &ok);
536 if (!ok) {
537 Scope scope(v4);
538 ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
540 }
541
543}
544
547{
548 if (argc == 0)
550
551 ExecutionEngine *v4 = b->engine();
552 QString uriString = argv[0].toQString();
553 bool ok;
554 QString out = encode(uriString, uriUnescapedReserved, &ok);
555 if (!ok) {
556 Scope scope(v4);
557 ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
559 }
560
562}
563
566{
567 if (argc == 0)
569
570 ExecutionEngine *v4 = b->engine();
571 QString uriString = argv[0].toQString();
572 bool ok;
573 QString out = encode(uriString, uriUnescaped, &ok);
574 if (!ok) {
575 Scope scope(v4);
576 ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
578 }
579
581}
582
584{
585 ExecutionEngine *v4 = b->engine();
586 if (!argc)
587 RETURN_RESULT(v4->newString(QStringLiteral("undefined")));
588
589 QString str = argv[0].toQString();
591}
592
594{
595 ExecutionEngine *v4 = b->engine();
596 if (!argc)
597 RETURN_RESULT(v4->newString(QStringLiteral("undefined")));
598
599 QString str = argv[0].toQString();
601}
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr QStringView mid(qsizetype pos, qsizetype n=-1) const noexcept
Returns the substring of length length starting at position start in this object.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
EGLContext ctx
QString str
[2]
Scoped< FunctionObject > ScopedFunctionObject
quint64 ReturnedValue
ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
Scoped< String > ScopedString
Scoped< ExecutionContext > ScopedContext
constexpr char toHexUpper(char32_t value) noexcept
Definition qtools_p.h:27
constexpr int fromHex(char32_t c) noexcept
Definition qtools_p.h:44
DBusConnection const char DBusError * error
double qstrtod(const char *s00, char const **se, bool *ok)
#define Q_INFINITY
Definition qnumeric.h:77
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLboolean r
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLfloat GLfloat f
GLuint start
GLfloat GLfloat GLfloat GLfloat h
GLdouble s
[6]
Definition qopenglext.h:235
const GLubyte * c
GLuint64EXT * result
[6]
GLenum GLenum GLenum input
static bool isStrict(const QmlIR::Document *doc)
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QStringLiteral(str)
unsigned char uchar
Definition qtypes.h:32
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned short ushort
Definition qtypes.h:33
#define decode(x)
#define encode(x)
static void addEscapeSequence(QString &output, uchar ch)
static const char uriUnescapedReserved[]
static QString unescape(const QString &input)
static int toInt(const QChar &qc, int R)
static const char uriReserved[]
static const char uriUnescaped[]
static QString escape(const QString &input)
@ DecodeNonReserved
@ DecodeAll
#define CHECK_EXCEPTION()
#define RETURN_UNDEFINED()
#define RETURN_RESULT(r)
#define DEFINE_OBJECT_VTABLE(classname)
QT_BEGIN_NAMESPACE typedef uchar * output
static int sign(int x)
QByteArray ba
[0]
QTextStream out(stdout)
[7]
QDate d1(1995, 5, 17)
[0]
QDate d2(1995, 5, 20)
QJSEngine engine
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
ReturnedValue thisObject() const
static constexpr ReturnedValue undefined()
CppStackFrame * currentStackFrame
ReturnedValue evalCall(const Value *thisObject, const Value *argv, int argc, bool directCall) const
String * id_eval() const
Heap::String * newString(char16_t c)
ExecutionContext * scriptContext() const
ReturnedValue throwURIError(const Value &msg)
ExecutionContext * currentContext() const
static Heap::FunctionObject * createScriptFunction(ExecutionContext *scope, Function *function)
bool isStrict() const
static ReturnedValue method_unescape(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_parseInt(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_parseFloat(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_isNaN(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
isNaN [15.1.2.4]
static ReturnedValue method_isFinite(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
isFinite [15.1.2.5]
static ReturnedValue method_encodeURIComponent(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
encodeURIComponent [15.1.3.4]
static ReturnedValue method_decodeURI(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
decodeURI [15.1.3.1]
static ReturnedValue method_decodeURIComponent(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
decodeURIComponent [15.1.3.2]
static ReturnedValue method_encodeURI(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
encodeURI [15.1.3.3]
static ReturnedValue method_escape(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
void init(ExecutionEngine *engine)
ExecutionEngine * engine() const
ExecutionEngine * engine
Function * function()
bool strictMode
Definition qv4script_p.h:54
bool inheritContext
Definition qv4script_p.h:55
void parse()
Definition qv4script.cpp:44
constexpr ReturnedValue asReturnedValue() const
static constexpr VTable::Call virtualCall
static constexpr Value fromInt32(int i)
Definition qv4value_p.h:187
QML_NEARLY_ALWAYS_INLINE String * stringValue() const
Definition qv4value_p.h:55
static constexpr Value undefinedValue()
Definition qv4value_p.h:191
double toNumber() const
Definition qv4value_p.h:323
QString toQString() const
Definition qv4value.cpp:158