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
10MythJSONSerialiser::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
21void 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
31void 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
94void 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
128void 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
141void 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
157void 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
172QString 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}
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