1 // This is the implementation of the Chimera class.
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 <QByteArray>
24 #include <QMetaObject>
25 #include <QMetaType>
26
27 #include "qpycore_chimera.h"
28 #include "qpycore_misc.h"
29 #include "qpycore_pyqtpyobject.h"
30 #include "qpycore_types.h"
31
32 #include "sipAPIQtCore.h"
33
34
35 // The registered Python enum types.
36 QSet<PyObject *> Chimera::_py_enum_types;
37
38 // The cache of previously parsed argument type lists.
39 QHash<QByteArray, QList<const Chimera *> > Chimera::_previously_parsed;
40
41 // The registered QVariant to PyObject convertors.
42 Chimera::FromQVariantConvertors Chimera::registeredFromQVariantConvertors;
43
44 // The registered PyObject to QVariant convertors.
45 Chimera::ToQVariantConvertors Chimera::registeredToQVariantConvertors;
46
47 // The registered PyObject to QVariant data convertors.
48 Chimera::ToQVariantDataConvertors Chimera::registeredToQVariantDataConvertors;
49
50 const int UnknownType = QMetaType::UnknownType;
51
52 // Construct an invalid type.
Chimera()53 Chimera::Chimera()
54 : _type(0), _py_type(0), _metatype(UnknownType), _inexact(false),
55 _is_qflags(false)
56 {
57 }
58
59
60 // Construct a copy.
Chimera(const Chimera & other)61 Chimera::Chimera(const Chimera &other)
62 {
63 _type = other._type;
64
65 _py_type = other._py_type;
66 Py_XINCREF((PyObject *)_py_type);
67
68 _metatype = other._metatype;
69 _inexact = other._inexact;
70 _is_qflags = other._is_qflags;
71 _name = other._name;
72 }
73
74
75 // Destroy the type.
~Chimera()76 Chimera::~Chimera()
77 {
78 Py_XDECREF((PyObject *)_py_type);
79 }
80
81
82 // Register the type of a Python enum.
registerPyEnum(PyObject * enum_type)83 void Chimera::registerPyEnum(PyObject *enum_type)
84 {
85 Py_INCREF(enum_type);
86 _py_enum_types.insert(enum_type);
87 }
88
89
90 // Parse an object as a type.
parse(PyObject * obj)91 const Chimera *Chimera::parse(PyObject *obj)
92 {
93 Chimera *ct = new Chimera;
94 bool parse_ok;
95
96 if (PyType_Check(obj))
97 {
98 // Parse the type object.
99 parse_ok = ct->parse_py_type((PyTypeObject *)obj);
100
101 if (!parse_ok)
102 raiseParseException(obj);
103 }
104 else
105 {
106 const char *cpp_type_name = sipString_AsASCIIString(&obj);
107
108 if (cpp_type_name)
109 {
110 // Always use normalised type names so that we have a consistent
111 // standard.
112 QByteArray norm_name = QMetaObject::normalizedType(cpp_type_name);
113 Py_DECREF(obj);
114
115 // Parse the type name.
116 parse_ok = ct->parse_cpp_type(norm_name);
117
118 if (!parse_ok)
119 raiseParseCppException(cpp_type_name);
120 }
121 else
122 {
123 parse_ok = false;
124 }
125 }
126
127 if (!parse_ok)
128 {
129 delete ct;
130 return 0;
131 }
132
133 return ct;
134 }
135
136
137 // Parse a C++ type name as a type.
parse(const QByteArray & name)138 const Chimera *Chimera::parse(const QByteArray &name)
139 {
140 Chimera *ct = new Chimera;
141
142 if (!ct->parse_cpp_type(name))
143 {
144 delete ct;
145
146 raiseParseCppException(name.constData());
147
148 return 0;
149 }
150
151 return ct;
152 }
153
154
155 // Parse a meta-property as a type.
parse(const QMetaProperty & mprop)156 const Chimera *Chimera::parse(const QMetaProperty &mprop)
157 {
158 Chimera *ct = new Chimera;
159 const char *type_name = mprop.typeName();
160
161 ct->_type = sipFindType(type_name);
162 ct->_metatype = mprop.userType();
163 ct->_inexact = true;
164 ct->_is_qflags = mprop.isFlagType();
165 ct->_name = type_name;
166
167 return ct;
168 }
169
170
171 // Parse a normalised C++ signature as a list of types.
parse(const QByteArray & sig,const char * context)172 Chimera::Signature *Chimera::parse(const QByteArray &sig, const char *context)
173 {
174 // Extract the argument list.
175 int start_idx = sig.indexOf('(');
176
177 if (start_idx < 0)
178 start_idx = 0;
179 else
180 ++start_idx;
181
182 int end_idx = sig.lastIndexOf(')');
183
184 int len;
185
186 if (end_idx < start_idx)
187 len = -1;
188 else
189 len = end_idx - start_idx;
190
191 // Parse each argument type.
192 Chimera::Signature *parsed_sig = new Chimera::Signature(sig, true);
193
194 if (len > 0)
195 {
196 QByteArray args_str = sig.mid(start_idx, len);
197
198 // Check we haven't already done it.
199 QList<const Chimera *> parsed_args = _previously_parsed.value(args_str);
200
201 if (parsed_args.isEmpty())
202 {
203 int i, arg_start, template_level;
204
205 i = arg_start = template_level = 0;
206
207 // Extract each argument allowing for commas in templates.
208 for (;;)
209 {
210 char ch = (i < args_str.size() ? args_str.at(i) : '\0');
211 QByteArray arg;
212
213 switch (ch)
214 {
215 case '<':
216 ++template_level;
217 break;
218
219 case '>':
220 --template_level;
221 break;
222
223 case '\0':
224 arg = args_str.mid(arg_start, i - arg_start);
225 break;
226
227 case ',':
228 if (template_level == 0)
229 {
230 arg = args_str.mid(arg_start, i - arg_start);
231 arg_start = i + 1;
232 }
233
234 break;
235 }
236
237 if (!arg.isEmpty())
238 {
239 Chimera *ct = new Chimera;
240
241 if (!ct->parse_cpp_type(arg))
242 {
243 delete ct;
244 delete parsed_sig;
245 qDeleteAll(parsed_args.constBegin(),
246 parsed_args.constEnd());
247
248 raiseParseCppException(arg.constData(), context);
249
250 return 0;
251 }
252
253 parsed_args.append(ct);
254
255 if (ch == '\0')
256 break;
257 }
258
259 ++i;
260 }
261
262 // Only parse once.
263 _previously_parsed.insert(args_str, parsed_args);
264 }
265
266 parsed_sig->parsed_arguments = parsed_args;
267 }
268
269 return parsed_sig;
270 }
271
272
273 // Parses a C++ signature given as a Python tuple of types and an optional
274 // name. Return 0 if there was an error.
parse(PyObject * types,const char * name,const char * context)275 Chimera::Signature *Chimera::parse(PyObject *types, const char *name,
276 const char *context)
277 {
278 if (!name)
279 name = "";
280
281 Chimera::Signature *parsed_sig = new Chimera::Signature(name, false);
282
283 parsed_sig->signature.append('(');
284 parsed_sig->py_signature.append('[');
285
286 for (Py_ssize_t i = 0; i < PyTuple_Size(types); ++i)
287 {
288 PyObject *type = PyTuple_GetItem(types, i);
289 const Chimera *parsed_type = parse(type);
290
291 if (!parsed_type)
292 {
293 delete parsed_sig;
294
295 raiseParseException(type, context);
296
297 return 0;
298 }
299
300 parsed_sig->parsed_arguments.append(parsed_type);
301
302 if (i > 0)
303 {
304 parsed_sig->signature.append(',');
305 parsed_sig->py_signature.append(", ");
306 }
307
308 parsed_sig->signature.append(parsed_type->name());
309
310 if (parsed_type->_py_type)
311 parsed_sig->py_signature.append(sipPyTypeName(parsed_type->_py_type));
312 else
313 parsed_sig->py_signature.append(parsed_type->name());
314 }
315
316 parsed_sig->signature.append(')');
317 parsed_sig->py_signature.append(']');
318
319 return parsed_sig;
320 }
321
322
323 // Raise an exception after parse() of a Python type has failed.
raiseParseException(PyObject * type,const char * context)324 void Chimera::raiseParseException(PyObject *type, const char *context)
325 {
326 if (PyType_Check(type))
327 {
328 if (context)
329 PyErr_Format(PyExc_TypeError,
330 "Python type '%s' is not supported as %s type",
331 sipPyTypeName((PyTypeObject *)type), context);
332 else
333 PyErr_Format(PyExc_TypeError, "unknown Python type '%s'",
334 sipPyTypeName((PyTypeObject *)type));
335 }
336 else
337 {
338 const char *cpp_type_name = sipString_AsASCIIString(&type);
339
340 if (cpp_type_name)
341 {
342 raiseParseCppException(cpp_type_name, context);
343 Py_DECREF(type);
344 }
345 }
346 }
347
348
349 // Raise an exception after parse() of a C++ type has failed.
raiseParseCppException(const char * type,const char * context)350 void Chimera::raiseParseCppException(const char *type, const char *context)
351 {
352 if (context)
353 PyErr_Format(PyExc_TypeError,
354 "C++ type '%s' is not supported as %s type", type, context);
355 else
356 PyErr_Format(PyExc_TypeError, "unknown C++ type '%s'", type);
357 }
358
359
360 // Parse the given Python type object.
parse_py_type(PyTypeObject * type_obj)361 bool Chimera::parse_py_type(PyTypeObject *type_obj)
362 {
363 const sipTypeDef *td = sipTypeFromPyTypeObject(type_obj);
364
365 if (td)
366 {
367 if (sipTypeIsNamespace(td))
368 return false;
369
370 _type = td;
371 _name = sipTypeName(td);
372
373 if (sipTypeIsClass(td))
374 set_qflags();
375
376 if (sipTypeIsEnum(td) || _is_qflags)
377 {
378 _metatype = QMetaType::Int;
379 }
380 else
381 {
382 // If there is no assignment helper then assume it is a
383 // pointer-type.
384 if (!get_assign_helper())
385 _name.append('*');
386
387 _metatype = QMetaType::type(_name.constData());
388
389 // If it is a user type then it must be a type that SIP knows
390 // about but was registered by Qt.
391 if (_metatype < QMetaType::User)
392 {
393 if (PyType_IsSubtype(type_obj, sipTypeAsPyTypeObject(sipType_QObject)))
394 {
395 _metatype = QMetaType::QObjectStar;
396 }
397 else if (sipIsUserType((sipWrapperType *)type_obj))
398 {
399 // It is a non-QObject Python sub-class so make sure it
400 // gets wrapped in a PyQt_PyObject.
401 _type = 0;
402 _metatype = PyQt_PyObject::metatype;
403 _name.clear();
404 }
405 }
406 }
407 }
408 else if (_py_enum_types.contains((PyObject *)type_obj))
409 {
410 _metatype = QMetaType::Int;
411 _name = sipPyTypeName(type_obj);
412 }
413 else if (type_obj == &PyList_Type)
414 {
415 _metatype = QMetaType::QVariantList;
416 }
417 #if PY_MAJOR_VERSION >= 3
418 else if (type_obj == &PyUnicode_Type)
419 {
420 _type = sipType_QString;
421 _metatype = QMetaType::QString;
422 }
423 #else
424 else if (type_obj == &PyString_Type || type_obj == &PyUnicode_Type)
425 {
426 // In this case we accept that the reverse conversion will result in an
427 // object of a different type (i.e. a QString rather than a Python
428 // string).
429 _type = sipType_QString;
430 _metatype = QMetaType::QString;
431 }
432 #endif
433 else if (type_obj == &PyBool_Type)
434 {
435 _metatype = QMetaType::Bool;
436 }
437 #if PY_MAJOR_VERSION < 3
438 else if (type_obj == &PyInt_Type)
439 {
440 // We choose to map to a C++ int, even though a Python int is
441 // potentially much larger, as it represents the most common usage in
442 // Qt. However we will allow a larger type to be used if the context
443 // is right.
444 _metatype = QMetaType::Int;
445 _inexact = true;
446 }
447 #endif
448 else if (type_obj == &PyLong_Type)
449 {
450 // We choose to map to a C++ int for the same reasons as above and to
451 // be consistent with Python3 where everything is a long object. If
452 // this isn't appropriate the user can always use a string to specify
453 // the exact C++ type they want.
454 _metatype = QMetaType::Int;
455 _inexact = true;
456 }
457 else if (type_obj == &PyFloat_Type)
458 {
459 _metatype = QMetaType::Double;
460 }
461 else if (type_obj == sipVoidPtr_Type)
462 {
463 _metatype = QMetaType::VoidStar;
464 _name = "void*";
465 }
466
467 // Fallback to using a PyQt_PyObject.
468 if (_metatype == UnknownType)
469 _metatype = PyQt_PyObject::metatype;
470
471 // If there is no name so far then use the meta-type name.
472 if (_name.isEmpty())
473 _name = QMetaType::typeName(_metatype);
474
475 _py_type = type_obj;
476 Py_INCREF((PyObject *)_py_type);
477
478 return true;
479 }
480
481
482 // Set the internal QFlags flag.
set_qflags()483 void Chimera::set_qflags()
484 {
485 if (qpycore_is_pyqt_class(_type))
486 _is_qflags = ((pyqt5ClassPluginDef *)sipTypePluginData(_type))->flags & 0x01;
487 }
488
489
490 // Update a C++ type so that any typedefs are resolved.
resolve_types(const QByteArray & type)491 QByteArray Chimera::resolve_types(const QByteArray &type)
492 {
493 // Split into a base type and a possible list of template arguments.
494 QByteArray resolved = type.simplified();
495
496 // Get the raw type, ie. without any "const", "&" or "*".
497 QByteArray raw_type;
498 int original_raw_start;
499
500 if (resolved.startsWith("const "))
501 original_raw_start = 6;
502 else
503 original_raw_start = 0;
504
505 raw_type = resolved.mid(original_raw_start);
506
507 while (raw_type.endsWith('&') || raw_type.endsWith('*') || raw_type.endsWith(' '))
508 raw_type.chop(1);
509
510 int original_raw_len = raw_type.size();
511
512 if (original_raw_len == 0)
513 return QByteArray();
514
515 // Get any template arguments.
516 QList<QByteArray> args;
517 int tstart = raw_type.indexOf('<');
518
519 if (tstart >= 0)
520 {
521 // Make sure the template arguments are terminated.
522 if (!raw_type.endsWith('>'))
523 return QByteArray();
524
525 // Split the template arguments taking nested templates into account.
526 int depth = 1, arg_start = tstart + 1;
527
528 for (int i = arg_start; i < raw_type.size(); ++i)
529 {
530 int arg_end = -1;
531 char ch = raw_type.at(i);
532
533 if (ch == '<')
534 {
535 ++depth;
536 }
537 else if (ch == '>')
538 {
539 --depth;
540
541 if (depth < 0)
542 return QByteArray();
543
544 if (depth == 0)
545 arg_end = i;
546 }
547 else if (ch == ',' && depth == 1)
548 {
549 arg_end = i;
550 }
551
552 if (arg_end >= 0)
553 {
554 QByteArray arg = resolve_types(raw_type.mid(arg_start, arg_end - arg_start));
555
556 if (arg.isEmpty())
557 return QByteArray();
558
559 args.append(arg);
560
561 arg_start = arg_end + 1;
562 }
563 }
564
565 if (depth != 0)
566 return QByteArray();
567
568 // Remove the template arguments.
569 raw_type.truncate(tstart);
570 }
571
572 // Expand any typedef.
573 const char *base_type = sipResolveTypedef(raw_type.constData());
574
575 if (base_type)
576 raw_type = base_type;
577
578 // Add any (now resolved) template arguments.
579 if (args.count() > 0)
580 {
581 raw_type.append('<');
582
583 for (QList<QByteArray>::const_iterator it = args.begin();;)
584 {
585 raw_type.append(*it);
586
587 if (++it == args.end())
588 break;
589
590 raw_type.append(',');
591 }
592
593 if (raw_type.endsWith('>'))
594 raw_type.append(' ');
595
596 raw_type.append('>');
597 }
598
599 // Replace the original raw type with the resolved one.
600 resolved.replace(original_raw_start, original_raw_len, raw_type);
601
602 return resolved;
603 }
604
605
606 // Parse the given C++ type name.
parse_cpp_type(const QByteArray & type)607 bool Chimera::parse_cpp_type(const QByteArray &type)
608 {
609 _name = type;
610 QByteArray nonconst_name = type.mid(type.startsWith("const ") ? 6 : 0);
611
612 // Resolve any types.
613 QByteArray resolved = resolve_types(nonconst_name);
614
615 if (resolved.isEmpty())
616 return false;
617
618 // See if the type is known to Qt.
619 _metatype = QMetaType::type(resolved.constData());
620
621 // If not then use the PyQt_PyObject wrapper.
622 if (_metatype == UnknownType)
623 _metatype = PyQt_PyObject::metatype;
624
625 // See if the type (without a pointer) is known to SIP.
626 bool is_ptr = resolved.endsWith('*');
627
628 if (is_ptr)
629 {
630 resolved.chop(1);
631
632 if (resolved.endsWith('*'))
633 return false;
634 }
635
636 _type = sipFindType(resolved.constData());
637
638 // If we didn't find the type and we have resolved some typedefs then try
639 // again with the original type. This means that QVector<qreal> will work
640 // as a signal argument type. It may be that we should always lookup the
641 // original type - but we don't want to risk breaking things.
642 if (!_type && nonconst_name != resolved)
643 _type = sipFindType(nonconst_name.constData());
644
645 if (!_type)
646 {
647 // This is the only fundamental pointer type recognised by Qt.
648 if (_metatype == QMetaType::VoidStar)
649 return true;
650
651 // This is 'int', 'bool', etc.
652 if (_metatype != PyQt_PyObject::metatype && !is_ptr)
653 return true;
654
655 if (resolved == "char" && is_ptr)
656 {
657 // This is a special value meaning a (hopefully) '\0' terminated
658 // string.
659 _metatype = -1;
660
661 return true;
662 }
663
664 // This is an explicit 'PyQt_PyObject'.
665 if (resolved == "PyQt_PyObject" && !is_ptr)
666 return true;
667
668 return false;
669 }
670
671 if (sipTypeIsNamespace(_type))
672 return false;
673
674 if (sipTypeIsClass(_type))
675 {
676 set_qflags();
677
678 if (is_ptr)
679 {
680 PyTypeObject *type_obj = sipTypeAsPyTypeObject(_type);
681
682 if (PyType_IsSubtype(type_obj, sipTypeAsPyTypeObject(sipType_QObject)))
683 {
684 _metatype = QMetaType::QObjectStar;
685 }
686 }
687 }
688
689 // We don't support pointers to enums.
690 if (sipTypeIsEnum(_type) && is_ptr)
691 _type = 0;
692
693 if (sipTypeIsEnum(_type) || _is_qflags)
694 _metatype = QMetaType::Int;
695
696 return true;
697 }
698
699
700 // Convert a Python object to C++ at a given address. This has a lot in common
701 // with the method that converts to a QVariant. However, unlike that method,
702 // we have no control over the size of the destination storage and so must
703 // convert exactly as requested.
fromPyObject(PyObject * py,void * cpp) const704 bool Chimera::fromPyObject(PyObject *py, void *cpp) const
705 {
706 // Let any registered convertors have a go first.
707 for (int i = 0; i < registeredToQVariantDataConvertors.count(); ++i)
708 {
709 bool ok;
710
711 if (registeredToQVariantDataConvertors.at(i)(py, cpp, _metatype, &ok))
712 return ok;
713 }
714
715 int iserr = 0;
716
717 PyErr_Clear();
718
719 switch (_metatype)
720 {
721 case QMetaType::Bool:
722 *reinterpret_cast<bool *>(cpp) = PyLong_AsLong(py);
723 break;
724
725 case QMetaType::Int:
726 // Truncate it if necessary to fit into a C++ int. This will
727 // automatically handle enums and flag types as Python knows how to
728 // convert them to ints.
729 #if PY_MAJOR_VERSION >= 3
730 *reinterpret_cast<int *>(cpp) = PyLong_AsLong(py);
731 #else
732 *reinterpret_cast<int *>(cpp) = PyInt_AsLong(py);
733 #endif
734 break;
735
736 case QMetaType::UInt:
737 *reinterpret_cast<unsigned int *>(cpp) = sipLong_AsUnsignedLong(py);
738 break;
739
740 case QMetaType::Double:
741 *reinterpret_cast<double *>(cpp) = PyFloat_AsDouble(py);
742 break;
743
744 case QMetaType::VoidStar:
745 *reinterpret_cast<void **>(cpp) = sipConvertToVoidPtr(py);
746 break;
747
748 case QMetaType::Long:
749 *reinterpret_cast<long *>(cpp) = PyLong_AsLong(py);
750 break;
751
752 case QMetaType::LongLong:
753 *reinterpret_cast<qlonglong *>(cpp) = PyLong_AsLongLong(py);
754 break;
755
756 case QMetaType::Short:
757 *reinterpret_cast<short *>(cpp) = PyLong_AsLong(py);
758 break;
759
760 case QMetaType::Char:
761 if (SIPBytes_Check(py) && SIPBytes_Size(py) == 1)
762 *reinterpret_cast<char *>(cpp) = *SIPBytes_AsString(py);
763 else
764 iserr = 1;
765 break;
766
767 case QMetaType::ULong:
768 *reinterpret_cast<unsigned long *>(cpp) = sipLong_AsUnsignedLong(py);
769 break;
770
771 case QMetaType::ULongLong:
772 *reinterpret_cast<qulonglong *>(cpp) = static_cast<qulonglong>(PyLong_AsUnsignedLongLong(py));
773 break;
774
775 case QMetaType::UShort:
776 *reinterpret_cast<unsigned short *>(cpp) = sipLong_AsUnsignedLong(py);
777 break;
778
779 case QMetaType::UChar:
780 if (SIPBytes_Check(py) && SIPBytes_Size(py) == 1)
781 *reinterpret_cast<unsigned char *>(cpp) = *SIPBytes_AsString(py);
782 else
783 iserr = 1;
784 break;
785
786 case QMetaType::Float:
787 *reinterpret_cast<float *>(cpp) = PyFloat_AsDouble(py);
788 break;
789
790 case QMetaType::QObjectStar:
791 *reinterpret_cast<void **>(cpp) = sipForceConvertToType(py,
792 sipType_QObject, 0, SIP_NO_CONVERTORS, 0, &iserr);
793 break;
794
795 case QMetaType::QVariantList:
796 {
797 QVariantList ql;
798
799 if (to_QVariantList(py, ql))
800 *reinterpret_cast<QVariantList *>(cpp) = ql;
801 else
802 iserr = 1;
803
804 break;
805 }
806
807 case QMetaType::QVariantMap:
808 {
809 QVariantMap qm;
810
811 if (qpycore_toQVariantMap(py, qm))
812 *reinterpret_cast<QVariantMap *>(cpp) = qm;
813 else
814 iserr = 1;
815
816 break;
817 }
818
819 case QMetaType::QVariantHash:
820 {
821 QVariantHash qh;
822
823 if (to_QVariantHash(py, qh))
824 *reinterpret_cast<QVariantHash *>(cpp) = qh;
825 else
826 iserr = 1;
827
828 break;
829 }
830
831 case -1:
832 {
833 const char **ptr = reinterpret_cast<const char **>(cpp);
834
835 if (SIPBytes_Check(py))
836 *ptr = SIPBytes_AsString(py);
837 else if (py == Py_None)
838 *ptr = 0;
839 else
840 iserr = 1;
841
842 break;
843 }
844
845 default:
846 if (_type)
847 {
848 if (_name.endsWith('*'))
849 {
850 // This must be a pointer-type.
851
852 *reinterpret_cast<void **>(cpp) = sipForceConvertToType(py,
853 _type, 0, SIP_NO_CONVERTORS, 0, &iserr);
854 }
855 else
856 {
857 // This must be a value-type.
858
859 sipAssignFunc assign = get_assign_helper();
860
861 if (assign)
862 {
863 int state;
864 void *value_class;
865
866 value_class = sipForceConvertToType(py, _type, 0,
867 SIP_NOT_NONE, &state, &iserr);
868
869 if (!iserr)
870 assign(cpp, 0, value_class);
871
872 sipReleaseType(value_class, _type, state);
873 }
874 else
875 {
876 iserr = 1;
877 }
878 }
879 }
880 else
881 {
882 iserr = 1;
883 }
884 }
885
886 if (iserr || PyErr_Occurred())
887 {
888 PyErr_Format(PyExc_TypeError,
889 "unable to convert a Python '%s' object to a C++ '%s' instance",
890 sipPyTypeName(Py_TYPE(py)), _name.constData());
891
892 return false;
893 }
894
895 return true;
896 }
897
898
899 // Return the assignment helper for the type, if any.
get_assign_helper() const900 sipAssignFunc Chimera::get_assign_helper() const
901 {
902 if (sipTypeIsClass(_type))
903 return ((sipClassTypeDef *)_type)->ctd_assign;
904
905 if (sipTypeIsMapped(_type))
906 return ((sipMappedTypeDef *)_type)->mtd_assign;
907
908 return 0;
909 }
910
911
912 // Convert a Python object to a QVariant.
fromPyObject(PyObject * py,QVariant * var,bool strict) const913 bool Chimera::fromPyObject(PyObject *py, QVariant *var, bool strict) const
914 {
915 // Deal with the simple case of wrapping the Python object rather than
916 // converting it.
917 if (_type != sipType_QVariant && _metatype == PyQt_PyObject::metatype)
918 {
919 // If the type was specified by a Python type (as opposed to
920 // 'PyQt_PyObject') then check the object is an instance of it.
921 if (_py_type && !PyObject_TypeCheck(py, _py_type))
922 return false;
923
924 *var = keep_as_pyobject(py);
925 return true;
926 }
927
928 // Let any registered convertors have a go first. However don't invoke
929 // then for None because that is effectively reserved for representing a
930 // null QString.
931 if (py != Py_None)
932 {
933 for (int i = 0; i < registeredToQVariantConvertors.count(); ++i)
934 {
935 bool ok;
936
937 if (registeredToQVariantConvertors.at(i)(py, *var, &ok))
938 return ok;
939 }
940 }
941
942 int iserr = 0, value_class_state;
943 void *ptr_class, *value_class = 0;
944
945 // Temporary storage for different types.
946 union {
947 bool tmp_bool;
948 int tmp_int;
949 unsigned int tmp_unsigned_int;
950 double tmp_double;
951 void *tmp_void_ptr;
952 long tmp_long;
953 qlonglong tmp_qlonglong;
954 short tmp_short;
955 char tmp_char;
956 unsigned long tmp_unsigned_long;
957 qulonglong tmp_qulonglong;
958 unsigned short tmp_unsigned_short;
959 unsigned char tmp_unsigned_char;
960 float tmp_float;
961 } tmp_storage;
962
963 void *variant_data = &tmp_storage;
964
965 PyErr_Clear();
966
967 QVariant variant;
968 int metatype_used = _metatype;
969
970 switch (_metatype)
971 {
972 case QMetaType::Bool:
973 tmp_storage.tmp_bool = PyLong_AsLong(py);
974 break;
975
976 case QMetaType::Int:
977 if (!_inexact || isEnum())
978 {
979 // It must fit into a C++ int.
980 #if PY_MAJOR_VERSION >= 3
981 tmp_storage.tmp_int = PyLong_AsLong(py);
982 #else
983 tmp_storage.tmp_int = PyInt_AsLong(py);
984 #endif
985 }
986 else
987 {
988 // Fit it into the smallest C++ type we can.
989
990 qlonglong qll = PyLong_AsLongLong(py);
991
992 if (PyErr_Occurred())
993 {
994 // Try again in case the value is unsigned and will fit with
995 // the extra bit.
996
997 PyErr_Clear();
998
999 qulonglong qull = static_cast<qulonglong>(PyLong_AsUnsignedLongLong(py));
1000
1001 if (PyErr_Occurred())
1002 {
1003 // It won't fit into any C++ type so pass it as a Python
1004 // object.
1005
1006 PyErr_Clear();
1007
1008 *var = keep_as_pyobject(py);
1009 metatype_used = UnknownType;
1010 }
1011 else
1012 {
1013 tmp_storage.tmp_qulonglong = qull;
1014 metatype_used = QMetaType::ULongLong;
1015 }
1016 }
1017 else if ((qlonglong)(int)qll == qll)
1018 {
1019 // It fits in a C++ int.
1020 tmp_storage.tmp_int = qll;
1021 }
1022 else if ((qulonglong)(unsigned int)qll == (qulonglong)qll)
1023 {
1024 // The extra bit is enough for it to fit.
1025 tmp_storage.tmp_unsigned_int = qll;
1026 metatype_used = QMetaType::UInt;
1027 }
1028 else
1029 {
1030 // This fits.
1031 tmp_storage.tmp_qlonglong = qll;
1032 metatype_used = QMetaType::LongLong;
1033 }
1034 }
1035
1036 break;
1037
1038 case QMetaType::UInt:
1039 tmp_storage.tmp_unsigned_int = sipLong_AsUnsignedLong(py);
1040 break;
1041
1042 case QMetaType::Double:
1043 tmp_storage.tmp_double = PyFloat_AsDouble(py);
1044 break;
1045
1046 case QMetaType::VoidStar:
1047 tmp_storage.tmp_void_ptr = sipConvertToVoidPtr(py);
1048 break;
1049
1050 case QMetaType::Long:
1051 tmp_storage.tmp_long = PyLong_AsLong(py);
1052 break;
1053
1054 case QMetaType::LongLong:
1055 tmp_storage.tmp_qlonglong = PyLong_AsLongLong(py);
1056 break;
1057
1058 case QMetaType::Short:
1059 tmp_storage.tmp_short = PyLong_AsLong(py);
1060 break;
1061
1062 case QMetaType::Char:
1063 if (SIPBytes_Check(py) && SIPBytes_Size(py) == 1)
1064 tmp_storage.tmp_char = *SIPBytes_AsString(py);
1065 else
1066 iserr = 1;
1067 break;
1068
1069 case QMetaType::ULong:
1070 tmp_storage.tmp_unsigned_long = sipLong_AsUnsignedLong(py);
1071 break;
1072
1073 case QMetaType::ULongLong:
1074 tmp_storage.tmp_qulonglong = static_cast<qulonglong>(PyLong_AsUnsignedLongLong(py));
1075 break;
1076
1077 case QMetaType::UShort:
1078 tmp_storage.tmp_unsigned_short = sipLong_AsUnsignedLong(py);
1079 break;
1080
1081 case QMetaType::UChar:
1082 if (SIPBytes_Check(py) && SIPBytes_Size(py) == 1)
1083 tmp_storage.tmp_unsigned_char = *SIPBytes_AsString(py);
1084 else
1085 iserr = 1;
1086 break;
1087
1088 case QMetaType::Float:
1089 tmp_storage.tmp_float = PyFloat_AsDouble(py);
1090 break;
1091
1092 case QMetaType::QObjectStar:
1093 tmp_storage.tmp_void_ptr = sipForceConvertToType(py, sipType_QObject,
1094 0, SIP_NO_CONVERTORS, 0, &iserr);
1095 break;
1096
1097 case QMetaType::QVariantList:
1098 {
1099 QVariantList ql;
1100
1101 if (to_QVariantList(py, ql))
1102 {
1103 *var = QVariant(ql);
1104 metatype_used = UnknownType;
1105 }
1106 else
1107 {
1108 iserr = 1;
1109 }
1110
1111 break;
1112 }
1113
1114 case QMetaType::QVariantMap:
1115 {
1116 QVariantMap qm;
1117
1118 if (qpycore_toQVariantMap(py, qm))
1119 {
1120 *var = QVariant(qm);
1121 metatype_used = UnknownType;
1122 }
1123 else if (strict)
1124 {
1125 iserr = 1;
1126 }
1127 else
1128 {
1129 // Assume the failure is because the key was the wrong type.
1130 PyErr_Clear();
1131
1132 *var = keep_as_pyobject(py);
1133 metatype_used = UnknownType;
1134 }
1135
1136 break;
1137 }
1138
1139 case QMetaType::QVariantHash:
1140 {
1141 QVariantHash qh;
1142
1143 if (to_QVariantHash(py, qh))
1144 {
1145 *var = QVariant(qh);
1146 metatype_used = UnknownType;
1147 }
1148 else
1149 {
1150 iserr = 1;
1151 }
1152
1153 break;
1154 }
1155
1156 case -1:
1157 metatype_used = QMetaType::VoidStar;
1158
1159 if (SIPBytes_Check(py))
1160 tmp_storage.tmp_void_ptr = SIPBytes_AsString(py);
1161 else if (py == Py_None)
1162 tmp_storage.tmp_void_ptr = 0;
1163 else
1164 iserr = 1;
1165
1166 break;
1167
1168 default:
1169 if (_type)
1170 {
1171 if (_name.endsWith('*'))
1172 {
1173 ptr_class = sipForceConvertToType(py, _type, 0,
1174 SIP_NO_CONVERTORS, 0, &iserr);
1175
1176 variant_data = &ptr_class;
1177 }
1178 else
1179 {
1180 value_class = sipForceConvertToType(py, _type, 0,
1181 SIP_NOT_NONE, &value_class_state, &iserr);
1182
1183 variant_data = value_class;
1184 }
1185 }
1186 else
1187 {
1188 // This is a class we don't recognise.
1189 iserr = 1;
1190 }
1191 }
1192
1193 if (iserr || PyErr_Occurred())
1194 {
1195 PyErr_Format(PyExc_TypeError,
1196 "unable to convert a Python '%s' object to a C++ '%s' instance",
1197 sipPyTypeName(Py_TYPE(py)), _name.constData());
1198
1199 iserr = 1;
1200 }
1201 else if (_type == sipType_QVariant)
1202 {
1203 *var = QVariant(*reinterpret_cast<QVariant *>(variant_data));
1204 }
1205 else if (metatype_used != UnknownType)
1206 {
1207 *var = QVariant(metatype_used, variant_data);
1208 }
1209
1210 // Release any temporary value-class instance now that QVariant will have
1211 // made a copy.
1212 if (value_class)
1213 sipReleaseType(value_class, _type, value_class_state);
1214
1215 return (iserr == 0);
1216 }
1217
1218
1219 // Convert a Python object to a QVariant based on the type of the object.
fromAnyPyObject(PyObject * py,int * is_err)1220 QVariant Chimera::fromAnyPyObject(PyObject *py, int *is_err)
1221 {
1222 QVariant variant;
1223
1224 if (py != Py_None)
1225 {
1226 // Let any registered convertors have a go first.
1227 for (int i = 0; i < registeredToQVariantConvertors.count(); ++i)
1228 {
1229 QVariant var;
1230 bool ok;
1231
1232 if (registeredToQVariantConvertors.at(i)(py, var, &ok))
1233 {
1234 *is_err = !ok;
1235
1236 return var;
1237 }
1238 }
1239
1240 Chimera ct;
1241
1242 if (ct.parse_py_type(Py_TYPE(py)))
1243 {
1244 // If the type is a dict then try and convert it to a QVariantMap
1245 // if possible.
1246 if (Py_TYPE(py) == &PyDict_Type)
1247 ct._metatype = QMetaType::QVariantMap;
1248
1249 // The conversion is non-strict in case the type was a dict and we
1250 // can't convert it to a QVariantMap.
1251 if (!ct.fromPyObject(py, &variant, false))
1252 {
1253 *is_err = 1;
1254 }
1255 }
1256 else
1257 {
1258 *is_err = 1;
1259 }
1260 }
1261
1262 return variant;
1263 }
1264
1265
1266 // Convert a QVariant to Python.
toPyObject(const QVariant & var) const1267 PyObject *Chimera::toPyObject(const QVariant &var) const
1268 {
1269 if (_type != sipType_QVariant)
1270 {
1271 // For some reason (see qvariant_p.h) an invalid QVariant can be
1272 // returned when a QMetaType::Void is expected.
1273 if (!var.isValid() && _metatype == QMetaType::Void)
1274 {
1275 Py_INCREF(Py_None);
1276 return Py_None;
1277 }
1278
1279 // Handle the reverse of non-strict conversions of dict to QVariantMap,
1280 // ie. we want a dict but we have a QVariantMap.
1281 if (_metatype == PyQt_PyObject::metatype && _py_type == &PyDict_Type && var.type() == QVariant::Map)
1282 return qpycore_fromQVariantMap(var.toMap());
1283
1284 // A sanity check.
1285 if (_metatype != var.userType())
1286 {
1287 PyErr_Format(PyExc_TypeError,
1288 "unable to convert a QVariant of type %d to a QMetaType of type %d",
1289 var.userType(), _metatype);
1290
1291 return 0;
1292 }
1293
1294 // Deal with the simple case of unwrapping a Python object rather than
1295 // converting it.
1296 if (_metatype == PyQt_PyObject::metatype)
1297 {
1298 PyQt_PyObject pyobj_wrapper = var.value<PyQt_PyObject>();
1299
1300 if (!pyobj_wrapper.pyobject)
1301 {
1302 PyErr_SetString(PyExc_TypeError,
1303 "unable to convert a QVariant back to a Python object");
1304
1305 return 0;
1306 }
1307
1308 Py_INCREF(pyobj_wrapper.pyobject);
1309
1310 return pyobj_wrapper.pyobject;
1311 }
1312 }
1313
1314 // Let any registered convertors have a go first.
1315 for (int i = 0; i < registeredFromQVariantConvertors.count(); ++i)
1316 {
1317 PyObject *py;
1318
1319 if (registeredFromQVariantConvertors.at(i)(var, &py))
1320 return py;
1321 }
1322
1323 return toPyObject(const_cast<void *>(var.data()));
1324 }
1325
1326
1327 // Convert a C++ object at an arbitary address to Python.
toPyObject(void * cpp) const1328 PyObject *Chimera::toPyObject(void *cpp) const
1329 {
1330 if (_metatype == PyQt_PyObject::metatype)
1331 {
1332 if (_type)
1333 {
1334 // SIP knows the type (therefore it isn't really wrapped in a
1335 // PyQt_PyObject) but it's not registered with Qt.
1336 if (_name.endsWith('*'))
1337 cpp = *reinterpret_cast<void **>(cpp);
1338
1339 return sipConvertFromType(cpp, _type, 0);
1340 }
1341 else
1342 {
1343 // Otherwise unwrap the Python object.
1344 PyQt_PyObject *pyobj_wrapper = reinterpret_cast<PyQt_PyObject *>(cpp);
1345
1346 if (!pyobj_wrapper->pyobject)
1347 {
1348 PyErr_SetString(PyExc_TypeError,
1349 "unable to convert a QVariant back to a Python object");
1350
1351 return 0;
1352 }
1353
1354 Py_INCREF(pyobj_wrapper->pyobject);
1355
1356 return pyobj_wrapper->pyobject;
1357 }
1358 }
1359
1360 PyObject *py = 0;
1361
1362 switch (_metatype)
1363 {
1364 case QMetaType::Bool:
1365 py = PyBool_FromLong(*reinterpret_cast<bool *>(cpp));
1366 break;
1367
1368 case QMetaType::Int:
1369 if (_is_qflags)
1370 {
1371 py = sipConvertFromType(cpp, _type, 0);
1372 }
1373 else if (isCppEnum())
1374 {
1375 py = sipConvertFromEnum(*reinterpret_cast<int *>(cpp), _type);
1376 }
1377 else
1378 {
1379 py = SIPLong_FromLong(*reinterpret_cast<int *>(cpp));
1380 }
1381
1382 break;
1383
1384 case QMetaType::UInt:
1385 {
1386 long ui = *reinterpret_cast<unsigned int *>(cpp);
1387
1388 if (ui < 0)
1389 py = PyLong_FromUnsignedLong((unsigned long)ui);
1390 else
1391 py = SIPLong_FromLong(ui);
1392
1393 break;
1394 }
1395
1396 case QMetaType::Double:
1397 py = PyFloat_FromDouble(*reinterpret_cast<double *>(cpp));
1398 break;
1399
1400 case QMetaType::VoidStar:
1401 py = sipConvertFromVoidPtr(*reinterpret_cast<void **>(cpp));
1402 break;
1403
1404 case QMetaType::Long:
1405 py = SIPLong_FromLong(*reinterpret_cast<long *>(cpp));
1406 break;
1407
1408 case QMetaType::LongLong:
1409 py = PyLong_FromLongLong(*reinterpret_cast<qlonglong *>(cpp));
1410 break;
1411
1412 case QMetaType::Short:
1413 py = SIPLong_FromLong(*reinterpret_cast<short *>(cpp));
1414 break;
1415
1416 case QMetaType::Char:
1417 case QMetaType::UChar:
1418 py = SIPBytes_FromStringAndSize(reinterpret_cast<char *>(cpp), 1);
1419 break;
1420
1421 case QMetaType::ULong:
1422 py = PyLong_FromUnsignedLong(*reinterpret_cast<unsigned long *>(cpp));
1423 break;
1424
1425 case QMetaType::ULongLong:
1426 py = PyLong_FromUnsignedLongLong(*reinterpret_cast<qulonglong *>(cpp));
1427 break;
1428
1429 case QMetaType::UShort:
1430 py = SIPLong_FromLong(*reinterpret_cast<unsigned short *>(cpp));
1431 break;
1432
1433 case QMetaType::Float:
1434 py = PyFloat_FromDouble(*reinterpret_cast<float *>(cpp));
1435 break;
1436
1437 case QMetaType::QObjectStar:
1438 py = sipConvertFromType(*reinterpret_cast<void **>(cpp),
1439 sipType_QObject, 0);
1440 break;
1441
1442 case QMetaType::QVariantList:
1443 {
1444 QVariantList *ql = reinterpret_cast<QVariantList *>(cpp);
1445
1446 py = PyList_New(ql->size());
1447
1448 if (py)
1449 {
1450 for (int i = 0; i < ql->size(); ++i)
1451 {
1452 PyObject *val_obj = toAnyPyObject(ql->at(i));
1453
1454 if (!val_obj)
1455 {
1456 Py_DECREF(py);
1457 py = 0;
1458
1459 break;
1460 }
1461
1462 PyList_SetItem(py, i, val_obj);
1463 }
1464 }
1465
1466 break;
1467 }
1468
1469 case QMetaType::QVariantMap:
1470 py = qpycore_fromQVariantMap(*reinterpret_cast<QVariantMap *>(cpp));
1471 break;
1472
1473 case QMetaType::QVariantHash:
1474 {
1475 py = PyDict_New();
1476
1477 if (py)
1478 {
1479 QVariantHash *qh = reinterpret_cast<QVariantHash *>(cpp);
1480
1481 for (QVariantHash::const_iterator it = qh->constBegin(); it != qh->constEnd(); ++it)
1482 if (!addVariantToDict(py, it.key(), it.value()))
1483 {
1484 Py_DECREF(py);
1485 py = 0;
1486
1487 break;
1488 }
1489 }
1490
1491 break;
1492 }
1493
1494 case -1:
1495 {
1496 char *s = *reinterpret_cast<char **>(cpp);
1497
1498 if (s)
1499 {
1500 py = SIPBytes_FromString(s);
1501 }
1502 else
1503 {
1504 Py_INCREF(Py_None);
1505 py = Py_None;
1506 }
1507
1508 break;
1509 }
1510
1511 default:
1512 if (_type)
1513 {
1514 if (sipTypeIsEnum(_type))
1515 {
1516 py = sipConvertFromEnum(*reinterpret_cast<int *>(cpp), _type);
1517 }
1518 else if (_name.endsWith('*'))
1519 {
1520 py = sipConvertFromType(*reinterpret_cast<void **>(cpp),
1521 _type, 0);
1522 }
1523 else
1524 {
1525 // Make a copy as it is a value type.
1526 void *copy = QMetaType::create(_metatype, cpp);
1527
1528 py = sipConvertFromNewType(copy, _type, 0);
1529
1530 if (!py)
1531 QMetaType::destroy(_metatype, copy);
1532 }
1533 }
1534 else if (_name.contains("_QMLTYPE_"))
1535 {
1536 // These correspond to objects defined in QML. We assume that they
1537 // are all sub-classes of QObject. If this proves not to be the
1538 // case then we will have to look at the first part of _name (and
1539 // possibly move this code the the QtQml module).
1540 py = sipConvertFromType(*reinterpret_cast<void **>(cpp),
1541 sipType_QObject, 0);
1542 }
1543 else if (_name.endsWith('*'))
1544 {
1545 // It's a pointer to an unknown type so convert it to a voidptr in
1546 // case that can be used.
1547 py = sipConvertFromVoidPtr(cpp);
1548 }
1549 }
1550
1551 if (!py)
1552 PyErr_Format(PyExc_TypeError,
1553 "unable to convert a C++ '%s' instance to a Python object",
1554 _name.constData());
1555
1556 return py;
1557 }
1558
1559
1560 // Add a QVariant to a Python dict with a QString key.
addVariantToDict(PyObject * dict,const QString & key_ref,const QVariant & val_ref)1561 bool Chimera::addVariantToDict(PyObject *dict, const QString &key_ref,
1562 const QVariant &val_ref)
1563 {
1564 QString *key = new QString(key_ref);
1565 PyObject *key_obj = sipConvertFromNewType(key, sipType_QString, 0);
1566
1567 PyObject *val_obj = toAnyPyObject(val_ref);
1568
1569 if (!key_obj || !val_obj || PyDict_SetItem(dict, key_obj, val_obj) < 0)
1570 {
1571 if (key_obj)
1572 Py_DECREF(key_obj);
1573 else
1574 delete key;
1575
1576 Py_XDECREF(val_obj);
1577
1578 return false;
1579 }
1580
1581 Py_DECREF(key_obj);
1582 Py_DECREF(val_obj);
1583
1584 return true;
1585 }
1586
1587
1588 // Convert a QVariant to a Python object based on the type of the object.
toAnyPyObject(const QVariant & var)1589 PyObject *Chimera::toAnyPyObject(const QVariant &var)
1590 {
1591 if (!var.isValid())
1592 {
1593 Py_INCREF(Py_None);
1594 return Py_None;
1595 }
1596
1597 const char *type_name = var.typeName();
1598
1599 // Qt v5.8.0 changed the way it was handling null in QML. We treat it as a
1600 // special case though there may be other implications still to be
1601 // discovered.
1602 if (qstrcmp(type_name, "std::nullptr_t") == 0)
1603 {
1604 Py_INCREF(Py_None);
1605 return Py_None;
1606 }
1607
1608 const sipTypeDef *td = sipFindType(type_name);
1609 Chimera *ct = new Chimera;
1610
1611 ct->_type = td;
1612 ct->_name = type_name;
1613 ct->_metatype = var.userType();
1614
1615 if (td && sipTypeIsClass(td))
1616 ct->set_qflags();
1617
1618 PyObject *py = ct->toPyObject(var);
1619 delete ct;
1620
1621 return py;
1622 }
1623
1624
1625 // Wrap a Python object in a QVariant without any conversion.
keep_as_pyobject(PyObject * py)1626 QVariant Chimera::keep_as_pyobject(PyObject *py)
1627 {
1628 PyQt_PyObject pyobj_wrapper(py);
1629
1630 return QVariant(PyQt_PyObject::metatype, &pyobj_wrapper);
1631 }
1632
1633
1634 // Convert a Python list object to a QVariantList and return true if there was
1635 // no error.
to_QVariantList(PyObject * py,QVariantList & cpp) const1636 bool Chimera::to_QVariantList(PyObject *py, QVariantList &cpp) const
1637 {
1638 Q_ASSERT(PyList_CheckExact(py));
1639
1640 for (Py_ssize_t i = 0; i < PyList_Size(py); ++i)
1641 {
1642 PyObject *val_obj = PyList_GetItem(py, i);
1643
1644 if (!val_obj)
1645 return false;
1646
1647 int val_state, iserr = 0;
1648
1649 QVariant *val = reinterpret_cast<QVariant *>(sipForceConvertToType(
1650 val_obj, sipType_QVariant, 0, SIP_NOT_NONE, &val_state,
1651 &iserr));
1652
1653 if (iserr)
1654 return false;
1655
1656 cpp.append(*val);
1657
1658 sipReleaseType(val, sipType_QVariant, val_state);
1659 }
1660
1661 return true;
1662 }
1663
1664
1665 // Convert a Python object to a QVariantHash and return true if there was no
1666 // error.
to_QVariantHash(PyObject * py,QVariantHash & cpp) const1667 bool Chimera::to_QVariantHash(PyObject *py, QVariantHash &cpp) const
1668 {
1669 Q_ASSERT(PyDict_CheckExact(py));
1670
1671 PyObject *key_obj, *val_obj;
1672 Py_ssize_t i;
1673
1674 i = 0;
1675 while (PyDict_Next(py, &i, &key_obj, &val_obj))
1676 {
1677 int key_state, val_state, iserr = 0;
1678
1679 QString *key = reinterpret_cast<QString *>(sipForceConvertToType(
1680 key_obj, sipType_QString, NULL, SIP_NOT_NONE, &key_state,
1681 &iserr));
1682
1683 QVariant *val = reinterpret_cast<QVariant *>(sipForceConvertToType(
1684 val_obj, sipType_QVariant, NULL, SIP_NOT_NONE, &val_state,
1685 &iserr));
1686
1687 if (iserr)
1688 return false;
1689
1690 cpp.insert(*key, *val);
1691
1692 sipReleaseType(key, sipType_QString, key_state);
1693 sipReleaseType(val, sipType_QVariant, val_state);
1694 }
1695
1696 return true;
1697 }
1698
1699
1700 // Return true if the type is either a C++ or Python enum.
isEnum() const1701 bool Chimera::isEnum() const
1702 {
1703 if (isCppEnum())
1704 return true;
1705
1706 if (_is_qflags)
1707 return true;
1708
1709 return (_py_type ? _py_enum_types.contains((PyObject *)_py_type) : false);
1710 }
1711
1712
1713 // Convert a Python object to C++, allocating storage as necessary.
fromPyObjectToStorage(PyObject * py) const1714 Chimera::Storage *Chimera::fromPyObjectToStorage(PyObject *py) const
1715 {
1716 Chimera::Storage *st = new Chimera::Storage(this, py);
1717
1718 if (!st->isValid())
1719 {
1720 delete st;
1721 st = 0;
1722 }
1723
1724 return st;
1725 }
1726
1727
1728 // Create the storage for a type.
storageFactory() const1729 Chimera::Storage *Chimera::storageFactory() const
1730 {
1731 return new Chimera::Storage(this);
1732 }
1733