MythTV  master
mythjsonserialiser.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QMetaProperty>
3 #include <QSequentialIterable>
4 
5 // MythTV
6 #include "mythdate.h"
7 #include "http/mythhttpdata.h"
9 
10 MythJSONSerialiser::MythJSONSerialiser(const QString& Name, const QVariant& Value)
11 {
12  m_first.push(true);
13  m_writer.setDevice(&m_buffer);
14  QString name = Name;
15  if (name.startsWith("V2"))
16  name.remove(0,2);
17  AddObject(name, Value);
18  m_writer.flush();
19 }
20 
21 void MythJSONSerialiser::AddObject(const QString& Name, const QVariant& Value)
22 {
23  if (!m_first.top())
24  m_writer << ",";
25  m_writer << "{\"" << Name << "\": ";
26  AddValue(Value);
27  m_writer << "}";
28  m_first.top() = false;
29 }
30 
31 void MythJSONSerialiser::AddValue(const QVariant& Value, const QMetaProperty *MetaProperty)
32 {
33  if (Value.isNull() || !Value.isValid())
34  {
35  m_writer << "null";
36  return;
37  }
38 
39  auto * object = Value.value<QObject*>();
40  if (object)
41  {
42  QVariant isNull = object->property("isNull");
43  if (isNull.value<bool>())
44  {
45  m_writer << "null";
46  return;
47  }
48  AddQObject(object);
49  return;
50  }
51 
52  // Enum ?
53  if (MetaProperty && (MetaProperty->isEnumType() || MetaProperty->isFlagType()))
54  {
55  QMetaEnum metaEnum = MetaProperty->enumerator();
56  QString value = MetaProperty->isFlagType() ? metaEnum.valueToKeys(Value.toInt()).constData() :
57  metaEnum.valueToKey(Value.toInt());
58  // If couldn't convert to enum name, return raw value
59  value = (value.isEmpty() ? Value.toString() : value);
60  m_writer << "\"" << Encode(value) << "\"";
61  return;
62  }
63 
64  switch (
65 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
66  static_cast<QMetaType::Type>(Value.type())
67 #else
68  static_cast<QMetaType::Type>(Value.typeId())
69 #endif
70  )
71  {
72  case QMetaType::Int:
73  case QMetaType::UInt:
74  case QMetaType::LongLong:
75  case QMetaType::ULongLong:
76  m_writer << Value.toString();
77  break;
78  case QMetaType::Double:
79  m_writer << QString::number(Value.toDouble(),'f',6);
80  break;
81  case QMetaType::Float:
82  m_writer << QString::number(Value.toFloat(),'f',6);
83  break;
84  case QMetaType::Bool: m_writer << (Value.toBool() ? "true" : "false"); break;
85  case QMetaType::QStringList: AddStringList(Value); break;
86  case QMetaType::QVariantList: AddList(Value); break;
87  case QMetaType::QVariantMap: AddMap(Value.toMap()); break;
88  case QMetaType::QDateTime: m_writer << "\"" << Encode(MythDate::toString(Value.toDateTime(), MythDate::ISODate)) << "\""; break;
89  default:
90  m_writer << "\"" << Encode(Value.toString()) << "\"";
91  }
92 }
93 
94 void MythJSONSerialiser::AddQObject(const QObject* Object)
95 {
96  if (!Object)
97  return;
98  const auto * metaobject = Object->metaObject();
99  int count = metaobject->propertyCount();
100  m_first.push(true);
101  QString first;
102  m_writer << "{";
103  for (int index = 0; index < count; ++index )
104  {
105  QMetaProperty metaProperty = metaobject->property(index);
106  if (
107 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
108  metaProperty.isUser(Object)
109 #else
110  metaProperty.isUser()
111 #endif
112  )
113  {
114  const char *rawname = metaProperty.name();
115  QString name(rawname);
116  if (name.compare("objectName") == 0)
117  continue;
118  QVariant value(Object->property(rawname));
119  m_writer << first << "\"" << name << "\": ";
120  AddValue(value, &metaProperty);
121  first = ", ";
122  }
123  }
124  m_writer << "}";
125  m_first.pop();
126 }
127 
128 void MythJSONSerialiser::AddStringList(const QVariant &Values)
129 {
130  QString first;
131  m_writer << "[";
132  auto values = Values.value<QSequentialIterable>();
133  for (const auto & value : values)
134  {
135  m_writer << first << "\"" << Encode(value.toString()) << "\"";
136  first = ",";
137  }
138  m_writer << "]";
139 }
140 
141 void MythJSONSerialiser::AddList(const QVariant& Values)
142 {
143  m_first.push(true);
144  QString first;
145  m_writer << "[";
146  auto values = Values.value<QSequentialIterable>();
147  for (const auto & value : values)
148  {
149  m_writer << first;
150  AddValue(value);
151  first = ",";
152  }
153  m_writer << "]";
154  m_first.pop();
155 }
156 
157 void MythJSONSerialiser::AddMap(const QVariantMap& Map)
158 {
159  m_first.push(true);
160  QString first;
161  m_writer << "{";
162  for (auto it = Map.cbegin(); it != Map.cend(); ++it)
163  {
164  m_writer << first << "\"" << it.key() << "\":";
165  AddValue(it.value());
166  first = ",";
167  }
168  m_writer << "}";
169  m_first.pop();
170 }
171 
172 QString MythJSONSerialiser::Encode(const QString& Value)
173 {
174  if (Value.isEmpty())
175  return Value;
176 
177  QString value = Value;
178  value.replace( '\\', "\\\\" ); // This must be first
179  value.replace( '"' , "\\\"" );
180  value.replace( '\b', "\\b" ); // ^H (\u0008)
181  value.replace( '\f', "\\f" ); // ^L (\u000C)
182  value.replace( '\n', "\\n" ); // ^J (\u000A)
183  value.replace( "\r", "\\r" ); // ^M (\u000D)
184  value.replace( "\t", "\\t" ); // ^I (\u0009)
185  value.replace( "/", "\\/" );
186 
187  // Escape remaining chars from \u0000 - \u001F
188  // Details at https://en.wikipedia.org/wiki/C0_and_C1_control_codes
189  value.replace(QChar('\u0000'), "\\u0000"); // ^@ NULL
190  value.replace(QChar('\u0001'), "\\u0001"); // ^A
191  value.replace(QChar('\u0002'), "\\u0002"); // ^B
192  value.replace(QChar('\u0003'), "\\u0003"); // ^C
193  value.replace(QChar('\u0004'), "\\u0004"); // ^D
194  value.replace(QChar('\u0005'), "\\u0005"); // ^E
195  value.replace(QChar('\u0006'), "\\u0006"); // ^F
196  value.replace(QChar('\u0007'), "\\u0007"); // ^G (\a)
197  value.replace(QChar('\u000B'), "\\u000B"); // ^K (\v)
198  value.replace(QChar('\u000E'), "\\u000E"); // ^N
199  value.replace(QChar('\u000F'), "\\u000F"); // ^O
200  value.replace(QChar('\u0010'), "\\u0010"); // ^P
201  value.replace(QChar('\u0011'), "\\u0011"); // ^Q XON
202  value.replace(QChar('\u0012'), "\\u0012"); // ^R
203  value.replace(QChar('\u0013'), "\\u0013"); // ^S XOFF
204  value.replace(QChar('\u0014'), "\\u0014"); // ^T
205  value.replace(QChar('\u0015'), "\\u0015"); // ^U
206  value.replace(QChar('\u0016'), "\\u0016"); // ^V
207  value.replace(QChar('\u0017'), "\\u0017"); // ^W
208  value.replace(QChar('\u0018'), "\\u0018"); // ^X
209  value.replace(QChar('\u0019'), "\\u0019"); // ^Y
210  value.replace(QChar('\u001A'), "\\u001A"); // ^Z
211  value.replace(QChar('\u001B'), "\\u001B");
212  value.replace(QChar('\u001C'), "\\u001C");
213  value.replace(QChar('\u001D'), "\\u001D");
214  value.replace(QChar('\u001E'), "\\u001E");
215  value.replace(QChar('\u001F'), "\\u001F");
216 
217  return value;
218 }
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MythJSONSerialiser::MythJSONSerialiser
MythJSONSerialiser(const QString &Name, const QVariant &Value)
Definition: mythjsonserialiser.cpp:10
MythJSONSerialiser::Encode
static QString Encode(const QString &Value)
Definition: mythjsonserialiser.cpp:172
mythjsonserialiser.h
MythSerialiser::m_buffer
QBuffer m_buffer
Definition: mythserialiser.h:22
mythhttpdata.h
mythdate.h
MythJSONSerialiser::AddList
void AddList(const QVariant &Values)
Definition: mythjsonserialiser.cpp:141
MythJSONSerialiser::AddObject
void AddObject(const QString &Name, const QVariant &Value)
Definition: mythjsonserialiser.cpp:21
MythJSONSerialiser::m_first
std::stack< bool > m_first
Definition: mythjsonserialiser.h:27
MythJSONSerialiser::m_writer
QTextStream m_writer
Definition: mythjsonserialiser.h:26
MythJSONSerialiser::AddQObject
void AddQObject(const QObject *Object)
Definition: mythjsonserialiser.cpp:94
Name
Definition: channelsettings.cpp:71
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
MythJSONSerialiser::AddStringList
void AddStringList(const QVariant &Values)
Definition: mythjsonserialiser.cpp:128
MythJSONSerialiser::AddValue
void AddValue(const QVariant &Value, const QMetaProperty *MetaProperty=nullptr)
Definition: mythjsonserialiser.cpp:31
MythJSONSerialiser::AddMap
void AddMap(const QVariantMap &Map)
Definition: mythjsonserialiser.cpp:157