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