swift
json.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "misc/json.h"
5 
6 #include <QDateTime>
7 #include <QJsonDocument>
8 #include <QStringList>
9 
10 #include "misc/imageutils.h"
11 #include "misc/jsonexception.h"
12 #include "misc/stringutils.h"
13 
14 using namespace swift::misc;
15 
16 class QPixmap;
17 
18 const QJsonValue &operator>>(const QJsonValue &json, int &value)
19 {
20  value = json.toInt();
21  return json;
22 }
23 
24 const QJsonValue &operator>>(const QJsonValue &json, qlonglong &value)
25 {
26  value = static_cast<qlonglong>(json.toDouble());
27  return json;
28 }
29 
30 const QJsonValue &operator>>(const QJsonValue &json, qulonglong &value)
31 {
32  value = static_cast<qulonglong>(json.toDouble());
33  return json;
34 }
35 
36 const QJsonValue &operator>>(const QJsonValue &json, uint &value)
37 {
38  value = static_cast<uint>(json.toInt());
39  return json;
40 }
41 
42 const QJsonValue &operator>>(const QJsonValue &json, qint16 &value)
43 {
44  value = static_cast<qint16>(json.toInt());
45  return json;
46 }
47 
48 const QJsonValue &operator>>(const QJsonValue &json, QString &value)
49 {
50  value = json.toString();
51  return json;
52 }
53 
54 const QJsonValue &operator>>(const QJsonValue &json, std::string &value)
55 {
56  value = json.toString().toStdString();
57  return json;
58 }
59 
60 const QJsonValue &operator>>(const QJsonValue &json, QStringList &value)
61 {
62  for (auto &&element : json.toArray()) { value << element.toString(); }
63  return json;
64 }
65 
66 const QJsonValue &operator>>(const QJsonValue &json, double &value)
67 {
68  value = json.toDouble();
69  return json;
70 }
71 
72 const QJsonValue &operator>>(const QJsonValue &json, bool &value)
73 {
74  value = json.toBool();
75  return json;
76 }
77 
78 const QJsonValue &operator>>(const QJsonValue &json, QDateTime &value)
79 {
80  value = fromStringUtc(json.toString());
81  return json;
82 }
83 
84 const QJsonValue &operator>>(const QJsonValue &json, QPixmap &value)
85 {
86  const QString hex(json.toString());
88  return json;
89 }
90 
91 const QJsonValue &operator>>(const QJsonValue &json, QByteArray &value)
92 {
93  const QString hex(json.toString());
94  value = QByteArray::fromHex(hex.toLatin1());
95  return json;
96 }
97 
98 QJsonValueRef operator>>(QJsonValueRef json, int &value)
99 {
100  value = json.toInt();
101  return json;
102 }
103 
104 QJsonValueRef operator>>(QJsonValueRef json, qlonglong &value)
105 {
106  value = static_cast<qlonglong>(json.toDouble());
107  return json;
108 }
109 
110 QJsonValueRef operator>>(QJsonValueRef json, qulonglong &value)
111 {
112  value = static_cast<qulonglong>(json.toDouble());
113  return json;
114 }
115 
116 QJsonValueRef operator>>(QJsonValueRef json, uint &value)
117 {
118  value = static_cast<uint>(json.toInt());
119  return json;
120 }
121 
122 QJsonValueRef operator>>(QJsonValueRef json, qint16 &value)
123 {
124  value = static_cast<qint16>(json.toInt());
125  return json;
126 }
127 
128 QJsonValueRef operator>>(QJsonValueRef json, QString &value)
129 {
130  value = json.toString();
131  return json;
132 }
133 
134 QJsonValueRef operator>>(QJsonValueRef json, std::string &value)
135 {
136  value = json.toString().toStdString();
137  return json;
138 }
139 
140 QJsonValueRef operator>>(QJsonValueRef json, QStringList &value)
141 {
142  for (auto &&element : json.toArray()) { value << element.toString(); }
143  return json;
144 }
145 
146 QJsonValueRef operator>>(QJsonValueRef json, double &value)
147 {
148  value = json.toDouble();
149  return json;
150 }
151 
152 QJsonValueRef operator>>(QJsonValueRef json, bool &value)
153 {
154  value = json.toBool();
155  return json;
156 }
157 
158 QJsonValueRef operator>>(QJsonValueRef json, QDateTime &value)
159 {
160  value = fromStringUtc(json.toString());
161  return json;
162 }
163 
164 QJsonValueRef operator>>(QJsonValueRef json, QPixmap &value)
165 {
166  const QString hex(json.toString());
168  return json;
169 }
170 
171 QJsonValueRef operator>>(QJsonValueRef json, QByteArray &value)
172 {
173  const QString hex(json.toString());
174  value = QByteArray::fromHex(hex.toLatin1());
175  return json;
176 }
177 
178 QJsonArray &operator<<(QJsonArray &json, const int value)
179 {
180  json.append(QJsonValue(value));
181  return json;
182 }
183 
184 QJsonArray &operator<<(QJsonArray &json, const qint16 value)
185 {
186  json.append(QJsonValue(value));
187  return json;
188 }
189 
190 QJsonArray &operator<<(QJsonArray &json, const qlonglong value)
191 {
192  json.append(QJsonValue(value));
193  return json;
194 }
195 
196 QJsonArray &operator<<(QJsonArray &json, const uint value)
197 {
198  json.append(QJsonValue(static_cast<int>(value)));
199  return json;
200 }
201 
202 QJsonArray &operator<<(QJsonArray &json, const qulonglong value)
203 {
204  json.append(QJsonValue(static_cast<int>(value)));
205  return json;
206 }
207 
209 {
210  json.append(QJsonValue(value));
211  return json;
212 }
213 
214 QJsonArray &operator<<(QJsonArray &json, const std::string &value)
215 {
217  return json;
218 }
219 
220 QJsonArray &operator<<(QJsonArray &json, const double value)
221 {
222  json.append(QJsonValue(value));
223  return json;
224 }
225 
226 QJsonArray &operator<<(QJsonArray &json, const bool value)
227 {
228  json.append(QJsonValue(value));
229  return json;
230 }
231 
233 {
234  json.append(QJsonValue(value.toString()));
235  return json;
236 }
237 
239 {
241  json.append(QJsonValue(pm));
242  return json;
243 }
244 
246 {
247  QString pm(QByteArray::fromHex(value));
248  json.append(QJsonValue(pm));
249  return json;
250 }
251 
252 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const int &> &value)
253 {
254  json.insert(value.first, QJsonValue(value.second));
255  return json;
256 }
257 
258 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const qint16 &> &value)
259 {
260  json.insert(value.first, QJsonValue(value.second));
261  return json;
262 }
263 
264 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const qulonglong &> &value)
265 {
266  json.insert(value.first, QJsonValue(static_cast<int>(value.second)));
267  return json;
268 }
269 
270 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const qlonglong &> &value)
271 {
272  json.insert(value.first, QJsonValue(value.second));
273  return json;
274 }
275 
276 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const uint &> &value)
277 {
278  json.insert(value.first, QJsonValue(static_cast<int>(value.second)));
279  return json;
280 }
281 
282 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const QString &> &value)
283 {
284  json.insert(value.first, QJsonValue(value.second));
285  return json;
286 }
287 
288 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const std::string &> &value)
289 {
290  json[value.first] = QJsonValue(QString::fromStdString(value.second));
291  return json;
292 }
293 
294 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const QStringList &> &value)
295 {
296  json.insert(value.first, QJsonValue(QJsonArray::fromStringList(value.second)));
297  return json;
298 }
299 
300 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const double &> &value)
301 {
302  json.insert(value.first, QJsonValue(value.second));
303  return json;
304 }
305 
306 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const bool &> &value)
307 {
308  json.insert(value.first, QJsonValue(value.second));
309  return json;
310 }
311 
312 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const QDateTime &> &value)
313 {
314  json.insert(value.first, QJsonValue(value.second.toString()));
315  return json;
316 }
317 
318 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const QPixmap &> &value)
319 {
320  QString pm(swift::misc::pixmapToPngHexString(value.second));
321  json.insert(value.first, pm);
322  return json;
323 }
324 
325 QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const QByteArray &> &value)
326 {
327  QString pm(value.second.toHex());
328  json.insert(value.first, pm);
329  return json;
330 }
331 
332 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const int &> &value)
333 {
334  json[value.first] = QJsonValue(value.second);
335  return json;
336 }
337 
338 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const qint16 &> &value)
339 {
340  json[value.first] = QJsonValue(value.second);
341  return json;
342 }
343 
344 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const qulonglong &> &value)
345 {
346  json[value.first] = QJsonValue(static_cast<int>(value.second));
347  return json;
348 }
349 
350 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const qlonglong &> &value)
351 {
352  json[value.first] = QJsonValue(value.second);
353  return json;
354 }
355 
356 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const uint &> &value)
357 {
358  json[value.first] = QJsonValue(static_cast<int>(value.second));
359  return json;
360 }
361 
362 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const QString &> &value)
363 {
364  json[value.first] = QJsonValue(value.second);
365  return json;
366 }
367 
368 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const std::string &> &value)
369 {
370  json[value.first] = QJsonValue(QString::fromStdString(value.second));
371  return json;
372 }
373 
374 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const QStringList &> &value)
375 {
376  json[value.first] = QJsonValue(QJsonArray::fromStringList(value.second));
377  return json;
378 }
379 
380 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const double &> &value)
381 {
382  json[value.first] = QJsonValue(value.second);
383  return json;
384 }
385 
386 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const bool &> &value)
387 {
388  json[value.first] = QJsonValue(value.second);
389  return json;
390 }
391 
392 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const QDateTime &> &value)
393 {
394  json[value.first] = QJsonValue(value.second.toString());
395  return json;
396 }
397 
398 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const QPixmap &> &value)
399 {
400  QString pm(swift::misc::pixmapToPngHexString(value.second));
401  json[value.first] = pm;
402  return json;
403 }
404 
405 QJsonObject &operator<<(QJsonObject &json, const std::pair<CExplicitLatin1String, const QByteArray &> &value)
406 {
407  json[value.first] = QString(value.second.toHex());
408  return json;
409 }
410 
411 namespace swift::misc::json
412 {
413  QJsonObject jsonObjectFromString(const QString &json, bool acceptCacheFormat)
414  {
415  if (json.isEmpty()) { return QJsonObject(); }
416 
417  QJsonParseError error {};
418  const QJsonDocument jsonDoc(QJsonDocument::fromJson(json.toUtf8(), &error));
419  if (error.error != QJsonParseError::NoError) { throw CJsonException(error.errorString()); }
420 
421  return acceptCacheFormat ? json::unwrapCache(jsonDoc.object()) : jsonDoc.object();
422  }
423 
425  {
426  const QJsonDocument doc(jsonObject);
427  const QString strJson(doc.toJson(format));
428  return strJson;
429  }
430 
432  {
433  if (json.isEmpty()) { return QJsonArray(); }
434  const QJsonDocument jsonDoc(QJsonDocument::fromJson(json.toUtf8()));
435  return jsonDoc.array();
436  }
437 
438  QJsonObject &appendJsonObject(QJsonObject &target, const QJsonObject &toBeAppended)
439  {
440  if (toBeAppended.isEmpty()) return target;
441  const QStringList keys = toBeAppended.keys();
442  foreach (const QString &key, keys) { target.insert(key, toBeAppended.value(key)); }
443  return target;
444  }
445 
446  QJsonObject getIncrementalObject(const QJsonObject &previousObject, const QJsonObject &currentObject)
447  {
448  QJsonObject incrementalObject = currentObject;
449  for (const auto &key : previousObject.keys()) // clazy:exclude=range-loop
450  {
451  if (previousObject.value(key).isObject())
452  {
453  auto child =
454  getIncrementalObject(previousObject.value(key).toObject(), currentObject.value(key).toObject());
455  if (child.isEmpty())
456  incrementalObject.remove(key);
457  else
458  incrementalObject.insert(key, child);
459  }
460  else
461  {
462  if (currentObject.value(key) == previousObject.value(key)) incrementalObject.remove(key);
463  }
464  }
465  return incrementalObject;
466  }
467 
468  QJsonObject applyIncrementalObject(const QJsonObject &previousObject, const QJsonObject &incrementalObject)
469  {
470  QJsonObject currentObject = previousObject;
471  for (const auto &key : incrementalObject.keys()) // clazy:exclude=range-loop
472  {
473  // If it is not an object, just insert the value
474  if (!incrementalObject.value(key).isObject()) { currentObject.insert(key, incrementalObject.value(key)); }
475  else
476  {
477  auto child = applyIncrementalObject(currentObject.value(key).toObject(),
478  incrementalObject.value(key).toObject());
479  currentObject.insert(key, child);
480  }
481  }
482  return currentObject;
483  }
484 
485  bool looksLikeJson(const QString &json)
486  {
487  if (json.isEmpty()) { return false; }
488  const QString t = json.trimmed();
489  return t.startsWith('{') && t.endsWith('}');
490  }
491 
492  bool looksLikeSwiftJson(const QString &json)
493  {
494  // further checks would go here
495  return looksLikeJson(json);
496  }
497 
498  bool looksLikeSwiftDataObjectJson(const QJsonObject &object)
499  {
500  // key
501  // - type
502  // - value
503  if (object.size() != 1) { return false; }
504  const QStringList keys = object.keys();
505  if (keys.size() != 1) { return false; }
506  const QString key = keys.front();
507  const QJsonObject cacheObject = object.value(key).toObject();
508  return (cacheObject.contains("type") && cacheObject.contains("value"));
509  }
510 
511  QJsonObject swiftDataObjectValue(const QString &jsonString)
512  {
513  const QJsonObject obj = jsonObjectFromString(jsonString);
514  if (obj.isEmpty()) { return obj; }
515  return swiftDataObjectValue(obj);
516  }
517 
518  QJsonObject swiftDataObjectValue(const QJsonObject &object)
519  {
520  // key
521  // - type
522  // - value
523  if (object.size() != 1) { return object; } // no cache format
524  const QJsonObject cacheObject = object.constBegin()->toObject();
525  if (cacheObject.contains("type") && cacheObject.contains("value"))
526  {
527 #ifdef QT_DEBUG
528  const QString key = object.constBegin().key(); // clazy:exclude=unused-non-trivial-variable
529  const QString type = cacheObject.value("type").toString(); // clazy:exclude=unused-non-trivial-variable
530  Q_UNUSED(key);
531  Q_UNUSED(type);
532 #endif
533  return cacheObject.value("value").toObject();
534  }
535  return object;
536  }
537 
538  QJsonObject unwrapCache(const QJsonObject &object)
539  {
540  if (object.size() != 1) { return object; } // no cache format
541  const QJsonObject cacheObject = object.constBegin()->toObject();
542  if (cacheObject.contains("type") && cacheObject.contains("value"))
543  {
544  // return object in form type/value
545  const QString type = cacheObject.value("type").toString(); // just to verify in debugger
546  Q_UNUSED(type);
547  return cacheObject;
548  }
549  return object;
550  }
551 
552  QJsonObject unwrapCache(const QString &jsonString)
553  {
554  const QJsonObject obj = jsonObjectFromString(jsonString);
555  if (obj.isEmpty()) { return obj; }
556  return unwrapCache(obj);
557  }
558 
559  bool looksLikeSwiftContainerJson(const QJsonObject &object)
560  {
561  // CContainerbase::convertFromJson
562  return object.contains("containerbase");
563  }
564 
565  bool looksLikeSwiftTypeValuePairJson(const QJsonObject &object)
566  {
567  return (object.contains("type") && object.contains("value"));
568  }
569 
570  bool looksLikeSwiftDbJson(const QJsonObject &object) { return (object.contains("data")); }
571 
572  QString firstJsonValueAsString(const QString &json)
573  {
574  static const QString empty;
575  if (json.isEmpty()) { return empty; }
576  const QJsonObject obj = jsonObjectFromString(json);
577  return firstJsonValueAsString(obj);
578  }
579 
580  QString firstJsonValueAsString(const QJsonObject &json)
581  {
582  static const QString empty;
583  if (json.isEmpty()) { return empty; }
584  const QStringList keys1 = json.keys();
585  if (keys1.isEmpty()) { return empty; }
586  if (keys1.contains("value", Qt::CaseInsensitive)) { return json.value("value").toString(); }
587 
588  const QJsonObject jsonLevel1 = json.value(keys1.front()).toObject();
589  return jsonLevel1.value("value").toString();
590  }
591 
592  QStringList firstJsonValueAsStringList(const QString &json)
593  {
594  static const QStringList empty;
595  if (json.isEmpty()) { return empty; }
596  const QJsonObject obj = jsonObjectFromString(json);
597  return firstJsonValueAsStringList(obj);
598  }
599 
600  int firstJsonValueAsInt(const QString &json, int defaultValue, bool *ok)
601  {
602  if (ok) { *ok = false; }
603  if (json.isEmpty()) { return defaultValue; }
604  const QJsonObject obj = jsonObjectFromString(json);
605  return firstJsonValueAsInt(obj, defaultValue, ok);
606  }
607 
608  int firstJsonValueAsInt(const QJsonObject &json, int defaultValue, bool *ok)
609  {
610  if (ok) { *ok = false; }
611  if (json.isEmpty()) { return defaultValue; }
612  const QStringList keys1 = json.keys();
613  if (keys1.isEmpty()) { return defaultValue; }
614  if (keys1.contains("value", Qt::CaseInsensitive))
615  {
616  if (ok) { *ok = true; }
617  return json.value("value").toInt(defaultValue);
618  }
619 
620  const QJsonObject jsonLevel1 = json.value(keys1.front()).toObject();
621  if (!jsonLevel1.contains("value")) { return defaultValue; }
622  if (ok) { *ok = true; }
623  return jsonLevel1.value("value").toInt(defaultValue);
624  }
625 
626  QStringList firstJsonValueAsStringList(const QJsonObject &json)
627  {
628  static const QStringList empty;
629  if (json.isEmpty()) { return empty; }
630  const QStringList keys1 = json.keys();
631  if (keys1.isEmpty()) { return empty; }
632  if (keys1.contains("value", Qt::CaseInsensitive)) { return arrayToQStringList(json.value("value").toArray()); }
633 
634  const QJsonObject jsonLevel1 = json.value(keys1.front()).toObject();
635  return arrayToQStringList(jsonLevel1.value("value").toArray());
636  }
637 
638  QStringList arrayToQStringList(const QJsonArray &array)
639  {
640  QStringList sl;
641  if (array.isEmpty()) { return sl; }
642  for (int i = 0; i < array.size(); i++)
643  {
644  if (!array.at(i).isString()) { continue; }
645  sl.push_back(array.at(i).toString());
646  }
647  return sl;
648  }
649 } // namespace swift::misc::json
650 
651 QDataStream &operator<<(QDataStream &s, const std::string &v)
652 {
653  s << QString::fromStdString(v);
654  return s;
655 }
656 QDataStream &operator>>(QDataStream &s, std::string &v)
657 {
658  QString vs;
659  s >> vs;
660  v = vs.toStdString();
661  return s;
662 }
Thrown when a convertFromJson method encounters an unrecoverable error in JSON data.
Definition: jsonexception.h:24
QString stringFromJsonObject(const QJsonObject &jsonObject, QJsonDocument::JsonFormat format)
JSON Object from string.
Definition: json.cpp:424
QJsonObject & appendJsonObject(QJsonObject &target, const QJsonObject &toBeAppended)
Append to first JSON object (concatenate)
Definition: json.cpp:438
QJsonObject jsonObjectFromString(const QString &json, bool acceptCacheFormat)
JSON Object from string.
Definition: json.cpp:413
QJsonArray jsonArrayFromString(const QString &json)
JSON Array from string.
Definition: json.cpp:431
const QJsonValue & operator>>(const QJsonValue &json, int &value)
Streaming operators for QJsonValue (to value)
Definition: json.cpp:18
Free functions in swift::misc.
SWIFT_MISC_EXPORT QString pixmapToPngHexString(const QPixmap &pixmap)
Pixmap as HEX string (for PNG image)
Definition: imageutils.cpp:33
SWIFT_MISC_EXPORT bool pngHexStringToPixmapRef(const QString &hexString, QPixmap &pixmap)
Hex encoded pixmap string to Pixmap.
Definition: imageutils.cpp:48
QDebug operator<<(QDebug d, const CRange< I > &range)
Streaming operators for CRange to qDebug.
Definition: range.h:298
SWIFT_MISC_EXPORT QDateTime fromStringUtc(const QString &dateTimeString, const QString &format)
Same as QDateTime::fromString but QDateTime will be set to UTC.
QByteArray fromHex(const QByteArray &hexEncoded)
QString toString(QStringView format) const const
void append(const QJsonValue &value)
QJsonValue at(qsizetype i) const const
QJsonArray fromStringList(const QStringList &list)
bool isEmpty() const const
qsizetype size() const const
QJsonArray array() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
QByteArray toJson(QJsonDocument::JsonFormat format) const const
QJsonObject::const_iterator constBegin() const const
bool contains(QLatin1StringView key) const const
QJsonObject::iterator insert(QLatin1StringView key, const QJsonValue &value)
bool isEmpty() const const
QStringList keys() const const
void remove(QLatin1StringView key)
QJsonValue value(QLatin1StringView key) const const
bool isObject() const const
bool isString() const const
QJsonArray toArray() const const
bool toBool(bool defaultValue) const const
double toDouble(double defaultValue) const const
int toInt(int defaultValue) const const
QJsonObject toObject() const const
QString toString() const const
QList< T >::reference front()
bool isEmpty() const const
void push_back(QList< T >::parameter_type value)
qsizetype size() const const
QString::const_iterator constBegin() const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString fromStdString(const std::string &str)
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
std::string toStdString() const const
QByteArray toUtf8() const const
QString trimmed() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
CaseInsensitive