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