1 // This is the implementation of the various Chimera helpers.
2 //
3 // Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of PyQt5.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file. Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license. For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19
20
21 #include <Python.h>
22
23 #include <QDBusArgument>
24 #include <QDBusObjectPath>
25 #include <QDBusSignature>
26 #include <QDBusVariant>
27 #include <QMetaType>
28
29 #include "qpydbus_chimera_helpers.h"
30
31 #include "sipAPIQtDBus.h"
32
33
34 // Forward declarations.
35 static PyObject *from_variant_type(const QDBusArgument &arg);
36 static PyObject *from_array_type(const QDBusArgument &arg);
37 static PyObject *from_structure_type(const QDBusArgument &arg);
38 static PyObject *from_map_type(const QDBusArgument &arg);
39 static PyObject *from_qstring(const QString &arg);
40 static PyObject *from_qvariant(const QVariant &arg);
41
42
43 // Convert a QVariant to a Python object.
qpydbus_from_qvariant_convertor(const QVariant & var,PyObject ** objp)44 bool qpydbus_from_qvariant_convertor(const QVariant &var, PyObject **objp)
45 {
46 // Handle QDBusObjectPath.
47 if (var.userType() == qMetaTypeId<QDBusObjectPath>())
48 {
49 *objp = from_qstring(var.value<QDBusObjectPath>().path());
50
51 return true;
52 }
53
54 // Handle QDBusSignature.
55 if (var.userType() == qMetaTypeId<QDBusSignature>())
56 {
57 *objp = from_qstring(var.value<QDBusSignature>().signature());
58
59 return true;
60 }
61
62 // Handle QDBusVariant.
63 if (var.userType() == qMetaTypeId<QDBusVariant>())
64 {
65 *objp = from_qvariant(var.value<QDBusVariant>().variant());
66
67 return true;
68 }
69
70 // Anything else must be a QDBusArgument.
71 if (var.userType() != qMetaTypeId<QDBusArgument>())
72 return false;
73
74 QDBusArgument arg = var.value<QDBusArgument>();
75
76 switch (arg.currentType())
77 {
78 case QDBusArgument::BasicType:
79 *objp = from_qvariant(arg.asVariant());
80 break;
81
82 case QDBusArgument::VariantType:
83 *objp = from_variant_type(arg);
84 break;
85
86 case QDBusArgument::ArrayType:
87 *objp = from_array_type(arg);
88 break;
89
90 case QDBusArgument::StructureType:
91 *objp = from_structure_type(arg);
92 break;
93
94 case QDBusArgument::MapType:
95 *objp = from_map_type(arg);
96 break;
97
98 default:
99 PyErr_Format(PyExc_TypeError, "unsupported DBus argument type %d",
100 (int)arg.currentType());
101 *objp = 0;
102 }
103
104 return true;
105 }
106
107
108 // Convert a QDBusArgument variant type to a Python object.
from_variant_type(const QDBusArgument & arg)109 static PyObject *from_variant_type(const QDBusArgument &arg)
110 {
111 QDBusVariant dbv;
112
113 arg >> dbv;
114
115 return from_qvariant(dbv.variant());
116 }
117
118
119 // Convert a QDBusArgument array type to a Python object.
from_array_type(const QDBusArgument & arg)120 static PyObject *from_array_type(const QDBusArgument &arg)
121 {
122 QVariantList vl;
123
124 arg.beginArray();
125
126 while (!arg.atEnd())
127 vl.append(arg.asVariant());
128
129 arg.endArray();
130
131 PyObject *obj = PyList_New(vl.count());
132
133 if (!obj)
134 return 0;
135
136 for (int i = 0; i < vl.count(); ++i)
137 {
138 PyObject *itm = from_qvariant(vl.at(i));
139
140 if (!itm)
141 {
142 Py_DECREF(obj);
143 return 0;
144 }
145
146 PyList_SetItem(obj, i, itm);
147 }
148
149 return obj;
150 }
151
152
153 // Convert a QDBusArgument structure type to a Python object.
from_structure_type(const QDBusArgument & arg)154 static PyObject *from_structure_type(const QDBusArgument &arg)
155 {
156 QVariantList vl;
157
158 arg.beginStructure();
159
160 while (!arg.atEnd())
161 vl.append(arg.asVariant());
162
163 arg.endStructure();
164
165 PyObject *obj = PyTuple_New(vl.count());
166
167 if (!obj)
168 return 0;
169
170 for (int i = 0; i < vl.count(); ++i)
171 {
172 PyObject *itm = from_qvariant(vl.at(i));
173
174 if (!itm)
175 {
176 Py_DECREF(obj);
177 return 0;
178 }
179
180 PyTuple_SetItem(obj, i, itm);
181 }
182
183 return obj;
184 }
185
186
187 // Convert a QDBusArgument map type to a Python object.
from_map_type(const QDBusArgument & arg)188 static PyObject *from_map_type(const QDBusArgument &arg)
189 {
190 PyObject *obj = PyDict_New();
191
192 if (!obj)
193 return 0;
194
195 arg.beginMap();
196
197 while (!arg.atEnd())
198 {
199 arg.beginMapEntry();
200
201 PyObject *key = from_qvariant(arg.asVariant());
202 PyObject *value = from_qvariant(arg.asVariant());
203
204 arg.endMapEntry();
205
206 if (!key || !value)
207 {
208 Py_XDECREF(key);
209 Py_XDECREF(value);
210 Py_DECREF(obj);
211
212 return 0;
213 }
214
215 int rc = PyDict_SetItem(obj, key, value);
216
217 Py_DECREF(key);
218 Py_DECREF(value);
219
220 if (rc < 0)
221 {
222 Py_DECREF(obj);
223
224 return 0;
225 }
226 }
227
228 arg.endMap();
229
230 return obj;
231 }
232
233
234 // Convert a QString to a Python object.
from_qstring(const QString & arg)235 static PyObject *from_qstring(const QString &arg)
236 {
237 QString *heap = new QString(arg);
238 PyObject *obj = sipConvertFromNewType(heap, sipType_QString, 0);
239
240 if (!obj)
241 delete heap;
242
243 return obj;
244 }
245
246
247 // Convert a QVariant to a Python object.
from_qvariant(const QVariant & arg)248 static PyObject *from_qvariant(const QVariant &arg)
249 {
250 QVariant *heap = new QVariant(arg);
251 PyObject *obj = sipConvertFromNewType(heap, sipType_QVariant, 0);
252
253 if (!obj)
254 delete heap;
255
256 return obj;
257 }
258