partial rootless JSON arrays support

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-02-21 07:58:12 +02:00
parent 5b0fcfa529
commit 808d94b266
4 changed files with 178 additions and 89 deletions

View file

@ -32,21 +32,21 @@ class QJsonDocumentPrivate {
public:
QJsonDocumentPrivate() : ref(1) { }
QVariantMap jsonToMap(const QByteArray &jsondata);
void mapToJson(const QVariantMap &jsonmap, json_t *jroot, quint16 jdepth);
QVariant jsonToVariant(const QByteArray &jsondata);
void variantToJson(const QVariant &jsonvariant, json_t *jroot, quint16 jdepth);
QAtomicInt ref;
QByteArray json;
QVariantMap map;
QVariant variant;
QString error;
private:
Q_DISABLE_COPY(QJsonDocumentPrivate);
};
QVariantMap QJsonDocumentPrivate::jsonToMap(const QByteArray &jsondata)
QVariant QJsonDocumentPrivate::jsonToVariant(const QByteArray &jsondata)
{
QVariantMap result;
QVariant result;
if (jsondata.isEmpty()) {
error = QCoreApplication::translate("QJsonDocument", "Data is empty");
@ -63,13 +63,14 @@ QVariantMap QJsonDocumentPrivate::jsonToMap(const QByteArray &jsondata)
switch(json_typeof(jroot)) {
case JSON_OBJECT: {
QVariantMap mapresult;
const char *jkey;
json_t *jobject;
json_object_foreach(jroot, jkey, jobject) {
switch(json_typeof(jobject)) {
case JSON_OBJECT: {
char* jdata = json_dumps(jobject, 0);
result.insert(jkey, jsonToMap(jdata));
mapresult.insert(jkey, jsonToVariant(jdata));
::free(jdata);
break;
}
@ -80,7 +81,7 @@ QVariantMap QJsonDocumentPrivate::jsonToMap(const QByteArray &jsondata)
switch(json_typeof(jarray)) {
case JSON_OBJECT: {
char* jdata = json_dumps(jarray, 0);
listvalue.append(jsonToMap(jdata));
listvalue.append(jsonToVariant(jdata));
::free(jdata);
break;
}
@ -114,31 +115,31 @@ QVariantMap QJsonDocumentPrivate::jsonToMap(const QByteArray &jsondata)
}
}
}
result.insert(jkey, listvalue);
mapresult.insert(jkey, listvalue);
break;
}
case JSON_STRING: {
result.insert(jkey, QVariant(json_string_value(jobject)));
mapresult.insert(jkey, QVariant(json_string_value(jobject)));
break;
}
case JSON_INTEGER: {
result.insert(jkey, QVariant(json_integer_value(jobject)));
mapresult.insert(jkey, QVariant(json_integer_value(jobject)));
break;
}
case JSON_REAL: {
result.insert(jkey, QVariant(json_real_value(jobject)));
mapresult.insert(jkey, QVariant(json_real_value(jobject)));
break;
}
case JSON_TRUE: {
result.insert(jkey, QVariant(true));
mapresult.insert(jkey, QVariant(true));
break;
}
case JSON_FALSE: {
result.insert(jkey, QVariant(false));
mapresult.insert(jkey, QVariant(false));
break;
}
case JSON_NULL: {
result.insert(jkey, QVariant());
mapresult.insert(jkey, QVariant());
break;
}
default: {
@ -147,10 +148,55 @@ QVariantMap QJsonDocumentPrivate::jsonToMap(const QByteArray &jsondata)
}
}
}
result = mapresult;
break;
}
case JSON_ARRAY: {
QVariantList listvalue;
for (size_t i = 0; i < json_array_size(jroot); i++) {
json_t *jarray = json_array_get(jroot, i);
switch(json_typeof(jarray)) {
case JSON_OBJECT: {
char* jdata = json_dumps(jarray, 0);
listvalue.append(jsonToVariant(jdata));
::free(jdata);
break;
}
case JSON_STRING: {
listvalue.append(QVariant(json_string_value(jarray)));
break;
}
case JSON_INTEGER: {
listvalue.append(QVariant(json_integer_value(jarray)));
break;
}
case JSON_REAL: {
listvalue.append(QVariant(json_real_value(jarray)));
break;
}
case JSON_TRUE: {
listvalue.append(QVariant(true));
break;
}
case JSON_FALSE: {
listvalue.append(QVariant(false));
break;
}
case JSON_NULL: {
listvalue.append(QVariant());
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Unknown JSON type in array");
break;
}
}
}
result = listvalue;
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Rootless array/values are not supported");
error = QCoreApplication::translate("QJsonDocument", "Rootless values are not supported");
break;
}
}
@ -162,72 +208,105 @@ QVariantMap QJsonDocumentPrivate::jsonToMap(const QByteArray &jsondata)
return result;
}
void QJsonDocumentPrivate::mapToJson(const QVariantMap &jsonmap, json_t *jroot, quint16 jdepth)
void QJsonDocumentPrivate::variantToJson(const QVariant &jsonvariant, json_t *jroot, quint16 jdepth)
{
if (jsonmap.isEmpty()) {
error = QCoreApplication::translate("QJsonDocument", "Data map is empty");
if (jsonvariant.isNull()) {
error = QCoreApplication::translate("QJsonDocument", "Data variant is null");
return;
} else if (Q_UNLIKELY(jdepth >= JSON_PARSER_MAX_DEPTH)) {
error = QCoreApplication::translate("QJsonDocument", "Maximum depth reached");
return;
}
foreach(const QString &key, jsonmap.keys()) {
const QVariant value = jsonmap.value(key);
const QByteArray bytearraykey = key.toUtf8();
switch(value.type()) {
case QVariant::Invalid: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_null());
break;
switch (jsonvariant.type()) {
case QVariant::Map:
case QVariant::Hash: {
const QVariantMap jsonmap = jsonvariant.toMap();
if (jdepth == 1 && jsonmap.isEmpty()) {
error = QCoreApplication::translate("QJsonDocument", "Data variant is null");
return;
}
case QVariant::Bool: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), value.toBool() ? json_true() : json_false());
break;
}
case QVariant::Int:
case QVariant::LongLong: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_integer(value.toLongLong()));
break;
}
case QVariant::UInt:
case QVariant::ULongLong: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_integer(value.toULongLong()));
break;
}
case QVariant::Float:
case QVariant::Double: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_real(value.toReal()));
break;
}
case QVariant::ByteArray:
case QVariant::String: {
const QByteArray bytearrayvalue = value.toByteArray();
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_string(bytearrayvalue.constData()));
break;
}
case QVariant::List: // this works only for QString-convertable types
case QVariant::StringList: {
json_t *jarray = json_array();
foreach(const QString &listvalue, value.toStringList()) {
const QByteArray bytearrayvalue = listvalue.toUtf8();
json_array_append_new(jarray, json_stringn_nocheck(bytearrayvalue.constData(), bytearrayvalue.size()));
foreach(const QString &key, jsonmap.keys()) {
const QVariant value = jsonmap.value(key);
const QByteArray bytearraykey = key.toUtf8();
switch(value.type()) {
case QVariant::Invalid: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_null());
break;
}
case QVariant::Bool: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), value.toBool() ? json_true() : json_false());
break;
}
case QVariant::Int:
case QVariant::LongLong: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_integer(value.toLongLong()));
break;
}
case QVariant::UInt:
case QVariant::ULongLong: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_integer(value.toULongLong()));
break;
}
case QVariant::Float:
case QVariant::Double: {
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_real(value.toReal()));
break;
}
case QVariant::ByteArray:
case QVariant::String: {
const QByteArray bytearrayvalue = value.toByteArray();
json_object_set_new_nocheck(jroot, bytearraykey.constData(), json_string(bytearrayvalue.constData()));
break;
}
case QVariant::List: // this works only for QString-convertable types
case QVariant::StringList: {
json_t *jarray = json_array();
foreach(const QString &listvalue, value.toStringList()) {
const QByteArray bytearrayvalue = listvalue.toUtf8();
json_array_append_new(jarray, json_stringn_nocheck(bytearrayvalue.constData(), bytearrayvalue.size()));
}
json_object_set_new_nocheck(jroot, bytearraykey.constData(), jarray);
break;
}
case QVariant::Hash:
case QVariant::Map: {
jdepth++;
json_t *jrootn = json_object();
variantToJson(value.toMap(), jrootn, jdepth);
json_object_set_new_nocheck(jroot, bytearraykey.constData(), jrootn);
jdepth--;
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Unknown variant type");
break;
}
}
json_object_set_new_nocheck(jroot, bytearraykey.constData(), jarray);
break;
}
case QVariant::Hash:
case QVariant::Map: {
jdepth++;
json_t *jrootn = json_object();
mapToJson(value.toMap(), jrootn, jdepth);
json_object_set_new_nocheck(jroot, bytearraykey.constData(), jrootn);
jdepth--;
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Unknown JSON type");
break;
}
break;
}
case QVariant::Invalid:
case QVariant::Bool:
case QVariant::Int:
case QVariant::LongLong:
case QVariant::UInt:
case QVariant::ULongLong:
case QVariant::Float:
case QVariant::Double:
case QVariant::ByteArray:
case QVariant::String: {
error = QCoreApplication::translate("QJsonDocument", "Rootless values are not supported");
break;
}
case QVariant::List:
case QVariant::StringList: {
error = QCoreApplication::translate("QJsonDocument", "Rootless arrays are not supported");
break;
}
default: {
error = QCoreApplication::translate("QJsonDocument", "Unknown variant type");
break;
}
}
@ -283,9 +362,9 @@ QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
static const size_t jflags = JSON_SORT_KEYS | JSON_INDENT(4);
QScopedPointer<QJsonDocumentPrivate> d(new QJsonDocumentPrivate());
d->map = variant.toMap();
d->variant = variant;
json_t *jroot = json_object();
d->mapToJson(d->map, jroot, 1);
d->variantToJson(d->variant, jroot, 1);
char *jdata = json_dumps(jroot, jflags);
d->json = jdata;
::free(jdata);
@ -294,7 +373,7 @@ QJsonDocument QJsonDocument::fromVariant(const QVariant &variant)
QJsonDocument jd;
if (Q_UNLIKELY(!d->error.isEmpty())) {
d->json.clear();
d->map.clear();
d->variant.clear();
}
jd.d_ptr = d.take();
@ -319,7 +398,7 @@ QVariant QJsonDocument::toVariant() const
return QVariant();
}
return d->map;
return d->variant;
}
/*!
@ -334,11 +413,11 @@ QJsonDocument QJsonDocument::fromJson(const QByteArray &json)
{
QScopedPointer<QJsonDocumentPrivate> d(new QJsonDocumentPrivate());
d->json = json;
d->map = d->jsonToMap(json);
d->variant = d->jsonToVariant(json);
if (Q_UNLIKELY(!d->error.isEmpty())) {
d->json.clear();
d->map.clear();
d->variant.clear();
}
QJsonDocument jd;
@ -373,7 +452,7 @@ bool QJsonDocument::operator==(const QJsonDocument &other) const
return false;
}
return (d->json == other.d_ptr->json && d->map == other.d_ptr->map);
return (d->json == other.d_ptr->json && d->variant == other.d_ptr->variant);
}
/*!
@ -393,7 +472,7 @@ bool QJsonDocument::operator==(const QJsonDocument &other) const
bool QJsonDocument::isNull() const
{
Q_D(const QJsonDocument);
return (!d || (d->json.isEmpty() && d->map.isEmpty()));
return (!d || (d->json.isEmpty() && d->variant.isNull()));
}
QString QJsonDocument::errorString() const

View file

@ -145,7 +145,7 @@ void tst_QJsonDocument::error()
QVERIFY(jsondoc.isNull());
jsondoc = QJsonDocument::fromVariant(QVariantMap());
QCOMPARE(jsondoc.errorString(), QLatin1String("Data map is empty"));
QCOMPARE(jsondoc.errorString(), QLatin1String("Data variant is null"));
QVERIFY(jsondoc.isNull());
// TODO: indermediate error test, e.g. maximum depth reached

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-19 20:09+0200\n"
"POT-Creation-Date: 2022-02-21 08:48+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -321,31 +321,41 @@ msgctxt "QJsonDocument"
msgid "Data is empty"
msgstr ""
#: src/core/tools/qjsondocument.cpp:112
#: src/core/tools/qjsondocument.cpp:113 src/core/tools/qjsondocument.cpp:190
msgctxt "QJsonDocument"
msgid "Unknown JSON type in array"
msgstr ""
#: src/core/tools/qjsondocument.cpp:145 src/core/tools/qjsondocument.cpp:228
#: src/core/tools/qjsondocument.cpp:146
msgctxt "QJsonDocument"
msgid "Unknown JSON type"
msgstr ""
#: src/core/tools/qjsondocument.cpp:153
#: src/core/tools/qjsondocument.cpp:199 src/core/tools/qjsondocument.cpp:299
msgctxt "QJsonDocument"
msgid "Rootless array/values are not supported"
msgid "Rootless values are not supported"
msgstr ""
#: src/core/tools/qjsondocument.cpp:168
#: src/core/tools/qjsondocument.cpp:214 src/core/tools/qjsondocument.cpp:226
msgctxt "QJsonDocument"
msgid "Data map is empty"
msgid "Data variant is null"
msgstr ""
#: src/core/tools/qjsondocument.cpp:171
#: src/core/tools/qjsondocument.cpp:217
msgctxt "QJsonDocument"
msgid "Maximum depth reached"
msgstr ""
#: src/core/tools/qjsondocument.cpp:282 src/core/tools/qjsondocument.cpp:308
msgctxt "QJsonDocument"
msgid "Unknown variant type"
msgstr ""
#: src/core/tools/qjsondocument.cpp:304
msgctxt "QJsonDocument"
msgid "Rootless arrays are not supported"
msgstr ""
#: src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp:82
msgctxt "QDeclarativeAnimatedImage"
msgid "Katie was built without support for QMovie"

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-19 20:09+0200\n"
"POT-Creation-Date: 2022-02-21 08:48+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"