qmjsonvalue.cpp
Go to the documentation of this file.
1 //
2 // QtMark JSON Library
3 //
4 // Copyright (C) 2015 Assured Information Security, Inc.
5 // Author: Rian Quinn <quinnr@ainfosec.com>
6 // Author: Rodney Forbes <forbesr@ainfosec.com>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 
22 // ============================================================================
23 // Includes
24 // ============================================================================
25 #include <qmjsonvalue.h>
26 
27 #include <qmjsonarray.h>
28 #include <qmjsonobject.h>
29 #include <qmjsontype_bool.h>
30 #include <qmjsontype_double.h>
31 #include <qmjsontype_qstring.h>
32 #include <qmjsontype_qmjsonarray.h>
34 
35 #ifdef QM_DBUS_ENABLED
36 #include <QtDBus>
37 #endif
38 
39 // ============================================================================
40 // Static Variables
41 // ============================================================================
42 
43 QMap<QString, FromComplexJsonFunc> QMJsonValue::mFromFuncs;
44 
45 // ============================================================================
46 // QMJsonValue Implementation
47 // ============================================================================
48 
50 {
51  mType = QMJsonValueType_Null;
52 }
53 
55 {
56  auto type = QMPointer<QMJsonType<bool> >(new QMJsonType<bool>(value));
57 
58  mType = QMJsonValueType_Bool;
59  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
60 }
61 
63 {
64  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
65 
66  mType = QMJsonValueType_Double;
67  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
68 }
69 
70 QMJsonValue::QMJsonValue(const QString &value)
71 {
72  auto type = QMPointer<QMJsonType<QString> >(new QMJsonType<QString>(value));
73 
74  mType = QMJsonValueType_String;
75  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
76 }
77 
78 QMJsonValue::QMJsonValue(const QMPointer<QMJsonValue> &value)
79 {
80  if(value.isNull() == true)
81  {
82  mType = QMJsonValueType_Null;
83  mValue = QMPointer<QMJsonTypeBase>();
84  }
85  else
86  {
87  mType = value->mType;
88  mValue = value->mValue;
89  }
90 }
91 
92 QMJsonValue::QMJsonValue(const QMPointer<QMJsonArray> &value)
93 {
94  mType = QMJsonValueType_Array;
95 
96  if(value.isNull() == true)
97  {
98  auto array = QMPointer<QMJsonArray>(new QMJsonArray());
99  auto type = QMPointer<QMJsonType<QMPointer<QMJsonArray> > >(new QMJsonType<QMPointer<QMJsonArray> >(array));
100  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
101  }
102  else
103  {
104  auto type = QMPointer<QMJsonType<QMPointer<QMJsonArray> > >(new QMJsonType<QMPointer<QMJsonArray> >(value));
105  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
106  }
107 }
108 
109 QMJsonValue::QMJsonValue(const QMPointer<QMJsonObject> &value)
110 {
111  mType = QMJsonValueType_Object;
112 
113  if(value.isNull() == true)
114  {
115  auto object = QMPointer<QMJsonObject>(new QMJsonObject());
116  auto type = QMPointer<QMJsonType<QMPointer<QMJsonObject> > >(new QMJsonType<QMPointer<QMJsonObject> >(object));
117  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
118  }
119  else
120  {
121  auto type = QMPointer<QMJsonType<QMPointer<QMJsonObject> > >(new QMJsonType<QMPointer<QMJsonObject> >(value));
122  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
123  }
124 }
125 
127 {
128  if(value == NULL)
129  {
130  mType = QMJsonValueType_Null;
131  mValue = QMPointer<QMJsonTypeBase>();
132  }
133  else
134  {
135  mType = value->mType;
136  mValue = value->mValue;
137  }
138 }
139 
141 {
142  mType = QMJsonValueType_Array;
143 
144  if(value == NULL)
145  {
146  auto array = QMPointer<QMJsonArray>(new QMJsonArray());
147  auto type = QMPointer<QMJsonType<QMPointer<QMJsonArray> > >(new QMJsonType<QMPointer<QMJsonArray> >(array));
148  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
149  }
150  else
151  {
152  auto array = QMPointer<QMJsonArray>(value);
153  auto type = QMPointer<QMJsonType<QMPointer<QMJsonArray> > >(new QMJsonType<QMPointer<QMJsonArray> >(array));
154  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
155  }
156 }
157 
159 {
160  mType = QMJsonValueType_Object;
161 
162  if(value == NULL)
163  {
164  auto object = QMPointer<QMJsonObject>(new QMJsonObject());
165  auto type = QMPointer<QMJsonType<QMPointer<QMJsonObject> > >(new QMJsonType<QMPointer<QMJsonObject> >(object));
166  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
167  }
168  else
169  {
170  auto object = QMPointer<QMJsonObject>(value);
171  auto type = QMPointer<QMJsonType<QMPointer<QMJsonObject> > >(new QMJsonType<QMPointer<QMJsonObject> >(object));
172  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
173  }
174 }
175 
176 QMJsonValue::QMJsonValue(const char *value)
177 {
178  auto type = QMPointer<QMJsonType<QString> >(new QMJsonType<QString>(value));
179 
180  mType = QMJsonValueType_String;
181  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
182 }
183 
185 {
186  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
187 
188  mType = QMJsonValueType_Double;
189  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
190 }
191 
193 {
194  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
195 
196  mType = QMJsonValueType_Double;
197  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
198 }
199 
201 {
202  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
203 
204  mType = QMJsonValueType_Double;
205  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
206 }
207 
209 {
210  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
211 
212  mType = QMJsonValueType_Double;
213  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
214 }
215 
217 {
218  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
219 
220  mType = QMJsonValueType_Double;
221  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
222 }
223 
225 {
226  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
227 
228  mType = QMJsonValueType_Double;
229  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
230 }
231 
233 {
234  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
235 
236  mType = QMJsonValueType_Double;
237  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
238 }
239 
241 {
242  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
243 
244  mType = QMJsonValueType_Double;
245  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
246 }
247 
249 {
250  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
251 
252  mType = QMJsonValueType_Double;
253  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
254 }
255 
257 {
258  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
259 
260  mType = QMJsonValueType_Double;
261  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
262 }
263 
264 #if UINTPTR_MAX == 0xffffffff
265 
266 QMJsonValue::QMJsonValue(long value)
267 {
268  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
269 
270  mType = QMJsonValueType_Double;
271  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
272 }
273 
274 QMJsonValue::QMJsonValue(unsigned long value)
275 {
276  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
277 
278  mType = QMJsonValueType_Double;
279  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
280 }
281 
282 #elif UINTPTR_MAX == 0xffffffffffffffff
283 
284 QMJsonValue::QMJsonValue(long long value)
285 {
286  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
287 
288  mType = QMJsonValueType_Double;
289  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
290 }
291 
292 QMJsonValue::QMJsonValue(unsigned long long value)
293 {
294  auto type = QMPointer<QMJsonType<double> >(new QMJsonType<double>(value));
295 
296  mType = QMJsonValueType_Double;
297  mValue = qSharedPointerDynamicCast<QMJsonTypeBase>(type);
298 }
299 
300 #endif
301 
303 {
304 }
305 
306 bool QMJsonValue::isNull(void) const
307 {
308  return mType == QMJsonValueType_Null;
309 }
310 
311 bool QMJsonValue::isBool(void) const
312 {
313  return mType == QMJsonValueType_Bool;
314 }
315 
316 bool QMJsonValue::isDouble(void) const
317 {
318  return mType == QMJsonValueType_Double;
319 }
320 
321 bool QMJsonValue::isString(void) const
322 {
323  return mType == QMJsonValueType_String;
324 }
325 
326 bool QMJsonValue::isArray(void) const
327 {
328  return mType == QMJsonValueType_Array;
329 }
330 
331 bool QMJsonValue::isObject(void) const
332 {
333  return mType == QMJsonValueType_Object;
334 }
335 
336 bool QMJsonValue::toBool(void) const
337 {
338  switch(mType)
339  {
341  return false;
342 
344  return this->toBool(false);
345 
347  if(this->toDouble(0) == 0)
348  return false;
349  else
350  return true;
351 
353  if(this->toString("").toLower() == "true")
354  return true;
355  else
356  return false;
357 
361  return false;
362  };
363 
364  return false;
365 }
366 
367 double QMJsonValue::toDouble(void) const
368 {
369  switch(mType)
370  {
372  return 0;
373 
375  if(this->toBool(false) == true)
376  return 1;
377  else
378  return 0;
379 
381  return this->toDouble(0);
382 
384  return this->toString("").toDouble();
385 
389  return 0;
390  };
391 
392  return 0;
393 }
394 
395 QString QMJsonValue::toString(void) const
396 {
397  switch(mType)
398  {
400  return "null";
401 
403  if(this->toBool(false) == true)
404  return "true";
405  else
406  return "false";
407 
409  return QString::number(this->toDouble(0));
410 
412  return this->toString(QString());
413 
417  return QString();
418  };
419 
420  return QString();
421 }
422 
423 const QMPointer<QMJsonArray> &QMJsonValue::toArray(void) const
424 {
425  static auto defaultValue = QMPointer<QMJsonArray>(new QMJsonArray);
426  auto type = qSharedPointerDynamicCast<QMJsonType<QMPointer<QMJsonArray> > >(mValue);
427 
428  if(type == NULL)
429  return defaultValue;
430 
431  return type->get();
432 }
433 
434 const QMPointer<QMJsonObject> &QMJsonValue::toObject(void) const
435 {
436  static auto defaultValue = QMPointer<QMJsonObject>(new QMJsonObject);
437  auto type = qSharedPointerDynamicCast<QMJsonType<QMPointer<QMJsonObject> > >(mValue);
438 
439  if(type == NULL)
440  return defaultValue;
441 
442  return type->get();
443 }
444 
445 bool QMJsonValue::toBool(bool defaultValue) const
446 {
447  auto type = qSharedPointerDynamicCast<QMJsonType<bool> >(mValue);
448 
449  if(type == NULL)
450  return defaultValue;
451 
452  return type->get();
453 }
454 
455 double QMJsonValue::toDouble(double defaultValue) const
456 {
457  auto type = qSharedPointerDynamicCast<QMJsonType<double> >(mValue);
458 
459  if(type == NULL)
460  return defaultValue;
461 
462  return type->get();
463 }
464 
465 const QString &QMJsonValue::toString(const QString &defaultValue) const
466 {
467  auto type = qSharedPointerDynamicCast<QMJsonType<QString> >(mValue);
468 
469  if(type == NULL)
470  return defaultValue;
471 
472  return type->get();
473 }
474 
475 const QMPointer<QMJsonArray> &QMJsonValue::toArray(const QMPointer<QMJsonArray> &defaultValue) const
476 {
477  auto type = qSharedPointerDynamicCast<QMJsonType<QMPointer<QMJsonArray> > >(mValue);
478 
479  if(type == NULL)
480  return defaultValue;
481 
482  return type->get();
483 }
484 
485 const QMPointer<QMJsonObject> &QMJsonValue::toObject(const QMPointer<QMJsonObject> &defaultValue) const
486 {
487  auto type = qSharedPointerDynamicCast<QMJsonType<QMPointer<QMJsonObject> > >(mValue);
488 
489  if(type == NULL)
490  return defaultValue;
491 
492  return type->get();
493 }
494 
495 bool QMJsonValue::fromBool(bool value)
496 {
497  switch(mType)
498  {
500  return false;
501 
503  return this->set<bool>(value);
504 
506  if(value == true)
507  return this->set<double>(1);
508  else
509  return this->set<double>(0);
510 
512  if(value == true)
513  return this->set<QString>("true");
514  else
515  return this->set<QString>("false");
516 
520  return false;
521  };
522 
523  return false;
524 }
525 
526 bool QMJsonValue::fromDouble(double value)
527 {
528  switch(mType)
529  {
531  return false;
532 
534  if(value == 0)
535  return this->set<bool>(false);
536  else
537  return this->set<bool>(true);
538 
540  return this->set<double>(value);
541 
543  return this->set<QString>(QString::number(value));
544 
548  return false;
549  };
550 
551  return false;
552 }
553 
554 bool QMJsonValue::fromString(const QString &value)
555 {
556  switch(mType)
557  {
559  return false;
560 
562  if(value == "true")
563  return this->set<bool>(true);
564  else
565  return this->set<bool>(false);
566 
568  {
569  auto ok = false;
570  auto result = value.toDouble(&ok);
571 
572  if(ok == false)
573  return false;
574 
575  return this->set<double>(result);
576  }
577 
579  return this->set<QString>(value);
580 
584  return false;
585  };
586 
587  return false;
588 }
589 
590 bool QMJsonValue::fromArray(const QMPointer<QMJsonArray> &value)
591 {
592  switch(mType)
593  {
598  return false;
599 
601  if(value.isNull() == true)
602  return this->set<QMPointer<QMJsonArray> >(QMPointer<QMJsonArray>(new QMJsonArray));
603  else
604  return this->set<QMPointer<QMJsonArray> >(value);
605 
608  return false;
609  };
610 
611  return false;
612 }
613 
614 bool QMJsonValue::fromObject(const QMPointer<QMJsonObject> &value)
615 {
616  switch(mType)
617  {
623  return false;
624 
626  if(value.isNull() == true)
627  return this->set<QMPointer<QMJsonObject> >(QMPointer<QMJsonObject>(new QMJsonObject));
628  else
629  return this->set<QMPointer<QMJsonObject> >(value);
630 
632  return false;
633  };
634 
635  return false;
636 }
637 
638 bool QMJsonValue::from(const QMPointer<QMJsonValue> &value)
639 {
640  if(value.isNull() == true)
641  return false;
642 
643  if(value->type() == QMJsonValueType_Custom)
644  return false;
645 
646  switch(mType)
647  {
649  return value->isNull();
650 
652  return this->fromBool(value->toBool());
653 
655  return this->fromDouble(value->toDouble());
656 
658  return this->fromString(value->toString());
659 
661  return this->fromArray(value->toArray());
662 
664  return this->fromObject(value->toObject());
665 
667  return false;
668  };
669 
670  return false;
671 }
672 
673 const QMPointer<QMJsonValue> &QMJsonValue::value(int32_t index) const
674 {
675  return this->toArray()->value(index);
676 }
677 
678 const QMPointer<QMJsonValue> &QMJsonValue::value(const QString &key) const
679 {
680  return this->toObject()->value(key);
681 }
682 
684 {
685  switch(mType)
686  {
688  return QVariant();
689 
691  return QVariant(this->toBool());
692 
694  return QVariant(this->toDouble());
695 
697  return QVariant(this->toString());
698 
700  {
701  auto list = QVariantList();
702 
703  for(const auto &value : this->toArray()->values())
704  list.append(value->toVariant());
705 
706  return QVariant::fromValue(list);
707  }
708 
710  {
711  auto hash = QVariantHash();
712  const auto &object = this->toObject();
713 
714  for(const auto &key : object->keys())
715  hash[key] = object->value(key)->toVariant();
716 
717  return QVariant::fromValue(hash);
718  }
719 
721  return QVariant();
722  };
723 
724  return QVariant();
725 }
726 
727 QMPointer<QMJsonValue> QMJsonValue::fromVariant(const QVariant &value)
728 {
729  switch(value.type())
730  {
731  case QMetaType::QVariantMap:
732  case QMetaType::QVariantHash:
733  {
734  auto object = QMPointer<QMJsonObject>(new QMJsonObject);
735  auto iterable = value.value<QAssociativeIterable>();
736  auto it = iterable.begin();
737  const auto end = iterable.end();
738 
739  for(; it != end; ++it)
740  object->insert(it.key().toString(), QMJsonValue::fromVariant(it.value()));
741 
742  return QMPointer<QMJsonValue>(new QMJsonValue(object));
743  }
744 
745  case QMetaType::QVariantList:
746  {
747  auto array = QMPointer<QMJsonArray>(new QMJsonArray);
748 
749  for(const auto &variant : value.value<QSequentialIterable>())
750  array->append(QMJsonValue::fromVariant(variant));
751 
752  return QMPointer<QMJsonValue>(new QMJsonValue(array));
753  }
754 
755  // case QMetaType::Void:
756  // return QMPointer<QMJsonValue>(new QMJsonValue());
757 
758  case QMetaType::Bool:
759  return QMPointer<QMJsonValue>(new QMJsonValue(value.value<bool>()));
760 
761  case QMetaType::Int:
762  case QMetaType::UInt:
763  // case QMetaType::Float:
764  case QMetaType::Double:
765  // case QMetaType::Long:
766  case QMetaType::LongLong:
767  // case QMetaType::ULong:
768  case QMetaType::ULongLong:
769  // case QMetaType::Short:
770  // case QMetaType::UShort:
771  // case QMetaType::Char:
772  // case QMetaType::SChar:
773  // case QMetaType::UChar:
774  return QMPointer<QMJsonValue>(new QMJsonValue(value.value<double>()));
775 
776  case QMetaType::QChar:
777  case QMetaType::QString:
778  case QMetaType::QByteArray:
779  return QMPointer<QMJsonValue>(new QMJsonValue(value.value<QString>()));
780 
781  case QMetaType::User:
782  {
783 
784 #ifdef QM_DBUS_ENABLED
785 
786  if(value.canConvert<QDBusArgument>() == true)
787  {
788  const auto &arg = value.value<QDBusArgument>();
789 
790  switch(arg.currentType())
791  {
792  case QDBusArgument::BasicType:
793  case QDBusArgument::VariantType:
794  case QDBusArgument::StructureType:
795  return QMJsonValue::fromVariant(arg.asVariant());
796 
797  case QDBusArgument::ArrayType:
798  {
799  auto array = QMPointer<QMJsonArray>(new QMJsonArray);
800 
801  arg.beginArray();
802  while(!arg.atEnd())
803  array->append(QMJsonValue::fromVariant(arg.asVariant()));
804  arg.endArray();
805 
806  return QMPointer<QMJsonValue>(new QMJsonValue(array));
807  }
808 
809  default:
810  return QMPointer<QMJsonValue>(new QMJsonValue());
811  }
812  }
813 
814  if(value.canConvert<QDBusObjectPath>() == true)
815  return QMPointer<QMJsonValue>(new QMJsonValue(value.value<QDBusObjectPath>().path()));
816 
817  if(value.canConvert<QDBusVariant>() == true)
818  return QMJsonValue::fromVariant(value.value<QDBusVariant>().variant());
819 
820 #endif
821  break;
822  }
823 
824  default:
825  break;
826  }
827 
828  return QMPointer<QMJsonValue>(new QMJsonValue());
829 }
830 
832 {
833  return mType;
834 }
835 
836 const QString &QMJsonValue::typeString(void) const
837 {
838  auto index = (int32_t)mType;
839  static auto strings = QList<QString>()
840  << "QMJsonValueType_Null"
841  << "QMJsonValueType_Bool"
842  << "QMJsonValueType_Double"
843  << "QMJsonValueType_String"
844  << "QMJsonValueType_Array"
845  << "QMJsonValueType_Object"
846  << "QMJsonValueType_Custom"
847  << "QMJsonValueType_Unknown";
848 
849  if(index < 0) index = strings.count() - 1;
850  if(index >= strings.count()) index = strings.count() - 1;
851 
852  return strings.at(index);
853 }
854 
855 QString QMJsonValue::toJson(QMJsonFormat format, QMJsonSort sort) const
856 {
857  if(mValue.isNull() == true)
858  return "null";
859 
860  // When we convert to JSON, we need to check to see if this is a base type.
861  // Base types don't need to be broken up into their base types, since they
862  // already are base types. If this is not a base type, it's a complex type,
863  // which means that we use it's complex version of toJson instead
864  if(mValue->isBaseType() == true)
865  {
866  return mValue->toJson(format, sort);
867  }
868  else
869  {
870  // Since this is a complex type, we need to first create a JSON Object,
871  // so that the conversion code can convert this type to an Object
872  // for us. Once this is done, we can just call the toJson on that
873  // object. Note that since this is a tree structure, the conversion
874  // function can provide other complex types. This same function will
875  // be recursively called and will handle embedded complex types for us
876  // auto-magically.
877  auto obj = QMPointer<QMJsonObject>(new QMJsonObject());
878  auto value = QMPointer<QMJsonValue>(new QMJsonValue(obj));
879 
880  // Do the conversion.
881  mValue->toComplexJson(obj);
882 
883  // We don't really care about what's in the object since this is
884  // custom, but we do care that at minimum, we have the type information.
885  // Otherwise, bad things are going to happen.
886  if(obj->contains("qmjsontype") == false)
887  return QString();
888 
889  // Now all that is left, is to convert the class to the base types.
890  // Note that the object might have complex types embedded in it, which
891  // means that this code will be called again.
892  return value->toJson(format, sort);
893  }
894 }
895 
896 bool QMJsonValue::toJsonFile(const QString &filename, QMJsonFormat format, QMJsonSort sort) const
897 {
898  QSaveFile file(filename);
899  QTextStream stream(&file);
900 
901  if(file.open(QIODevice::WriteOnly | QIODevice::Text) == false)
902  return false;
903 
904  stream << this->toJson(format, sort) << "\r\n";
905 
906  return file.commit();
907 
908 }
909 
910 QMPointer<QMJsonValue> QMJsonValue::fromJson(const QString &json)
911 {
912  auto index = 0;
913  auto value = QMPointer<QMJsonValue>();
914 
915  try
916  {
917  QMJsonValue::skipSpaces(json, index);
918 
919  if(index >= json.length())
920  return QMPointer<QMJsonValue>(new QMJsonValue());
921 
922  value = QMJsonValue::fromJson(json, index);
923 
924  if(value.isNull() == false)
925  return value;
926  }
927 
928  catch(const QString &str)
929  {
930  qDebug() << "QMJsonValue::fromJson Failed -" + str;
931  }
932 
933  return QMPointer<QMJsonValue>(new QMJsonValue());
934 }
935 
936 QMPointer<QMJsonValue> QMJsonValue::fromComplexJson(const QMPointer<QMJsonValue> &value)
937 {
938  if(value.isNull() == true)
939  return QMPointer<QMJsonValue>(new QMJsonValue());
940 
941  if(value->isObject() == true)
942  {
943  auto obj = value->toObject();
944 
945  if(obj->contains("qmjsontype") == true)
946  {
947  auto func = mFromFuncs[obj->value("qmjsontype")->toString()];
948 
949  if(func == NULL)
950  return value;
951 
952  auto result = func(obj);
953 
954  if(result.isNull() == true)
955  return value;
956 
957  return result;
958  }
959  }
960 
961  return value;
962 }
963 
964 void QMJsonValue::registerFromComplexJson(const QString &qmjsontype, FromComplexJsonFunc func)
965 {
966  if(qmjsontype.isEmpty() == true)
967  return;
968 
969  if(func == NULL)
970  return;
971 
972  mFromFuncs[qmjsontype] = func;
973 }
974 
975 void QMJsonValue::skipSpaces(const QString &json, int32_t &index)
976 {
977  while(index < json.length() && json.at(index).isSpace() == true)
978  index++;
979 }
980 
981 void QMJsonValue::verifyIndex(const QString &json, int32_t &index)
982 {
983  if(index >= json.length())
984  QMJsonValue::throwError(json, index, "Incomplete JSON");
985 }
986 
987 QMPointer<QMJsonValue> QMJsonValue::fromJson(const QString &json, int32_t &index)
988 {
989  auto value = QMPointer<QMJsonValue>();
990 
991  QMJsonValue::skipSpaces(json, index);
992  QMJsonValue::verifyIndex(json, index);
993 
994  // Per the JSON spec, we are in a JSON "value" which means that we need
995  // to figure out type we actually have. In other words, we need to
996  // traverse this state machine:
997  //
998  // | --|------- string --------|-- |
999  // |------- number --------|
1000  // |------- object --------|
1001  // |------- array --------|
1002  // |------- true --------|
1003  // |------- false --------|
1004  // |------- null --------|
1005  //
1006  // To do this, we need to look at "how" we can detect which type we are
1007  // dealing with.
1008  // - A string starts with "
1009  // - A number is the last thing we check (no good way to know up front)
1010  // - An object starts with {
1011  // - An array starts with [
1012  // - true, false, and null are just string comparisons.
1013  //
1014  // So the following logic takes this approach. It basically looks for
1015  // what type we are dealing with and attempts to parse based on what
1016  // the next character is.
1017  //
1018  // Note that we use a single pass implementation based on the state
1019  // machines outline in the JSON spec. This means that we only know
1020  // what we are currently looking at.
1021  //
1022  // Note that we use the default case as the number. This is because
1023  // there is no easy way to detect if this is a number, so we just
1024  // assume that if the the switch statement cannot make heads or
1025  // tails of the current character, that it must be a number. The number
1026  // logic will make sure that this is actually a number that we can parse.
1027  //
1028  // Note that this is a recursive function, so you do not know what the
1029  // value of index is at a given time, and you don't know what type you are
1030  // currently looking at. Its safe to assume that you are probably starting
1031  // with a JSON object or array, but other than that, all bets are off.
1032 
1033  switch(json.at(index).toLatin1())
1034  {
1035  case '"':
1036  return QMJsonType<QString>::fromJson(json, index);
1037 
1038  case '{':
1039  return QMJsonValue::fromComplexJson(QMJsonType<QMPointer<QMJsonObject> >::fromJson(json, index));
1040 
1041  case '[':
1042  return QMJsonType<QMPointer<QMJsonArray> >::fromJson(json, index);
1043 
1044  case 'T':
1045  case 't':
1046  case 'F':
1047  case 'f':
1048  return QMJsonType<bool>::fromJson(json, index);
1049 
1050  case 'N':
1051  case 'n':
1052  {
1053  auto valid = true;
1054 
1055  index++;
1056 
1057  QMJsonValue::verifyIndex(json, index); valid &= json.at(index).toLower() == 'u'; index++;
1058  QMJsonValue::verifyIndex(json, index); valid &= json.at(index).toLower() == 'l'; index++;
1059  QMJsonValue::verifyIndex(json, index); valid &= json.at(index).toLower() == 'l'; index++;
1060 
1061  if(valid == false)
1062  QMJsonValue::throwError(json, index, "Unexpected token. Expected \"NULL\" while parsing JSON.");
1063 
1064  return QMPointer<QMJsonValue>(new QMJsonValue());
1065  }
1066 
1067  case ']':
1068  case '}':
1069  QMJsonValue::throwError(json, index, "Unexpected closing bracket. Are there too many commas?");
1070 
1071  default:
1072  return QMJsonType<double>::fromJson(json, index);
1073  }
1074 
1075  return QMPointer<QMJsonValue>(new QMJsonValue());
1076 }
1077 
1078 QMPointer<QMJsonValue> QMJsonValue::fromJsonFile(const QString &filename)
1079 {
1080  QFile file(filename);
1081 
1082  if(file.exists() == false)
1083  return QMPointer<QMJsonValue>();
1084 
1085  if(file.open(QIODevice::ReadOnly | QIODevice::Text) == false)
1086  return QMPointer<QMJsonValue>();
1087 
1088  return QMJsonValue::fromJson(file.readAll());
1089 }
1090 
1091 void QMJsonValue::throwError(const QString &json, int32_t index, QString error)
1092 {
1093  throw(error + " - Line Number: " + QString::number(json.left(index).count("\n")));
1094 }
1095 
1096 QDebug operator<<(QDebug dbg, const QMJsonValue &value)
1097 {
1098  QDebugStateSaver saver(dbg);
1099  dbg.nospace() << "QMJsonValue(";
1100 
1101  if(value.mValue != NULL)
1102  {
1103  value.mValue->print(dbg);
1104  dbg << ")";
1105  }
1106  else
1107  {
1108  dbg << "NULL" << ")";
1109  }
1110 
1111  return dbg;
1112 }
1113 
1114 QDebug operator<<(QDebug dbg, const QMPointer<QMJsonValue> &value)
1115 {
1116  if(value.isNull() == true)
1117  {
1118  QDebugStateSaver saver(dbg);
1119 
1120  dbg.nospace() << "QMPointer<";
1121  dbg << "QMJsonValue" << ">: NULL";
1122 
1123  return dbg;
1124  }
1125  else
1126  {
1127  return dbg << *value;
1128  }
1129 }
virtual bool isDouble(void) const
virtual bool fromBool(bool value)
static QMPointer< QMJsonValue > fromJson(const QString &json)
virtual bool toJsonFile(const QString &filename, QMJsonFormat format=QMJsonFormat_Pretty, QMJsonSort sort=QMJsonSort_None) const
virtual bool isNull(void) const
virtual bool toBool(void) const
virtual const QString & typeString(void) const
QMJsonFormat
Definition: qmjsontype.h:62
virtual void set(const T &value)
Definition: qmjsontype.h:171
virtual bool isBool(void) const
static QMPointer< QMJsonValue > fromJson(const QString &json, int32_t &index)
Definition: qmjsontype.h:198
virtual QString toString(void) const
virtual bool isObject(void) const
virtual QVariant toVariant(void)
virtual const QMPointer< QMJsonValue > & value(int32_t index) const
virtual bool isArray(void) const
virtual bool isString(void) const
virtual bool fromObject(const QMPointer< QMJsonObject > &value)
virtual const QMPointer< QMJsonObject > & toObject(void) const
virtual bool fromArray(const QMPointer< QMJsonArray > &value)
virtual QMJsonValueType type(void) const
virtual QString toJson(QMJsonFormat format=QMJsonFormat_Pretty, QMJsonSort sort=QMJsonSort_None) const
virtual ~QMJsonValue()
virtual const QMPointer< QMJsonArray > & toArray(void) const
static QMPointer< QMJsonValue > fromVariant(const QVariant &value)
virtual bool fromDouble(double value)
virtual double toDouble(void) const
virtual bool from(const QMPointer< QMJsonValue > &value)
QDebug operator<<(QDebug dbg, const QMJsonValue &value)
QMJsonValueType
Definition: qmjsontype.h:45
static QMPointer< QMJsonValue > fromJsonFile(const QString &filename)
QMJsonSort
Definition: qmjsontype.h:68
virtual bool fromString(const QString &value)
QMPointer< QMJsonValue >(* FromComplexJsonFunc)(const QMPointer< QMJsonObject > &obj)
Definition: qmjsonvalue.h:42
static void registerFromComplexJson(const QString &qmjsontype, FromComplexJsonFunc func)