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