MythTV  master
mythhttpmetamethod.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QDateTime>
3 #include <QFileInfo>
4 #include <QTimeZone>
5 
6 // MythTV
7 #include "mythlogging.h"
9 
10 #define LOC QString("MetaMethod: ")
11 
19 MythHTTPMetaMethod::MythHTTPMetaMethod(int Index, QMetaMethod& Method, int RequestTypes,
20  const QString& ReturnName, bool Slot)
21  : m_index(Index),
22  m_requestTypes(RequestTypes),
23  m_method(Method)
24 {
25  // Static list of unsupported return types (cannot be serialised (QHash) or of no use (pointers))
26  static const std::vector<int> s_invalidTypes =
27  {
28  QMetaType::UnknownType, QMetaType::VoidStar, QMetaType::QObjectStar,
29  QMetaType::QVariantHash, QMetaType::QRect, QMetaType::QRectF,
30  QMetaType::QSize, QMetaType::QSizeF, QMetaType::QLine,
31  QMetaType::QLineF, QMetaType::QPoint, QMetaType::QPointF
32  };
33 
34  // Static list of unsupported parameters (all invalid types plus extras)
35  static const std::vector<int> s_invalidParams =
36  {
37  QMetaType::UnknownType, QMetaType::VoidStar, QMetaType::QObjectStar,
38  QMetaType::QVariantHash, QMetaType::QRect, QMetaType::QRectF,
39  QMetaType::QSize, QMetaType::QSizeF, QMetaType::QLine,
40  QMetaType::QLineF, QMetaType::QPoint, QMetaType::QPointF,
41  QMetaType::QVariantMap, QMetaType::QStringList, QMetaType::QVariantList
42  };
43 
44  int returntype = Method.returnType();
45 
46  // Discard methods with an unsupported return type
47  if (std::any_of(s_invalidTypes.cbegin(), s_invalidTypes.cend(), [&returntype](int Type) { return Type == returntype; }))
48  {
49  LOG(VB_HTTP, LOG_ERR, LOC + QString("Method '%1' has unsupported return type '%2'").arg(Method.name().constData(), Method.typeName()));
50  return;
51  }
52 
53  // Warn about complicated methods not supported by QMetaMethod - these will
54  // fail if all arguments are required and used
55  if (Method.parameterCount() > (Q_METAMETHOD_INVOKE_MAX_ARGS - 1))
56  {
57  LOG(VB_HTTP, LOG_WARNING, LOC + QString("Method '%1' takes more than %2 parameters; will probably fail")
58  .arg(Method.name().constData()).arg(Q_METAMETHOD_INVOKE_MAX_ARGS - 1));
59  }
60 
61  // Decide on the name of the returned type
62  if (Slot && ValidReturnType(returntype))
63  {
64  // Explicitly set via Q_CLASSINFO (name=XXX)
65  m_returnTypeName = ReturnName;
66  if (m_returnTypeName.isEmpty())
67  {
68  // If this is a user type, we assume its name should be used, otherwise
69  // prefer deduction from methodname
70  if (returntype <= QMetaType::User)
71  if (QString(Method.name()).startsWith(QStringLiteral("Get"), Qt::CaseInsensitive))
72  m_returnTypeName = Method.name().mid(3);
73  // Default to the type name
74  if (m_returnTypeName.isEmpty())
75  m_returnTypeName = Method.typeName();
76  // Duplicated from MythXMLSerialiser
77  if (m_returnTypeName.startsWith("Q"))
79  m_returnTypeName.remove("DTC::");
80  m_returnTypeName.remove(QChar('*'));
81  }
82  }
83 
84  // Add method name and return type
85  m_types.emplace_back(returntype >= 0 ? returntype : 0);
86  m_names.emplace_back(Method.name());
87 
88  // Add type/value for each method parameter
89  auto names = Method.parameterNames();
90  auto types = Method.parameterTypes();
91 
92  // Add type/value for each method parameter
93  for (int i = 0; i < names.size(); ++i)
94  {
95 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
96  int type = QMetaType::type(types[i]);
97 #else
98  int type = QMetaType::fromName(types[i]).id();
99 #endif
100 
101  // Discard methods that use unsupported parameter types.
102  // Note: slots only - these are supportable for signals
103  if (Slot && std::any_of(s_invalidParams.cbegin(), s_invalidParams.cend(), [&type](int Type) { return type == Type; }))
104  {
105  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Method '%1' has unsupported parameter type '%2' (%3)")
106  .arg(Method.name().constData(), types[i].constData()).arg(type));
107  return;
108  }
109 
110  m_names.emplace_back(names[i]);
111  m_types.emplace_back(type);
112  }
113 
114  m_valid = true;
115 }
116 
117 HTTPMethodPtr MythHTTPMetaMethod::Create(int Index, QMetaMethod &Method, int RequestTypes,
118  const QString &ReturnName, bool Slot)
119 {
120  HTTPMethodPtr result =
121  std::shared_ptr<MythHTTPMetaMethod>(new MythHTTPMetaMethod(Index, Method, RequestTypes, ReturnName, Slot));
122  if (result->m_valid)
123  return result;
124  return nullptr;
125 }
126 
132 void* MythHTTPMetaMethod::CreateParameter(void* Parameter, int Type, const QString& Value)
133 {
134 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
135  QByteArray typeName = QMetaType::typeName(Type);
136 #else
137  QByteArray typeName = QMetaType(Type).name();
138 #endif
139 
140  // Enum types
141 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
142  auto typeflags = QMetaType::typeFlags(Type);
143 #else
144  auto typeflags = QMetaType(Type).flags();
145 #endif
146  if ((typeflags & QMetaType::IsEnumeration) == QMetaType::IsEnumeration)
147  {
148  // QMetaEnum::keyToValue will return -1 for an unrecognised enumerant, so
149  // default to -1 for all error cases
150  int value = -1;
151  if (int index = typeName.lastIndexOf("::" ); index > -1)
152  {
153  QString enumname = typeName.mid(index + 2);
154 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
155  const auto * metaobject = QMetaType::metaObjectForType(Type);
156 #else
157  const auto * metaobject = QMetaType(Type).metaObject();
158 #endif
159  if (metaobject)
160  {
161  int enumindex = metaobject->indexOfEnumerator(enumname.toUtf8());
162  if (enumindex >= 0)
163  {
164  QMetaEnum metaEnum = metaobject->enumerator(enumindex);
165  value = metaEnum.keyToValue(Value.toUtf8());
166  }
167  }
168  }
169  *(static_cast<int*>(Parameter)) = value;
170  return Parameter;
171  }
172 
173  // Handle parameters of type std::chrono::seconds
174  if (typeName == "std::chrono::seconds")
175  {
176  *(static_cast<std::chrono::seconds*>(Parameter)) = std::chrono::seconds(Value.toInt());
177  return Parameter;
178  }
179 
180  switch (Type)
181  {
182  case QMetaType::QVariant : *(static_cast<QVariant *>(Parameter)) = QVariant(Value); break;
183  case QMetaType::Bool : *(static_cast<bool *>(Parameter)) = ToBool(Value ); break;
184  case QMetaType::Char : *(static_cast<char *>(Parameter)) = (Value.length() > 0) ? Value.at(0).toLatin1() : 0; break;
185  case QMetaType::UChar : *(static_cast<unsigned char*>(Parameter)) = (Value.length() > 0) ? static_cast<unsigned char>(Value.at(0).toLatin1()) : 0; break;
186  case QMetaType::QChar : *(static_cast<QChar *>(Parameter)) = (Value.length() > 0) ? Value.at(0) : QChar(0); break;
187  case QMetaType::Short : *(static_cast<short *>(Parameter)) = Value.toShort(); break;
188  case QMetaType::UShort : *(static_cast<ushort *>(Parameter)) = Value.toUShort(); break;
189  case QMetaType::Int : *(static_cast<int *>(Parameter)) = Value.toInt(); break;
190  case QMetaType::UInt : *(static_cast<uint *>(Parameter)) = Value.toUInt(); break;
191  case QMetaType::Long : *(static_cast<long *>(Parameter)) = Value.toLong(); break;
192  case QMetaType::ULong : *(static_cast<ulong *>(Parameter)) = Value.toULong(); break;
193  case QMetaType::LongLong : *(static_cast<qlonglong *>(Parameter)) = Value.toLongLong(); break;
194  case QMetaType::ULongLong : *(static_cast<qulonglong *>(Parameter)) = Value.toULongLong(); break;
195  case QMetaType::Double : *(static_cast<double *>(Parameter)) = Value.toDouble(); break;
196  case QMetaType::Float : *(static_cast<float *>(Parameter)) = Value.toFloat(); break;
197  case QMetaType::QString : *(static_cast<QString *>(Parameter)) = Value; break;
198  case QMetaType::QByteArray: *(static_cast<QByteArray *>(Parameter)) = Value.toUtf8(); break;
199  case QMetaType::QTime : *(static_cast<QTime *>(Parameter)) = QTime::fromString(Value, Qt::ISODate ); break;
200  case QMetaType::QDate : *(static_cast<QDate *>(Parameter)) = QDate::fromString(Value, Qt::ISODate ); break;
201  case QMetaType::QDateTime :
202  {
203  QDateTime dt = QDateTime::fromString(Value, Qt::ISODate);
204 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
205  dt.setTimeSpec(Qt::UTC);
206 #else
207  dt.setTimeZone(QTimeZone(QTimeZone::UTC));
208 #endif
209  *(static_cast<QDateTime*>(Parameter)) = dt;
210  break;
211  }
212  default:
213  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Unknown QMetaType:%1 %2").arg(Type).arg(QString(typeName)));
214  break;
215  }
216  return Parameter;
217 }
218 
219 QVariant MythHTTPMetaMethod::CreateReturnValue(int Type, void* Value)
220 {
221  if (!(ValidReturnType(Type)))
222  return {};
223 
224  // This assumes any user type will be derived from QObject...
225  // (Exception for QFileInfo)
226  if (
227 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
228  Type == QMetaType::type("QFileInfo")
229 #else
230  Type == QMetaType::fromName("QFileInfo").id()
231 #endif
232  )
233  return QVariant::fromValue<QFileInfo>(*(static_cast<QFileInfo*>(Value)));
234 
235  if (Type > QMetaType::User)
236  {
237  QObject* object = *(static_cast<QObject**>(Value));
238  return QVariant::fromValue<QObject*>(object);
239  }
240 
241 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
242  return {Type, Value};
243 #else
244  return QVariant(QMetaType(Type), Value);
245 #endif
246 }
types
static const struct wl_interface * types[]
Definition: idle_inhibit_unstable_v1.c:39
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythHTTPMetaMethod::Create
static HTTPMethodPtr Create(int Index, QMetaMethod &Method, int RequestTypes, const QString &ReturnName={}, bool Slot=true)
Definition: mythhttpmetamethod.cpp:117
MythHTTPMetaMethod::ToBool
static bool ToBool(const QString &Value)
Definition: mythhttpmetamethod.h:47
mythlogging.h
MythHTTPMetaMethod::CreateParameter
static void * CreateParameter(void *Parameter, int Type, const QString &Value)
Populate the QMetaType object referenced by Parameter with Value.
Definition: mythhttpmetamethod.cpp:132
LOC
#define LOC
Definition: mythhttpmetamethod.cpp:10
MythHTTPMetaMethod::ValidReturnType
static bool ValidReturnType(int Type)
Definition: mythhttpmetamethod.h:42
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:39
MythHTTPMetaMethod::m_names
std::vector< QString > m_names
Definition: mythhttpmetamethod.h:31
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
MythHTTPMetaMethod::MythHTTPMetaMethod
MythHTTPMetaMethod(int Index, QMetaMethod &Method, int RequestTypes, const QString &ReturnName, bool Slot)
Definition: mythhttpmetamethod.cpp:19
MythHTTPMetaMethod::CreateReturnValue
static QVariant CreateReturnValue(int Type, void *Value)
Definition: mythhttpmetamethod.cpp:219
MythHTTPMetaMethod::m_valid
bool m_valid
Definition: mythhttpmetamethod.h:26
mythhttpmetamethod.h
MythHTTPMetaMethod::m_returnTypeName
QString m_returnTypeName
Definition: mythhttpmetamethod.h:33
HTTPMethodPtr
std::shared_ptr< MythHTTPMetaMethod > HTTPMethodPtr
Definition: mythhttpmetamethod.h:14
MythHTTPMetaMethod::m_types
std::vector< int > m_types
Definition: mythhttpmetamethod.h:32
uint
unsigned int uint
Definition: freesurround.h:24