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				objectWithCoercedPyObject: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+(id <NSObject>)objectWithPythonObject:(PyObject *) obj
216{
217	id instance;
218	if (likely(PyObjCObject_Check(obj))) {
219		instance = PyObjCObject_GetObject(obj);
220	} else {
221		instance = [[self alloc] initWithPyObject:obj];
222		[instance autorelease];
223	}
224	return instance;
225}
226
227+(id <NSObject>)objectWithCoercedPyObject:(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] initWithPyObject:obj];
313	PyObjC_END_WITH_GIL
314	[instance autorelease];
315	return instance;
316}
317
318+(id)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+(id)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-(id)initWithPyObject:(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-(BOOL)supportsWeakPointers { return YES; }
382
383-(oneway void)release
384{
385	/* See comment in OC_PythonUnicode */
386	PyObjC_BEGIN_WITH_GIL
387		[super release];
388	PyObjC_END_WITH_GIL
389}
390
391
392
393-(void)dealloc
394{
395	PyObjC_BEGIN_WITH_GIL
396		PyObjC_UnregisterObjCProxy(pyObject, self);
397		Py_XDECREF(pyObject); pyObject = NULL;
398
399	PyObjC_END_WITH_GIL
400
401	[super dealloc];
402}
403
404-(id)copyWithZone:(NSZone*)zone
405{
406	(void)zone;
407	NSObject* result = nil;
408	PyObject* copy;
409
410	if (PyObjC_CopyFunc == NULL) {
411		[NSException raise:NSInvalidArgumentException
412					format:@"cannot copy Python objects"];
413
414	} else {
415		PyObjC_BEGIN_WITH_GIL
416			copy = PyObject_CallFunctionObjArgs(PyObjC_CopyFunc, pyObject, NULL);
417			if (copy == NULL) {
418				PyObjC_GIL_FORWARD_EXC();
419			}
420
421			result = PyObjC_PythonToId(copy);
422			Py_DECREF(copy);
423
424		PyObjC_END_WITH_GIL
425	}
426
427	if (result) {
428		[result retain];
429	}
430	return result;
431}
432
433-(id)copy
434{
435	return [self copyWithZone:NULL];
436}
437
438/* Undocumented method used by NSLog, this seems to work. */
439-(NSString*) _copyDescription
440{
441	return [[self description] copy];
442}
443
444-(NSString*) description
445{
446	PyObject *repr;
447
448	if (pyObject == NULL) return @"no python object";
449
450	PyObjC_BEGIN_WITH_GIL
451
452		repr = PyObject_Repr (pyObject);
453
454#if PY_MAJOR_VERSION == 2
455		if (repr) {
456			int err;
457			NSString* result;
458			PyObject *urepr = PyUnicode_FromEncodedObject(
459				repr,
460				NULL,
461				"replace");
462			Py_DECREF(repr);
463			if (urepr == NULL) {
464				PyObjC_GIL_FORWARD_EXC();
465			}
466			err = depythonify_c_value (@encode(id), urepr, &result);
467			Py_DECREF (urepr);
468			if (err == -1) {
469				PyObjC_GIL_FORWARD_EXC();
470			}
471			PyObjC_GIL_RETURN(result);
472		} else {
473			PyObjC_GIL_FORWARD_EXC();
474		}
475#else
476		if (repr) {
477			int err;
478			NSString* result;
479
480			err = depythonify_c_value (@encode(id), repr, &result);
481			Py_DECREF(repr);
482			if (err == -1) {
483				PyObjC_GIL_FORWARD_EXC();
484			}
485
486			PyObjC_GIL_RETURN(result);
487		} else {
488			PyObjC_GIL_FORWARD_EXC();
489		}
490#endif
491
492	PyObjC_END_WITH_GIL
493
494	/* not reached */
495	return @"a python object";
496}
497
498-(void)doesNotRecognizeSelector:(SEL) aSelector
499{
500	[NSException raise:NSInvalidArgumentException
501				format:@"%@ does not recognize -%s",
502				self, sel_getName(aSelector)];
503}
504
505
506/*#F Check the argument count of the method/function @var{pymethod},
507  returning the method itself if it matches @var{argcount}, NULL
508  otherwise. */
509static inline PyObject *
510check_argcount (PyObject *pymethod, Py_ssize_t argcount)
511{
512	PyCodeObject *func_code;
513
514	if (PyFunction_Check(pymethod)) {
515		func_code = (PyCodeObject *)PyFunction_GetCode(pymethod);
516		if (argcount == func_code->co_argcount) {
517			return pymethod;
518		}
519	} else if (PyMethod_Check(pymethod)) {
520		func_code = (PyCodeObject *)PyFunction_GetCode(
521			PyMethod_Function (pymethod));
522		if (argcount == func_code->co_argcount - 1) {
523			return pymethod;
524		}
525	}
526
527	return NULL;
528}
529
530
531/*#F If the Python object @var{obj} implements a method whose name matches
532  the Objective-C selector @var{aSelector} and accepts the correct number
533  of arguments, return that method, otherwise NULL. */
534static PyObject*
535get_method_for_selector(PyObject *obj, SEL aSelector)
536{
537	const char*  meth_name;
538	char         pymeth_name[256];
539	Py_ssize_t   argcount;
540	PyObject*    pymethod;
541	const char*  p;
542	PyObject*    result;
543
544	if (!aSelector) {
545		[NSException raise:NSInvalidArgumentException
546			     format:@"nil selector"];
547	}
548
549	meth_name = sel_getName(aSelector);
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		NSKeyedArchiver* 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		NSArchiver* 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		NSCoder* 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		NSPortCoder* 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 (pyObject == NULL) {
926			PyObject* r = PyObjCObject_New(self, PyObjCObject_kDEFAULT, YES);
927			PyObjC_GIL_RETURN(r);
928		} else {
929			Py_XINCREF(pyObject);
930			PyObjC_GIL_RETURN(pyObject);
931		}
932	PyObjC_END_WITH_GIL
933}
934-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
935{
936	PyObjC_BEGIN_WITH_GIL
937	*cookie = 0;
938	Py_INCREF(pyObject);
939	PyObjC_END_WITH_GIL
940	return pyObject;
941}
942
943+(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
944{
945	PyObject* rval;
946
947	PyObjC_BEGIN_WITH_GIL
948	rval =  PyObjCClass_New([OC_PythonObject class]);
949	*cookie = 0;
950	PyObjC_END_WITH_GIL
951
952
953	return rval;
954}
955
956/*
957 * Implementation for Key-Value Coding.
958 *
959 * Because this is a subclass of NSProxy we must implement all of the protocol,
960 * and cannot rely on the implementation in our superclass.
961 *
962 */
963
964+ (BOOL)useStoredAccessor
965{
966	return YES;
967}
968
969+ (BOOL)accessInstanceVariablesDirectly
970{
971	return YES;
972}
973
974
975static PyObject*
976getModuleFunction(char* modname, char* funcname)
977{
978	PyObject* func;
979	PyObject* name;
980	PyObject* mod;
981
982	name = PyText_FromString(modname);
983	if (name == NULL) {
984		return NULL;
985	}
986
987	mod = PyImport_Import(name);
988	if (mod == NULL) {
989		Py_DECREF(name);
990		return NULL;
991	}
992	func = PyObject_GetAttrString(mod, funcname);
993	if (func == NULL) {
994		Py_DECREF(name);
995		Py_DECREF(mod);
996		return NULL;
997	}
998	Py_DECREF(name);
999	Py_DECREF(mod);
1000
1001	return func;
1002}
1003
1004/*
1005 *  Call PyObjCTools.KeyValueCoding.getKey to get the value for a key
1006 */
1007-(id)valueForKey:(NSString*) key
1008{
1009static  PyObject* getKeyFunc = NULL;
1010
1011	PyObject* keyName;
1012	PyObject* val;
1013	id res = nil;
1014
1015	PyObjC_BEGIN_WITH_GIL
1016
1017		if (getKeyFunc == NULL) {
1018			getKeyFunc = getModuleFunction(
1019				"PyObjCTools.KeyValueCoding",
1020				"getKey");
1021			if (getKeyFunc == NULL) {
1022				PyObjC_GIL_FORWARD_EXC();
1023			}
1024		}
1025
1026		keyName = PyObjC_IdToPython(key);
1027		if (keyName == NULL) {
1028			PyObjC_GIL_FORWARD_EXC();
1029		}
1030
1031		val = PyObject_CallFunction(getKeyFunc, "OO", pyObject, keyName);
1032		Py_DECREF(keyName);
1033		if (val == NULL) {
1034			PyObjC_GIL_FORWARD_EXC();
1035		}
1036
1037		if (depythonify_c_value(@encode(id), val, &res) < 0) {
1038			Py_DECREF(val);
1039			PyObjC_GIL_FORWARD_EXC();
1040		}
1041		Py_DECREF(val);
1042
1043	PyObjC_END_WITH_GIL
1044
1045	return res;
1046}
1047
1048-(id)storedValueForKey: (NSString*) key
1049{
1050	return [self valueForKey: key];
1051}
1052
1053
1054/* Calls PyObjCTools.KeyValueCoding.setKey to set the key */
1055
1056/* This is the 10.2 flavour of this method, deprecated in 10.3 */
1057-(void)takeValue: value forKey: (NSString*) key
1058{
1059	[self setValue: value forKey: key];
1060}
1061
1062-(void)setValue: value forKey: (NSString*) key
1063{
1064static  PyObject* setKeyFunc = NULL;
1065
1066	PyObject* keyName;
1067	PyObject* pyValue;
1068	PyObject* val;
1069
1070	PyObjC_BEGIN_WITH_GIL
1071
1072		if (setKeyFunc == NULL) {
1073			setKeyFunc = getModuleFunction(
1074				"PyObjCTools.KeyValueCoding",
1075				"setKey");
1076			if (setKeyFunc == NULL) {
1077				PyObjC_GIL_FORWARD_EXC();
1078			}
1079		}
1080
1081		keyName = PyObjC_IdToPython(key);
1082		if (keyName == NULL) {
1083			PyObjC_GIL_FORWARD_EXC();
1084		}
1085
1086		pyValue = PyObjC_IdToPython(value);
1087		if (pyValue == NULL) {
1088			Py_DECREF(keyName);
1089			PyObjC_GIL_FORWARD_EXC();
1090		}
1091
1092		val = PyObject_CallFunction(setKeyFunc, "OOO",
1093				pyObject, keyName, pyValue);
1094		Py_DECREF(keyName);
1095		Py_DECREF(pyValue);
1096		if (val == NULL) {
1097			PyObjC_GIL_FORWARD_EXC();
1098		}
1099
1100		Py_DECREF(val);
1101
1102	PyObjC_END_WITH_GIL
1103}
1104
1105-(void)takeStoredValue: value forKey: (NSString*) key
1106{
1107	[self takeValue: value forKey: key];
1108}
1109
1110-(NSDictionary*)valuesForKeys: (NSArray*)keys
1111{
1112	NSMutableDictionary* result;
1113	NSEnumerator* enumerator;
1114	id aKey, aValue;
1115
1116	enumerator = [keys objectEnumerator];
1117	result = [NSMutableDictionary dictionary];
1118
1119	while ((aKey = [enumerator nextObject]) != NULL) {
1120		aValue = [self valueForKey: aKey];
1121		[result setObject: aValue forKey: aKey];
1122	}
1123
1124	return result;
1125}
1126
1127-(id)valueForKeyPath: (NSString*) keyPath
1128{
1129	NSArray* elems = [keyPath componentsSeparatedByString:@"."];
1130	NSEnumerator* enumerator = [elems objectEnumerator];
1131	id aKey;
1132	id target;
1133
1134	target = self;
1135	while ((aKey = [enumerator nextObject]) != NULL) {
1136		target = [target valueForKey: aKey];
1137	}
1138
1139	return target;
1140}
1141
1142/* takeValue:forKeyPath: was deprecated in 10.3, and is the right way on 10.2 */
1143-(void)takeValue: value forKeyPath: (NSString*)keyPath
1144{
1145	[self setValue: value forKeyPath: keyPath];
1146}
1147
1148-(void)setValue: value forKeyPath: (NSString*) keyPath
1149{
1150	NSArray* elems = [keyPath componentsSeparatedByString:@"."];
1151	id target;
1152	NSInteger len;
1153	NSInteger i;
1154
1155	len = [elems count];
1156	target = self;
1157	for (i = 0; i < len-1; i++) {
1158		target = [target valueForKey: [elems objectAtIndex: i]];
1159	}
1160
1161	[target takeValue: value forKey: [elems objectAtIndex: len-1]];
1162}
1163
1164-(void)takeValuesFromDictionary: (NSDictionary*) aDictionary
1165{
1166	[self setValuesForKeysWithDictionary: aDictionary];
1167}
1168
1169-(void)setValuesForKeysWithDictionary: (NSDictionary*) aDictionary
1170{
1171	NSEnumerator* enumerator = [aDictionary keyEnumerator];
1172	id aKey;
1173	id aValue;
1174
1175	while ((aKey = [enumerator nextObject]) != NULL) {
1176		aValue = [aDictionary objectForKey: aKey];
1177		[self takeValue: aValue forKey: aKey];
1178	}
1179}
1180
1181-(void)unableToSetNilForKey: (NSString*) key
1182{
1183	[NSException
1184		raise: NSUnknownKeyException
1185		format: @"cannot set Nil for key: %@", key];
1186}
1187
1188-(void)handleQueryWithUnboundKey: (NSString*) key
1189{
1190	[self valueForUndefinedKey: key];
1191}
1192
1193-(void)valueForUndefinedKey: (NSString*)key
1194{
1195	[NSException
1196		raise: NSUnknownKeyException
1197		format: @"query for unknown key: %@", key];
1198}
1199
1200-(void)handleTakeValue: value forUnboundKey: (NSString*) key
1201{
1202	[self setValue: value forUndefinedKey: key];
1203}
1204
1205-(void)setValue: value forUndefinedKey: (NSString*) key
1206{
1207	[NSException
1208		raise: NSUnknownKeyException
1209		format: @"setting unknown key: %@ to <%@>", key, value];
1210}
1211
1212#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
1213-(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
1214{
1215	NSLog(@"*** Ignoring *** %@ for '%@' (of %@ with %#lx in %p).\n", NSStringFromSelector(_cmd), keyPath, observer, (long)options, context);
1216	return;
1217}
1218-(void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath
1219{
1220	NSLog(@"*** Ignoring *** %@ for '%@' (of %@).", NSStringFromSelector(_cmd), keyPath, observer);
1221}
1222#endif
1223
1224/* NSObject protocol */
1225-(NSUInteger)hash
1226{
1227    PyObjC_BEGIN_WITH_GIL
1228        int rval;
1229        rval = PyObject_Hash([self pyObject]);
1230        if (rval == -1) {
1231            PyErr_Clear();
1232            rval = (NSUInteger)[self pyObject];
1233        }
1234        PyObjC_GIL_RETURN((NSUInteger)rval);
1235    PyObjC_END_WITH_GIL
1236}
1237
1238-(BOOL)isEqual:(id)anObject
1239{
1240    if (anObject == nil) {
1241        return NO;
1242    } else if (self == anObject) {
1243        return YES;
1244    }
1245    PyObjC_BEGIN_WITH_GIL
1246        PyObject *otherPyObject = PyObjC_IdToPython(anObject);
1247        if (otherPyObject == NULL) {
1248            PyErr_Clear();
1249            PyObjC_GIL_RETURN(NO);
1250        }
1251        if (otherPyObject == [self pyObject]) {
1252            PyObjC_GIL_RETURN(YES);
1253        }
1254        switch (PyObject_RichCompareBool([self pyObject], otherPyObject, Py_EQ)) {
1255            case -1:
1256                PyErr_Clear();
1257            case 0:
1258                PyObjC_GIL_RETURN(NO);
1259                break;
1260            default:
1261                PyObjC_GIL_RETURN(YES);
1262        }
1263    PyObjC_END_WITH_GIL
1264}
1265
1266/* NSObject methods */
1267-(NSComparisonResult)compare:(id)other
1268{
1269    if (other == nil) {
1270        [NSException raise: NSInvalidArgumentException
1271                    format: @"nil argument"];
1272    } else if (self == other) {
1273        return NSOrderedSame;
1274    }
1275    PyObjC_BEGIN_WITH_GIL
1276        PyObject *otherPyObject = PyObjC_IdToPython(other);
1277        if (otherPyObject == NULL) {
1278            PyObjC_GIL_FORWARD_EXC();
1279        }
1280        if (otherPyObject == [self pyObject]) {
1281            PyObjC_GIL_RETURN(NSOrderedSame);
1282        }
1283        int r;
1284        if (PyObject_Cmp([self pyObject], otherPyObject, &r) == -1) {
1285            PyObjC_GIL_FORWARD_EXC();
1286        }
1287        NSComparisonResult rval;
1288        switch (r) {
1289            case -1:
1290                rval = NSOrderedAscending;
1291                break;
1292            case 0:
1293                rval = NSOrderedSame;
1294                break;
1295            default:
1296                rval = NSOrderedDescending;
1297        }
1298        PyObjC_GIL_RETURN(rval);
1299    PyObjC_END_WITH_GIL
1300}
1301
1302
1303/*
1304 * Support of the NSCoding protocol
1305 */
1306-(void)encodeWithCoder:(NSCoder*)coder
1307{
1308	PyObjC_encodeWithCoder(pyObject, coder);
1309}
1310
1311/*
1312 * Helper method for initWithCoder, needed to deal with
1313 * recursive objects (e.g. o.value = o)
1314 */
1315-(void)pyobjcSetValue:(NSObject*)other
1316{
1317	PyObjC_BEGIN_WITH_GIL
1318		PyObject* value = PyObjC_IdToPython(other);
1319		Py_XDECREF(pyObject);
1320		pyObject = value;
1321	PyObjC_END_WITH_GIL
1322}
1323
1324-(id)initWithCoder:(NSCoder*)coder
1325{
1326	pyObject = NULL;
1327
1328	if (PyObjC_Decoder != NULL) {
1329		PyObjC_BEGIN_WITH_GIL
1330			PyObject* cdr = PyObjC_IdToPython(coder);
1331			if (cdr == NULL) {
1332				PyObjC_GIL_FORWARD_EXC();
1333			}
1334
1335			PyObject* setValue;
1336			PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
1337			setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
1338
1339			PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
1340			Py_DECREF(cdr);
1341			Py_DECREF(setValue);
1342			Py_DECREF(selfAsPython);
1343
1344			if (v == NULL) {
1345				PyObjC_GIL_FORWARD_EXC();
1346			}
1347
1348			Py_XDECREF(pyObject);
1349			pyObject = v;
1350
1351			NSObject* proxy = PyObjC_FindObjCProxy(pyObject);
1352			if (proxy == NULL) {
1353				PyObjC_RegisterObjCProxy(pyObject, self);
1354			} else {
1355				[self release];
1356				[proxy retain];
1357				self = (OC_PythonObject*)proxy;
1358			}
1359
1360
1361		PyObjC_END_WITH_GIL
1362
1363		return self;
1364
1365	} else {
1366		[NSException raise:NSInvalidArgumentException
1367				format:@"decoding Python objects is not supported"];
1368		return nil;
1369
1370	}
1371}
1372
1373-(id)awakeAfterUsingCoder:(NSCoder*)coder
1374{
1375	(void)coder;
1376	return self;
1377}
1378
1379-(NSObject*)replacementObjectForArchiver:(NSObject*)archiver
1380{
1381	(void)archiver;
1382	return (NSObject*)self;
1383}
1384
1385-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver
1386{
1387	(void)archiver;
1388	return (NSObject*)self;
1389}
1390
1391-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver
1392{
1393	(void)archiver;
1394	return (NSObject*)self;
1395}
1396
1397-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver
1398{
1399	(void)archiver;
1400	return (NSObject*)self;
1401}
1402
1403-(Class)classForArchiver
1404{
1405	return [OC_PythonObject class];
1406}
1407
1408-(Class)classForKeyedArchiver
1409{
1410	return [OC_PythonObject class];
1411}
1412
1413+(Class)classForUnarchiver
1414{
1415	return [OC_PythonObject class];
1416}
1417
1418+(Class)classForKeyedUnarchiver
1419{
1420	return [OC_PythonObject class];
1421}
1422
1423-(Class)classForCoder
1424{
1425	return [OC_PythonObject class];
1426}
1427
1428-(Class)classForPortCoder
1429{
1430	return [OC_PythonObject class];
1431}
1432
1433/* NOTE: NSProxy does not implement isKindOfClass on Leopard, therefore we
1434 * have to provide it ourself.
1435 *
1436 * Luckily that's kind of easy, we know the entiry class hierarcy and also
1437 * know there are no subclasses.
1438 */
1439-(BOOL)isKindOfClass:(Class)aClass
1440{
1441	if (aClass == [NSProxy class] || aClass == [OC_PythonObject class]) {
1442		return YES;
1443	}
1444	return NO;
1445}
1446
1447/*
1448 * This is needed to be able to add a python object to a
1449 * NSArray and then use array.description()
1450 */
1451-(BOOL)isNSArray__
1452{
1453	        return NO;
1454}
1455-(BOOL)isNSDictionary__
1456{
1457	        return NO;
1458}
1459-(BOOL)isNSSet__
1460{
1461	        return NO;
1462}
1463-(BOOL)isNSNumber__
1464{
1465	        return NO;
1466}
1467-(BOOL)isNSData__
1468{
1469	        return NO;
1470}
1471-(BOOL)isNSDate__
1472{
1473	        return NO;
1474}
1475-(BOOL)isNSString__
1476{
1477	        return NO;
1478}
1479-(BOOL)isNSValue__
1480{
1481	        return NO;
1482}
1483
1484
1485+(id)classFallbacksForKeyedArchiver
1486{
1487	return nil;
1488}
1489
1490
1491/*
1492 * Fake implementation for _cfTypeID, which gets called by
1493 * system frameworks on some occassions.
1494 */
1495static BOOL haveTypeID = NO;
1496static CFTypeID _NSObjectTypeID;
1497
1498-(CFTypeID)_cfTypeID
1499{
1500	if (haveTypeID) {
1501		NSObject* obj = [[NSObject alloc] init];
1502		_NSObjectTypeID = CFGetTypeID((CFTypeRef)obj);
1503		[obj release];
1504		haveTypeID = YES;
1505	}
1506	return _NSObjectTypeID;
1507}
1508
1509
1510@end /* OC_PythonObject class implementation */
1511
1512
1513void PyObjC_encodeWithCoder(PyObject* pyObject, NSCoder* coder)
1514{
1515	if (PyObjC_Encoder != NULL) {
1516		PyObjC_BEGIN_WITH_GIL
1517			PyObject* cdr = PyObjC_IdToPython(coder);
1518			if (cdr == NULL) {
1519            			PyObjC_GIL_FORWARD_EXC();
1520			}
1521
1522			PyObject* r = PyObject_CallFunction(PyObjC_Encoder, "OO", pyObject, cdr);
1523			Py_DECREF(cdr);
1524			if (r == NULL) {
1525            			PyObjC_GIL_FORWARD_EXC();
1526			}
1527			Py_DECREF(r);
1528
1529		PyObjC_END_WITH_GIL
1530
1531	} else {
1532		[NSException raise:NSInvalidArgumentException
1533				format:@"encoding Python objects is not supported"];
1534	}
1535}
1536