1/* 2 * Copyright (c) 2006-2008, The RubyCocoa Project. 3 * Copyright (c) 2001-2006, FUJIMOTO Hisakuni. 4 * All Rights Reserved. 5 * 6 * RubyCocoa is free software, covered under either the Ruby's license or the 7 * LGPL. See the COPYRIGHT file for more information. 8 */ 9 10#import <objc/objc-class.h> 11#import <Foundation/Foundation.h> 12#import "ocdata_conv.h" 13#import "RBObject.h" 14#import "mdl_osxobjc.h" 15#import <CoreFoundation/CFString.h> // CFStringEncoding 16#import "st.h" 17#import "BridgeSupport.h" 18#import "internal_macros.h" 19 20#define CACHE_LOCKING 0 21 22#define DATACONV_LOG(fmt, args...) DLOG("DATACNV", fmt, ##args) 23 24static struct st_table *rb2ocCache; 25static struct st_table *oc2rbCache; 26 27static VALUE _ocid_to_rbobj (VALUE context_obj, id ocid, BOOL is_class); 28 29#if CACHE_LOCKING 30static pthread_mutex_t rb2ocCacheLock; 31static pthread_mutex_t oc2rbCacheLock; 32# define CACHE_LOCK(x) (pthread_mutex_lock(x)) 33# define CACHE_UNLOCK(x) (pthread_mutex_unlock(x)) 34#else 35# define CACHE_LOCK(x) 36# define CACHE_UNLOCK(x) 37#endif 38 39#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 40// On MacOS X 10.4 or earlier, +signatureWithObjCTypes: is a SPI 41@interface NSMethodSignature (WarningKiller) 42+ (id) signatureWithObjCTypes:(const char*)types; 43@end 44#endif 45 46@interface RBObject (Private) 47- (id)_initWithRubyObject: (VALUE)rbobj retains: (BOOL) flag; 48@end 49 50void init_rb2oc_cache(void) 51{ 52 rb2ocCache = st_init_numtable(); 53#if CACHE_LOCKING 54 pthread_mutex_init(&rb2ocCacheLock, NULL); 55#endif 56} 57 58void init_oc2rb_cache(void) 59{ 60 oc2rbCache = st_init_numtable(); 61#if CACHE_LOCKING 62 pthread_mutex_init(&oc2rbCacheLock, NULL); 63#endif 64} 65 66void remove_from_oc2rb_cache(id ocid) 67{ 68 CACHE_LOCK(&oc2rbCacheLock); 69 st_delete(oc2rbCache, (st_data_t *)&ocid, NULL); 70 CACHE_UNLOCK(&oc2rbCacheLock); 71} 72 73void remove_from_rb2oc_cache(VALUE rbobj) 74{ 75 CACHE_LOCK(&rb2ocCacheLock); 76 st_delete(rb2ocCache, (st_data_t *)&rbobj, NULL); 77 CACHE_UNLOCK(&rb2ocCacheLock); 78} 79 80static BOOL 81convert_cary(VALUE *result, void *ocdata, char *octype_str, BOOL to_ruby) 82{ 83 long i, count, size, pos; 84 VALUE ary; 85 BOOL ok; 86 87 octype_str++; 88 89 // first, get the number of entries 90 count = 0; 91 while (isdigit(*octype_str)) { 92 count *= 10; 93 count += (long)(*octype_str - '0'); 94 octype_str++; 95 } 96 97 // second, remove the trailing ']' 98 pos = strlen(octype_str) - 1; 99 octype_str[pos] = '\0'; /* ((char*)octype_str)[pos] = '\0'; */ 100 size = ocdata_size(octype_str); 101 102 // third, do the conversion 103 if (to_ruby) { 104 ary = rb_ary_new(); 105 for (i = 0; i < count; i++) { 106 VALUE entry; 107 void *p; 108 109 p = *(void **)ocdata + (i * size); 110 if (!ocdata_to_rbobj(Qnil, octype_str, p, &entry, NO)) { 111 *result = Qnil; 112 ok = NO; 113 goto bail; 114 } 115 rb_ary_push(ary, entry); 116 } 117 118 *result = ary; 119 ok = YES; 120 } 121 else { 122 volatile VALUE ary; 123 124 ary = *result; 125 126 Check_Type(ary, T_ARRAY); 127 if (RARRAY(ary)->len > count) 128 rb_raise(rb_eArgError, 129 "Given Array expected with maximum %d elements, but got %d", 130 count, RARRAY(ary)->len); 131 132 for (i = 0; i < RARRAY(ary)->len; i++) { 133 VALUE val; 134 void *p; 135 136 val = RARRAY(ary)->ptr[i]; 137 p = ocdata + (i * size); 138 if (!rbobj_to_ocdata(val, octype_str, p, NO)) { 139 ok = NO; 140 goto bail; 141 } 142 } 143 ok = YES; 144 } 145 146bail: 147 // put back the trailing ']' 148 octype_str[pos] = ']'; /* ((char*)octype_str)[pos] = ']'; */ 149 return ok; 150} 151 152static BOOL 153rbobj_to_cary (VALUE obj, void *data, const char *octype_str) 154{ 155 return convert_cary(&obj, data, (char *)octype_str, NO); 156} 157 158static BOOL 159cary_to_rbary (void *data, const char *octype_str, VALUE *result) 160{ 161 return convert_cary(result, data, (char *)octype_str, YES); 162} 163 164size_t ocdata_alloc_size(const char* octype_str) 165{ 166#if BYTE_ORDER == BIG_ENDIAN 167 size_t size = ocdata_size(octype_str); 168 if (size == 0) return 0; 169 return size < sizeof(void*) ? sizeof(void*) : size; 170#else 171 return ocdata_size(octype_str); 172#endif 173} 174 175size_t 176ocdata_size(const char* octype_str) 177{ 178 size_t result; 179 struct bsBoxed *bs_boxed; 180 181 if (*octype_str == _C_CONST) 182 octype_str++; 183 184 bs_boxed = find_bs_boxed_by_encoding(octype_str); 185 if (bs_boxed != NULL) 186 return bs_boxed_size(bs_boxed); 187 188 if (find_bs_cf_type_by_encoding(octype_str) != NULL) 189 octype_str = "@"; 190 191 result = 0; 192 193 switch (*octype_str) { 194 case _C_ID: 195 case _C_CLASS: 196 result = sizeof(id); 197 break; 198 199 case _C_SEL: 200 result = sizeof(SEL); 201 break; 202 203 case _C_CHR: 204 case _C_UCHR: 205 result = sizeof(char); 206 break; 207 208 case _C_SHT: 209 case _C_USHT: 210 result = sizeof(short); 211 break; 212 213 case _C_INT: 214 case _C_UINT: 215 result = sizeof(int); 216 break; 217 218 case _C_LNG: 219 case _C_ULNG: 220 result = sizeof(long); 221 break; 222 223#if HAVE_LONG_LONG 224 case _C_LNG_LNG: 225 result = sizeof(long long); 226 break; 227 228 case _C_ULNG_LNG: 229 result = sizeof(unsigned long long); 230 break; 231#endif 232 233 case _C_FLT: 234 result = sizeof(float); 235 break; 236 237 case _C_DBL: 238 result = sizeof(double); 239 break; 240 241 case _C_CHARPTR: 242 result = sizeof(char*); 243 break; 244 245 case _C_VOID: 246 result = 0; 247 break; 248 249 case _C_BOOL: 250 result = sizeof(BOOL); 251 break; 252 253 case _C_PTR: 254 result = sizeof(void*); 255 break; 256 257 case _C_BFLD: 258 if (octype_str != NULL) { 259 char *type; 260 long lng; 261 262 type = (char *)octype_str; 263 lng = strtol(type, &type, 10); 264 265 // while next type is a bit field 266 while (*type == _C_BFLD) { 267 long next_lng; 268 269 // skip over _C_BFLD 270 type++; 271 272 // get next bit field length 273 next_lng = strtol(type, &type, 10); 274 275 // if spans next word then align to next word 276 if ((lng & ~31) != ((lng + next_lng) & ~31)) 277 lng = (lng + 31) & ~31; 278 279 // increment running length 280 lng += next_lng; 281 } 282 result = (lng + 7) / 8; 283 } 284 break; 285 286 default: 287 @try { 288 NSGetSizeAndAlignment(octype_str, 289#if __LP64__ 290 (unsigned long *)&result, 291#else 292 (unsigned int *)&result, 293#endif 294 NULL); 295 } 296 @catch (id exception) { 297 rb_raise(rb_eRuntimeError, "Cannot compute size of type `%s' : %s", 298 octype_str, [[exception description] UTF8String]); 299 } 300 break; 301 } 302 303 return result; 304} 305 306void * 307ocdata_malloc(const char* octype_str) 308{ 309 size_t s = ocdata_alloc_size(octype_str); 310 if (s == 0) return NULL; 311 return malloc(s); 312} 313 314BOOL 315ocdata_to_rbobj (VALUE context_obj, const char *octype_str, const void *ocdata, VALUE *result, BOOL from_libffi) 316{ 317 BOOL f_success = YES; 318 volatile VALUE rbval = Qnil; 319 struct bsBoxed *bs_boxed; 320 321#if BYTE_ORDER == BIG_ENDIAN 322 // libffi casts all types as a void pointer, which is problematic on PPC for types sized less than a void pointer (char, uchar, short, ushort, ...), as we have to shift the bytes to get the real value. 323 if (from_libffi) { 324 int delta = sizeof(void *) - ocdata_size(octype_str); 325 if (delta > 0) 326 ocdata += delta; 327 } 328#endif 329 330 octype_str = encoding_skip_qualifiers(octype_str); 331 332 bs_boxed = find_bs_boxed_by_encoding(octype_str); 333 if (bs_boxed != NULL) { 334 *result = rb_bs_boxed_new_from_ocdata(bs_boxed, (void *)ocdata); 335 return YES; 336 } 337 338 if (find_bs_cf_type_by_encoding(octype_str) != NULL) 339 octype_str = "@"; 340 341 switch (*octype_str) { 342 case _C_ID: 343 case _C_CLASS: 344 rbval = _ocid_to_rbobj(context_obj, *(id*)ocdata, *octype_str == _C_CLASS); 345 break; 346 347 case _C_PTR: 348 if (is_boxed_ptr(octype_str, &bs_boxed)) { 349 rbval = rb_bs_boxed_ptr_new_from_ocdata(bs_boxed, *(void **)ocdata); 350 } 351 else { 352 void *cptr = *(void**)ocdata; 353 rbval = cptr == NULL ? Qnil : objcptr_s_new_with_cptr (cptr, octype_str); 354 } 355 break; 356 357 case _C_ARY_B: 358 f_success = cary_to_rbary(*(void **)ocdata, octype_str, (VALUE*)&rbval); 359 break; 360 361 case _C_BOOL: 362 rbval = bool_to_rbobj(*(BOOL*)ocdata); 363 break; 364 365 case _C_SEL: 366 rbval = rb_str_new2(sel_getName(*(SEL*)ocdata)); 367 break; 368 369 case _C_CHR: 370 rbval = INT2NUM(*(char*)ocdata); 371 break; 372 373 case _C_UCHR: 374 rbval = UINT2NUM(*(unsigned char*)ocdata); 375 break; 376 377 case _C_SHT: 378 rbval = INT2NUM(*(short*)ocdata); 379 break; 380 381 case _C_USHT: 382 rbval = UINT2NUM(*(unsigned short*)ocdata); 383 break; 384 385 case _C_INT: 386 rbval = INT2NUM(*(int*)ocdata); 387 break; 388 389 case _C_UINT: 390 rbval = UINT2NUM(*(unsigned int*)ocdata); 391 break; 392 393 case _C_LNG: 394 rbval = INT2NUM(*(long*)ocdata); 395 break; 396 397 case _C_ULNG: 398 rbval = UINT2NUM(*(unsigned long*)ocdata); 399 break; 400 401#if HAVE_LONG_LONG 402 case _C_LNG_LNG: 403 rbval = LL2NUM(*(long long*)ocdata); 404 break; 405 406 case _C_ULNG_LNG: 407 rbval = ULL2NUM(*(unsigned long long*)ocdata); 408 break; 409#endif 410 411 case _C_FLT: 412 rbval = rb_float_new((double)(*(float*)ocdata)); 413 break; 414 415 case _C_DBL: 416 rbval = rb_float_new(*(double*)ocdata); 417 break; 418 419 case _C_CHARPTR: 420 if (*(void **)ocdata == NULL) 421 rbval = Qnil; 422 else 423 rbval = rb_str_new2(*(char **)ocdata); 424 break; 425 426 default: 427 f_success = NO; 428 rbval = Qnil; 429 break; 430 } 431 432 if (f_success) 433 *result = rbval; 434 435 return f_success; 436} 437 438static BOOL 439rbary_to_nsary (VALUE rbary, id* nsary) 440{ 441 long i, len; 442 id *objects; 443 444 len = RARRAY(rbary)->len; 445 objects = (id *)alloca(sizeof(id) * len); 446 ASSERT_ALLOC(objects); 447 448 for (i = 0; i < len; i++) 449 if (!rbobj_to_nsobj(RARRAY(rbary)->ptr[i], &objects[i])) 450 return NO; 451 452 *nsary = [[[NSMutableArray alloc] initWithObjects:objects count:len] autorelease]; 453 return YES; 454} 455 456// FIXME: we should use the CoreFoundation API for x_to_y functions 457// (should be faster than Foundation) 458 459static BOOL 460rbhash_to_nsdic (VALUE rbhash, id* nsdic) 461{ 462 volatile VALUE ary_keys; 463 VALUE* keys; 464 VALUE val; 465 long i, len; 466 id *nskeys, *nsvals; 467 468 ary_keys = rb_funcall(rbhash, rb_intern("keys"), 0); 469 len = RARRAY(ary_keys)->len; 470 keys = RARRAY(ary_keys)->ptr; 471 472 nskeys = (id *)alloca(sizeof(id) * len); 473 ASSERT_ALLOC(nskeys); 474 nsvals = (id *)alloca(sizeof(id) * len); 475 ASSERT_ALLOC(nsvals); 476 477 for (i = 0; i < len; i++) { 478 if (!rbobj_to_nsobj(keys[i], &nskeys[i])) 479 return NO; 480 val = rb_hash_aref(rbhash, keys[i]); 481 if (!rbobj_to_nsobj(val, &nsvals[i])) 482 return NO; 483 } 484 485 *nsdic = [[[NSMutableDictionary alloc] initWithObjects:nsvals forKeys:nskeys count:len] autorelease]; 486 return YES; 487} 488 489static BOOL 490rbbool_to_nsnum (VALUE rbval, id* nsval) 491{ 492 *nsval = [NSNumber numberWithBool:RTEST(rbval)]; 493 return YES; 494} 495 496static BOOL 497rbint_to_nsnum (VALUE rbval, id* nsval) 498{ 499#if HAVE_LONG_LONG 500 long long val; 501 val = NUM2LL(rbval); 502 *nsval = [NSNumber numberWithLongLong:val]; 503#else 504 long val; 505 val = NUM2LONG(rbval); 506 *nsval = [NSNumber numberWithLong:val]; 507#endif 508 return YES; 509} 510 511static BOOL 512rbfloat_to_nsnum (VALUE rbval, id* nsval) 513{ 514 double val; 515 val = NUM2DBL(rbval); 516 *nsval = [NSNumber numberWithDouble:val]; 517 return YES; 518} 519 520static BOOL 521rbtime_to_nsdate (VALUE rbval, id* nsval) 522{ 523 NSTimeInterval seconds; 524 seconds = NUM2LONG(rb_funcall(rbval, rb_intern("to_i"), 0)); 525 *nsval = [NSDate dateWithTimeIntervalSince1970:seconds]; 526 return [(*nsval) isKindOfClass: [NSDate class]]; 527} 528 529static BOOL 530rbobj_convert_to_nsobj (VALUE obj, id* nsobj) 531{ 532 switch (TYPE(obj)) { 533 case T_NIL: 534 *nsobj = nil; 535 return YES; 536 537 case T_STRING: 538 obj = rb_obj_as_string(obj); 539 *nsobj = rbstr_to_ocstr(obj); 540 return YES; 541 542 case T_SYMBOL: 543 obj = rb_obj_as_string(obj); 544 *nsobj = [NSString stringWithUTF8String: RSTRING(obj)->ptr]; 545 return YES; 546 547 case T_ARRAY: 548 return rbary_to_nsary(obj, nsobj); 549 550 case T_HASH: 551 return rbhash_to_nsdic(obj, nsobj); 552 553 case T_TRUE: 554 case T_FALSE: 555 return rbbool_to_nsnum(obj, nsobj); 556 557 case T_FIXNUM: 558 case T_BIGNUM: 559 return rbint_to_nsnum(obj, nsobj); 560 561 case T_FLOAT: 562 return rbfloat_to_nsnum(obj, nsobj); 563 564 default: 565 if (rb_obj_is_kind_of(obj, rb_cTime)) 566 return rbtime_to_nsdate(obj, nsobj); 567 568 *nsobj = [[[RBObject alloc] initWithRubyObject:obj] autorelease]; 569 return YES; 570 } 571 return YES; 572} 573 574BOOL 575rbobj_to_nsobj (VALUE obj, id* nsobj) 576{ 577 BOOL ok; 578 579 if (obj == Qnil) { 580 *nsobj = nil; 581 return YES; 582 } 583 584 // Cache new Objective-C object addresses in an internal table to 585 // avoid duplication. 586 // 587 // We are locking the access to the cache twice (lookup + insert) as 588 // rbobj_convert_to_nsobj is succeptible to call us again, to avoid 589 // a deadlock. 590 591 CACHE_LOCK(&rb2ocCacheLock); 592 ok = st_lookup(rb2ocCache, (st_data_t)obj, (st_data_t *)nsobj); 593 CACHE_UNLOCK(&rb2ocCacheLock); 594 595 if (!ok) { 596 *nsobj = rbobj_get_ocid(obj); 597 if (*nsobj != nil || rbobj_convert_to_nsobj(obj, nsobj)) { 598 BOOL magic_cookie; 599 if (*nsobj == nil) return YES; 600 601 magic_cookie = find_magic_cookie_const_by_value(*nsobj) != NULL; 602 if (magic_cookie || ([*nsobj isProxy] && [*nsobj isRBObject])) { 603 CACHE_LOCK(&rb2ocCacheLock); 604 // Check out that the hash is still empty for us, to avoid a race condition. 605 if (!st_lookup(rb2ocCache, (st_data_t)obj, (st_data_t *)nsobj)) 606 st_insert(rb2ocCache, (st_data_t)obj, (st_data_t)*nsobj); 607 CACHE_UNLOCK(&rb2ocCacheLock); 608 } 609 ok = YES; 610 } 611 } 612 613 return ok; 614} 615 616BOOL 617rbobj_to_bool (VALUE obj) 618{ 619 return RTEST(obj) ? YES : NO; 620} 621 622VALUE 623bool_to_rbobj (BOOL val) 624{ 625 return (val ? Qtrue : Qfalse); 626} 627 628VALUE 629sel_to_rbobj (SEL val) 630{ 631 VALUE rbobj; 632 633 // FIXME: this should be optimized 634 635 if (ocdata_to_rbobj(Qnil, ":", &val, &rbobj, NO)) { 636 rbobj = rb_obj_as_string(rbobj); 637 // str.tr!(':','_') 638 rb_funcall(rbobj, rb_intern("tr!"), 2, rb_str_new2(":"), rb_str_new2("_")); 639 // str.sub!(/_+$/,'') 640 rb_funcall(rbobj, rb_intern("sub!"), 2, rb_str_new2("_+$"), rb_str_new2("")); 641 } 642 else { 643 rbobj = Qnil; 644 } 645 return rbobj; 646} 647 648VALUE 649int_to_rbobj (int val) 650{ 651 return INT2NUM(val); 652} 653 654VALUE 655uint_to_rbobj (unsigned int val) 656{ 657 return UINT2NUM(val); 658} 659 660VALUE 661double_to_rbobj (double val) 662{ 663 return rb_float_new(val); 664} 665 666VALUE 667ocid_to_rbobj_cache_only (id ocid) 668{ 669 VALUE result; 670 BOOL ok; 671 672 CACHE_LOCK(&oc2rbCacheLock); 673 ok = st_lookup(oc2rbCache, (st_data_t)ocid, (st_data_t *)&result); 674 CACHE_UNLOCK(&oc2rbCacheLock); 675 676 return ok ? result : Qnil; 677} 678 679static VALUE 680_ocid_to_rbobj (VALUE context_obj, id ocid, BOOL is_class) 681{ 682 VALUE result; 683 BOOL ok, shouldCache; 684 struct bsConst * bs_const; 685 686 if (ocid == nil) 687 return Qnil; 688 689 // Cache new Ruby object addresses in an internal table to 690 // avoid duplication. 691 // 692 // We are locking the access to the cache twice (lookup + insert) as 693 // ocobj_s_new is succeptible to call us again, to avoid a deadlock. 694 695 bs_const = find_magic_cookie_const_by_value(ocid); 696 697 if (bs_const == NULL 698 && (is_class 699 || [ocid isProxy] 700 || find_bs_cf_type_by_type_id(CFGetTypeID(ocid)) != NULL)) { 701 // We don't cache CF-based objects because we don't have yet a reliable 702 // way to remove them from the cache. 703 ok = shouldCache = NO; 704 } 705 else { 706 CACHE_LOCK(&oc2rbCacheLock); 707 ok = st_lookup(oc2rbCache, (st_data_t)ocid, (st_data_t *)&result); 708 CACHE_UNLOCK(&oc2rbCacheLock); 709 shouldCache = context_obj != Qfalse; 710 } 711 712 if (!ok) { 713 if (bs_const != NULL) { 714 result = ocobj_s_new_with_class_name(ocid, bs_const->class_name); 715 } 716 else { 717 result = ocid_get_rbobj(ocid); 718 if (result == Qnil) 719 result = rbobj_get_ocid(context_obj) == ocid 720 ? context_obj : ocobj_s_new(ocid); 721 } 722 723 if (shouldCache) { 724 CACHE_LOCK(&oc2rbCacheLock); 725 // Check out that the hash is still empty for us, to avoid a race 726 // condition. 727 if (!st_lookup(oc2rbCache, (st_data_t)ocid, (st_data_t *)&result)) 728 st_insert(oc2rbCache, (st_data_t)ocid, (st_data_t)result); 729 CACHE_UNLOCK(&oc2rbCacheLock); 730 } 731 } 732 733 return result; 734} 735 736VALUE 737ocid_to_rbobj (VALUE context_obj, id ocid) 738{ 739 return _ocid_to_rbobj(context_obj, ocid, NO); 740} 741 742static SEL 743rbobj_to_cselstr (VALUE obj) 744{ 745 int i; 746 volatile VALUE str; 747 char *sel; 748 749 str = rb_obj_is_kind_of(obj, rb_cString) 750 ? obj : rb_obj_as_string(obj); 751 752 if (rb_ivar_defined(str, rb_intern("@__is_sel__")) == Qtrue) 753 return sel_registerName(RSTRING(str)->ptr); 754 755 sel = (char *)alloca(RSTRING(str)->len + 1); 756 sel[0] = RSTRING(str)->ptr[0]; 757 for (i = 1; i < RSTRING(str)->len; i++) { 758 char c = RSTRING(str)->ptr[i]; 759 if (c == '_') 760 c = ':'; 761 sel[i] = c; 762 } 763 sel[RSTRING(str)->len] = '\0'; 764 765 return sel_registerName(sel); 766} 767 768SEL 769rbobj_to_nssel (VALUE obj) 770{ 771 return NIL_P(obj) ? NULL : rbobj_to_cselstr(obj); 772} 773 774struct funcptr_closure_context { 775 char * rettype; 776 char ** argtypes; 777 unsigned argc; 778 VALUE block; 779}; 780 781static void 782funcptr_closure_handler (ffi_cif *cif, void *resp, void **args, void *userdata) 783{ 784 struct funcptr_closure_context *context; 785 volatile VALUE rb_args; 786 unsigned i; 787 VALUE retval; 788 789 context = (struct funcptr_closure_context *)userdata; 790 rb_args = rb_ary_new2(context->argc); 791 792 for (i = 0; i < context->argc; i++) { 793 VALUE arg; 794 795 if (!ocdata_to_rbobj(Qnil, context->argtypes[i], args[i], &arg, NO)) 796 rb_raise(rb_eRuntimeError, "Can't convert Objective-C argument #%d of octype '%s' to Ruby value", i, context->argtypes[i]); 797 798 DATACONV_LOG("converted arg #%d of type %s to Ruby value %p", i, context->argtypes[i], arg); 799 800 rb_ary_store(rb_args, i, arg); 801 } 802 803 DATACONV_LOG("calling Ruby block with %d args...", RARRAY(rb_args)->len); 804 retval = rb_funcall2(context->block, rb_intern("call"), RARRAY(rb_args)->len, RARRAY(rb_args)->ptr); 805 DATACONV_LOG("called Ruby block"); 806 807 if (*encoding_skip_to_first_type(context->rettype) != _C_VOID) { 808 if (!rbobj_to_ocdata(retval, context->rettype, resp, YES)) 809 rb_raise(rb_eRuntimeError, "Can't convert return Ruby value to Objective-C value of octype '%s'", context->rettype); 810 } 811} 812 813static BOOL 814rbobj_to_funcptr (VALUE obj, void **cptr, const char *octype_str) 815{ 816 unsigned argc; 817 unsigned i; 818 char * rettype; 819 char ** argtypes; 820 int block_arity; 821 struct funcptr_closure_context * context; 822 823 if (TYPE(obj) == T_NIL) { 824 *cptr = NULL; 825 return YES; 826 } 827 828 if (rb_obj_is_kind_of(obj, rb_cProc) == Qfalse) 829 return NO; 830 831 if (*octype_str != '?') 832 return NO; 833 octype_str++; 834 if (octype_str == NULL) 835 return NO; 836 837 decode_method_encoding(octype_str, nil, &argc, &rettype, &argtypes, NO); 838 839 block_arity = FIX2INT(rb_funcall(obj, rb_intern("arity"), 0)); 840 if (block_arity != argc) { 841 free(rettype); 842 if (argtypes != NULL) { 843 for (i = 0; i < argc; i++) 844 free(argtypes[i]); 845 free(argtypes); 846 } 847 // Should we return NO there? Probably better to raise an exception directly. 848 rb_raise(rb_eArgError, "Given Proc object has an invalid number of arguments (expected %d, got %d)", 849 argc, block_arity); 850 return NO; // to be sure... 851 } 852 853 context = (struct funcptr_closure_context *)malloc(sizeof(struct funcptr_closure_context)); 854 ASSERT_ALLOC(context); 855 context->rettype = rettype; 856 context->argtypes = argtypes; 857 context->argc = argc; 858 context->block = obj; 859 860 *cptr = ffi_make_closure(rettype, (const char **)argtypes, argc, funcptr_closure_handler, context); 861 862 return YES; 863} 864 865static BOOL 866rbobj_to_objcptr (VALUE obj, void** cptr, const char *octype_str) 867{ 868 if (TYPE(obj) == T_NIL) { 869 *cptr = NULL; 870 } 871 else if (TYPE(obj) == T_STRING) { 872 *cptr = RSTRING(obj)->ptr; 873 } 874 else if (TYPE(obj) == T_ARRAY) { 875 if (RARRAY(obj)->len > 0) { 876 size_t len; 877 void *ary; 878 unsigned i; 879 880 len = ocdata_size(octype_str); 881 ary = *cptr; 882 883 for (i = 0; i < RARRAY(obj)->len; i++) { 884 if (!rbobj_to_ocdata(RARRAY(obj)->ptr[i], octype_str, ary + (i * len), NO)) 885 return NO; 886 } 887 } 888 else { 889 *cptr = NULL; 890 } 891 } 892 else if (rb_obj_is_kind_of(obj, objid_s_class()) == Qtrue) { 893 *cptr = OBJCID_ID(obj); 894 } 895 else if (rb_obj_is_kind_of(obj, objcptr_s_class()) == Qtrue) { 896 *cptr = objcptr_cptr(obj); 897 } 898 else if (rb_obj_is_kind_of(obj, objboxed_s_class()) == Qtrue) { 899 struct bsBoxed *bs_boxed; 900 void *data; 901 BOOL ok; 902 903 bs_boxed = find_bs_boxed_for_klass(CLASS_OF(obj)); 904 if (bs_boxed == NULL) 905 return NO; 906 907 data = rb_bs_boxed_get_data(obj, bs_boxed->encoding, NULL, &ok, YES); 908 if (!ok) 909 return NO; 910 *cptr = data; 911 } 912 else { 913 return NO; 914 } 915 return YES; 916} 917 918static BOOL 919rbobj_to_idptr (VALUE obj, id** idptr) 920{ 921 if (TYPE(obj) == T_NIL) { 922 *idptr = nil; 923 } 924 else if (TYPE(obj) == T_ARRAY) { 925 if (RARRAY(obj)->len > 0) { 926 id *ary; 927 unsigned i; 928 929 ary = *idptr; 930 for (i = 0; i < RARRAY(obj)->len; i++) { 931 if (!rbobj_to_nsobj(RARRAY(obj)->ptr[i], &ary[i])) { 932 *idptr = nil; 933 return NO; 934 } 935 } 936 } 937 else { 938 *idptr = nil; 939 } 940 } 941 else if (rb_obj_is_kind_of(obj, objid_s_class()) == Qtrue) { 942 id old_id = OBJCID_ID(obj); 943 if (old_id) [old_id release]; 944 OBJCID_ID(obj) = nil; 945 *idptr = OBJCID_IDPTR(obj); 946 } 947 else { 948 return NO; 949 } 950 return YES; 951} 952 953BOOL 954rbobj_to_ocdata (VALUE obj, const char *octype_str, void* ocdata, BOOL to_libffi) 955{ 956 BOOL f_success = YES; 957 958#if BYTE_ORDER == BIG_ENDIAN 959 // libffi casts all types as a void pointer, which is problematic on PPC for types sized less than a void pointer (char, uchar, short, ushort, ...), as we have to shift the bytes to get the real value. 960 if (to_libffi) { 961 int delta = sizeof(void *) - ocdata_size(octype_str); 962 if (delta > 0) { 963 memset(ocdata, 0, delta); 964 ocdata += delta; 965 } 966 } 967#endif 968 969 octype_str = encoding_skip_qualifiers(octype_str); 970 971 // Make sure we convert booleans to NSNumber booleans. 972 if (*octype_str != _C_ID && *octype_str != _C_BOOL) { 973 if (TYPE(obj) == T_TRUE) { 974 obj = INT2NUM(1); 975 } 976 else if (TYPE(obj) == T_FALSE) { 977 obj = INT2NUM(0); 978 } 979 } 980 981 if (find_bs_boxed_by_encoding(octype_str) != NULL) { 982 void *data; 983 size_t size; 984 985 data = rb_bs_boxed_get_data(obj, octype_str, &size, &f_success, YES); 986 if (f_success) { 987 if (data == NULL) 988 *(void **)ocdata = NULL; 989 else 990 memcpy(ocdata, data, size); 991 return YES; 992 } 993 } 994 995 if (find_bs_cf_type_by_encoding(octype_str) != NULL) 996 octype_str = "@"; 997 998 switch (*octype_str) { 999 case _C_ID: 1000 case _C_CLASS: 1001 { 1002 id nsobj; 1003 f_success = rbobj_to_nsobj(obj, &nsobj); 1004 if (f_success) *(id*)ocdata = nsobj; 1005 break; 1006 } 1007 1008 case _C_SEL: 1009 *(SEL*)ocdata = rbobj_to_nssel(obj); 1010 break; 1011 1012 case _C_UCHR: 1013 *(unsigned char*)ocdata = (unsigned char) NUM2UINT(rb_Integer(obj)); 1014 break; 1015 1016 case _C_BOOL: 1017 { 1018 unsigned char v; 1019 1020 switch (TYPE(obj)) { 1021 case T_FALSE: 1022 case T_NIL: 1023 v = 0; 1024 break; 1025 case T_TRUE: 1026 // All other types should be converted as true, to follow the 1027 // Ruby semantics (where for example any integer is always true, 1028 // even 0). 1029 default: 1030 v = 1; 1031 break; 1032 } 1033 *(unsigned char*)ocdata = v; 1034 } 1035 break; 1036 1037 case _C_CHR: 1038 *(char*)ocdata = (char) NUM2INT(rb_Integer(obj)); 1039 break; 1040 1041 case _C_SHT: 1042 *(short*)ocdata = (short) NUM2INT(rb_Integer(obj)); 1043 break; 1044 1045 case _C_USHT: 1046 *(unsigned short*)ocdata = (unsigned short) NUM2UINT(rb_Integer(obj)); 1047 break; 1048 1049 case _C_INT: 1050 *(int*)ocdata = (int) NUM2INT(rb_Integer(obj)); 1051 break; 1052 1053 case _C_UINT: 1054 *(unsigned int*)ocdata = (unsigned int) NUM2UINT(rb_Integer(obj)); 1055 break; 1056 1057 case _C_LNG: 1058 *(long*)ocdata = (long) NUM2LONG(rb_Integer(obj)); 1059 break; 1060 1061 case _C_ULNG: 1062 *(unsigned long*)ocdata = (unsigned long) NUM2ULONG(rb_Integer(obj)); 1063 break; 1064 1065#if HAVE_LONG_LONG 1066 case _C_LNG_LNG: 1067 *(long long*)ocdata = (long long) NUM2LL(rb_Integer(obj)); 1068 break; 1069 1070 case _C_ULNG_LNG: 1071 *(unsigned long long*)ocdata = (unsigned long long) NUM2ULL(rb_Integer(obj)); 1072 break; 1073#endif 1074 1075 case _C_FLT: 1076 *(float*)ocdata = (float) RFLOAT(rb_Float(obj))->value; 1077 break; 1078 1079 case _C_DBL: 1080 *(double*)ocdata = RFLOAT(rb_Float(obj))->value; 1081 break; 1082 1083 case _C_CHARPTR: 1084 { 1085 VALUE str = rb_obj_as_string(obj); 1086 *(char**)ocdata = StringValuePtr(str); 1087 } 1088 break; 1089 1090 case _C_PTR: 1091 if (is_id_ptr(octype_str)) { 1092 f_success = rbobj_to_idptr(obj, ocdata); 1093 } 1094 else { 1095 f_success = rbobj_to_objcptr(obj, ocdata, octype_str + 1); 1096 if (!f_success) 1097 f_success = rbobj_to_funcptr(obj, ocdata, octype_str + 1); 1098 } 1099 break; 1100 1101 case _C_ARY_B: 1102 f_success = rbobj_to_cary(obj, ocdata, octype_str); 1103 break; 1104 1105 default: 1106 f_success = NO; 1107 break; 1108 } 1109 1110 return f_success; 1111} 1112 1113static 1114NSStringEncoding kcode_to_nsencoding (const char* kcode) 1115{ 1116 if (strcmp(kcode, "UTF8") == 0) 1117 return NSUTF8StringEncoding; 1118 else if (strcmp(kcode, "SJIS") == 0) 1119 return CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingMacJapanese); 1120 else if (strcmp(kcode, "EUC") == 0) 1121 return NSJapaneseEUCStringEncoding; 1122 else // "NONE" 1123 return NSUTF8StringEncoding; 1124} 1125#define KCODE_NSSTRENCODING kcode_to_nsencoding(rb_get_kcode()) 1126 1127id 1128rbstr_to_ocstr(VALUE obj) 1129{ 1130 return [[[NSMutableString alloc] initWithData:[NSData dataWithBytes:RSTRING(obj)->ptr 1131 length: RSTRING(obj)->len] 1132 encoding:KCODE_NSSTRENCODING] autorelease]; 1133} 1134 1135VALUE 1136ocstr_to_rbstr(id ocstr) 1137{ 1138 NSData * data = [(NSString *)ocstr dataUsingEncoding:KCODE_NSSTRENCODING 1139 allowLossyConversion:YES]; 1140 return rb_str_new ([data bytes], [data length]); 1141} 1142 1143static void 1144__decode_method_encoding_with_method_signature(NSMethodSignature *methodSignature, unsigned *argc, char **retval_type, char ***arg_types, BOOL strip_first_two_args) 1145{ 1146 *argc = [methodSignature numberOfArguments]; 1147 if (strip_first_two_args) 1148 *argc -= 2; 1149 *retval_type = strdup([methodSignature methodReturnType]); 1150 if (*argc > 0) { 1151 unsigned i; 1152 char **l_arg_types; 1153 l_arg_types = (char **)malloc(sizeof(char *) * *argc); 1154 for (i = 0; i < *argc; i++) 1155 l_arg_types[i] = strdup([methodSignature getArgumentTypeAtIndex:i + (strip_first_two_args ? 2 : 0)]); 1156 *arg_types = l_arg_types; 1157 } 1158 else { 1159 *arg_types = NULL; 1160 } 1161} 1162 1163static inline const char * 1164__iterate_until(const char *type, char end) 1165{ 1166 char begin; 1167 unsigned nested; 1168 1169 begin = *type; 1170 nested = 0; 1171 1172 do { 1173 type++; 1174 if (*type == begin) { 1175 nested++; 1176 } 1177 else if (*type == end) { 1178 if (nested == 0) 1179 return type; 1180 nested--; 1181 } 1182 } 1183 while (YES); 1184 1185 return NULL; 1186} 1187 1188BOOL 1189is_id_ptr (const char *type) 1190{ 1191 if (*type != _C_PTR) 1192 return NO; 1193 1194 type++; 1195 type = encoding_skip_to_first_type(type); 1196 1197 return *type == _C_ID; 1198} 1199 1200BOOL 1201is_boxed_ptr (const char *type, struct bsBoxed **boxed) 1202{ 1203 struct bsBoxed *b; 1204 1205 if (*type != _C_PTR) 1206 return NO; 1207 1208 type++; 1209 1210 b = find_bs_boxed_by_encoding(type); 1211 if (b != NULL) { 1212 if (boxed != NULL) 1213 *boxed = b; 1214 return YES; 1215 } 1216 1217 return NO; 1218} 1219 1220const char * 1221encoding_skip_to_first_type(const char *type) 1222{ 1223 while (YES) { 1224 switch (*type) { 1225 case _C_CONST: 1226 case _C_PTR: 1227 case 'O': // bycopy 1228 case 'n': // in 1229 case 'o': // out 1230 case 'N': // inout 1231 case 'V': // oneway 1232 type++; 1233 break; 1234 1235 default: 1236 return type; 1237 } 1238 } 1239 return NULL; 1240} 1241 1242const char * 1243encoding_skip_qualifiers(const char *type) 1244{ 1245 while (YES) { 1246 switch (*type) { 1247 case _C_CONST: 1248 case 'O': // bycopy 1249 case 'n': // in 1250 case 'o': // out 1251 case 'N': // inout 1252 case 'V': // oneway 1253 type++; 1254 break; 1255 1256 default: 1257 return type; 1258 } 1259 } 1260 return NULL; 1261} 1262 1263static const char * 1264__get_first_encoding(const char *type, char *buf, size_t buf_len) 1265{ 1266 const char *orig_type; 1267 const char *p; 1268 1269 orig_type = type; 1270 1271 type = encoding_skip_to_first_type(type); 1272 1273 switch (*type) { 1274 case '\0': 1275 return NULL; 1276 case _C_ARY_B: 1277 type = __iterate_until(type, _C_ARY_E); 1278 break; 1279 case _C_STRUCT_B: 1280 type = __iterate_until(type, _C_STRUCT_E); 1281 break; 1282 case _C_UNION_B: 1283 type = __iterate_until(type, _C_UNION_E); 1284 break; 1285 } 1286 1287 type++; 1288 p = type; 1289 while (*p >= '0' && *p <= '9') { p++; } 1290 1291 if (buf != NULL) { 1292 size_t len = (long)(type - orig_type); 1293 assert(len < buf_len); 1294 strncpy(buf, orig_type, len); 1295 buf[len] = '\0'; 1296 } 1297 1298 return p; 1299} 1300 1301// 10.4 or lower, use NSMethodSignature. 1302// Otherwise, use the Objective-C runtime API, which is faster and more reliable with structures encoding. 1303void 1304decode_method_encoding(const char *encoding, NSMethodSignature *methodSignature, unsigned *argc, char **retval_type, char ***arg_types, BOOL strip_first_two_args) 1305{ 1306 assert(encoding != NULL || methodSignature != nil); 1307 1308 if (encoding == NULL) { 1309 DATACONV_LOG("decoding method encoding using method signature %p", methodSignature); 1310 __decode_method_encoding_with_method_signature(methodSignature, argc, retval_type, arg_types, strip_first_two_args); 1311 } 1312 else { 1313 char buf[1024]; 1314 1315 DATACONV_LOG("decoding method encoding '%s' manually", encoding); 1316 encoding = __get_first_encoding(encoding, buf, sizeof buf); 1317 DATACONV_LOG("retval -> %s", buf); 1318 *retval_type = strdup(buf); 1319 if (strip_first_two_args) { 1320 DATACONV_LOG("skipping first two args"); 1321 encoding = __get_first_encoding(encoding, NULL, 0); 1322 encoding = __get_first_encoding(encoding, NULL, 0); 1323 } 1324 *argc = 0; 1325 // Do a first pass to know the argc 1326 if (encoding != NULL) { 1327 const char *p = encoding; 1328 while ((p = __get_first_encoding(p, NULL, 0)) != NULL) { (*argc)++; } 1329 } 1330 DATACONV_LOG("argc -> %d", *argc); 1331 if (*argc > 0) { 1332 unsigned i; 1333 char **p; 1334 i = 0; 1335 p = (char **)malloc(sizeof(char *) * (*argc)); 1336 while ((encoding = __get_first_encoding(encoding, buf, sizeof buf)) != NULL) { 1337 DATACONV_LOG("arg[%d] -> %s", i, buf); 1338 p[i++] = strdup(buf); 1339 } 1340 *arg_types = p; 1341 } 1342 else { 1343 *arg_types = NULL; 1344 } 1345 } 1346} 1347 1348void 1349set_octypes_for_format_str (char **octypes, unsigned len, char *format_str) 1350{ 1351 unsigned i, j, format_str_len; 1352 1353 // We cannot display this log because the given `format_str' format string will be evaluated within 1354 // the output message. Fortunately, Ruby format string APIs do not do that. 1355 //DATACONV_LOG("decoding format string `%s' types for %d argument(s)", format_str, len); 1356 1357 format_str_len = strlen(format_str); 1358 i = j = 0; 1359 1360 while (i < format_str_len) { 1361 if (format_str[i++] != '%') 1362 continue; 1363 if (i < format_str_len && format_str[i] == '%') { 1364 i++; 1365 continue; 1366 } 1367 while (i < format_str_len) { 1368 char *type = NULL; 1369 switch (format_str[i++]) { 1370 case 'd': 1371 case 'i': 1372 case 'o': 1373 case 'u': 1374 case 'x': 1375 case 'X': 1376 case 'c': 1377 case 'C': 1378 type = "i"; // _C_INT; 1379 break; 1380 1381 case 'D': 1382 case 'O': 1383 case 'U': 1384 type = "l"; // _C_LNG; 1385 break; 1386 1387 case 'f': 1388 case 'F': 1389 case 'e': 1390 case 'E': 1391 case 'g': 1392 case 'G': 1393 case 'a': 1394 case 'A': 1395 type = "d"; // _C_DBL; 1396 break; 1397 1398 case 's': 1399 case 'S': 1400 type = "*"; // _C_CHARPTR; 1401 break; 1402 1403 case 'p': 1404 type = "^"; // _C_PTR; 1405 break; 1406 1407 case '@': 1408 type = "@"; // _C_ID; 1409 break; 1410 } 1411 1412 if (type != NULL) { 1413 DATACONV_LOG("found format string token #%d of type '%s'", j, type); 1414 1415 if (len == 0 || j >= len) 1416 rb_raise(rb_eArgError, "Too much tokens in the format string `%s' for the given %d argument(s)", format_str, len); 1417 1418 octypes[j++] = type; 1419 1420 break; 1421 } 1422 } 1423 } 1424 for (; j < len; j++) 1425 octypes[j] = "@"; // _C_ID; 1426} 1427