1/*
2 * Implementation of objective-C object wrapper
3 *
4 * NOTE: We're using CFRetain and CFRelease to manage the retaincount of the Objective-C
5 * objects because that will do the right thing when Garbage Collection is involved.
6 */
7#include "pyobjc.h"
8
9#include <stddef.h>
10
11#include <objc/Object.h>
12
13/*
14 * Support for NSKeyValueObserving on MacOS X 10.3 and later.
15 *
16 */
17
18/*
19 * XXX: for reasons beyond my current comprehension the "legacy" block must be active, otherwise we
20 * get a fatal python error.
21 */
22#if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3
23
24/* Deal with platforms that don't support KVO */
25
26static int
27_KVOHackLevel(void) {
28	static int _checkedKVO = 0;
29	if (_checkedKVO == 0) {
30		if ([NSObject instancesRespondToSelector:@selector(willChangeValueForKey:)] &&
31			[NSObject instancesRespondToSelector:@selector(didChangeValueForKey:)]) {
32			_checkedKVO = 1;
33
34		} else {
35
36			_checkedKVO = -1;
37		}
38	}
39	return _checkedKVO;
40}
41
42static void
43_UseKVO(NSObject *self, NSString *key, BOOL willChange)
44{
45    PyObjC_DURING
46        int _checkedKVO = _KVOHackLevel();
47        if (_checkedKVO == -1 || [key characterAtIndex:0] == (unichar)'_') {
48		/* pass */
49        } else if (willChange) {
50            [self willChangeValueForKey:key];
51        } else {
52            [self didChangeValueForKey:key];
53        }
54    PyObjC_HANDLER
55    PyObjC_ENDHANDLER
56}
57
58#else
59
60static void
61_UseKVO(NSObject *self, NSString *key, BOOL willChange)
62{
63    PyObjC_DURING
64        if ([key characterAtIndex:0] == (unichar)'_') {
65	    /* pass */
66	} else if (willChange) {
67            [self willChangeValueForKey:key];
68        } else {
69            [self didChangeValueForKey:key];
70        }
71    PyObjC_HANDLER
72    PyObjC_ENDHANDLER
73}
74
75#endif
76
77static PyObject*
78object_new(
79	PyTypeObject*  type __attribute__((__unused__)),
80	PyObject* args,
81	PyObject* kwds)
82{
83static char* keywords[] = { "cobject", "c_void_p", NULL };
84	PyObject* cobject = NULL;
85	PyObject* c_void_p = NULL;
86
87	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", keywords, &cobject, &c_void_p)) {
88		return NULL;
89	}
90
91	if (cobject != NULL && c_void_p != NULL) {
92		PyErr_SetString(PyExc_TypeError,
93				"Pass either cobject or c_void_p, but not both");
94		return NULL;
95	}
96
97	if (cobject != NULL && PyCapsule_CheckExact(cobject)) {
98		NSObject* p = PyCapsule_GetPointer(cobject, "objc.__object__");
99		if (PyErr_Occurred()) {
100			return NULL;
101		}
102
103		return PyObjC_IdToPython(p);
104
105	} else if (c_void_p != NULL) {
106		NSObject* p;
107		PyObject* attrval;
108
109		if (PyLong_Check(c_void_p)
110#if PY_MAJOR_VERSION == 2
111				|| PyInt_Check(c_void_p)
112#endif
113			) {
114				attrval = c_void_p;
115				Py_INCREF(attrval);
116		} else {
117			attrval = PyObject_GetAttrString(c_void_p, "value");
118			if (attrval == NULL) {
119				return NULL;
120			}
121		}
122
123		if (
124#if PY_MAJOR_VERSION == 2
125			PyInt_Check(attrval) ||
126			/* NOTE: PyLong_AsVoidPtr works on Int objects as well */
127#endif /* PY_MAJOR_VERSION == 2 */
128			PyLong_Check(attrval)
129		) {
130			p = PyLong_AsVoidPtr(attrval);
131			if (p == NULL && PyErr_Occurred()) {
132				Py_DECREF(attrval);
133				return NULL;
134			}
135
136		} else {
137			PyErr_SetString(PyExc_ValueError,
138				"c_void_p.value is not an integer");
139			return NULL;
140		}
141		Py_DECREF(attrval);
142		return PyObjC_IdToPython(p);
143
144	} else {
145		PyErr_SetString(PyExc_TypeError,
146			"Use class methods to instantiate new Objective-C objects");
147		return NULL;
148	}
149}
150
151static PyObject*
152object_repr(PyObject* _self)
153{
154	PyObjCObject* self = (PyObjCObject*)_self;
155	PyObject* res;
156
157	if (self->flags & PyObjCObject_kMAGIC_COOKIE) {
158		return PyText_FromFormat(
159			"<%s objective-c magic instance %p>",
160			Py_TYPE(self)->tp_name, self->objc_object);
161	}
162
163	if ((self->flags & PyObjCObject_kUNINITIALIZED) == 0 && !PyObjCObject_IsClassic(self)) {
164		/* Try to call the method 'description', which is the ObjC
165		 * equivalent of __repr__. If that fails we'll fall back to
166		 * the default repr.
167		 * Don't call 'description' for uninitialized objects, that
168		 * is undefined behaviour and will crash the interpreter sometimes.
169		 */
170		res = PyObject_CallMethod((PyObject*)self, "description", NULL);
171		//res = NULL;
172		if (res == NULL) {
173			PyErr_Clear();
174		} else {
175			return res;
176		}
177	}
178	return PyText_FromFormat(
179		"<%s objective-c instance %p>",
180		Py_TYPE(self)->tp_name, self->objc_object);
181}
182
183static void
184object_del(PyObject* obj __attribute__((__unused__)))
185{
186	/* Dummy function, we do not want the default implementation */
187}
188
189
190static void
191object_dealloc(PyObject* obj)
192{
193	/*
194  	 * Save exception information, needed because releasing the object
195	 * might clear or modify the exception state.
196	 */
197	PyObject* ptype, *pvalue, *ptraceback;
198	PyErr_Fetch(&ptype, &pvalue, &ptraceback);
199
200	if (PyObjCObject_IsBlock(obj)) {
201		PyObjCMethodSignature* v = PyObjCObject_GetBlock(obj);
202		PyObjCObject_SET_BLOCK(obj, NULL);
203		Py_XDECREF(v);
204	}
205
206
207	if (PyObjCObject_GetFlags(obj) != PyObjCObject_kDEALLOC_HELPER
208			&& PyObjCObject_GetObject(obj) != nil) {
209		/* Release the proxied object, we don't have to do this when
210		 * there is no proxied object.
211		 */
212		PyObjC_UnregisterPythonProxy(
213			PyObjCObject_GetObject(obj), obj);
214
215		if (PyObjCObject_IsClassic(obj)) {
216			/* pass */
217
218		} else if ((((PyObjCObject*)obj)->flags
219				& PyObjCObject_kSHOULD_NOT_RELEASE)) {
220			/* pass */
221
222		} else if (((PyObjCObject*)obj)->flags
223				& PyObjCObject_kUNINITIALIZED) {
224			/* Freeing of an uninitialized object, just leak because
225			 * there is no reliable manner to free such objects.
226			 *
227			 * - [obj release] doesn't work because some classes
228			 *   cause crashes for uninitialized objects
229			 * - [[obj init] release] also doesn't work because
230			 *   not all classes implement -init
231			 * - [obj dealloc] doesn't work for class
232			 *   clusters like NSArray.
233			 */
234			char buf[256];
235			snprintf(buf, sizeof(buf),
236				"leaking an uninitialized object of type %s",
237				Py_TYPE(obj)->tp_name);
238			PyErr_Warn(PyObjCExc_UnInitDeallocWarning, buf);
239			((PyObjCObject*)obj)->objc_object = nil;
240
241		} else {
242			PyObjC_DURING
243				if (((PyObjCObject*)obj)->flags & PyObjCObject_kCFOBJECT) {
244					CFRelease(((PyObjCObject*)obj)->objc_object);
245				} else if (strcmp(object_getClassName(((PyObjCObject*)obj)->objc_object),
246						"NSAutoreleasePool") != 0) {
247
248				        CFRelease(((PyObjCObject*)obj)->objc_object);
249				} else {
250					CFRelease(((PyObjCObject*)obj)->objc_object);
251				}
252
253			PyObjC_HANDLER
254				NSLog(@"PyObjC: Exception during dealloc of proxy: %@",
255					localException);
256
257			PyObjC_ENDHANDLER
258			((PyObjCObject*)obj)->objc_object = nil;
259		}
260	}
261
262	Py_TYPE(obj)->tp_free(obj);
263
264	PyErr_Restore(ptype, pvalue, ptraceback);
265}
266
267
268static inline PyObject*
269_type_lookup(PyTypeObject* tp, PyObject* name)
270{
271	Py_ssize_t i, n;
272	PyObject *mro, *base, *dict;
273	PyObject *descr = NULL;
274	PyObject* protDict;
275	PyObject* res;
276
277	/* FIXME: Support for method name cache */
278
279	/* Look in tp_dict of types in MRO */
280	mro = tp->tp_mro;
281	if (mro == NULL) {
282		return NULL;
283	}
284	res = NULL;
285	assert(PyTuple_Check(mro));
286	n = PyTuple_GET_SIZE(mro);
287	for (i = 0; i < n; i++) {
288		base = PyTuple_GET_ITEM(mro, i);
289
290		if (PyObjCClass_Check(base)) {
291			PyObjCClass_CheckMethodList(base, 0);
292			protDict = ((PyObjCClassObject*)base)->protectedMethods;
293			dict = ((PyTypeObject *)base)->tp_dict;
294
295		} else if (PyType_Check(base)) {
296			protDict = NULL;
297			dict = ((PyTypeObject *)base)->tp_dict;
298
299
300#if PY_MAJOR_VERSION == 2
301		} else if (PyClass_Check(base)) {
302			dict = ((PyClassObject*)base)->cl_dict;
303			protDict = NULL;
304#endif
305		} else {
306			return NULL;
307		}
308		assert(dict && PyDict_Check(dict));
309		descr = PyDict_GetItem(dict, name);
310		if (descr != NULL) {
311			break;
312		}
313
314		if (protDict) {
315			descr = PyDict_GetItem(protDict, name);
316			if (descr != NULL) {
317				break;
318			}
319		}
320	}
321
322	return descr;
323}
324
325static PyObject** _get_dictptr(PyObject* obj)
326{
327	Py_ssize_t dictoffset;
328	id obj_object;
329	dictoffset = PyObjCClass_DictOffset((PyObject*)Py_TYPE(obj));
330	if (dictoffset == 0) return NULL;
331	obj_object = PyObjCObject_GetObject(obj);
332	assert(obj_object != nil);
333	return (PyObject**)(((char*)obj_object) + dictoffset);
334}
335
336
337static PyObject *
338object_getattro(PyObject *obj, PyObject * volatile name)
339{
340	PyTypeObject *tp = NULL;
341	PyObject *descr = NULL;
342	PyObject *res = NULL;
343	descrgetfunc f;
344	PyObject** dictptr;
345	char* namestr;
346	id obj_inst;
347	PyObject* bytes;
348
349	if (name == NULL) {
350		PyErr_SetString(PyExc_TypeError, "<nil> name");
351		return NULL;
352	}
353
354	if (PyUnicode_Check(name)) {
355		bytes = PyUnicode_AsEncodedString(name, NULL, NULL);
356		if (bytes == NULL) return NULL;
357#if PY_MAJOR_VERSION == 2
358	} else if (PyString_Check(name)) {
359		bytes = name; Py_INCREF(bytes);
360#endif
361	} else {
362		PyErr_Format(PyExc_TypeError,
363			"attribute name must be string, got %s",
364			Py_TYPE(name)->tp_name);
365		return NULL;
366	}
367
368
369
370	namestr = PyBytes_AsString(bytes);
371	if (namestr == NULL) {
372		if (!PyErr_Occurred()) {
373			PyErr_SetString(PyExc_ValueError, "Empty name");
374		}
375		return NULL;
376	}
377
378	obj_inst = PyObjCObject_GetObject(obj);
379	if (!obj_inst) {
380#if PY_MAJOR_VERSION == 2
381		PyErr_Format(PyExc_AttributeError,
382		     "cannot access attribute '%.400s' of NIL '%.50s' object",
383		     PyString_AS_STRING(name),
384		     Py_TYPE(obj)->tp_name);
385#else
386		PyErr_Format(PyExc_AttributeError,
387		     "cannot access attribute '%U' of NIL '%.50s' object",
388		     name,
389		     Py_TYPE(obj)->tp_name);
390#endif
391		goto done;
392	}
393
394	if (PyObjCObject_GetFlags(obj) & PyObjCObject_kMAGIC_COOKIE) {
395		/* A magic cookie object, don't treat this like a normal
396		 * object because that might cause havoc.
397		 */
398
399	} else {
400		/* Special hack for KVO on MacOS X, when an object is observed it's
401		 * ISA is changed by the runtime. We change the python type as well.
402		 */
403		tp = (PyTypeObject*)PyObjCClass_New(object_getClass(obj_inst));
404
405		descr = NULL;
406
407		if (tp != Py_TYPE(obj)) {
408			/* Workaround for KVO implementation feature */
409			PyObject* dict;
410
411			if (tp->tp_dict == NULL) {
412				if (PyType_Ready(tp) < 0)
413					goto done;
414			}
415
416// XXX: You'd expect the code below works, but it actually doesn't. Need to check why.
417//			Py_DECREF(Py_TYPE(obj));
418//			Py_TYPE(obj) = tp;
419//
420
421			PyObjCClass_CheckMethodList((PyObject*)tp, 0);
422			dict = tp->tp_dict;
423
424			assert(dict && PyDict_Check(dict));
425			descr = PyDict_GetItem(dict, name);
426		}
427		Py_DECREF(tp); tp = NULL;
428	}
429
430	tp = Py_TYPE(obj);
431	if (tp->tp_dict == NULL) {
432		if (PyType_Ready(tp) < 0)
433			goto done;
434	}
435
436	/* replace _PyType_Lookup */
437	if (descr == NULL) {
438		descr = _type_lookup(tp, name);
439	}
440
441	f = NULL;
442	if (descr != NULL
443#if PY_MAJOR_VERSION == 2
444		&& PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS)
445#endif
446	    ) {
447		f = Py_TYPE(descr)->tp_descr_get;
448		if (f != NULL && PyDescr_IsData(descr)) {
449			res = f(descr, obj, (PyObject*)Py_TYPE(obj));
450			goto done;
451		}
452	}
453
454	if (strcmp(PyBytes_AS_STRING(bytes), "__del__") == 0) {
455		res = PyObjCClass_GetDelMethod((PyObject*)Py_TYPE(obj));
456		if (res != NULL) {
457			/* XXX: bind self */
458		}
459		goto done;
460	}
461
462	/* First try the __dict__ */
463	dictptr = _get_dictptr(obj);
464
465	if (dictptr != NULL) {
466		PyObject *dict;
467
468		if (strcmp(PyBytes_AS_STRING(bytes), "__dict__") == 0) {
469			res = *dictptr;
470			if (res == NULL) {
471				*dictptr = PyDict_New();
472				if (*dictptr == NULL) {
473					PyErr_Clear();
474				}
475				res = *dictptr;
476			}
477			if (res != NULL) {
478				Py_INCREF(res);
479				goto done;
480			}
481		} else {
482			dict = *dictptr;
483			if (dict != NULL) {
484				res = PyDict_GetItem(dict, name);
485				if (res != NULL) {
486					Py_INCREF(res);
487					goto done;
488				}
489			}
490		}
491	}
492
493	if (f != NULL) {
494		res = f(descr, obj, (PyObject*)Py_TYPE(obj));
495		goto done;
496	}
497
498	if (descr != NULL) {
499		Py_INCREF(descr);
500		res = descr;
501		goto done;
502	}
503
504	if (!PyObjCObject_IsClassic(obj)) {
505		res = PyObjCSelector_FindNative(obj, namestr);
506		if (res) goto done;
507	}
508
509	PyErr_Format(PyExc_AttributeError,
510	     "'%.50s' object has no attribute '%.400s'",
511	     tp->tp_name, namestr);
512
513done:
514	if (res != NULL) {
515		/* class methods cannot be accessed through instances */
516		if (PyObjCSelector_Check(res)
517				&& PyObjCSelector_IsClassMethod(res)) {
518			Py_DECREF(res);
519#if PY_MAJOR_VERSION == 2
520			PyErr_Format(PyExc_AttributeError,
521			     "'%.50s' object has no attribute '%.400s'",
522			     tp->tp_name, PyString_AS_STRING(name));
523#else
524			PyErr_Format(PyExc_AttributeError,
525			     "'%.50s' object has no attribute '%U'",
526			     tp->tp_name, name);
527#endif
528			res = NULL;
529		}
530	}
531	Py_DECREF(bytes);
532	return res;
533}
534
535
536static int
537object_setattro(PyObject *obj, PyObject *name, PyObject *value)
538{
539	PyTypeObject *tp = Py_TYPE(obj);
540	PyObject *descr;
541	descrsetfunc f;
542	PyObject** dictptr;
543	int res;
544	id obj_inst;
545	NSString *obj_name;
546	PyObject* bytes;
547
548	if (PyUnicode_Check(name)) {
549		bytes = PyUnicode_AsEncodedString(name, NULL, NULL);
550		if (bytes == NULL) return -1;
551#if PY_MAJOR_VERSION == 2
552	} else if (PyString_Check(name)) {
553		bytes = name; Py_INCREF(bytes);
554#endif
555	} else {
556		PyErr_Format(PyExc_TypeError,
557			"attribute name must be string, got %s",
558			Py_TYPE(name)->tp_name);
559		return -1;
560	}
561
562	obj_inst = PyObjCObject_GetObject(obj);
563	if (obj_inst == nil) {
564		PyErr_Format(PyExc_AttributeError,
565		     "Cannot set '%s.400s' on NIL '%.50s' object",
566		     PyBytes_AS_STRING(bytes),
567		     tp->tp_name);
568		Py_DECREF(bytes);
569		return -1;
570	}
571
572	obj_name = nil;
573	if (((PyObjCClassObject*)tp)->useKVO) {
574		if ((PyObjCObject_GetFlags(obj) & PyObjCObject_kUNINITIALIZED) == 0) {
575			obj_name = [NSString stringWithUTF8String:PyBytes_AS_STRING(bytes)];
576			_UseKVO((NSObject *)obj_inst, obj_name, YES);
577		}
578	}
579	descr = _type_lookup(tp, name);
580	f = NULL;
581	if (descr != NULL
582#if PY_MAJOR_VERSION == 2
583		&& PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_HAVE_CLASS)
584#endif
585	   ) {
586		f = Py_TYPE(descr)->tp_descr_set;
587		if (f != NULL && PyDescr_IsData(descr)) {
588			res = f(descr, obj, value);
589			goto done;
590		}
591	}
592
593	dictptr = _get_dictptr(obj);
594	if (dictptr != NULL) {
595		PyObject *dict;
596
597		dict = *dictptr;
598
599		if (dict == NULL && value != NULL) {
600			dict = PyDict_New();
601			if (dict == NULL) {
602				res = -1;
603				goto done;
604			}
605
606			*dictptr = dict;
607		}
608		if (dict != NULL) {
609			if (value == NULL) {
610				res = PyDict_DelItem(dict, name);
611			} else {
612				res = PyDict_SetItem(dict, name, value);
613			}
614			if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) {
615				PyErr_SetObject(PyExc_AttributeError, name);
616			}
617			goto done;
618		}
619	}
620
621	if (f != NULL) {
622		res = f(descr, obj, value);
623		goto done;
624	}
625
626	if (descr == NULL) {
627		PyErr_Format(PyExc_AttributeError,
628			     "'%.50s' object has no attribute '%.400s'",
629			     tp->tp_name, PyBytes_AS_STRING(bytes));
630		res = -1;
631		goto done;
632	}
633
634	PyErr_Format(PyExc_AttributeError,
635		     "'%.50s' object attribute '%.400s' is read-only",
636		     tp->tp_name, PyBytes_AS_STRING(bytes));
637	res = -1;
638  done:
639	if (obj_inst && obj_name) {
640		_UseKVO((NSObject *)obj_inst, obj_name, NO);
641	}
642	Py_DECREF(bytes);
643	return res;
644}
645
646PyDoc_STRVAR(objc_get_real_class_doc, "Return the current ISA of the object");
647static PyObject*
648objc_get_real_class(PyObject* self, void* closure __attribute__((__unused__)))
649{
650	id obj_object;
651	PyObject* ret;
652
653	obj_object = PyObjCObject_GetObject(self);
654	assert(obj_object != nil);
655	ret = PyObjCClass_New(object_getClass(obj_object));
656	if (ret != (PyObject*)Py_TYPE(self)) {
657		Py_DECREF(Py_TYPE(self));
658		Py_TYPE(self) = (PyTypeObject*)ret;
659		Py_INCREF(ret);
660	}
661	return ret;
662}
663
664PyDoc_STRVAR(obj_get_instanceMethods_doc,
665"The attributes of this field are the instance methods of this object. This\n"
666"can be used to force access to an instance method."
667);
668static PyObject*
669obj_get_instanceMethods(PyObject* _self, void* closure __attribute__((__unused__)))
670{
671	PyObjCObject* self = (PyObjCObject*)_self;
672	return PyObjCMethodAccessor_New((PyObject*)self, 0);
673}
674
675static PyObject*
676obj_get_blocksignature(PyObject* self, void* closure __attribute__((__unused__)))
677{
678	if (PyObjCObject_IsBlock(self)) {
679		PyObject* v = (PyObject*)PyObjCObject_GetBlock(self);
680		if (v != NULL) {
681			Py_INCREF(v);
682			return v;
683		}
684	}
685	Py_INCREF(Py_None);
686	return Py_None;
687}
688
689static int
690obj_set_blocksignature(PyObject* self, PyObject* newVal, void* closure __attribute__((__unused__)))
691{
692	if (!PyObjCObject_IsBlock(self)) {
693		PyErr_SetString(PyExc_TypeError, "You can only change this value on blocks");
694		return  -1;
695	}
696
697	if (newVal != NULL) {
698		if (!PyObjCMethodSignature_Check(newVal)) {
699			PyErr_SetString(PyExc_TypeError, "New value must be a method signature");
700			return -1;
701		}
702	}
703
704	PyObject* v = (PyObject*)PyObjCObject_GetBlock(self);
705	if (v != NULL) {
706		Py_DECREF(v);
707	}
708
709
710	Py_XINCREF(newVal);
711	PyObjCObject_SET_BLOCK(self, (PyObjCMethodSignature*)newVal);
712	return 0;
713}
714
715
716static PyGetSetDef obj_getset[] = {
717	{
718		"pyobjc_ISA",
719		objc_get_real_class,
720		NULL,
721		objc_get_real_class_doc,
722		0
723	},
724	{
725		"pyobjc_instanceMethods",
726		obj_get_instanceMethods,
727		NULL,
728		obj_get_instanceMethods_doc,
729		0
730	},
731	{
732		"__block_signature__",
733		obj_get_blocksignature,
734		obj_set_blocksignature,
735		"Call signature for a block, or None",
736		0
737	},
738	{ 0, 0, 0, 0, 0 }
739};
740
741/*
742 * We don't support pickling of Objective-C objects at the moment. The new
743 * version 2 of the pickle protocol has a default pickle method for new-style
744 * classes that doesn't work for us (it will write incomplete values to the
745 * pickle). This method forces a failure during pickling.
746 */
747static PyObject*
748meth_reduce(PyObject* self __attribute__((__unused__)))
749{
750	PyErr_SetString(PyExc_TypeError,
751		"Cannot pickle Objective-C objects");
752	return NULL;
753}
754
755static PyObject*
756as_cobject(PyObject* self)
757{
758	if (PyObjCObject_GetObject(self) == nil) {
759		Py_INCREF(Py_None);
760		return Py_None;
761	}
762	return PyCapsule_New(PyObjCObject_GetObject(self), "objc.__object__", NULL);
763}
764
765static PyObject*
766get_c_void_p(void)
767{
768static  PyObject* c_void_p = NULL;
769	if (c_void_p == NULL) {
770		PyObject* mod_ctypes = PyImport_ImportModule("ctypes");
771		if (mod_ctypes == NULL) {
772			/* ctypes is nota available */
773			return NULL;
774		}
775		c_void_p = PyObject_GetAttrString(mod_ctypes, "c_void_p");
776		Py_DECREF(mod_ctypes);
777		if (c_void_p == NULL) {
778			/* invalid or incomplete module */
779			return NULL;
780		}
781	}
782	return c_void_p;
783}
784
785static PyObject*
786as_ctypes_voidp(PyObject* self)
787{
788	PyObject* c_void_p;
789
790	if (PyObjCObject_GetObject(self) == nil) {
791		Py_INCREF(Py_None);
792		return Py_None;
793	}
794
795	c_void_p = get_c_void_p();
796	if (c_void_p == NULL) {
797		return NULL;
798	}
799
800	return PyObject_CallFunction(c_void_p, "k", (long)PyObjCObject_GetObject(self));
801}
802
803
804
805
806static PyMethodDef obj_methods[] = {
807	{
808		"__reduce__",
809		(PyCFunction)meth_reduce,
810		METH_NOARGS,
811		"Used for pickling"
812	},
813	{
814		"__cobject__",
815		(PyCFunction)as_cobject,
816		METH_NOARGS,
817		"Return a CObject representing this object"
818	},
819	{
820		"__c_void_p__",
821		(PyCFunction)as_ctypes_voidp,
822		METH_NOARGS,
823		"Return a ctypes.c_void_p representing this object"
824	},
825	{
826		NULL,
827		NULL,
828		0,
829		NULL
830	}
831};
832
833
834PyObjCClassObject PyObjCObject_Type = {
835   {
836     {
837	PyVarObject_HEAD_INIT(&PyObjCClass_Type, 0)
838	"objc_object",				/* tp_name */
839	sizeof(PyObjCObject),			/* tp_basicsize */
840	0,					/* tp_itemsize */
841	/* methods */
842	object_dealloc,		 		/* tp_dealloc */
843	0,					/* tp_print */
844	0,					/* tp_getattr */
845	0,					/* tp_setattr */
846	0,					/* tp_compare */
847	object_repr,				/* tp_repr */
848	0,					/* tp_as_number */
849	0,					/* tp_as_sequence */
850	0,		       			/* tp_as_mapping */
851	0,					/* tp_hash */
852	0,					/* tp_call */
853	0,					/* tp_str */
854	object_getattro,			/* tp_getattro */
855	object_setattro,			/* tp_setattro */
856	0,					/* tp_as_buffer */
857	Py_TPFLAGS_DEFAULT
858		| Py_TPFLAGS_BASETYPE,          /* tp_flags */
859 	0,					/* tp_doc */
860 	0,					/* tp_traverse */
861 	0,					/* tp_clear */
862	0,					/* tp_richcompare */
863	0,					/* tp_weaklistoffset */
864	0,					/* tp_iter */
865	0,					/* tp_iternext */
866	obj_methods,				/* tp_methods */
867	0,					/* tp_members */
868	obj_getset,				/* tp_getset */
869	0,					/* tp_base */
870	0,					/* tp_dict */
871	0,					/* tp_descr_get */
872	0,					/* tp_descr_set */
873	0,					/* tp_dictoffset */
874	0,					/* tp_init */
875	PyType_GenericAlloc,			/* tp_alloc */
876	object_new,				/* tp_new */
877	0,		        		/* tp_free */
878	0,					/* tp_is_gc */
879	0,					/* tp_bases */
880	0,					/* tp_mro */
881	0,					/* tp_cache */
882	0, 					/* tp_subclasses */
883	0,					/* tp_weaklist */
884	(destructor)object_del			/* tp_del */
885
886#if PY_VERSION_HEX >= 0x02060000
887	, 0                                     /* tp_version_tag */
888#endif
889
890     },
891#if PY_MAJOR_VERSION == 2
892     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
893       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
894#if PY_VERSION_HEX >= 0x02050000
895       , 0
896#endif
897     }, /* as_number */
898     { 0, 0, 0 },			/* as_mapping */
899     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },	/* as_sequence */
900     { 0, 0, 0, 0
901#if PY_VERSION_HEX >= 0x02060000
902	 , 0, 0
903#endif
904     },			/* as_buffer */
905     0,					/* name */
906     0,					/* slots */
907#else /* Python 3 */
908     { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
909     }, /* as_number */
910     { 0,0,0
911     }, /* as_mapping */
912     { 0,0,0,0,0,0,0,0,0,0
913     }, /* as_sequence */
914     { 0,0
915     }, /* as_buffer */
916     0, 0 /* ht_name, ht_slots */
917#if PY_VERSION_HEX >= 0x03030000
918     , 0, 0 /* ht_qualname, ht_cached_keys */
919#endif
920
921
922#endif /* Python 3 */
923   }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
924};
925
926/*
927 *  Allocate a proxy object for use during the call of __del__,
928 *  this isn't a full-featured proxy object.
929 */
930PyObject*
931_PyObjCObject_NewDeallocHelper(id objc_object)
932{
933	PyObject* res;
934	PyTypeObject* cls_type;
935
936	assert(objc_object != nil);
937	cls_type = (PyTypeObject*)PyObjCClass_New(object_getClass(objc_object));
938	if (cls_type == NULL) {
939		return NULL;
940	}
941
942	res = cls_type->tp_alloc(cls_type, 0);
943	Py_DECREF(cls_type);
944	if (res == NULL) {
945		return NULL;
946	}
947
948	PyObjCClass_CheckMethodList((PyObject*)Py_TYPE(res), 1);
949
950	((PyObjCObject*)res)->objc_object = objc_object;
951	((PyObjCObject*)res)->flags = PyObjCObject_kDEALLOC_HELPER;
952	return res;
953}
954
955void
956_PyObjCObject_FreeDeallocHelper(PyObject* obj)
957{
958	if (Py_REFCNT(obj) != 1) {
959		/* Someone revived this object. Objective-C doesn't like
960		 * this at all, therefore warn the user about this and
961		 * zero out the instance.
962		 */
963		char buf[256];
964		snprintf(buf, sizeof(buf),
965			"revived Objective-C object of type %s. Object is zero-ed out.",
966			Py_TYPE(obj)->tp_name);
967
968		PyErr_Warn(PyObjCExc_ObjCRevivalWarning, buf);
969
970		id objc_object = PyObjCObject_GetObject(obj);
971
972		/* XXX: release the object */
973		if (((PyObjCObject*)obj)->flags & PyObjCObject_kSHOULD_NOT_RELEASE) {
974			/* pass */
975		} else if (((PyObjCObject*)obj)->flags & PyObjCObject_kUNINITIALIZED) {
976			/* pass */
977		} else {
978			CFRelease(objc_object);
979		}
980
981		PyObjC_UnregisterPythonProxy(
982			objc_object, obj);
983		((PyObjCObject*)obj)->objc_object = nil;
984
985		Py_DECREF(obj);
986
987		return;
988	}
989	Py_DECREF(obj);
990}
991
992
993PyObject*
994PyObjCObject_New(id objc_object, int flags, int retain)
995{
996	Class cls = object_getClass(objc_object);
997	PyTypeObject* cls_type;
998	PyObject*     res;
999
1000	res = PyObjC_FindPythonProxy(objc_object);
1001	if (res) return res;
1002
1003	assert(objc_object != nil);
1004
1005	cls_type = (PyTypeObject*)PyObjCClass_New(cls);
1006	if (cls_type == NULL) {
1007		return NULL;
1008	}
1009
1010	res = cls_type->tp_alloc(cls_type, 0);
1011	Py_DECREF(cls_type);
1012	if (res == NULL) {
1013		return NULL;
1014	}
1015
1016	if (cls_type->tp_basicsize == sizeof(PyObjCBlockObject)) {
1017		flags |= PyObjCObject_kBLOCK;
1018	}
1019
1020	/* This should be in the tp_alloc for the new class, but
1021	 * adding a tp_alloc to PyObjCClass_Type doesn't seem to help
1022	 */
1023	PyObjCClass_CheckMethodList((PyObject*)Py_TYPE(res), 1);
1024
1025	((PyObjCObject*)res)->objc_object = objc_object;
1026	((PyObjCObject*)res)->flags = flags;
1027
1028	if (flags & PyObjCObject_kBLOCK) {
1029		((PyObjCBlockObject*)res)->signature = NULL;
1030        }
1031
1032	if (retain) {
1033		if (strcmp(object_getClassName(objc_object),
1034						"NSAutoreleasePool") != 0) {
1035			/* NSAutoreleasePool doesn't like retain */
1036			CFRetain(objc_object);
1037		}
1038	}
1039
1040	/*
1041	 * Don't register if we use the default flags, other parts will do
1042	 * that if necessary. I don't like this, but don't want to pollute
1043	 * the interface of this function with yet another argument.
1044	 */
1045	if (flags != PyObjCObject_kDEFAULT) {
1046		PyObjC_RegisterPythonProxy(objc_object, res);
1047	}
1048	return res;
1049}
1050
1051PyObject*
1052PyObjCObject_FindSelector(PyObject* object, SEL selector)
1053{
1054	PyObject* meth;
1055
1056	meth = PyObjCClass_FindSelector((PyObject*)Py_TYPE(object), selector, NO);
1057
1058	if (meth == NULL) {
1059		return NULL;
1060	} else {
1061		return meth;
1062	}
1063}
1064
1065id
1066(PyObjCObject_GetObject)(PyObject* object)
1067{
1068	if (!PyObjCObject_Check(object)) {
1069		PyErr_Format(PyExc_TypeError,
1070			"'objc.objc_object' expected, got '%s'",
1071			Py_TYPE(object)->tp_name);
1072
1073	}
1074	return PyObjCObject_GetObject(object);
1075}
1076
1077void
1078PyObjCObject_ClearObject(PyObject* object)
1079{
1080	if (!PyObjCObject_Check(object)) {
1081		PyErr_Format(PyExc_TypeError,
1082			"'objc.objc_object' expected, got '%s'",
1083			Py_TYPE(object)->tp_name);
1084
1085	}
1086	PyObjC_UnregisterPythonProxy(
1087			((PyObjCObject*)object)->objc_object, object);
1088	((PyObjCObject*)object)->objc_object = nil;
1089}
1090
1091PyObject* PyObjCObject_GetAttr(PyObject* obj, PyObject* name)
1092{
1093	return object_getattro(obj, name);
1094}
1095
1096
1097PyObject* PyObjCObject_GetAttrString(PyObject* obj, char* name)
1098{
1099	PyObject* pyname = PyText_FromString(name);
1100	if (pyname == NULL) return NULL;
1101
1102	PyObject* rv = object_getattro(obj, pyname);
1103	Py_DECREF(pyname);
1104	return rv;
1105}
1106