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