1/* 2 * Objective-C runtime 2.0 compatibility for MacOS X 10.4 and earlier. 3 * 4 * This code works by poking into the ObjC runtime, which means loads of 5 * warnings on 10.5+ ;-) 6 */ 7 8#define PYOBJC_COMPAT_IMPL 9#include "pyobjc.h" 10 11 12 13 14#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) &&!defined(__OBJC2__) 15 16BOOL PyObjC_class_isSubclassOf(Class child, Class parent) 17{ 18 if (parent == nil) return YES; 19 20 while (child != nil) { 21 if (child == parent) { 22 return YES; 23 } 24 child = PyObjC_class_getSuperclass(child); 25 } 26 return NO; 27} 28 29#import <mach-o/dyld.h> 30#import <mach-o/getsect.h> 31#import <mach-o/loader.h> 32 33typedef struct _ProtocolTemplate { @defs(Protocol) } ProtocolTemplate; 34 35 36 37struct objc10_object { 38 Class isa; 39}; 40 41struct PyObjC_ivar { 42 char* name; 43 size_t size; 44 uint8_t alignment; 45 char* types; 46}; 47 48 49static Protocol** compat_objc_copyProtocolList(unsigned int* outCount) 50{ 51 Protocol** protocols = NULL; 52 *outCount = 0; 53 54 uint32_t image_count, image_index; 55 image_count = _dyld_image_count(); 56 for (image_index = 0; image_index < image_count; image_index++) { 57 uint32_t size = 0; 58 const struct mach_header *mh = _dyld_get_image_header(image_index); 59 intptr_t slide = _dyld_get_image_vmaddr_slide(image_index); 60 ProtocolTemplate *protos = (ProtocolTemplate*)( 61 ((char *)getsectdatafromheader(mh, SEG_OBJC, "__protocol", &size)) + 62 slide); 63 uint32_t nprotos = size / sizeof(ProtocolTemplate); 64 uint32_t i; 65 66 if (nprotos == 0) continue; 67 68 if (protocols == NULL) { 69 protocols = malloc(sizeof(Protocol*) * nprotos); 70 if (protocols == NULL) { 71 return NULL; 72 } 73 } else { 74 Protocol** tmp = realloc(protocols, 75 sizeof(Protocol*) * (*outCount+nprotos)); 76 if (tmp == NULL) { 77 free(protocols); 78 return NULL; 79 } 80 protocols = tmp; 81 } 82 83 for (i = 0; i < nprotos; i++) { 84 protocols[(*outCount)++] = (Protocol*)&protos[i]; 85 } 86 } 87 return protocols; 88} 89 90static Protocol* compat_objc_getProtocol(const char* name) 91{ 92 uint32_t image_count, image_index; 93 image_count = _dyld_image_count(); 94 for (image_index = 0; image_index < image_count; image_index++) { 95 uint32_t size = 0; 96 const struct mach_header *mh = _dyld_get_image_header(image_index); 97 intptr_t slide = _dyld_get_image_vmaddr_slide(image_index); 98 ProtocolTemplate *protos = (ProtocolTemplate*)( 99 ((char *)getsectdatafromheader(mh, SEG_OBJC, "__protocol", &size)) + 100 slide); 101 uint32_t nprotos = size / sizeof(ProtocolTemplate); 102 uint32_t i; 103 104 if (nprotos == 0) continue; 105 106 for (i = 0; i < nprotos; i++) { 107 Protocol* p = (Protocol*)&protos[i]; 108 if (strcmp([p name], name) == 0) { 109 return p; 110 } 111 } 112 } 113 return nil; 114} 115 116 117static void 118compat_objc_registerClassPair(Class cls) 119{ 120 struct objc_method_list* list; 121 122 /* Add the list in the official way, just in case class_addMethods 123 * does something special. 124 */ 125 list = cls->methodLists[0]; 126 cls->methodLists[0] = (struct objc_method_list*)-1; 127 class_addMethods(cls, list); 128 129 list = cls->isa->methodLists[0]; 130 cls->isa->methodLists[0] = (struct objc_method_list*)-1; 131 class_addMethods(cls->isa, list); 132 133 objc_addClass(cls); 134} 135 136static Class 137compat_objc_allocateClassPair(Class super_class, const char* name, size_t extra) 138{ 139 struct objc_class* result; 140 Class root_class; 141 142 if (objc_getClass(name)) { 143 return Nil; 144 } 145 146 root_class = super_class; 147 while (root_class->super_class) { 148 root_class = root_class->super_class; 149 } 150 151 result = malloc(sizeof(struct objc_class) * 2 + extra); 152 if (result == NULL) { 153 return Nil; 154 } 155 memset(result, 0, sizeof(struct objc_class) * 2 + extra); 156 157 result->super_class = super_class; 158 result->isa = result + 1; 159 160 result[0].methodLists = NULL; 161 result[1].methodLists = NULL; 162 163 result[0].info = CLS_CLASS; 164 result[1].info = CLS_META; 165 166 result[0].name = strdup(name); 167 if (result[0].name == NULL) goto error_cleanup; 168 169 result[1].name = result[0].name; 170 result[0].methodLists = malloc(sizeof(struct objc_method_list*)); 171 if (result[0].methodLists == NULL) goto error_cleanup; 172 memset(result[0].methodLists, 0, sizeof(struct objc_method_list*)); 173 174 result[1].methodLists = malloc(sizeof(struct objc_method_list*)); 175 if (result[1].methodLists == NULL) goto error_cleanup; 176 memset(result[1].methodLists, 0, sizeof(struct objc_method_list*)); 177 178 /* 179 * This is MacOS X specific, and an undocumented feature (long live 180 * Open Source!). 181 * 182 * The code in the objc runtime assumes that the method lists are 183 * terminated by '-1', and will happily overwite existing data if 184 * they aren't. 185 * 186 * Ronald filed a bugreport for this: Radar #3317376 187 */ 188 result[0].methodLists[0] = (struct objc_method_list*)-1; 189 result[1].methodLists[0] = (struct objc_method_list*)-1; 190 191 result[0].methodLists[0] = malloc(sizeof(struct objc_method_list)); 192 if (result[0].methodLists[0] == NULL) goto error_cleanup; 193 result[0].methodLists[0]->method_count = 0; 194 result[0].methodLists[0]->obsolete = NULL; 195 196 result[1].methodLists[0] = malloc(sizeof(struct objc_method_list)); 197 if (result[1].methodLists[0] == NULL) goto error_cleanup; 198 result[1].methodLists[0]->method_count = 0; 199 result[1].methodLists[0]->obsolete = NULL; 200 201 202 result[0].super_class = super_class; 203 result[1].super_class = ((struct objc10_object*)super_class)->isa; 204 result[1].isa = ((struct objc10_object*)root_class)->isa; 205 206 result[0].instance_size = super_class->instance_size; 207 result[1].instance_size = result[1].super_class->instance_size; 208 209 /* Initialize to NULL, otherwise poseAs: won't work */ 210 result[0].ivars = result[1].ivars = NULL; 211 212 result[0].protocols = result[1].protocols = NULL; 213 214 return result; 215 216 217error_cleanup: 218 if (result) { 219 if (result[0].methodLists) { 220 if (result[0].methodLists[0] != 0 && 221 result[0].methodLists[0] != 0) { 222 free(result[0].methodLists[0]); 223 } 224 free(result[0].methodLists); 225 } 226 if (result[1].methodLists) { 227 if (result[1].methodLists[1] != 0 && 228 result[1].methodLists[0] != 0) { 229 free(result[1].methodLists[0]); 230 } 231 free(result[1].methodLists); 232 } 233 234 if (result[0].ivars) { 235 free(result[0].ivars); 236 } 237 if (result[1].ivars) { 238 free(result[1].ivars); 239 } 240 241 if (result[0].name) { 242 free((char*)result[0].name); 243 } 244 free(result); 245 } 246 return Nil; 247 248} 249 250static void 251compat_objc_disposeClassPair(Class cls) 252{ 253 struct objc_class* val = cls; 254 int i; 255 256 for (i = 0; i < 2; i++) { 257 if (val[i].methodLists) { 258 struct objc_method_list** cur; 259 260 cur = val[i].methodLists; 261 if (*cur != (struct objc_method_list*)-1) { 262 free(*cur); 263 *cur = NULL; 264 } 265 free(val[i].methodLists); 266 val[i].methodLists = NULL; 267 } 268 } 269 270 free((char*)val[0].name); 271 val[0].name = val[1].name = NULL; 272 free(val); 273} 274 275 276static size_t 277compat_methodlist_magic(Class cls) 278{ 279 void* iterator = NULL; 280 struct objc_method_list* mlist; 281 size_t res = 0, cnt = 0; 282 283 if (cls == NULL) return -1; 284 285 while ( (mlist = class_nextMethodList(cls, &iterator )) != NULL ) { 286 res += mlist->method_count; 287 cnt++; 288 } 289 290 return (cnt << 16) | (res & 0xFFFF); 291} 292 293#ifndef NO_OBJC2_RUNTIME 294static size_t 295objc20_methodlist_magic(Class cls) 296{ 297 Method* methods; 298 unsigned int count; 299 unsigned int i; 300 size_t result; 301 302 methods = class_copyMethodList(cls, &count); 303 result = 0; 304 for (i = 0; i < count; i++) { 305 result = (1000003*result) ^ ((size_t)( 306 method_getImplementation(methods[i])) >> 3); 307 } 308 result = result | (count << 16); 309 free(methods); 310 return result; 311} 312#endif 313 314static Class 315compat_object_setClass(id obj, Class cls) 316{ 317 Class prev; 318 if (obj == nil) { 319 return Nil; 320 } 321 prev = ((struct objc10_object*)obj)->isa; 322 ((struct objc10_object*)obj)->isa = cls; 323 return prev; 324} 325 326 327 328static Class 329compat_object_getClass(id obj) 330{ 331 return ((struct objc10_object*)obj)->isa; 332} 333 334static const char* 335compat_object_getClassName(id obj) 336{ 337 return ((struct objc10_object*)obj)->isa->name; 338} 339 340 341 342static Method* 343compat_class_copyMethodList(Class cls, unsigned int* outCount) 344{ 345 struct objc_method_list* mlist; 346 void* iterator; 347 unsigned int count; 348 Method* result; 349 Method* tmp; 350 351 iterator = NULL; 352 count = 0; 353 354 mlist = class_nextMethodList(cls, &iterator); 355 result = NULL; 356 while (mlist != NULL) { 357 int i; 358 359 tmp = realloc(result, (count + mlist->method_count) * sizeof(Method)); 360 if (tmp == NULL) { 361 free(result); 362 return NULL; 363 } else { 364 result = tmp; 365 } 366 367 for (i = 0; i < mlist->method_count; i++) { 368 result[count] = mlist->method_list + i; 369 if (result[count] == NULL) continue; 370 count++; 371 } 372 mlist = class_nextMethodList(cls, &iterator); 373 } 374 375 if (outCount != NULL) { 376 *outCount = count; 377 } 378 return result; 379} 380 381static Ivar* 382compat_class_copyIvarList(Class cls, unsigned int* outCount) 383{ 384 Ivar* list; 385 int i; 386 struct objc_ivar_list* ivars = cls->ivars; 387 388 if (ivars) { 389 list = malloc(sizeof(Ivar) * ivars->ivar_count); 390 if (list == NULL) { 391 return NULL; 392 } 393 394 395 for (i = 0; i < ivars->ivar_count; i++) { 396 list[i] = ivars->ivar_list + i; 397 } 398 *outCount = ivars->ivar_count; 399 return list; 400 401 } else { 402 list = malloc(1); 403 if (list == NULL) { 404 return NULL; 405 } 406 407 *outCount = 0; 408 return list; 409 } 410 411} 412 413static Protocol** 414compat_class_copyProtocolList(Class cls, unsigned int* outCount) 415{ 416 Protocol** list; 417 unsigned int count = 0; 418 struct objc_protocol_list *protocol_list; 419 420 protocol_list = cls->protocols; 421 list = malloc(0); 422 423 while (protocol_list != NULL) { 424 list = realloc(list, (count + protocol_list->count)*sizeof(Protocol*)); 425 if (list == NULL) { 426 /* Whoops, memory leak */ 427 *outCount = 0; 428 return NULL; 429 } 430 memcpy(list + count, protocol_list->list, protocol_list->count*sizeof(Protocol*)); 431 count += protocol_list->count; 432 protocol_list = protocol_list->next; 433 } 434 435 *outCount = count; 436 return list; 437} 438 439 440static const char* 441compat_class_getName(Class cls) 442{ 443 return cls->name; 444} 445 446static Class 447compat_class_getSuperclass(Class cls) 448{ 449 return cls->super_class; 450} 451 452static BOOL 453compat_class_addMethod(Class cls, SEL name, IMP imp, const char* types) 454{ 455 struct objc_method_list* methodsToAdd; 456 struct objc_method* objcMethod; 457 458 methodsToAdd = malloc(sizeof(struct objc_method_list) + 459 2*sizeof(struct objc_method)); 460 methodsToAdd->method_count = 1; 461 methodsToAdd->obsolete = NULL; 462 463 objcMethod = methodsToAdd->method_list; 464 objcMethod->method_name = name; 465 objcMethod->method_imp = imp; 466 objcMethod->method_types = (char*)types; 467 468 class_addMethods(cls, methodsToAdd); 469 return YES; /* Have to return something ... */ 470} 471 472static BOOL 473compat_preclass_addMethod(Class cls, SEL name, IMP imp, const char* types) 474{ 475 /* Resize in-place, this is only valid during class construction. */ 476 struct objc_method_list* new_list; 477 struct objc_method* objcMethod; 478 479 new_list = realloc(cls->methodLists[0], 480 sizeof(struct objc_method_list) + 481 (sizeof(struct objc_method 482 )*(cls->methodLists[0]->method_count+1))); 483 if (new_list == NULL) { 484 return NO; 485 } 486 cls->methodLists[0] = new_list; 487 objcMethod = new_list->method_list + (new_list->method_count)++; 488 489 objcMethod->method_name = name; 490 objcMethod->method_imp = imp; 491 objcMethod->method_types = strdup(types); 492 if (objcMethod == NULL) { 493 new_list->method_count--; 494 return NO; 495 } 496 497 return YES; 498} 499 500static BOOL 501compat_preclass_addIvar( 502 Class cls, 503 const char* name, 504 size_t size, 505 uint8_t align, const char* types) 506{ 507 /* Update the class structure, only valid during class construction */ 508 struct objc_ivar_list* new_ivars; 509 struct objc_ivar* ivar; 510 511 if (cls->ivars) { 512 new_ivars = realloc(cls->ivars, 513 sizeof(struct objc_ivar_list) + 514 ((cls->ivars->ivar_count+1) * sizeof(struct objc_ivar))); 515 } else { 516 new_ivars = malloc( 517 sizeof(struct objc_ivar_list) + 518 sizeof(struct objc_ivar)); 519 new_ivars->ivar_count = 0; 520 } 521 if (new_ivars == NULL) { 522 return NO; 523 } 524 cls->ivars = new_ivars; 525 ivar = new_ivars->ivar_list + new_ivars->ivar_count; 526 ivar->ivar_name = strdup(name); 527 if (ivar->ivar_name == NULL) { 528 return NO; 529 } 530 531 ivar->ivar_type = strdup(types); 532 if (ivar->ivar_type == NULL) { 533 free(ivar->ivar_name); 534 return NO; 535 } 536 537 ivar->ivar_offset = cls->instance_size; 538 if (ivar->ivar_offset % align) { 539 ivar->ivar_offset += align - (ivar->ivar_offset % align); 540 } 541 542 new_ivars->ivar_count ++; 543 cls->instance_size = ivar->ivar_offset + size; 544 return YES; 545} 546 547static BOOL 548compat_preclass_addProtocol(Class cls, Protocol* protocol) 549{ 550 struct objc_protocol_list* protocols; 551 552 if (cls->protocols) { 553 protocols = realloc(cls->protocols, 554 sizeof(struct objc_protocol_list) + 555 (sizeof(Protocol*)*(cls->protocols->count+1))); 556 } else { 557 protocols = malloc(sizeof(struct objc_protocol_list) 558 + sizeof(Protocol*)); 559 protocols->count = 0; 560 protocols->next = NULL; 561 } 562 if (protocols == NULL) { 563 return NO; 564 } 565 cls->protocols = protocols; 566 protocols->list[protocols->count] = protocol; 567 protocols->count++; 568 return YES; 569} 570 571static SEL 572compat_method_getName(Method m) 573{ 574 return m->method_name; 575} 576 577static IMP 578compat_method_getImplementation(Method m) 579{ 580 return m->method_imp; 581} 582 583static IMP 584compat_method_setImplementation(Method m, IMP imp) 585{ 586 IMP result = m->method_imp; 587 m->method_imp = imp; 588 return result; 589} 590 591static const char * 592compat_method_getTypeEncoding(Method m) 593{ 594 return m->method_types; 595} 596 597static BOOL 598compat_sel_isEqual(SEL lhs, SEL rhs) 599{ 600 return lhs == rhs; 601} 602 603static const char* 604compat_ivar_getName(Ivar var) 605{ 606 return var->ivar_name; 607} 608 609static const char* 610compat_ivar_getTypeEncoding(Ivar var) 611{ 612 return var->ivar_type; 613} 614 615static ptrdiff_t 616compat_ivar_getOffset(Ivar var) 617{ 618 return var->ivar_offset; 619} 620 621 622#ifndef NO_OBJC2_RUNTIME 623static BOOL 624objc20_class_addMethodList(Class cls, 625 struct PyObjC_method* list, unsigned int count) 626{ 627 unsigned int i; 628 BOOL r; 629 Method m; 630 631 for (i = 0; i < count; i++) { 632 r = class_addMethod(cls, 633 list[i].name, list[i].imp, list[i].type); 634 if (!r) { 635 m = class_getInstanceMethod(cls, list[i].name); 636 if (m != NULL) { 637 method_setImplementation(m, list[i].imp); 638 } else { 639 return NO; 640 } 641 } 642 } 643 return YES; 644} 645#endif 646 647static BOOL 648compat_class_isMetaClass(Class cls) 649{ 650 return CLS_GETINFO(cls, CLS_META) == CLS_META; 651} 652 653static BOOL 654compat_class_addMethodList(Class cls, 655 struct PyObjC_method* list, unsigned int count) 656{ 657 unsigned int i; 658 struct objc_method_list* method_list; 659 660 method_list = malloc( 661 sizeof(struct objc_method_list) + 662 ((count+1) * sizeof(struct objc_method))); 663 if (method_list == NULL) { 664 return NO; 665 } 666 memset(method_list, 0, 667 sizeof(struct objc_method_list) + 668 ((count+1) * sizeof(struct objc_method))); 669 670 method_list->method_count = 0; 671 method_list->obsolete = 0; 672 673 for (i = 0; i < count; i++) { 674 method_list->method_list[i].method_name = list[i].name; 675 method_list->method_list[i].method_types = (char*)list[i].type; 676 method_list->method_list[i].method_imp = list[i].imp; 677 } 678 method_list->method_count = count; 679 class_addMethods(cls, method_list); 680 return YES; 681} 682 683static BOOL 684compat_protocol_conformsToProtocol(Protocol *proto, Protocol *other) 685{ 686 return [proto conformsTo:other]; 687} 688 689static const char * 690compat_protocol_getName(Protocol *p) 691{ 692 return [p name]; 693} 694 695static struct objc_method_description * 696compat_protocol_copyMethodDescriptionList(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount) 697{ 698 if (!isRequiredMethod) { 699 *outCount = 0; 700 return NULL; 701 } 702 703 struct objc_method_description_list* list; 704 705 if (isInstanceMethod) { 706 list = ((ProtocolTemplate*)p)->instance_methods; 707 } else { 708 list = ((ProtocolTemplate*)p)->class_methods; 709 } 710 711 if (list == NULL || list->count == 0) { 712 *outCount = 0; 713 return NULL; 714 } 715 716 *outCount = list->count; 717 struct objc_method_description* result; 718 719 result = malloc(sizeof(struct objc_method_description) * list->count); 720 if (result == NULL) { 721 return NULL; 722 } 723 724 int i; 725 *outCount = 0; 726 for (i = 0; i < list->count; i++) { 727 if (list->list[i].name == NULL) continue; 728 result[*outCount].name = list->list[i].name; 729 result[*outCount].types = list->list[i].types; 730 (*outCount)++; 731 } 732 return result; 733} 734 735static Protocol ** 736compat_protocol_copyProtocolList(Protocol *proto, unsigned int *outCount) 737{ 738 struct objc_protocol_list* list = 739 ((ProtocolTemplate*)proto)->protocol_list; 740 741 *outCount = 0; 742 743 struct objc_protocol_list* cur; 744 for (cur = list; cur != NULL; cur = cur->next) { 745 *outCount += cur->count; 746 } 747 748 Protocol** result = (Protocol**)malloc(sizeof(Protocol*) * *outCount); 749 if (result == NULL) { 750 return NULL; 751 } 752 753 unsigned curIdx = 0; 754 for (cur = list; cur != NULL; cur = cur->next) { 755 int i; 756 for (i = 0; i < cur->count; i++) { 757 if (cur->list[i] != NULL) { 758 result[curIdx++] = cur->list[i]; 759 } else { 760 *outCount--; 761 } 762 } 763 } 764 return result; 765} 766 767static struct objc_method_description 768compat_protocol_getMethodDescription(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod) 769{ 770static struct objc_method_description empty_description = { NULL, NULL }; 771 if (!isRequiredMethod) { 772 return empty_description; 773 } 774 775 struct objc_method_description* result; 776 777 if (isInstanceMethod) { 778 result = [p descriptionForInstanceMethod: aSel]; 779 } else { 780 result = [p descriptionForClassMethod: aSel]; 781 } 782 783 if (result == NULL) { 784 return empty_description; 785 } else { 786 return *result; 787 } 788} 789 790static id 791compat_object_getIvar(id obj, Ivar ivar) 792{ 793 return *(id*)(((char*)obj) + ivar->ivar_offset); 794} 795static void 796compat_object_setIvar(id obj, Ivar ivar, id value) 797{ 798 *(id*)(((char*)obj) + ivar->ivar_offset) = value; 799} 800 801/* Dispatch table */ 802BOOL (*PyObjC_protocol_conformsToProtocol)(Protocol *proto, Protocol *other) = NULL; 803const char *(*PyObjC_protocol_getName)(Protocol *p) = NULL; 804struct objc_method_description *(*PyObjC_protocol_copyMethodDescriptionList)(Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount) = NULL; 805Protocol **(*PyObjC_protocol_copyProtocolList)(Protocol *proto, unsigned int *outCount) = NULL; 806struct objc_method_description (*PyObjC_protocol_getMethodDescription)(Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod) = NULL; 807 808id (*PyObjC_object_getIvar)(id obj, Ivar ivar) = NULL; 809void (*PyObjC_object_setIvar)(id obj, Ivar ivar, id value) = NULL; 810 811 812 813Class (*PyObjC_objc_allocateClassPair)(Class, const char*, size_t) = NULL; 814void (*PyObjC_objc_registerClassPair)(Class) = NULL; 815void (*PyObjC_objc_disposeClassPair)(Class) = NULL; 816Protocol** (*PyObjC_objc_copyProtocolList)(unsigned int*) = NULL; 817Protocol* (*PyObjC_objc_getProtocol)(const char* name) = NULL; 818 819BOOL (*PyObjC_preclass_addMethod)(Class, SEL, IMP, const char*) = NULL; 820BOOL (*PyObjC_preclass_addIvar)(Class cls, 821 const char *name, size_t size, uint8_t alignment, 822 const char *types) = NULL; 823BOOL (*PyObjC_preclass_addProtocol)(Class cls, Protocol *protocol) = NULL; 824 825 826Class (*PyObjC_object_getClass)(id obj) = NULL; 827Class (*PyObjC_object_setClass)(id obj, Class cls) = NULL; 828const char* (*PyObjC_object_getClassName)(id obj) = NULL; 829 830Method* (*PyObjC_class_copyMethodList)(Class, unsigned int*) = NULL; 831const char* (*PyObjC_class_getName)(Class) = NULL; 832Class (*PyObjC_class_getSuperclass)(Class) = NULL; 833BOOL (*PyObjC_class_addMethod)(Class, SEL, IMP, const char*) = NULL; 834BOOL (*PyObjC_class_addMethodList)(Class, 835 struct PyObjC_method*, unsigned int) = NULL; 836Ivar* (*PyObjC_class_copyIvarList)(Class, unsigned int*) = NULL; 837Protocol** (*PyObjC_class_copyProtocolList)(Class, unsigned int*) = NULL; 838BOOL (*PyObjC_class_isMetaClass)(Class) = NULL; 839 840SEL (*PyObjC_method_getName)(Method m) = NULL; 841IMP (*PyObjC_method_getImplementation)(Method m) = NULL; 842IMP (*PyObjC_method_setImplementation)(Method m, IMP imp) = NULL; 843const char *(*PyObjC_method_getTypeEncoding)(Method m) = NULL; 844 845BOOL (*PyObjC_sel_isEqual)(SEL, SEL) = NULL; 846 847size_t (*PyObjC_methodlist_magic)(Class cls); 848 849const char* (*PyObjC_ivar_getName)(Ivar) = NULL; 850const char* (*PyObjC_ivar_getTypeEncoding)(Ivar) = NULL; 851ptrdiff_t (*PyObjC_ivar_getOffset)(Ivar) = NULL; 852 853 854 855 856#else 857 858 859BOOL PyObjC_class_isSubclassOf(Class child, Class parent) 860{ 861 if (parent == nil) return YES; 862 863 while (child != nil) { 864 if (child == parent) { 865 return YES; 866 } 867 child = class_getSuperclass(child); 868 } 869 return NO; 870} 871 872BOOL PyObjC_class_addMethodList(Class cls, 873 struct PyObjC_method* list, unsigned int count) 874{ 875 unsigned int i; 876 BOOL r; 877 Method m; 878 879 for (i = 0; i < count; i++) { 880 /* 881 * XXX: First try class_addMethod, if that fails assume this is 882 * because the method already exists in the class. 883 * Strictly speaking this isn't correct, but this is the best 884 * we can do through the 2.0 API (see 4809039 in RADAR) 885 */ 886 r = class_addMethod(cls, 887 list[i].name, list[i].imp, list[i].type); 888 if (!r) { 889 m = class_getInstanceMethod(cls, list[i].name); 890 if (m != NULL) { 891 method_setImplementation(m, list[i].imp); 892 } else { 893 return NO; 894 } 895 } 896 } 897 return YES; 898} 899 900size_t PyObjC_methodlist_magic(Class cls) 901{ 902 /* This is likely to be much slower than compat_methodlist_magic, 903 * but should works on the 64-bit runtime. Hopefully a callback will 904 * be added to the 2.0 runtime that will take away the need for this 905 * function... 906 */ 907 Method* methods; 908 unsigned int count; 909 910 methods = class_copyMethodList(cls, &count); 911 free(methods); 912 return (size_t)count; 913} 914 915#endif 916 917#if defined(__x86_64__) 918 919@implementation Protocol (NSOBjectCompat) 920- (id)self 921{ 922 return self; 923} 924@end 925 926#if PyObjC_BUILD_RELEASE < 1008 927@implementation Object (NSOBjectCompat) 928- (id)self 929{ 930 return self; 931} 932 933-doesNotRecognizeSelector:(SEL)sel 934{ 935 printf("--> %s\n", sel_getName(sel)); 936 abort(); 937} 938@end 939#endif 940 941 942#endif 943 944#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7) 945Protocol* (*PyObjC_objc_allocateProtocol)(const char *) = NULL; 946void (*PyObjC_objc_registerProtocol)(Protocol*) = NULL; 947void (*PyObjC_protocol_addMethodDescription)(Protocol*, SEL, const char*, BOOL, BOOL) = NULL; 948void (*PyObjC_protocol_addProtocol)(Protocol*, Protocol*) = NULL; 949 950#ifndef __LP64__ 951struct Protocol_struct { 952 Class _isa; 953 char *protocol_name; 954 struct objc_protocol_list *protocol_list; 955 struct objc_method_description_list *instance_methods, *class_methods; 956 struct objc_method_description_list *optional_instance_methods, *optional_class_methods; 957 void *instance_properties; 958}; 959 960static Protocol* compat_objc_allocateProtocol(const char *name) 961{ 962 struct Protocol_struct* result; 963 964 result = (struct Protocol_struct*)NSAllocateObject([Protocol class], 0, NULL); 965 if (result == NULL) { 966 return NULL; 967 } 968 result->protocol_name = strdup(name); 969 if (result->protocol_name == NULL) { 970 /* Leaking object */ 971 return NULL; 972 } 973 result->protocol_list = NULL; 974 result->instance_methods = NULL; 975 result->class_methods = NULL; 976 result->optional_instance_methods = NULL; 977 result->optional_class_methods = NULL; 978 result->instance_properties = NULL; 979 return (Protocol*)result; 980} 981 982static void compat_objc_registerProtocol(Protocol* proto __attribute__((__unused__))) 983{ 984 /* Don't know how to register a new protocol in classic 985 * runtime. Luckily we don't actually need this. 986 */ 987} 988 989static void compat_protocol_addMethodDescription(Protocol* proto, SEL sel, const char* types, BOOL required, BOOL instance_method) 990{ 991 struct Protocol_struct* proto_struct = (struct Protocol_struct*)proto; 992 struct objc_method_description_list** plist; 993 994 if (!instance_method) { 995 if (required) { 996 plist = &(proto_struct->class_methods); 997 } else { 998 plist = &(proto_struct->optional_class_methods); 999 } 1000 } else { 1001 if (required) { 1002 plist = &(proto_struct->instance_methods); 1003 } else { 1004 plist = &(proto_struct->optional_instance_methods); 1005 } 1006 } 1007 1008 if (*plist == NULL) { 1009 *plist = malloc(sizeof(struct objc_method_description_list) + (2*sizeof(struct objc_method_description))); 1010 if (*plist == NULL) { 1011 /* Cannot report errors */ 1012 abort(); 1013 } 1014 (*plist)->count = 0; 1015 } else { 1016 *plist = realloc(*plist, sizeof(struct objc_method_description_list) + (2+((*plist)->count)*sizeof(struct objc_method_description))); 1017 if (*plist == NULL) { 1018 /* Cannot report errors */ 1019 abort(); 1020 } 1021 } 1022 (*plist)->list[(*plist)->count].name = sel; 1023 (*plist)->list[(*plist)->count].types = strdup(types); 1024 if ((*plist)->list[(*plist)->count].types == NULL) { 1025 /* Cannot report errors */ 1026 abort(); 1027 } 1028 (*plist)->count++; 1029 1030 (*plist)->list[(*plist)->count].name = NULL; 1031 (*plist)->list[(*plist)->count].types = NULL; 1032} 1033 1034static void compat_protocol_addProtocol(Protocol* proto, Protocol* newProto) 1035{ 1036 struct Protocol_struct* proto_struct = (struct Protocol_struct*)proto; 1037 1038 if (proto_struct->protocol_list == NULL) { 1039 proto_struct->protocol_list = malloc(sizeof(struct objc_protocol_list) + 2*sizeof(Protocol*)); 1040 if (proto_struct->protocol_list == NULL) { 1041 /* Cannot report an error! */ 1042 abort(); 1043 } 1044 proto_struct->protocol_list->next = NULL; 1045 proto_struct->protocol_list->count = 0; 1046 } else { 1047 proto_struct->protocol_list = realloc(proto_struct->protocol_list, 1048 sizeof(struct objc_protocol_list) + (2+proto_struct->protocol_list->count)*sizeof(Protocol*)); 1049 if (proto_struct->protocol_list == NULL) { 1050 /* Cannot report an error! */ 1051 abort(); 1052 } 1053 } 1054 proto_struct->protocol_list->list[proto_struct->protocol_list->count] = newProto; 1055 proto_struct->protocol_list->list[proto_struct->protocol_list->count+1] = NULL; 1056 proto_struct->protocol_list->count++; 1057} 1058 1059#endif 1060#endif 1061 1062void PyObjC_SetupRuntimeCompat(void) 1063{ 1064#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(__OBJC2__) 1065 1066#ifdef NO_OBJC2_RUNTIME 1067 /* 1068 * Don't use ObjC 2.0 runtime (compiling on 10.4 or earlier), always 1069 * use the compat implementation. 1070 */ 1071 PyObjC_class_addMethodList = compat_class_addMethodList; 1072 PyObjC_methodlist_magic = compat_methodlist_magic; 1073 PyObjC_objc_disposeClassPair = compat_objc_disposeClassPair; 1074 PyObjC_preclass_addMethod = compat_preclass_addMethod; 1075 PyObjC_preclass_addIvar = compat_preclass_addIvar; 1076 PyObjC_preclass_addProtocol = compat_preclass_addProtocol; 1077 1078# define SETUP(funcname) \ 1079 PyObjC_##funcname = compat_##funcname 1080 1081#else 1082 if (class_addMethod) { 1083 PyObjC_class_addMethodList = objc20_class_addMethodList; 1084 PyObjC_preclass_addMethod = class_addMethod; 1085 PyObjC_preclass_addIvar = class_addIvar; 1086 PyObjC_preclass_addProtocol= class_addProtocol; 1087 } else { 1088 PyObjC_class_addMethodList = compat_class_addMethodList; 1089 PyObjC_preclass_addMethod = compat_preclass_addMethod; 1090 PyObjC_preclass_addIvar = compat_preclass_addIvar; 1091 PyObjC_preclass_addProtocol= compat_preclass_addProtocol; 1092 } 1093 1094 1095 if (class_copyMethodList) { 1096 PyObjC_methodlist_magic = objc20_methodlist_magic; 1097 } else { 1098 PyObjC_methodlist_magic = compat_methodlist_magic; 1099 } 1100 1101# define SETUP(funcname) \ 1102 if ((funcname) == NULL) { \ 1103 PyObjC_##funcname = compat_##funcname; \ 1104 } else { \ 1105 PyObjC_##funcname = funcname; \ 1106 } 1107#endif 1108 SETUP(protocol_getName); 1109 SETUP(protocol_conformsToProtocol); 1110 SETUP(protocol_copyMethodDescriptionList); 1111 SETUP(protocol_copyProtocolList); 1112 SETUP(protocol_getMethodDescription); 1113 1114 SETUP(objc_allocateClassPair); 1115 SETUP(objc_registerClassPair); 1116 SETUP(objc_disposeClassPair); 1117 SETUP(objc_copyProtocolList); 1118 SETUP(objc_getProtocol); 1119 1120 SETUP(object_getClass); 1121 SETUP(object_setClass); 1122 SETUP(object_getClassName); 1123 SETUP(object_getIvar); 1124 SETUP(object_setIvar); 1125 1126 SETUP(class_getSuperclass); 1127 SETUP(class_addMethod); 1128 SETUP(class_copyIvarList); 1129 SETUP(class_copyProtocolList); 1130 SETUP(class_copyMethodList); 1131 SETUP(class_getName); 1132 SETUP(class_isMetaClass); 1133 1134 SETUP(method_getName); 1135 SETUP(method_getTypeEncoding); 1136 SETUP(method_getImplementation); 1137 SETUP(method_setImplementation); 1138 1139 SETUP(sel_isEqual); 1140 1141 SETUP(ivar_getName); 1142 SETUP(ivar_getTypeEncoding); 1143 SETUP(ivar_getOffset); 1144#endif /* MIN_REQUIRED < 10.5 && !OBJC2 */ 1145 1146#ifdef SETUP 1147#undef SETUP 1148#endif 1149 1150 1151#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7) 1152 /* Compat definitions for protocol creation 1153 * 1154 * - Runtime APIs were introduced in OSX 10.7 1155 * - Compat functions can only be implemented for 32-bit runtime 1156 */ 1157 1158#if PyObjC_BUILD_RELEASE < 1007 1159 1160#ifndef __LP64__ 1161 PyObjC_objc_allocateProtocol = compat_objc_allocateProtocol; 1162 PyObjC_objc_registerProtocol = compat_objc_registerProtocol; 1163 PyObjC_protocol_addMethodDescription = compat_protocol_addMethodDescription; 1164 PyObjC_protocol_addProtocol = compat_protocol_addProtocol; 1165#endif 1166 1167 1168#elif defined(__LP64__) 1169 PyObjC_objc_allocateProtocol = objc_allocateProtocol; 1170 PyObjC_objc_registerProtocol = objc_registerProtocol; 1171 PyObjC_protocol_addMethodDescription = protocol_addMethodDescription; 1172 PyObjC_protocol_addProtocol = protocol_addProtocol; 1173 1174#else 1175# define SETUP(funcname) \ 1176 if ((funcname) == NULL) { \ 1177 PyObjC_##funcname = compat_##funcname; \ 1178 } else { \ 1179 PyObjC_##funcname = funcname; \ 1180 } 1181 SETUP(objc_allocateProtocol); 1182 SETUP(objc_registerProtocol); 1183 SETUP(protocol_addMethodDescription); 1184 SETUP(protocol_addProtocol); 1185#endif 1186 1187#endif 1188 1189#undef SETUP 1190} 1191