4#include <qv4jsonobject_p.h>
5#include <qv4objectproto_p.h>
6#include <qv4numberobject_p.h>
7#include <qv4stringobject_p.h>
8#include <qv4booleanobject_p.h>
9#include <qv4objectiterator_p.h>
10#include <qv4scopedvalue_p.h>
11#include <qv4runtime_p.h>
12#include <qv4variantobject_p.h>
14#include <qv4symbol_p.h>
17#include <qstringlist.h>
19#include <wtf/MathExtras.h>
26#define BEGIN qDebug() << QByteArray(4
*indent++, ' ').constData()
28#define DEBUG qDebug() << QByteArray(4
*indent, ' ').constData()
30#define BEGIN if (1
) ; else qDebug()
31#define END do {} while (0
)
32#define DEBUG if (1
) ; else qDebug()
41JsonParser::JsonParser(ExecutionEngine *engine,
const QChar *json,
int length)
42 : engine(engine), head(json), json(json), nestingLevel(0), lastError(QJsonParseError::NoError)
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
89bool JsonParser::eatSpace()
92 const char16_t ch = json->unicode();
105QChar JsonParser::nextToken()
109 QChar token = *json++;
110 switch (token.unicode()) {
129
130
131ReturnedValue JsonParser::parse(QJsonParseError *error)
135 qDebug() <<
">>>>> parser begin";
141 ScopedValue v(scope);
142 if (!parseValue(v)) {
144 qDebug() <<
">>>>> parser error";
146 if (lastError == QJsonParseError::NoError)
147 lastError = QJsonParseError::IllegalValue;
148 error->offset = json - head;
149 error->error = lastError;
150 return Encode::undefined();
155 lastError = QJsonParseError::IllegalValue;
156 error->offset = json - head;
157 error->error = lastError;
158 return Encode::undefined();
163 error->error = QJsonParseError::NoError;
164 return v->asReturnedValue();
168
169
170
172ReturnedValue JsonParser::parseObject()
174 if (++nestingLevel > nestingLimit) {
175 lastError = QJsonParseError::DeepNesting;
176 return Encode::undefined();
179 BEGIN <<
"parseObject pos=" << json;
182 ScopedObject o(scope, engine->newObject());
184 QChar token = nextToken();
185 while (token.unicode() == Quote) {
187 return Encode::undefined();
189 if (token.unicode() != ValueSeparator)
192 if (token.unicode() == EndObject) {
193 lastError = QJsonParseError::MissingObject;
194 return Encode::undefined();
198 DEBUG <<
"end token=" << token;
199 if (token.unicode() != EndObject) {
200 lastError = QJsonParseError::UnterminatedObject;
201 return Encode::undefined();
207 return o.asReturnedValue();
211
212
213bool JsonParser::parseMember(Object *o)
215 BEGIN <<
"parseMember";
219 if (!parseString(&key))
221 QChar token = nextToken();
222 if (token.unicode() != NameSeparator) {
223 lastError = QJsonParseError::MissingNameSeparator;
226 ScopedValue val(scope);
227 if (!parseValue(val))
230 ScopedString s(scope, engine->newString(key));
231 PropertyKey skey = s->toPropertyKey();
232 if (skey.isArrayIndex()) {
233 o->put(skey.asArrayIndex(), val);
236 o->insertMember(s, val);
244
245
246ReturnedValue JsonParser::parseArray()
249 BEGIN <<
"parseArray";
250 ScopedArrayObject array(scope, engine->newArrayObject());
252 if (++nestingLevel > nestingLimit) {
253 lastError = QJsonParseError::DeepNesting;
254 return Encode::undefined();
258 lastError = QJsonParseError::UnterminatedArray;
259 return Encode::undefined();
261 if (json->unicode() == EndArray) {
266 ScopedValue val(scope);
267 if (!parseValue(val))
268 return Encode::undefined();
269 array->arraySet(index, val);
270 QChar token = nextToken();
271 if (token.unicode() == EndArray)
273 else if (token.unicode() != ValueSeparator) {
275 lastError = QJsonParseError::UnterminatedArray;
277 lastError = QJsonParseError::MissingValueSeparator;
278 return Encode::undefined();
284 DEBUG <<
"size =" << array->getLength();
288 return array.asReturnedValue();
292
293
294
296bool JsonParser::parseValue(Value *val)
298 BEGIN <<
"parse Value" << *json;
300 switch ((json++)->unicode()) {
302 if (end - json < 3) {
303 lastError = QJsonParseError::IllegalValue;
306 if (*json++ == u'u' &&
309 *val = Value::nullValue();
310 DEBUG <<
"value: null";
314 lastError = QJsonParseError::IllegalValue;
317 if (end - json < 3) {
318 lastError = QJsonParseError::IllegalValue;
321 if (*json++ == u'r' &&
324 *val = Value::fromBoolean(
true);
325 DEBUG <<
"value: true";
329 lastError = QJsonParseError::IllegalValue;
332 if (end - json < 4) {
333 lastError = QJsonParseError::IllegalValue;
336 if (*json++ == u'a' &&
340 *val = Value::fromBoolean(
false);
341 DEBUG <<
"value: false";
345 lastError = QJsonParseError::IllegalValue;
349 if (!parseString(&value))
351 DEBUG <<
"value: string";
353 *val = Value::fromHeapObject(engine->newString(value));
358 if (val->isUndefined())
360 DEBUG <<
"value: array";
365 *val = parseObject();
366 if (val->isUndefined())
368 DEBUG <<
"value: object";
373 lastError = QJsonParseError::MissingObject;
377 if (!parseNumber(val))
379 DEBUG <<
"value: number";
391
392
393
394
395
396
397
398
399
400
401
402
404bool JsonParser::parseNumber(Value *val)
406 BEGIN <<
"parseNumber" << *json;
408 const QChar *start = json;
412 if (json < end && *json == u'-')
416 if (json < end && *json == u'0') {
419 while (json < end && *json >= u'0' && *json <= u'9')
424 if (json < end && *json == u'.') {
427 while (json < end && *json >= u'0' && *json <= u'9')
432 if (json < end && (*json == u'e' || *json == u'E')) {
435 if (json < end && (*json == u'-' || *json == u'+'))
437 while (json < end && *json >= u'0' && *json <= u'9')
441 QString number(start, json - start);
442 DEBUG <<
"numberstring" << number;
446 int n = number.toInt(&ok);
447 if (ok && n < (1<<25) && n > -(1<<25)) {
448 *val = Value::fromInt32(n);
456 d = number.toDouble(&ok);
459 lastError = QJsonParseError::IllegalNumber;
463 * val = Value::fromDouble(d);
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
493 ushort d = digit.unicode();
495 if (d >= u'0' && d <= u'9')
496 *result |= (d - u'0');
497 else if (d >= u'a' && d <= u'f')
498 *result |= (d - u'a') + 10;
499 else if (d >= u'A' && d <= u'F')
500 *result |= (d - u'A') + 10;
512 DEBUG <<
"scan escape";
513 uint escaped = (json++)->unicode();
535 for (
int i = 0; i < 4; ++i) {
536 if (!addHexDigit(*json, ch))
549bool JsonParser::parseString(QString *string)
551 BEGIN <<
"parse string stringPos=" << json;
556 else if (*json == u'\\') {
558 if (!scanEscapeSequence(json, end, &ch)) {
559 lastError = QJsonParseError::IllegalEscapeSequence;
562 if (QChar::requiresSurrogates(ch)) {
563 *string += QChar(QChar::highSurrogate(ch)) + QChar(QChar::lowSurrogate(ch));
565 *string += QChar(ch);
568 if (json->unicode() <= 0x1f) {
569 lastError = QJsonParseError::IllegalEscapeSequence;
579 lastError = QJsonParseError::UnterminatedString;
591 FunctionObject *replacerFunction;
592 QV4::String *propertyList;
593 int propertyListSize;
596 QStack<Object *> stack;
598 bool stackContains(Object *o) {
599 for (
int i = 0; i < stack.size(); ++i)
600 if (stack.at(i)->d() == o->d())
605 Stringify(ExecutionEngine *e) : v4(e), replacerFunction(
nullptr), propertyList(
nullptr), propertyListSize(0) {}
607 QString Str(
const QString &key,
const Value &v);
608 QString JA(Object *a);
609 QString JO(Object *o);
611 QString makeMember(
const QString &key,
const Value &v);
614class [[nodiscard]] CallDepthAndCycleChecker
616 Q_DISABLE_COPY_MOVE(CallDepthAndCycleChecker);
619 CallDepthAndCycleChecker(Stringify *stringify, Object *o)
620 : m_callDepthRecorder(stringify->v4)
622 if (stringify->stackContains(o)) {
623 stringify->v4->throwTypeError(
624 QStringLiteral(
"Cannot convert circular structure to JSON"));
627 const bool hasOverflow = stringify->v4->checkStackLimits();
628 Q_UNUSED(hasOverflow);
631 bool foundProblem()
const {
return m_callDepthRecorder.ee->hasException; }
634 ExecutionEngineCallDepthRecorder<1> m_callDepthRecorder;
637QString quote(
const QString &str)
640 const int length = str.size();
641 product.reserve(length + 2);
643 for (
int i = 0; i < length; ++i) {
645 switch (c.unicode()) {
647 product += QLatin1String(
"\\\"");
650 product += QLatin1String(
"\\\\");
653 product += QLatin1String(
"\\b");
656 product += QLatin1String(
"\\f");
659 product += QLatin1String(
"\\n");
662 product += QLatin1String(
"\\r");
665 product += QLatin1String(
"\\t");
668 if (c.unicode() <= 0x1f) {
669 product += QLatin1String(
"\\u00");
670 product += (c.unicode() > 0xf ? u'1' : u'0') +
671 QLatin1Char(
"0123456789abcdef"[c.unicode() & 0xf]);
681QString Stringify::Str(
const QString &key,
const Value &v)
685 ScopedValue value(scope, v);
686 ScopedObject o(scope, value);
688 ScopedString s(scope, v4->newString(QStringLiteral(
"toJSON")));
689 ScopedFunctionObject toJSON(scope, o->get(s));
691 JSCallArguments jsCallData(scope, 1);
692 *jsCallData.thisObject = value;
693 jsCallData.args[0] = v4->newString(key);
694 value = toJSON->call(jsCallData);
695 if (v4->hasException)
700 if (replacerFunction) {
701 JSCallArguments jsCallData(scope, 2);
702 jsCallData.args[0] = v4->newString(key);
703 jsCallData.args[1] = value;
705 if (stack.isEmpty()) {
706 ScopedObject holder(scope, v4->newObject());
707 holder->put(scope.engine->id_empty(), v);
708 *jsCallData.thisObject = holder;
710 *jsCallData.thisObject = stack.top();
713 value = replacerFunction->call(jsCallData);
714 if (v4->hasException)
718 o = value->asReturnedValue();
721 value = Encode(n->value());
722 else if (StringObject *so = o->as<StringObject>())
723 value = so->d()->string;
725 value = Encode(b->value());
729 return QStringLiteral(
"null");
730 if (value->isBoolean())
731 return value->booleanValue() ? QStringLiteral(
"true") : QStringLiteral(
"false");
732 if (QV4::String *stringValue = value->stringValue())
733 return quote(stringValue->toQString());
735 if (value->isNumber()) {
736 double d = value->toNumber();
737 return std::isfinite(d) ? value->toQString() : QStringLiteral(
"null");
740 if (
const QV4::VariantObject *v = value->as<QV4::VariantObject>()) {
741 return quote(v->d()->data().toString());
744 o = value->asReturnedValue();
746 if (!o->as<FunctionObject>()) {
747 if (o->isArrayLike()) {
748 return JA(o.getPointer());
758QString Stringify::makeMember(
const QString &key,
const Value &v)
760 QString strP = Str(key, v);
761 if (!strP.isEmpty()) {
762 QString member = quote(key) + u':';
771QString Stringify::JO(Object *o)
773 CallDepthAndCycleChecker check(
this, o);
774 if (check.foundProblem())
781 QString stepback = indent;
785 if (!propertyListSize) {
786 ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
787 ScopedValue name(scope);
789 ScopedValue val(scope);
791 name = it.nextPropertyNameAsString(val);
794 QString key = name->toQString();
795 QString member = makeMember(key, val);
796 if (!member.isEmpty())
800 ScopedValue v(scope);
801 for (
int i = 0; i < propertyListSize; ++i) {
803 String *s = propertyList + i;
804 v = o->get(s, &exists);
807 QString member = makeMember(s->toQString(), v);
808 if (!member.isEmpty())
813 if (partial.isEmpty()) {
814 result = QStringLiteral(
"{}");
815 }
else if (gap.isEmpty()) {
816 result = u'{' + partial.join(u',') + u'}';
818 QString separator = QLatin1String(
",\n") + indent;
819 result = QLatin1String(
"{\n") + indent + partial.join(separator) + u'\n'
823 indent = std::move(stepback);
828QString Stringify::JA(Object *a)
830 CallDepthAndCycleChecker check(
this, a);
831 if (check.foundProblem())
834 Scope scope(a->engine());
838 QString stepback = indent;
842 uint len = a->getLength();
843 ScopedValue v(scope);
844 for (uint i = 0; i < len; ++i) {
846 v = a->get(i, &exists);
848 partial += QStringLiteral(
"null");
851 QString strP = Str(QString::number(i), v);
855 partial += QStringLiteral(
"null");
858 if (partial.isEmpty()) {
859 result = QStringLiteral(
"[]");
860 }
else if (gap.isEmpty()) {
861 result = u'[' + partial.join(u',') + u']';
863 QString separator = QLatin1String(
",\n") + indent;
864 result = QLatin1String(
"[\n") + indent + partial.join(separator) + u'\n' + stepback + u']';
867 indent = std::move(stepback);
874void Heap::JsonObject::init()
877 Scope scope(internalClass->engine);
878 ScopedObject o(scope,
this);
880 o->defineDefaultProperty(QStringLiteral(
"parse"), QV4::JsonObject::method_parse, 2);
881 o->defineDefaultProperty(QStringLiteral(
"stringify"), QV4::JsonObject::method_stringify, 3);
882 ScopedString json(scope, scope.engine->newString(QStringLiteral(
"JSON")));
883 o->defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), json);
887ReturnedValue JsonObject::method_parse(
const FunctionObject *b,
const Value *,
const Value *argv,
int argc)
889 ExecutionEngine *v4 = b->engine();
892 jtext = argv[0].toQString();
894 DEBUG <<
"parsing source = " << jtext;
895 JsonParser parser(v4, jtext.constData(), jtext.size());
896 QJsonParseError error;
897 ReturnedValue result = parser.parse(&error);
898 if (error.error != QJsonParseError::NoError) {
899 DEBUG <<
"parse error" << error.errorString();
900 RETURN_RESULT(v4->throwSyntaxError(QStringLiteral(
"JSON.parse: Parse error")));
906ReturnedValue JsonObject::method_stringify(
const FunctionObject *b,
const Value *,
const Value *argv,
int argc)
909 Stringify stringify(scope.engine);
911 ScopedObject o(scope, argc > 1 ? argv[1] : Value::undefinedValue());
913 stringify.replacerFunction = o->as<FunctionObject>();
914 if (o->isArrayObject()) {
915 int arrayLen = scope.engine->safeForAllocLength(o->getLength());
917 stringify.propertyList =
static_cast<QV4::String *>(scope.constructUndefined(arrayLen));
918 for (
int i = 0; i < arrayLen; ++i) {
919 Value *v = stringify.propertyList + i;
921 if (v->as<NumberObject>() || v->as<StringObject>() || v->isNumber())
922 *v = v->toString(scope.engine);
923 if (!v->isString()) {
926 for (
int j = 0; j <i; ++j) {
927 if (stringify.propertyList[j].m() == v->m()) {
937 ScopedValue s(scope, argc > 2 ? argv[2] : Value::undefinedValue());
938 if (NumberObject *n = s->as<NumberObject>())
939 s = Encode(n->value());
940 else if (StringObject *so = s->as<StringObject>())
944 stringify.gap = QString(qMin(10, (
int)s->toInteger()), u' ');
945 }
else if (String *str = s->stringValue()) {
946 stringify.gap = str->toQString().left(10);
950 ScopedValue arg0(scope, argc ? argv[0] : Value::undefinedValue());
951 QString result = stringify.Str(QString(), arg0);
952 if (result.isEmpty() || scope.hasException())
954 return Encode(scope.engine->newString(result));
959ReturnedValue JsonObject::fromJsonValue(ExecutionEngine *engine,
const QJsonValue &value)
961 if (value.isString())
962 return engine->newString(value.toString())->asReturnedValue();
963 else if (value.isDouble())
964 return Encode(value.toDouble());
965 else if (value.isBool())
966 return Encode(value.toBool());
967 else if (value.isArray())
968 return fromJsonArray(engine, value.toArray());
969 else if (value.isObject())
970 return fromJsonObject(engine, value.toObject());
971 else if (value.isNull())
972 return Encode::null();
974 return Encode::undefined();
977QJsonValue JsonObject::toJsonValue(
const Value &value, V4ObjectSet &visitedObjects)
979 if (value.isNumber())
980 return QJsonValue(value.toNumber());
981 else if (value.isBoolean())
982 return QJsonValue((
bool)value.booleanValue());
983 else if (value.isNull())
984 return QJsonValue(QJsonValue::Null);
985 else if (value.isUndefined())
986 return QJsonValue(QJsonValue::Undefined);
987 else if (String *s = value.stringValue())
988 return QJsonValue(s->toQString());
990 Q_ASSERT(value.isObject());
991 Scope scope(value.as<Object>()->engine());
992 if (ScopedArrayObject a{ scope, value }) {
993 return toJsonArray(a, visitedObjects);
994 }
else if (Scoped<QV4::Sequence> a{ scope, value }) {
995 return toJsonArray(a, visitedObjects);
996 }
else if (Scoped<QmlListWrapper> lw{ scope, value }) {
997 return toJsonArray(lw, visitedObjects);
998 }
else if (ScopedObject o{ scope, value }) {
999 return toJsonObject(o, visitedObjects);
1002 return QJsonValue(value.toQString());
1005QV4::ReturnedValue JsonObject::fromJsonObject(ExecutionEngine *engine,
const QJsonObject &object)
1007 Scope scope(engine);
1008 ScopedObject o(scope, engine->newObject());
1009 ScopedString s(scope);
1010 ScopedValue v(scope);
1011 for (QJsonObject::const_iterator it = object.begin(), cend = object.end(); it != cend; ++it) {
1012 v = fromJsonValue(engine, it.value());
1013 o->put((s = engine->newString(it.key())), v);
1015 return o.asReturnedValue();
1018QJsonObject JsonObject::toJsonObject(
const Object *o, V4ObjectSet &visitedObjects)
1021 if (!o || o->as<FunctionObject>())
1024 Scope scope(o->engine());
1026 if (visitedObjects.contains(ObjectItem(o))) {
1033 visitedObjects.insert(ObjectItem(o));
1035 ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
1036 ScopedValue name(scope);
1037 QV4::ScopedValue val(scope);
1039 name = it.nextPropertyNameAsString(val);
1043 QString key = name->toQStringNoThrow();
1044 if (!val->as<FunctionObject>())
1045 result.insert(key, toJsonValue(val, visitedObjects));
1048 visitedObjects.remove(ObjectItem(o));
1053QV4::ReturnedValue JsonObject::fromJsonArray(ExecutionEngine *engine,
const QJsonArray &array)
1055 Scope scope(engine);
1056 int size = array.size();
1057 ScopedArrayObject a(scope, engine->newArrayObject());
1058 a->arrayReserve(size);
1059 ScopedValue v(scope);
1060 for (
int i = 0; i < size; i++)
1061 a->arrayPut(i, (v = fromJsonValue(engine, array.at(i))));
1062 a->setArrayLengthUnchecked(size);
1063 return a.asReturnedValue();
1066QJsonArray JsonObject::toJsonArray(
const Object *a, V4ObjectSet &visitedObjects)
1072 Scope scope(a->engine());
1074 if (visitedObjects.contains(ObjectItem(a))) {
1081 visitedObjects.insert(ObjectItem(a));
1083 ScopedValue v(scope);
1084 quint32 length = a->getLength();
1085 for (quint32 i = 0; i < length; ++i) {
1087 if (v->as<FunctionObject>())
1089 result.append(toJsonValue(v, visitedObjects));
1092 visitedObjects.remove(ObjectItem(a));
static bool scanEscapeSequence(const QChar *&json, const QChar *end, uint *ch)
static const int nestingLimit
DEFINE_OBJECT_VTABLE(JsonObject)
static bool addHexDigit(QChar digit, uint *result)
#define CHECK_EXCEPTION()
#define RETURN_UNDEFINED()