1/* Copyright (c) 1996,97 by Lele Gaifax.  All Rights Reserved
2 * Copyright 2002, 2003 Ronald Oussoren, Jack Jansen
3 *
4 * This software may be used and distributed freely for any purpose
5 * provided that this notice is included unchanged on any and all
6 * copies. The author does not warrant or guarantee this software in
7 * any way.
8 *
9 * This file is part of the PyObjC package.
10 *
11 * RCSfile: OC_PythonObject.m,v
12 * Revision: 1.23
13 * Date: 1998/08/18 15:35:52
14 *
15 * Created Wed Sep  4 19:57:44 1996.
16 */
17
18#include "pyobjc.h"
19#include "compile.h" /* From Python */
20#include <dlfcn.h>
21
22#include <stdarg.h>
23
24#import  <Foundation/NSObject.h>
25#import  <Foundation/NSMethodSignature.h>
26#import  <Foundation/NSInvocation.h>
27#import  <Foundation/NSString.h>
28#import  <Foundation/NSDictionary.h>
29#import  <Foundation/NSEnumerator.h>
30
31#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
32#import  <Foundation/NSKeyValueObserving.h>
33#endif
34
35#import "OC_PythonUnicode.h"
36#import "OC_PythonString.h"
37
38extern NSString * const NSUnknownKeyException; /* Radar #3336042 */
39
40PyObject *OC_PythonObject_DepythonifyTable = NULL;
41PyObject *OC_PythonObject_PythonifyStructTable = NULL;
42
43static int       py_version = 0;
44PyObject* PyObjC_Encoder = NULL;
45PyObject* PyObjC_Decoder = NULL;
46PyObject* PyObjC_CopyFunc = NULL;
47
48@implementation OC_PythonObject
49+ (void)setVersion:(int) version coder:(NSObject*)coder decoder:(NSObject*)decoder copier:(NSObject*)copier
50{
51	py_version = version;
52
53	Py_XDECREF(PyObjC_Encoder);
54	PyObjC_Encoder = PyObjC_IdToPython(coder);
55
56	Py_XDECREF(PyObjC_Decoder);
57	PyObjC_Decoder = PyObjC_IdToPython(decoder);
58
59	Py_XDECREF(PyObjC_CopyFunc);
60	PyObjC_CopyFunc = PyObjC_IdToPython(copier);
61}
62
63+ (int)wrapPyObject:(PyObject *)argument toId:(id *)datum
64{
65	int r;
66	id rval;
67	PyObject *anObject;
68
69	if (unlikely(argument == Py_None)) {
70		rval = nil;
71		r = 0;
72		goto end;
73	}
74
75	rval = PyObjC_FindObjCProxy(argument);
76	if (unlikely(rval != nil)) {
77		[[rval retain] autorelease];
78		r = 0;
79		goto end;
80	}
81
82	if (likely(PyObjCObject_Check (argument))) {
83		rval = PyObjCObject_GetObject(argument);
84		r = 0;
85		goto end;
86	} else if (unlikely(PyObjCClass_Check(argument))) {
87		rval = (id)PyObjCClass_GetClass(argument);
88		r = 0;
89		goto end;
90	}
91
92	anObject = PyObject_GetAttrString(argument, "__pyobjc_object__");
93	if (unlikely(anObject)) {
94		if (anObject != argument) {
95			r = [self wrapPyObject:anObject toId:datum];
96			Py_DECREF(anObject);
97			return r;
98		} else {
99			Py_DECREF(anObject);
100		}
101	}
102	PyErr_Clear();
103
104	if (PyUnicode_Check(argument)) {
105		rval = [OC_PythonUnicode
106			unicodeWithPythonObject:argument];
107		if (rval) {
108			PyObjC_RegisterObjCProxy(argument, rval);
109			r = 0;
110		} else {
111			r = -1;
112		}
113	} else if (PyBool_Check(argument)) {
114		/* This is needed because some low-level API's behaves
115		 * differently with [NSNumber numberWithBool:] than
116		 * [NSNumber numberWithInt:]
117		 */
118		if (argument == Py_True) {
119			rval = [NSNumber numberWithBool:1];
120		} else  {
121			rval = [NSNumber numberWithBool:0];
122		}
123		PyObjC_RegisterObjCProxy(argument, rval);
124		r = 0;
125
126#if PY_MAJOR_VERSION == 2
127	} else if (PyInt_Check (argument)) {
128		rval = [OC_PythonNumber numberWithPythonObject:argument];
129		PyObjC_RegisterObjCProxy(argument, rval);
130		r = 0;
131#endif
132
133	} else if (PyFloat_Check (argument)) {
134		rval = [OC_PythonNumber numberWithPythonObject:argument];
135		PyObjC_RegisterObjCProxy(argument, rval);
136		r = 0;
137
138	} else if (PyLong_Check(argument)) {
139		rval = [OC_PythonNumber numberWithPythonObject:argument];
140		PyObjC_RegisterObjCProxy(argument, rval);
141		r = 0;
142
143	} else if (PyList_Check(argument) || PyTuple_Check(argument)) {
144		rval = [OC_PythonArray
145			arrayWithPythonObject:argument];
146		PyObjC_RegisterObjCProxy(argument, rval);
147		r = 0;
148	} else if (PyDict_Check(argument)) {
149		rval = [OC_PythonDictionary
150			dictionaryWithPythonObject:argument];
151		PyObjC_RegisterObjCProxy(argument, rval);
152		r = 0;
153#if PY_MAJOR_VERSION == 2
154	} else if (PyString_Check(argument)) {
155		r = 0;
156		if (PyObjC_StrBridgeEnabled == 0) {
157			if (PyErr_Warn(PyObjCStrBridgeWarning, "use unicode(str, encoding) for NSString")) {
158				r = -1;
159				rval = nil;
160			}
161		}
162		if (r == 0) {
163			rval = [OC_PythonString
164				stringWithPythonObject:argument];
165			if (rval) {
166				PyObjC_RegisterObjCProxy(argument, rval);
167				r = 0;
168			} else {
169				r = -1;
170			}
171		}
172#endif /* ! Python3 */
173	} else if (PyObject_CheckReadBuffer(argument)) {
174		rval = [OC_PythonData
175			dataWithPythonObject:argument];
176		if (rval) {
177			PyObjC_RegisterObjCProxy(argument, rval);
178			r = 0;
179		} else {
180			r = -1;
181		}
182
183	} else if (PyAnySet_Check(argument)) {
184		rval = [OC_PythonSet setWithPythonObject:argument];
185		if (rval) {
186			PyObjC_RegisterObjCProxy(argument, rval);
187			r = 0;
188		} else {
189			r = -1;
190		}
191
192	} else if ((rval = PyObjC_CFTypeToID(argument))) {
193		// unwrapped cf
194		r = 0;
195	} else {
196		PyObjC_DURING
197			rval = [OC_PythonObject
198				objectWithCoercedObject:argument];
199
200			r = 0;
201
202		PyObjC_HANDLER
203			PyObjCErr_FromObjC(localException);
204			rval = nil;
205			r = -1;
206
207		PyObjC_ENDHANDLER
208	}
209
210end:
211	*datum = rval;
212	return r;
213}
214
215+ objectWithPythonObject:(PyObject *) obj
216{
217	id instance;
218	if (likely(PyObjCObject_Check(obj))) {
219		instance = PyObjCObject_GetObject(obj);
220	} else {
221		instance = [[self alloc] initWithObject:obj];
222		[instance autorelease];
223	}
224	return instance;
225}
226
227+ objectWithCoercedObject:(PyObject *)obj
228{
229	id instance;
230	PyObjC_BEGIN_WITH_GIL
231		if (PyObjCObject_Check(obj)) {
232			instance = PyObjCObject_GetObject(obj);
233			PyObjC_GIL_RETURN(instance);
234		}
235		if(PyObjCFormalProtocol_Check(obj)) {
236			instance = PyObjCFormalProtocol_GetProtocol(obj);
237			PyObjC_GIL_RETURN(instance);
238		}
239		if (OC_PythonObject_DepythonifyTable != NULL &&
240			PyList_Check(OC_PythonObject_DepythonifyTable)) {
241			int i;
242			for (i=0; i<PyList_GET_SIZE(OC_PythonObject_DepythonifyTable); i++) {
243				PyObject *tpl = PyList_GET_ITEM(OC_PythonObject_DepythonifyTable, i);
244				PyObject *cls;
245				if (!PyTuple_Check(tpl)) continue;
246
247				cls = PyTuple_GET_ITEM(tpl, 0);
248				if (PyObject_IsInstance(obj, cls)) {
249					PyObject *fn;
250					PyObject *res;
251					int err;
252					fn = PyTuple_GET_ITEM(tpl, 1);
253					res = PyObject_CallFunctionObjArgs(fn, obj, NULL);
254					if (res == NULL) {
255						PyObjC_GIL_FORWARD_EXC();
256					}
257					if (PyObject_IsInstance(res, cls)) {
258						Py_DECREF(res);
259						continue;
260					}
261					err = depythonify_c_value (@encode(id), res, &instance);
262					Py_DECREF(res);
263					if (err == -1) {
264						PyObjC_GIL_FORWARD_EXC();
265					} else {
266						PyObjC_GIL_RETURN(instance);
267					}
268				}
269			}
270		}
271
272		/* Check if the object is "sequence-like" */
273		instance = [OC_PythonArray depythonifyObject:obj];
274		if (instance != nil) {
275			PyObjC_RegisterObjCProxy(obj, instance);
276			PyObjC_GIL_RETURN(instance);
277		}
278		if (PyErr_Occurred()) {
279			PyObjC_GIL_FORWARD_EXC();
280		}
281
282		/* Check if the object is "mapping-like" */
283		instance = [OC_PythonDictionary depythonifyObject:obj];
284		if (instance != nil) {
285			PyObjC_RegisterObjCProxy(obj, instance);
286			PyObjC_GIL_RETURN(instance);
287		}
288		if (PyErr_Occurred()) {
289			PyObjC_GIL_FORWARD_EXC();
290		}
291
292		/* Check if the object is "set-like" */
293		instance = [OC_PythonSet depythonifyObject:obj];
294		if (instance != nil) {
295			PyObjC_RegisterObjCProxy(obj, instance);
296			PyObjC_GIL_RETURN(instance);
297		}
298		if (PyErr_Occurred()) {
299			PyObjC_GIL_FORWARD_EXC();
300		}
301
302		/* Check if the object is "datetime-like" */
303		instance = [OC_PythonDate depythonifyObject:obj];
304		if (instance != nil) {
305			PyObjC_GIL_RETURN(instance);
306		}
307		if (PyErr_Occurred()) {
308			PyObjC_GIL_FORWARD_EXC();
309		}
310
311		/* If all else fails use the generic proxy */
312		instance = [[self alloc] initWithObject:obj];
313	PyObjC_END_WITH_GIL
314	[instance autorelease];
315	return instance;
316}
317
318+ depythonifyTable
319{
320	PyObjC_BEGIN_WITH_GIL
321		if (OC_PythonObject_DepythonifyTable == NULL) {
322			OC_PythonObject_DepythonifyTable = PyList_New(0);
323		}
324		id rval;
325		int err = depythonify_c_value(@encode(id), OC_PythonObject_DepythonifyTable, &rval);
326		if (err == -1) {
327			PyObjC_GIL_FORWARD_EXC();
328		}
329		PyObjC_GIL_RETURN(rval);
330	PyObjC_END_WITH_GIL
331}
332
333+ pythonifyStructTable
334{
335	PyObjC_BEGIN_WITH_GIL
336		if (OC_PythonObject_PythonifyStructTable == NULL) {
337			OC_PythonObject_PythonifyStructTable = PyDict_New();
338		}
339		id rval;
340		int err = depythonify_c_value(@encode(id), OC_PythonObject_PythonifyStructTable, &rval);
341		if (err == -1) {
342			PyObjC_GIL_FORWARD_EXC();
343		}
344		PyObjC_GIL_RETURN(rval);
345	PyObjC_END_WITH_GIL
346}
347
348+ (PyObject *)__pythonifyStruct:(PyObject*)obj withType:(const char *)type length:(Py_ssize_t)length
349{
350	if (OC_PythonObject_PythonifyStructTable == NULL) {
351		Py_INCREF(obj);
352		return obj;
353	}
354	PyObject *typeString = PyText_FromStringAndSize(type, length);
355	if (type == NULL) {
356		return NULL;
357	}
358	PyObject *convert = PyDict_GetItem(OC_PythonObject_PythonifyStructTable, typeString);
359	Py_DECREF(typeString);
360	if (convert == NULL) {
361		Py_INCREF(obj);
362		return obj;
363	}
364	return PyObject_CallFunctionObjArgs(convert, obj, NULL);
365}
366
367- initWithObject:(PyObject *) obj
368{
369	PyObjC_BEGIN_WITH_GIL
370		if (pyObject) {
371			PyObjC_UnregisterObjCProxy(pyObject, self);
372		}
373		PyObjC_RegisterObjCProxy(obj, self);
374		Py_XINCREF(obj);
375		Py_XDECREF(pyObject);
376		pyObject = obj;
377		PyObjC_GIL_RETURN(self);
378	PyObjC_END_WITH_GIL
379}
380
381-(void)release
382{
383	/* See comment in OC_PythonUnicode */
384	PyObjC_BEGIN_WITH_GIL
385		[super release];
386	PyObjC_END_WITH_GIL
387}
388
389
390
391- (void)dealloc
392{
393	PyObjC_BEGIN_WITH_GIL
394		PyObjC_UnregisterObjCProxy(pyObject, self);
395		Py_XDECREF(pyObject); pyObject = NULL;
396
397	PyObjC_END_WITH_GIL
398
399	[super dealloc];
400}
401
402-copyWithZone:(NSZone*)zone
403{
404	(void)zone;
405	NSObject* result = nil;
406	PyObject* copy;
407
408	if (PyObjC_CopyFunc == NULL) {
409		[NSException raise:NSInvalidArgumentException
410					format:@"cannot copy Python objects"];
411
412	} else {
413		PyObjC_BEGIN_WITH_GIL
414			copy = PyObject_CallFunctionObjArgs(PyObjC_CopyFunc, pyObject, NULL);
415			if (copy == NULL) {
416				PyObjC_GIL_FORWARD_EXC();
417			}
418
419			result = PyObjC_PythonToId(copy);
420			Py_DECREF(copy);
421
422		PyObjC_END_WITH_GIL
423	}
424
425	if (result) {
426		[result retain];
427	}
428	return result;
429}
430
431-copy
432{
433	return [self copyWithZone:NULL];
434}
435
436/* Undocumented method used by NSLog, this seems to work. */
437- (NSString*) _copyDescription
438{
439	return [[self description] copy];
440}
441
442- (NSString*) description
443{
444	PyObject *repr;
445
446	if (pyObject == NULL) return @"no python object";
447
448	PyObjC_BEGIN_WITH_GIL
449
450		repr = PyObject_Repr (pyObject);
451
452#if PY_MAJOR_VERSION == 2
453		if (repr) {
454			int err;
455			NSString* result;
456			PyObject *urepr = PyUnicode_FromEncodedObject(
457				repr,
458				NULL,
459				"replace");
460			Py_DECREF(repr);
461			if (urepr == NULL) {
462				PyObjC_GIL_FORWARD_EXC();
463			}
464			err = depythonify_c_value (@encode(id), urepr, &result);
465			Py_DECREF (urepr);
466			if (err == -1) {
467				PyObjC_GIL_FORWARD_EXC();
468			}
469			PyObjC_GIL_RETURN(result);
470		} else {
471			PyObjC_GIL_FORWARD_EXC();
472		}
473#else
474		if (repr) {
475			int err;
476			NSString* result;
477
478			err = depythonify_c_value (@encode(id), repr, &result);
479			Py_DECREF(repr);
480			if (err == -1) {
481				PyObjC_GIL_FORWARD_EXC();
482			}
483
484			PyObjC_GIL_RETURN(result);
485		} else {
486			PyObjC_GIL_FORWARD_EXC();
487		}
488#endif
489
490	PyObjC_END_WITH_GIL
491
492	/* not reached */
493	return @"a python object";
494}
495
496- (void) doesNotRecognizeSelector:(SEL) aSelector
497{
498	[NSException raise:NSInvalidArgumentException
499				format:@"%@ does not recognize -%s",
500				self, sel_getName(aSelector)];
501}
502
503
504/*#F Check the argument count of the method/function @var{pymethod},
505  returning the method itself if it matches @var{argcount}, NULL
506  otherwise. */
507static inline PyObject *
508check_argcount (PyObject *pymethod, Py_ssize_t argcount)
509{
510	PyCodeObject *func_code;
511
512	if (PyFunction_Check(pymethod)) {
513		func_code = (PyCodeObject *)PyFunction_GetCode(pymethod);
514		if (argcount == func_code->co_argcount) {
515			return pymethod;
516		}
517	} else if (PyMethod_Check(pymethod)) {
518		func_code = (PyCodeObject *)PyFunction_GetCode(
519			PyMethod_Function (pymethod));
520		if (argcount == func_code->co_argcount - 1) {
521			return pymethod;
522		}
523	}
524
525	return NULL;
526}
527
528
529/*#F If the Python object @var{obj} implements a method whose name matches
530  the Objective-C selector @var{aSelector} and accepts the correct number
531  of arguments, return that method, otherwise NULL. */
532static PyObject*
533get_method_for_selector(PyObject *obj, SEL aSelector)
534{
535	const char*  meth_name;
536	Py_ssize_t   len;
537	char         pymeth_name[256];
538	Py_ssize_t   argcount;
539	PyObject*    pymethod;
540	const char*  p;
541	PyObject*    result;
542
543	if (!aSelector) {
544		[NSException raise:NSInvalidArgumentException
545			     format:@"nil selector"];
546	}
547
548	meth_name = sel_getName(aSelector);
549	len = strlen(meth_name);
550
551	for (argcount=0, p=meth_name; *p; p++) {
552		if (*p == ':') {
553			argcount++;
554		}
555	}
556
557	pymethod = PyObject_GetAttrString(obj,
558			PyObjC_SELToPythonName(
559				aSelector, pymeth_name, sizeof(pymeth_name)));
560	if (pymethod == NULL) {
561		return NULL;
562	}
563
564	result =  check_argcount(pymethod, argcount);
565	if (result == NULL) {
566		Py_DECREF(pymethod);
567	}
568	return result;
569}
570
571
572- (BOOL) respondsToSelector:(SEL) aSelector
573{
574	PyObject *m;
575	Method* methods;
576	unsigned int method_count;
577	unsigned int i;
578	void* cookie;
579
580	/*
581	 * We cannot rely on NSProxy, it doesn't implement most of the
582	 * NSObject interface anyway.
583	 */
584
585	cookie = NULL;
586	methods = class_copyMethodList(object_getClass(self),
587			&method_count);
588	if (methods == NULL) {
589		return NO;
590	}
591
592	for (i = 0 ;i < method_count; i++) {
593		if (sel_isEqual(
594				method_getName(methods[i]), aSelector)) {
595			free(methods);
596			return YES;
597		}
598	}
599	free(methods);
600
601	PyObjC_BEGIN_WITH_GIL
602		m = get_method_for_selector(pyObject, aSelector);
603
604		if (m) {
605			Py_DECREF(m);
606			PyObjC_GIL_RETURN(YES);
607		} else {
608			PyErr_Clear();
609			PyObjC_GIL_RETURN(NO);
610		}
611
612	PyObjC_END_WITH_GIL
613}
614
615+ (NSMethodSignature *) methodSignatureForSelector:(SEL) sel
616{
617	Method		   m;
618
619	m = class_getInstanceMethod(self, sel);
620	if (m) {
621		/* A real Objective-C method */
622		return [NSMethodSignature
623		    signatureWithObjCTypes:method_getTypeEncoding(m)];
624	}
625
626	[NSException raise:NSInvalidArgumentException
627		format:@"Class %s: no such selector: %s",
628		class_getName(self), sel_getName(sel)];
629	return nil;
630}
631
632- (NSMethodSignature *) methodSignatureForSelector:(SEL) sel
633{
634	/* We can't call our superclass implementation, NSProxy just raises
635	 * an exception.
636	 */
637
638	char*    	   encoding;
639	PyObject*          pymethod;
640	PyCodeObject*      func_code;
641	Py_ssize_t         argcount;
642	Class		   cls;
643	Method		   m;
644
645	cls = object_getClass(self);
646	m = class_getInstanceMethod(cls, sel);
647	if (m) {
648		/* A real Objective-C method */
649		return [NSMethodSignature
650		    signatureWithObjCTypes:method_getTypeEncoding(m)];
651	}
652
653	PyObjC_BEGIN_WITH_GIL
654
655		pymethod = get_method_for_selector(pyObject, sel);
656		if (!pymethod) {
657			PyErr_Clear();
658			PyGILState_Release(_GILState);
659			[NSException raise:NSInvalidArgumentException
660				format:@"Class %s: no such selector: %s",
661				object_getClassName(self), sel_getName(sel)];
662		}
663
664
665		if (PyMethod_Check(pymethod)) {
666			func_code = (PyCodeObject*) PyFunction_GetCode(
667				PyMethod_Function (pymethod));
668			argcount = func_code->co_argcount-1;
669
670		} else {
671			func_code = (PyCodeObject*) PyFunction_GetCode(
672				pymethod);
673			argcount = func_code->co_argcount;
674		}
675		Py_DECREF(pymethod);
676
677		encoding = alloca(argcount+4);
678		memset(encoding, '@', argcount+3);
679		encoding[argcount+3] = '\0';
680		encoding[2] = ':';
681
682	PyObjC_END_WITH_GIL
683
684	return [NSMethodSignature signatureWithObjCTypes:encoding];
685}
686
687- (BOOL) _forwardNative:(NSInvocation*) invocation
688{
689	/* XXX: This should use libffi to call call native methods of this
690	 *      class. The implementation below works good enough for
691	 *      now...
692	 */
693	SEL aSelector = [invocation selector];
694
695	if (sel_isEqual(aSelector, @selector(description))) {
696		id res = [self description];
697		[invocation setReturnValue:&res];
698
699		return YES;
700
701	} else if (sel_isEqual(aSelector, @selector(_copyDescription))) {
702		id res = [self _copyDescription];
703		[invocation setReturnValue:&res];
704
705		return YES;
706
707	} else if (sel_isEqual(aSelector, @selector(respondsToSelector:))){
708		SEL	sel;
709		BOOL	b;
710
711		[invocation getArgument:&sel atIndex:2];
712
713		b = [self respondsToSelector: sel];
714		[invocation setReturnValue:&b];
715
716		return YES;
717
718	} else if (sel_isEqual(aSelector, @selector(classForKeyedArchiver))){
719		Class	c;
720
721		c = [self classForKeyedArchiver];
722		[invocation setReturnValue:&c];
723
724		return YES;
725
726	} else if (sel_isEqual(aSelector, @selector(classForArchiver))){
727		Class	c;
728
729		c = [self classForArchiver];
730		[invocation setReturnValue:&c];
731
732		return YES;
733
734	} else if (sel_isEqual(aSelector, @selector(classForCoder))){
735		Class	c;
736
737		c = [self classForCoder];
738		[invocation setReturnValue:&c];
739
740		return YES;
741
742	} else if (sel_isEqual(aSelector, @selector(classForPortCoder))){
743		Class	c;
744
745		c = [self classForPortCoder];
746		[invocation setReturnValue:&c];
747
748		return YES;
749
750	} else if (sel_isEqual(aSelector, @selector(replacementObjectForKeyedArchiver:))){
751		NSObject*	c;
752		NSObject* archiver;
753
754		[invocation getArgument:&archiver atIndex:2];
755		c = [self replacementObjectForKeyedArchiver:archiver];
756		[invocation setReturnValue:&c];
757
758		return YES;
759
760	} else if (sel_isEqual(aSelector, @selector(replacementObjectForArchiver:))){
761		NSObject*	c;
762		NSObject* archiver;
763
764		[invocation getArgument:&archiver atIndex:2];
765		c = [self replacementObjectForArchiver:archiver];
766		[invocation setReturnValue:&c];
767
768		return YES;
769
770	} else if (sel_isEqual(aSelector, @selector(replacementObjectForCoder:))){
771		NSObject*	c;
772		NSObject* archiver;
773
774		[invocation getArgument:&archiver atIndex:2];
775		c = [self replacementObjectForCoder:archiver];
776		[invocation setReturnValue:&c];
777
778		return YES;
779
780	} else if (sel_isEqual(aSelector, @selector(replacementObjectForPortCoder:))){
781		NSObject*	c;
782		NSObject* archiver;
783
784		[invocation getArgument:&archiver atIndex:2];
785		c = [self replacementObjectForPortCoder:archiver];
786		[invocation setReturnValue:&c];
787
788		return YES;
789
790	} else if (sel_isEqual(aSelector, @selector(copy))) {
791		NSObject*	c;
792
793		c = [self copy];
794		[invocation setReturnValue:&c];
795
796		return YES;
797
798	} else if (sel_isEqual(aSelector, @selector(copyWithZone:))) {
799		NSObject*	c;
800		NSZone* zone;
801
802		[invocation getArgument:&zone atIndex:2];
803		c = [self copyWithZone:zone];
804		[invocation setReturnValue:&c];
805
806		return YES;
807	}
808
809	return NO;
810}
811
812- (void) forwardInvocation:(NSInvocation *) invocation
813{
814	/* XXX: Needs cleanup */
815	NSMethodSignature* msign = [invocation methodSignature];
816	SEL                aSelector = [invocation selector];
817	PyObject*          pymethod;
818	PyObject*          result;
819	const char*        rettype = [msign methodReturnType];
820	int		   err;
821	PyObject*          args = NULL;
822	volatile unsigned int       i;
823	unsigned int       argcount;
824	Py_ssize_t	   retsize;
825	char*              retbuffer;
826
827	if ([self _forwardNative:invocation]) {
828		return;
829	}
830
831	PyObjC_BEGIN_WITH_GIL
832
833		retsize = PyObjCRT_SizeOfType (rettype);
834		if (retsize == -1) {
835			PyObjC_GIL_FORWARD_EXC();
836		}
837
838		retbuffer = alloca(retsize);
839
840		pymethod = get_method_for_selector(pyObject, aSelector);
841
842		if (!pymethod) {
843			PyGILState_Release(_GILState);
844			[self doesNotRecognizeSelector:aSelector];
845			return;
846		}
847
848		argcount = [msign numberOfArguments];
849		args = PyTuple_New(argcount-2);
850		if (args == NULL) {
851			Py_DECREF(pymethod);
852			PyObjC_GIL_FORWARD_EXC();
853		}
854		for (i=2; i< argcount; i++) {
855			const char *argtype;
856			char *argbuffer;
857			Py_ssize_t  argsize;
858			PyObject *pyarg;
859
860			argtype = [msign getArgumentTypeAtIndex:i];
861
862			/* What if argtype is a pointer? */
863
864			argsize = PyObjCRT_SizeOfType(argtype);
865			if (argsize == -1) {
866				Py_DECREF(args);
867				Py_DECREF(pymethod);
868				PyObjC_GIL_FORWARD_EXC();
869			}
870			argbuffer = alloca (argsize);
871
872			PyObjC_DURING
873				[invocation getArgument:argbuffer atIndex:i];
874
875			PyObjC_HANDLER
876				PyGILState_Release(_GILState);
877				[localException raise];
878
879			PyObjC_ENDHANDLER
880
881			pyarg = pythonify_c_value (argtype, argbuffer);
882			if (pyarg == NULL) {
883				Py_DECREF(args);
884				Py_DECREF(pymethod);
885				PyObjC_GIL_FORWARD_EXC();
886			}
887
888			PyTuple_SET_ITEM (args, i-2, pyarg);
889		}
890		result = PyObject_CallObject(pymethod, args);
891		Py_DECREF(args); args = NULL;
892		Py_DECREF(pymethod); pymethod = NULL;
893
894		if (result == NULL) {
895			PyObjC_GIL_FORWARD_EXC();
896			return;
897		}
898
899		err = depythonify_c_value (rettype, result, retbuffer);
900		Py_DECREF(result);
901		if (err == -1) {
902			PyObjC_GIL_FORWARD_EXC();
903		} else {
904			PyObjC_DURING
905				[invocation setReturnValue:retbuffer];
906
907			PyObjC_HANDLER
908				PyGILState_Release(_GILState);
909				[localException raise];
910			PyObjC_ENDHANDLER
911		}
912
913	PyObjC_END_WITH_GIL
914}
915
916
917- (PyObject *)  pyObject
918{
919	return pyObject;
920}
921
922- (PyObject *)  __pyobjc_PythonObject__
923{
924	PyObjC_BEGIN_WITH_GIL
925#if 1
926		if (pyObject == NULL) {
927#if 1
928			PyObject* r = PyObjCObject_New(self, PyObjCObject_kDEFAULT, YES);
929			PyObjC_GIL_RETURN(r);
930#else
931			Py_INCREF(Py_None);
932			PyObjC_GIL_RETURN(Py_None);
933#endif
934		} else
935#endif
936		{
937			Py_XINCREF(pyObject);
938			PyObjC_GIL_RETURN(pyObject);
939		}
940	PyObjC_END_WITH_GIL
941}
942-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
943{
944	PyObjC_BEGIN_WITH_GIL
945	*cookie = 0;
946	Py_INCREF(pyObject);
947	PyObjC_END_WITH_GIL
948	return pyObject;
949}
950
951+(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
952{
953	PyObject* rval;
954
955	PyObjC_BEGIN_WITH_GIL
956	rval =  PyObjCClass_New([OC_PythonObject class]);
957	*cookie = 0;
958	PyObjC_END_WITH_GIL
959
960
961	return rval;
962}
963
964/*
965 * Implementation for Key-Value Coding.
966 *
967 * Because this is a subclass of NSProxy we must implement all of the protocol,
968 * and cannot rely on the implementation in our superclass.
969 *
970 */
971
972+ (BOOL)useStoredAccessor
973{
974	return YES;
975}
976
977+ (BOOL)accessInstanceVariablesDirectly;
978{
979	return YES;
980}
981
982
983static PyObject*
984getModuleFunction(char* modname, char* funcname)
985{
986	PyObject* func;
987	PyObject* name;
988	PyObject* mod;
989
990	name = PyText_FromString(modname);
991	if (name == NULL) {
992		return NULL;
993	}
994
995	mod = PyImport_Import(name);
996	if (mod == NULL) {
997		Py_DECREF(name);
998		return NULL;
999	}
1000	func = PyObject_GetAttrString(mod, funcname);
1001	if (func == NULL) {
1002		Py_DECREF(name);
1003		Py_DECREF(mod);
1004		return NULL;
1005	}
1006	Py_DECREF(name);
1007	Py_DECREF(mod);
1008
1009	return func;
1010}
1011
1012/*
1013 *  Call PyObjCTools.KeyValueCoding.getKey to get the value for a key
1014 */
1015- valueForKey:(NSString*) key;
1016{
1017static  PyObject* getKeyFunc = NULL;
1018
1019	PyObject* keyName;
1020	PyObject* val;
1021	id res = nil;
1022
1023	PyObjC_BEGIN_WITH_GIL
1024
1025		if (getKeyFunc == NULL) {
1026			getKeyFunc = getModuleFunction(
1027				"PyObjCTools.KeyValueCoding",
1028				"getKey");
1029			if (getKeyFunc == NULL) {
1030				PyObjC_GIL_FORWARD_EXC();
1031			}
1032		}
1033
1034		keyName = PyObjC_IdToPython(key);
1035		if (keyName == NULL) {
1036			PyObjC_GIL_FORWARD_EXC();
1037		}
1038
1039		val = PyObject_CallFunction(getKeyFunc, "OO", pyObject, keyName);
1040		Py_DECREF(keyName);
1041		if (val == NULL) {
1042			PyObjC_GIL_FORWARD_EXC();
1043		}
1044
1045		if (depythonify_c_value(@encode(id), val, &res) < 0) {
1046			Py_DECREF(val);
1047			PyObjC_GIL_FORWARD_EXC();
1048		}
1049		Py_DECREF(val);
1050
1051	PyObjC_END_WITH_GIL
1052
1053	return res;
1054}
1055
1056- storedValueForKey: (NSString*) key;
1057{
1058	return [self valueForKey: key];
1059}
1060
1061
1062/* Calls PyObjCTools.KeyValueCoding.setKey to set the key */
1063
1064/* This is the 10.2 flavour of this method, deprecated in 10.3 */
1065- (void)takeValue: value forKey: (NSString*) key
1066{
1067	[self setValue: value forKey: key];
1068}
1069
1070- (void)setValue: value forKey: (NSString*) key;
1071{
1072static  PyObject* setKeyFunc = NULL;
1073
1074	PyObject* keyName;
1075	PyObject* pyValue;
1076	PyObject* val;
1077
1078	PyObjC_BEGIN_WITH_GIL
1079
1080		if (setKeyFunc == NULL) {
1081			setKeyFunc = getModuleFunction(
1082				"PyObjCTools.KeyValueCoding",
1083				"setKey");
1084			if (setKeyFunc == NULL) {
1085				PyObjC_GIL_FORWARD_EXC();
1086			}
1087		}
1088
1089		keyName = PyObjC_IdToPython(key);
1090		if (keyName == NULL) {
1091			PyObjC_GIL_FORWARD_EXC();
1092		}
1093
1094		pyValue = PyObjC_IdToPython(value);
1095		if (pyValue == NULL) {
1096			Py_DECREF(keyName);
1097			PyObjC_GIL_FORWARD_EXC();
1098		}
1099
1100		val = PyObject_CallFunction(setKeyFunc, "OOO",
1101				pyObject, keyName, pyValue);
1102		Py_DECREF(keyName);
1103		Py_DECREF(pyValue);
1104		if (val == NULL) {
1105			PyObjC_GIL_FORWARD_EXC();
1106		}
1107
1108		Py_DECREF(val);
1109
1110	PyObjC_END_WITH_GIL
1111}
1112
1113- (void)takeStoredValue: value forKey: (NSString*) key;
1114{
1115	[self takeValue: value forKey: key];
1116}
1117
1118- (NSDictionary*) valuesForKeys: (NSArray*)keys;
1119{
1120	NSMutableDictionary* result;
1121	NSEnumerator* enumerator;
1122	id aKey, aValue;
1123
1124	enumerator = [keys objectEnumerator];
1125	result = [NSMutableDictionary dictionary];
1126
1127	while ((aKey = [enumerator nextObject]) != NULL) {
1128		aValue = [self valueForKey: aKey];
1129		[result setObject: aValue forKey: aKey];
1130	}
1131
1132	return result;
1133}
1134
1135- valueForKeyPath: (NSString*) keyPath;
1136{
1137	NSArray* elems = [keyPath componentsSeparatedByString:@"."];
1138	NSEnumerator* enumerator = [elems objectEnumerator];
1139	id aKey;
1140	id target;
1141
1142	target = self;
1143	while ((aKey = [enumerator nextObject]) != NULL) {
1144		target = [target valueForKey: aKey];
1145	}
1146
1147	return target;
1148}
1149
1150/* takeValue:forKeyPath: was deprecated in 10.3, and is the right way on 10.2 */
1151- (void)takeValue: value forKeyPath: (NSString*)keyPath
1152{
1153	[self setValue: value forKeyPath: keyPath];
1154}
1155
1156- (void)setValue: value forKeyPath: (NSString*) keyPath;
1157{
1158	NSArray* elems = [keyPath componentsSeparatedByString:@"."];
1159	id target;
1160	int len;
1161	int i;
1162
1163	len = [elems count];
1164	target = self;
1165	for (i = 0; i < len-1; i++) {
1166		target = [target valueForKey: [elems objectAtIndex: i]];
1167	}
1168
1169	[target takeValue: value forKey: [elems objectAtIndex: len-1]];
1170}
1171
1172- (void)takeValuesFromDictionary: (NSDictionary*) aDictionary
1173{
1174	[self setValuesForKeysWithDictionary: aDictionary];
1175}
1176
1177- (void)setValuesForKeysWithDictionary: (NSDictionary*) aDictionary;
1178{
1179	NSEnumerator* enumerator = [aDictionary keyEnumerator];
1180	id aKey;
1181	id aValue;
1182
1183	while ((aKey = [enumerator nextObject]) != NULL) {
1184		aValue = [aDictionary objectForKey: aKey];
1185		[self takeValue: aValue forKey: aKey];
1186	}
1187}
1188
1189- (void)unableToSetNilForKey: (NSString*) key;
1190{
1191	[NSException
1192		raise: NSUnknownKeyException
1193		format: @"cannot set Nil for key: %@", key];
1194}
1195
1196- (void)handleQueryWithUnboundKey: (NSString*) key;
1197{
1198	[self valueForUndefinedKey: key];
1199}
1200
1201- (void)valueForUndefinedKey: (NSString*)key;
1202{
1203	[NSException
1204		raise: NSUnknownKeyException
1205		format: @"query for unknown key: %@", key];
1206}
1207
1208- (void)handleTakeValue: value forUnboundKey: (NSString*) key;
1209{
1210	[self setValue: value forUndefinedKey: key];
1211}
1212
1213- (void)setValue: value forUndefinedKey: (NSString*) key;
1214{
1215	[NSException
1216		raise: NSUnknownKeyException
1217		format: @"setting unknown key: %@ to <%@>", key, value];
1218}
1219
1220#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1221- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
1222{
1223	NSLog(@"*** Ignoring *** %@ for '%@' (of %@ with %#x in %p).\n", NSStringFromSelector(_cmd), keyPath, observer, options, context);
1224	return;
1225}
1226- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
1227{
1228	NSLog(@"*** Ignoring *** %@ for '%@' (of %@).", NSStringFromSelector(_cmd), keyPath, observer);
1229}
1230#endif
1231
1232/* NSObject protocol */
1233- (NSUInteger)hash
1234{
1235    PyObjC_BEGIN_WITH_GIL
1236        int rval;
1237        rval = PyObject_Hash([self pyObject]);
1238        if (rval == -1) {
1239            PyErr_Clear();
1240            rval = (NSUInteger)[self pyObject];
1241        }
1242        PyObjC_GIL_RETURN((NSUInteger)rval);
1243    PyObjC_END_WITH_GIL
1244}
1245
1246- (BOOL)isEqual:(id)anObject
1247{
1248    if (anObject == nil) {
1249        return NO;
1250    } else if (self == anObject) {
1251        return YES;
1252    }
1253    PyObjC_BEGIN_WITH_GIL
1254        PyObject *otherPyObject = PyObjC_IdToPython(anObject);
1255        if (otherPyObject == NULL) {
1256            PyErr_Clear();
1257            PyObjC_GIL_RETURN(NO);
1258        }
1259        if (otherPyObject == [self pyObject]) {
1260            PyObjC_GIL_RETURN(YES);
1261        }
1262        switch (PyObject_RichCompareBool([self pyObject], otherPyObject, Py_EQ)) {
1263            case -1:
1264                PyErr_Clear();
1265            case 0:
1266                PyObjC_GIL_RETURN(NO);
1267                break;
1268            default:
1269                PyObjC_GIL_RETURN(YES);
1270        }
1271    PyObjC_END_WITH_GIL
1272}
1273
1274/* NSObject methods */
1275- (NSComparisonResult)compare:(id)other
1276{
1277    if (other == nil) {
1278        [NSException raise: NSInvalidArgumentException
1279                    format: @"nil argument"];
1280    } else if (self == other) {
1281        return NSOrderedSame;
1282    }
1283    PyObjC_BEGIN_WITH_GIL
1284        PyObject *otherPyObject = PyObjC_IdToPython(other);
1285        if (otherPyObject == NULL) {
1286            PyObjC_GIL_FORWARD_EXC();
1287        }
1288        if (otherPyObject == [self pyObject]) {
1289            PyObjC_GIL_RETURN(NSOrderedSame);
1290        }
1291        int r;
1292        if (PyObject_Cmp([self pyObject], otherPyObject, &r) == -1) {
1293            PyObjC_GIL_FORWARD_EXC();
1294        }
1295        NSComparisonResult rval;
1296        switch (r) {
1297            case -1:
1298                rval = NSOrderedAscending;
1299                break;
1300            case 0:
1301                rval = NSOrderedSame;
1302                break;
1303            default:
1304                rval = NSOrderedDescending;
1305        }
1306        PyObjC_GIL_RETURN(rval);
1307    PyObjC_END_WITH_GIL
1308}
1309
1310
1311/*
1312 * Support of the NSCoding protocol
1313 */
1314- (void)encodeWithCoder:(NSCoder*)coder
1315{
1316	PyObjC_encodeWithCoder(pyObject, coder);
1317}
1318
1319/*
1320 * Helper method for initWithCoder, needed to deal with
1321 * recursive objects (e.g. o.value = o)
1322 */
1323-(void)pyobjcSetValue:(NSObject*)other
1324{
1325	PyObject* value = PyObjC_IdToPython(other);
1326	Py_XDECREF(pyObject);
1327	pyObject = value;
1328}
1329
1330- initWithCoder:(NSCoder*)coder
1331{
1332	pyObject = NULL;
1333
1334	if (PyObjC_Decoder != NULL) {
1335		PyObjC_BEGIN_WITH_GIL
1336			PyObject* cdr = PyObjC_IdToPython(coder);
1337			if (cdr == NULL) {
1338				PyObjC_GIL_FORWARD_EXC();
1339			}
1340
1341			PyObject* setValue;
1342			PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
1343			setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
1344
1345			PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
1346			Py_DECREF(cdr);
1347			Py_DECREF(setValue);
1348			Py_DECREF(selfAsPython);
1349
1350			if (v == NULL) {
1351				PyObjC_GIL_FORWARD_EXC();
1352			}
1353
1354			Py_XDECREF(pyObject);
1355			pyObject = v;
1356
1357			NSObject* proxy = PyObjC_FindObjCProxy(pyObject);
1358			if (proxy == NULL) {
1359				PyObjC_RegisterObjCProxy(pyObject, self);
1360			} else {
1361				[self release];
1362				[proxy retain];
1363				self = (OC_PythonObject*)proxy;
1364			}
1365
1366
1367		PyObjC_END_WITH_GIL
1368
1369		return self;
1370
1371	} else {
1372		[NSException raise:NSInvalidArgumentException
1373				format:@"decoding Python objects is not supported"];
1374		return nil;
1375
1376	}
1377}
1378
1379-(id)awakeAfterUsingCoder:(NSCoder*)coder
1380{
1381	(void)coder;
1382	return self;
1383}
1384
1385-(NSObject*)replacementObjectForArchiver:(NSObject*)archiver
1386{
1387	(void)archiver;
1388	return (NSObject*)self;
1389}
1390
1391-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
1392{
1393	(void)archiver;
1394	return (NSObject*)self;
1395}
1396
1397-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver
1398{
1399	(void)archiver;
1400	return (NSObject*)self;
1401}
1402
1403-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver
1404{
1405	(void)archiver;
1406	return (NSObject*)self;
1407}
1408
1409-(Class)classForArchiver
1410{
1411	return [OC_PythonObject class];
1412}
1413
1414-(Class)classForKeyedArchiver
1415{
1416	return [OC_PythonObject class];
1417}
1418
1419+(Class)classForUnarchiver
1420{
1421	return [OC_PythonObject class];
1422}
1423
1424+(Class)classForKeyedUnarchiver
1425{
1426	return [OC_PythonObject class];
1427}
1428
1429-(Class)classForCoder
1430{
1431	return [OC_PythonObject class];
1432}
1433
1434-(Class)classForPortCoder
1435{
1436	return [OC_PythonObject class];
1437}
1438
1439/* NOTE: NSProxy does not implement isKindOfClass on Leopard, therefore we
1440 * have to provide it ourself.
1441 *
1442 * Luckily that's kind of easy, we know the entiry class hierarcy and also
1443 * know there are no subclasses.
1444 */
1445- (BOOL)isKindOfClass:(Class)aClass
1446{
1447	if (aClass == [NSProxy class] || aClass == [OC_PythonObject class]) {
1448		return YES;
1449	}
1450	return NO;
1451}
1452
1453/*
1454 * This is needed to be able to add a python object to a
1455 * NSArray and then use array.description()
1456 */
1457-(BOOL)isNSArray__
1458{
1459	        return NO;
1460}
1461-(BOOL)isNSDictionary__
1462{
1463	        return NO;
1464}
1465-(BOOL)isNSSet__
1466{
1467	        return NO;
1468}
1469-(BOOL)isNSNumber__
1470{
1471	        return NO;
1472}
1473-(BOOL)isNSData__
1474{
1475	        return NO;
1476}
1477-(BOOL)isNSDate__
1478{
1479	        return NO;
1480}
1481-(BOOL)isNSString__
1482{
1483	        return NO;
1484}
1485-(BOOL)isNSValue__
1486{
1487	        return NO;
1488}
1489
1490
1491+classFallbacksForKeyedArchiver
1492{
1493	return nil;
1494}
1495
1496
1497/*
1498 * Fake implementation for _cfTypeID, which gets called by
1499 * system frameworks on some occassions.
1500 */
1501static BOOL haveTypeID = NO;
1502static CFTypeID _NSObjectTypeID;
1503
1504-(CFTypeID)_cfTypeID
1505{
1506	if (haveTypeID) {
1507		NSObject* obj = [[NSObject alloc] init];
1508		_NSObjectTypeID = CFGetTypeID((CFTypeRef)obj);
1509		[obj release];
1510		haveTypeID = YES;
1511	}
1512	return _NSObjectTypeID;
1513}
1514
1515
1516@end /* OC_PythonObject class implementation */
1517
1518
1519#if 0
1520/*
1521 * Generic implementation of the core of initWithCoder,
1522 * returns a reference to a new proxy object.
1523 *
1524 * NOTE: an implementation of initWithCoder will have to
1525 * release self and retain (and then return) the result of
1526 * this function.
1527 */
1528NSObject* PyObjC_decodeWithCoder(NSCoder* coder)
1529{
1530	PyObject* pyObject = NULL;
1531	NSObject* result = nil;
1532
1533	if (PyObjC_Decoder != NULL) {
1534		PyObjC_BEGIN_WITH_GIL
1535			PyObject* cdr = PyObjC_IdToPython(coder);
1536			if (cdr == NULL) {
1537				PyObjC_GIL_FORWARD_EXC();
1538			}
1539
1540			pyObject = PyObject_CallFunction(PyObjC_Decoder, "O", cdr);
1541			Py_DECREF(cdr);
1542			if (pyObject == NULL) {
1543				PyObjC_GIL_FORWARD_EXC();
1544			}
1545
1546			result = PyObjC_PythonToId(pyObject);
1547			Py_DECREF(pyObject);
1548
1549		PyObjC_END_WITH_GIL
1550		return result;
1551	} else {
1552		[NSException raise:NSInvalidArgumentException
1553				format:@"decoding Python objects is not supported"];
1554		return nil;
1555
1556	}
1557}
1558#endif
1559
1560void PyObjC_encodeWithCoder(PyObject* pyObject, NSCoder* coder)
1561{
1562	if (PyObjC_Encoder != NULL) {
1563		PyObjC_BEGIN_WITH_GIL
1564			PyObject* cdr = PyObjC_IdToPython(coder);
1565			if (cdr == NULL) {
1566            			PyObjC_GIL_FORWARD_EXC();
1567			}
1568
1569			PyObject* r = PyObject_CallFunction(PyObjC_Encoder, "OO", pyObject, cdr);
1570			Py_DECREF(cdr);
1571			if (r == NULL) {
1572            			PyObjC_GIL_FORWARD_EXC();
1573			}
1574			Py_DECREF(r);
1575
1576		PyObjC_END_WITH_GIL
1577
1578	} else {
1579		[NSException raise:NSInvalidArgumentException
1580				format:@"encoding Python objects is not supported"];
1581	}
1582}
1583